@adobe/alloy 2.30.1-beta.9 → 2.31.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (241) hide show
  1. package/libEs5/components/Advertising/createComponent.js +7 -3
  2. package/libEs5/components/Advertising/handlers/onBeforeSendEventHandler.js +8 -2
  3. package/libEs5/components/Advertising/handlers/sendAdConversion.js +11 -6
  4. package/libEs5/components/Advertising/handlers/viewThroughHandler.js +8 -2
  5. package/libEs5/components/Advertising/identities/collectSurferId.js +8 -1
  6. package/libEs5/components/Advertising/index.js +2 -1
  7. package/libEs5/components/BrandConcierge/configValidators.js +25 -0
  8. package/libEs5/components/BrandConcierge/constants.js +16 -0
  9. package/libEs5/components/BrandConcierge/createBuildEndpointUrl.js +33 -0
  10. package/libEs5/components/BrandConcierge/createConversationServiceRequest.js +35 -0
  11. package/libEs5/components/BrandConcierge/createSendConversationEvent.js +148 -0
  12. package/libEs5/components/BrandConcierge/createSendConversationServiceRequest.js +85 -0
  13. package/libEs5/components/BrandConcierge/createStreamParser.js +131 -0
  14. package/libEs5/components/BrandConcierge/createTimeoutWrapper.js +79 -0
  15. package/libEs5/components/BrandConcierge/index.js +102 -0
  16. package/libEs5/components/BrandConcierge/utils.js +33 -0
  17. package/libEs5/components/BrandConcierge/validateMessage.js +44 -0
  18. package/libEs5/components/Consent/types.js +12 -0
  19. package/libEs5/components/Context/createComponent.js +1 -2
  20. package/libEs5/components/Context/implementationDetails.js +7 -9
  21. package/libEs5/components/Context/index.js +4 -1
  22. package/libEs5/components/Context/injectDevice.js +2 -2
  23. package/libEs5/components/Context/injectEnvironment.js +2 -2
  24. package/libEs5/components/Context/injectHighEntropyUserAgentHints.js +2 -2
  25. package/libEs5/components/Context/injectOneTimeAnalyticsReferrer.js +52 -0
  26. package/libEs5/components/Context/injectPlaceContext.js +2 -2
  27. package/libEs5/components/Context/injectTimestamp.js +2 -3
  28. package/libEs5/components/Context/injectWeb.js +9 -11
  29. package/libEs5/components/EventMerge/createEventMergeId.js +1 -1
  30. package/libEs5/components/Personalization/createComponent.js +3 -1
  31. package/libEs5/components/Personalization/createFetchDataHandler.js +10 -4
  32. package/libEs5/components/Personalization/createNotificationHandler.js +5 -3
  33. package/libEs5/components/Personalization/createOnDecisionHandler.js +4 -3
  34. package/libEs5/components/Personalization/createPersonalizationDetails.js +1 -1
  35. package/libEs5/components/Personalization/dom-actions/initDomActionsModules.js +1 -1
  36. package/libEs5/components/Personalization/dom-actions/remapHeadOffers.js +5 -0
  37. package/libEs5/components/Personalization/handlers/createProcessInAppMessage.js +2 -1
  38. package/libEs5/components/Personalization/handlers/createProcessRedirect.js +2 -1
  39. package/libEs5/components/Personalization/handlers/injectCreateProposition.js +4 -1
  40. package/libEs5/components/Personalization/in-app-message-actions/actions/displayIframeContent.js +4 -2
  41. package/libEs5/components/Personalization/index.js +2 -2
  42. package/libEs5/components/PushNotifications/types.js +12 -0
  43. package/libEs5/components/RulesEngine/createApplyResponse.js +3 -1
  44. package/libEs5/components/RulesEngine/types.js +12 -0
  45. package/libEs5/components/StreamingMedia/createMediaEventManager.js +1 -1
  46. package/libEs5/constants/libraryVersion.js +1 -1
  47. package/libEs5/constants/surface.js +19 -0
  48. package/libEs5/core/componentCreators.js +8 -1
  49. package/libEs5/core/consent/types.js +12 -0
  50. package/libEs5/core/createEvent.js +7 -0
  51. package/libEs5/core/edgeNetwork/injectSendEdgeNetworkRequest.js +23 -0
  52. package/libEs5/core/edgeNetwork/types.js +12 -0
  53. package/libEs5/core/identity/types.js +12 -0
  54. package/libEs5/core/index.js +5 -1
  55. package/libEs5/core/types.js +12 -0
  56. package/libEs5/utils/clamp.js +25 -0
  57. package/libEs5/utils/createCollect.js +4 -2
  58. package/libEs5/utils/deepAssign.js +5 -0
  59. package/libEs5/utils/dom/createGetPageLocation.js +20 -0
  60. package/libEs5/utils/filterObject.js +1 -1
  61. package/libEs5/utils/index.js +8 -1
  62. package/libEs5/utils/prepareConfigOverridesForEdge.js +4 -2
  63. package/libEs5/utils/request/createDataCollectionRequestPayload.js +3 -0
  64. package/libEs5/utils/request/createRequest.js +5 -1
  65. package/libEs5/utils/request/createRequestParams.js +1 -0
  66. package/libEs5/utils/request/createRequestPayload.js +11 -1
  67. package/libEs5/utils/request/types.js +13 -0
  68. package/libEs5/utils/surfaceUtils.js +82 -0
  69. package/libEs5/utils/types.js +12 -0
  70. package/libEs6/components/Advertising/createComponent.js +7 -3
  71. package/libEs6/components/Advertising/handlers/onBeforeSendEventHandler.js +8 -2
  72. package/libEs6/components/Advertising/handlers/sendAdConversion.js +11 -6
  73. package/libEs6/components/Advertising/handlers/viewThroughHandler.js +8 -2
  74. package/libEs6/components/Advertising/identities/collectSurferId.js +8 -1
  75. package/libEs6/components/Advertising/index.js +2 -1
  76. package/libEs6/components/BrandConcierge/configValidators.js +22 -0
  77. package/libEs6/components/BrandConcierge/constants.js +13 -0
  78. package/libEs6/components/BrandConcierge/createBuildEndpointUrl.js +30 -0
  79. package/libEs6/components/BrandConcierge/createConversationServiceRequest.js +31 -0
  80. package/libEs6/components/BrandConcierge/createSendConversationEvent.js +144 -0
  81. package/libEs6/components/BrandConcierge/createSendConversationServiceRequest.js +81 -0
  82. package/libEs6/components/BrandConcierge/createStreamParser.js +127 -0
  83. package/libEs6/components/BrandConcierge/createTimeoutWrapper.js +76 -0
  84. package/libEs6/components/BrandConcierge/index.js +98 -0
  85. package/libEs6/components/BrandConcierge/utils.js +27 -0
  86. package/libEs6/components/BrandConcierge/validateMessage.js +40 -0
  87. package/libEs6/components/Consent/types.js +12 -0
  88. package/libEs6/components/Context/createComponent.js +1 -2
  89. package/libEs6/components/Context/implementationDetails.js +7 -9
  90. package/libEs6/components/Context/index.js +4 -1
  91. package/libEs6/components/Context/injectDevice.js +3 -3
  92. package/libEs6/components/Context/injectEnvironment.js +3 -3
  93. package/libEs6/components/Context/injectHighEntropyUserAgentHints.js +3 -3
  94. package/libEs6/components/Context/injectOneTimeAnalyticsReferrer.js +48 -0
  95. package/libEs6/components/Context/injectPlaceContext.js +3 -3
  96. package/libEs6/components/Context/injectTimestamp.js +2 -3
  97. package/libEs6/components/Context/injectWeb.js +9 -11
  98. package/libEs6/components/EventMerge/createEventMergeId.js +1 -1
  99. package/libEs6/components/Personalization/createComponent.js +3 -1
  100. package/libEs6/components/Personalization/createFetchDataHandler.js +10 -4
  101. package/libEs6/components/Personalization/createNotificationHandler.js +5 -3
  102. package/libEs6/components/Personalization/createOnDecisionHandler.js +4 -3
  103. package/libEs6/components/Personalization/createPersonalizationDetails.js +1 -1
  104. package/libEs6/components/Personalization/dom-actions/initDomActionsModules.js +1 -1
  105. package/libEs6/components/Personalization/dom-actions/remapHeadOffers.js +6 -1
  106. package/libEs6/components/Personalization/handlers/createProcessInAppMessage.js +2 -1
  107. package/libEs6/components/Personalization/handlers/createProcessRedirect.js +2 -1
  108. package/libEs6/components/Personalization/handlers/injectCreateProposition.js +4 -1
  109. package/libEs6/components/Personalization/in-app-message-actions/actions/displayIframeContent.js +4 -2
  110. package/libEs6/components/Personalization/index.js +2 -2
  111. package/libEs6/components/PushNotifications/types.js +12 -0
  112. package/libEs6/components/RulesEngine/createApplyResponse.js +3 -1
  113. package/libEs6/components/RulesEngine/types.js +12 -0
  114. package/libEs6/components/StreamingMedia/createMediaEventManager.js +1 -1
  115. package/libEs6/constants/libraryVersion.js +1 -1
  116. package/libEs6/constants/surface.js +16 -0
  117. package/libEs6/core/componentCreators.js +2 -1
  118. package/libEs6/core/consent/types.js +12 -0
  119. package/libEs6/core/createEvent.js +7 -0
  120. package/libEs6/core/edgeNetwork/injectSendEdgeNetworkRequest.js +23 -0
  121. package/libEs6/core/edgeNetwork/types.js +12 -0
  122. package/libEs6/core/identity/types.js +12 -0
  123. package/libEs6/core/index.js +5 -1
  124. package/libEs6/core/types.js +12 -0
  125. package/libEs6/utils/clamp.js +22 -0
  126. package/libEs6/utils/createCollect.js +4 -2
  127. package/libEs6/utils/deepAssign.js +6 -0
  128. package/libEs6/utils/dom/createGetPageLocation.js +17 -0
  129. package/libEs6/utils/filterObject.js +1 -1
  130. package/libEs6/utils/index.js +2 -1
  131. package/libEs6/utils/prepareConfigOverridesForEdge.js +4 -2
  132. package/libEs6/utils/request/createDataCollectionRequestPayload.js +3 -0
  133. package/libEs6/utils/request/createRequest.js +5 -1
  134. package/libEs6/utils/request/createRequestParams.js +1 -0
  135. package/libEs6/utils/request/createRequestPayload.js +11 -1
  136. package/libEs6/utils/request/types.js +13 -0
  137. package/libEs6/utils/surfaceUtils.js +76 -0
  138. package/libEs6/utils/types.js +12 -0
  139. package/package.json +32 -36
  140. package/scripts/helpers/path.js +12 -0
  141. package/scripts/helpers/versionBabelPlugin.js +12 -0
  142. package/types/components/Advertising/createComponent.d.ts +3 -2
  143. package/types/components/Advertising/createComponent.d.ts.map +1 -1
  144. package/types/components/Advertising/handlers/onBeforeSendEventHandler.d.ts.map +1 -1
  145. package/types/components/Advertising/handlers/sendAdConversion.d.ts +2 -1
  146. package/types/components/Advertising/handlers/sendAdConversion.d.ts.map +1 -1
  147. package/types/components/Advertising/handlers/viewThroughHandler.d.ts.map +1 -1
  148. package/types/components/Advertising/identities/collectSurferId.d.ts.map +1 -1
  149. package/types/components/Advertising/index.d.ts +1 -1
  150. package/types/components/Advertising/index.d.ts.map +1 -1
  151. package/types/components/BrandConcierge/configValidators.d.ts +3 -0
  152. package/types/components/BrandConcierge/configValidators.d.ts.map +1 -0
  153. package/types/components/BrandConcierge/constants.d.ts +3 -0
  154. package/types/components/BrandConcierge/constants.d.ts.map +1 -0
  155. package/types/components/BrandConcierge/createBuildEndpointUrl.d.ts +9 -0
  156. package/types/components/BrandConcierge/createBuildEndpointUrl.d.ts.map +1 -0
  157. package/types/components/BrandConcierge/createConversationServiceRequest.d.ts +7 -0
  158. package/types/components/BrandConcierge/createConversationServiceRequest.d.ts.map +1 -0
  159. package/types/components/BrandConcierge/createSendConversationEvent.d.ts +15 -0
  160. package/types/components/BrandConcierge/createSendConversationEvent.d.ts.map +1 -0
  161. package/types/components/BrandConcierge/createSendConversationServiceRequest.d.ts +11 -0
  162. package/types/components/BrandConcierge/createSendConversationServiceRequest.d.ts.map +1 -0
  163. package/types/components/BrandConcierge/createStreamParser.d.ts +7 -0
  164. package/types/components/BrandConcierge/createStreamParser.d.ts.map +1 -0
  165. package/types/components/BrandConcierge/createTimeoutWrapper.d.ts +6 -0
  166. package/types/components/BrandConcierge/createTimeoutWrapper.d.ts.map +1 -0
  167. package/types/components/BrandConcierge/index.d.ts +32 -0
  168. package/types/components/BrandConcierge/index.d.ts.map +1 -0
  169. package/types/components/BrandConcierge/utils.d.ts +6 -0
  170. package/types/components/BrandConcierge/utils.d.ts.map +1 -0
  171. package/types/components/BrandConcierge/validateMessage.d.ts +5 -0
  172. package/types/components/BrandConcierge/validateMessage.d.ts.map +1 -0
  173. package/types/components/Consent/types.d.ts.map +1 -1
  174. package/types/components/Context/createComponent.d.ts +1 -1
  175. package/types/components/Context/createComponent.d.ts.map +1 -1
  176. package/types/components/Context/implementationDetails.d.ts +1 -1
  177. package/types/components/Context/implementationDetails.d.ts.map +1 -1
  178. package/types/components/Context/index.d.ts +1 -1
  179. package/types/components/Context/index.d.ts.map +1 -1
  180. package/types/components/Context/injectDevice.d.ts +1 -1
  181. package/types/components/Context/injectDevice.d.ts.map +1 -1
  182. package/types/components/Context/injectEnvironment.d.ts +1 -1
  183. package/types/components/Context/injectEnvironment.d.ts.map +1 -1
  184. package/types/components/Context/injectHighEntropyUserAgentHints.d.ts +1 -1
  185. package/types/components/Context/injectHighEntropyUserAgentHints.d.ts.map +1 -1
  186. package/types/components/Context/injectOneTimeAnalyticsReferrer.d.ts +3 -0
  187. package/types/components/Context/injectOneTimeAnalyticsReferrer.d.ts.map +1 -0
  188. package/types/components/Context/injectPlaceContext.d.ts +1 -1
  189. package/types/components/Context/injectPlaceContext.d.ts.map +1 -1
  190. package/types/components/Context/injectTimestamp.d.ts +1 -1
  191. package/types/components/Context/injectTimestamp.d.ts.map +1 -1
  192. package/types/components/Context/injectWeb.d.ts +1 -1
  193. package/types/components/Context/injectWeb.d.ts.map +1 -1
  194. package/types/components/Personalization/createComponent.d.ts.map +1 -1
  195. package/types/components/Personalization/createFetchDataHandler.d.ts +2 -1
  196. package/types/components/Personalization/createFetchDataHandler.d.ts.map +1 -1
  197. package/types/components/Personalization/createNotificationHandler.d.ts +1 -1
  198. package/types/components/Personalization/createNotificationHandler.d.ts.map +1 -1
  199. package/types/components/Personalization/createOnDecisionHandler.d.ts +2 -1
  200. package/types/components/Personalization/createOnDecisionHandler.d.ts.map +1 -1
  201. package/types/components/Personalization/createPersonalizationDetails.d.ts.map +1 -1
  202. package/types/components/Personalization/dom-actions/remapHeadOffers.d.ts.map +1 -1
  203. package/types/components/Personalization/handlers/createProcessInAppMessage.d.ts.map +1 -1
  204. package/types/components/Personalization/handlers/createProcessRedirect.d.ts.map +1 -1
  205. package/types/components/Personalization/handlers/injectCreateProposition.d.ts +2 -1
  206. package/types/components/Personalization/handlers/injectCreateProposition.d.ts.map +1 -1
  207. package/types/components/Personalization/in-app-message-actions/actions/displayIframeContent.d.ts.map +1 -1
  208. package/types/components/Personalization/index.d.ts.map +1 -1
  209. package/types/components/PushNotifications/types.d.ts.map +1 -1
  210. package/types/components/RulesEngine/createApplyResponse.d.ts.map +1 -1
  211. package/types/components/RulesEngine/index.d.ts.map +1 -1
  212. package/types/components/RulesEngine/types.d.ts.map +1 -1
  213. package/types/constants/surface.d.ts +5 -0
  214. package/types/constants/surface.d.ts.map +1 -0
  215. package/types/core/componentCreators.d.ts +1 -0
  216. package/types/core/consent/types.d.ts.map +1 -1
  217. package/types/core/createEvent.d.ts +2 -0
  218. package/types/core/createEvent.d.ts.map +1 -1
  219. package/types/core/edgeNetwork/injectSendEdgeNetworkRequest.d.ts.map +1 -1
  220. package/types/core/edgeNetwork/types.d.ts.map +1 -1
  221. package/types/core/identity/types.d.ts.map +1 -1
  222. package/types/core/index.d.ts.map +1 -1
  223. package/types/core/types.d.ts.map +1 -1
  224. package/types/utils/clamp.d.ts +3 -0
  225. package/types/utils/clamp.d.ts.map +1 -0
  226. package/types/utils/createCollect.d.ts +2 -1
  227. package/types/utils/createCollect.d.ts.map +1 -1
  228. package/types/utils/deepAssign.d.ts.map +1 -1
  229. package/types/utils/dom/createGetPageLocation.d.ts +5 -0
  230. package/types/utils/dom/createGetPageLocation.d.ts.map +1 -0
  231. package/types/utils/index.d.ts +1 -0
  232. package/types/utils/prepareConfigOverridesForEdge.d.ts.map +1 -1
  233. package/types/utils/request/createDataCollectionRequestPayload.d.ts.map +1 -1
  234. package/types/utils/request/createRequest.d.ts.map +1 -1
  235. package/types/utils/request/createRequestParams.d.ts.map +1 -1
  236. package/types/utils/request/createRequestPayload.d.ts.map +1 -1
  237. package/types/utils/request/types.d.ts +2 -0
  238. package/types/utils/request/types.d.ts.map +1 -1
  239. package/types/utils/surfaceUtils.d.ts +4 -0
  240. package/types/utils/surfaceUtils.d.ts.map +1 -0
  241. package/types/utils/types.d.ts.map +1 -1
@@ -18,7 +18,8 @@ export default ({
18
18
  eventManager,
19
19
  cookieManager,
20
20
  adConversionHandler,
21
- getBrowser
21
+ getBrowser,
22
+ consent
22
23
  }) => {
23
24
  const componentConfig = config.advertising;
24
25
  const sendAdConversionHandler = createSendAdConversion({
@@ -27,12 +28,15 @@ export default ({
27
28
  adConversionHandler,
28
29
  logger,
29
30
  componentConfig,
30
- getBrowser
31
+ getBrowser,
32
+ consent
31
33
  });
32
34
  return {
33
35
  lifecycle: {
34
36
  onComponentsRegistered() {
35
- return sendAdConversionHandler();
37
+ // Fire-and-forget: don't return the promise so we don't block
38
+ // the configure command from resolving while waiting for consent.
39
+ sendAdConversionHandler();
36
40
  },
37
41
  onBeforeEvent: ({
38
42
  event,
@@ -1,7 +1,13 @@
1
1
  /*
2
2
  Copyright 2023 Adobe. All rights reserved.
3
- Licensed under the Apache License, Version 2.0.
4
- http://www.apache.org/licenses/LICENSE-2.0
3
+ This file is licensed to you under the Apache License, Version 2.0 (the "License");
4
+ you may not use this file except in compliance with the License. You may obtain a copy
5
+ of the License at http://www.apache.org/licenses/LICENSE-2.0
6
+
7
+ Unless required by applicable law or agreed to in writing, software distributed under
8
+ the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR REPRESENTATIONS
9
+ OF ANY KIND, either express or implied. See the License for the specific language
10
+ governing permissions and limitations under the License.
5
11
  */
6
12
 
7
13
  import collectSurferId from "../identities/collectSurferId.js";
@@ -25,16 +25,21 @@ export default ({
25
25
  adConversionHandler,
26
26
  logger,
27
27
  componentConfig,
28
- getBrowser
28
+ getBrowser,
29
+ consent
29
30
  }) => {
30
31
  const activeAdvertiserIds = componentConfig?.advertiserSettings ? normalizeAdvertiser(componentConfig.advertiserSettings) : "";
31
32
  return async () => {
32
- const {
33
- skwcid,
34
- efid
35
- } = getUrlParams();
36
- const isClickThru = !!(skwcid || efid);
37
33
  try {
34
+ // Wait for consent before any ad conversion processing.
35
+ // This ensures no advertising cookies are set without user consent.
36
+ // If consent is declined, awaitConsent() rejects and we exit gracefully.
37
+ await consent.awaitConsent();
38
+ const {
39
+ skwcid,
40
+ efid
41
+ } = getUrlParams();
42
+ const isClickThru = !!(skwcid || efid);
38
43
  if (isClickThru) {
39
44
  // wait for click through to complete
40
45
  return handleClickThrough({
@@ -1,7 +1,13 @@
1
1
  /*
2
2
  Copyright 2025 Adobe. All rights reserved.
3
- Licensed under the Apache License, Version 2.0.
4
- http://www.apache.org/licenses/LICENSE-2.0
3
+ This file is licensed to you under the Apache License, Version 2.0 (the "License");
4
+ you may not use this file except in compliance with the License. You may obtain a copy
5
+ of the License at http://www.apache.org/licenses/LICENSE-2.0
6
+
7
+ Unless required by applicable law or agreed to in writing, software distributed under
8
+ the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR REPRESENTATIONS
9
+ OF ANY KIND, either express or implied. See the License for the specific language
10
+ governing permissions and limitations under the License.
5
11
  */
6
12
 
7
13
  import collectAllIdentities from "../identities/collectAllIdentities.js";
@@ -1,6 +1,13 @@
1
1
  /*
2
2
  Copyright 2025 Adobe. All rights reserved.
3
- This file is licensed under the Apache License, Version 2.0.
3
+ This file is licensed to you under the Apache License, Version 2.0 (the "License");
4
+ you may not use this file except in compliance with the License. You may obtain a copy
5
+ of the License at http://www.apache.org/licenses/LICENSE-2.0
6
+
7
+ Unless required by applicable law or agreed to in writing, software distributed under
8
+ the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR REPRESENTATIONS
9
+ OF ANY KIND, either express or implied. See the License for the specific language
10
+ governing permissions and limitations under the License.
4
11
  */
5
12
 
6
13
  import { DISPLAY_CLICK_COOKIE_KEY, SURFER_ID, SURFER_PIXEL_HOST, SURFER_USER_ID, SURFER_TIMEOUT_MS, SURFER_TRUSTED_ORIGIN, SURFER_PARAM_KEY, DISPLAY_CLICK_COOKIE_KEY_EXPIRES } from "../constants/index.js";
@@ -41,7 +41,8 @@ const createAdvertising = ({
41
41
  eventManager,
42
42
  cookieManager,
43
43
  adConversionHandler,
44
- getBrowser
44
+ getBrowser,
45
+ consent
45
46
  });
46
47
  };
47
48
  createAdvertising.namespace = "Advertising";
@@ -0,0 +1,22 @@
1
+ /*
2
+ Copyright 2026 Adobe. All rights reserved.
3
+ This file is licensed to you under the Apache License, Version 2.0 (the "License");
4
+ you may not use this file except in compliance with the License. You may obtain a copy
5
+ of the License at http://www.apache.org/licenses/LICENSE-2.0
6
+
7
+ Unless required by applicable law or agreed to in writing, software distributed under
8
+ the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR REPRESENTATIONS
9
+ OF ANY KIND, either express or implied. See the License for the specific language
10
+ governing permissions and limitations under the License.
11
+ */
12
+ import { STREAM_START_TIMEOUT_MS } from "./constants.js";
13
+ import { number, objectOf, boolean } from "../../utils/validation/index.js";
14
+ export default objectOf({
15
+ conversation: objectOf({
16
+ stickyConversationSession: boolean().default(false),
17
+ streamTimeout: number().integer().minimum(STREAM_START_TIMEOUT_MS).default(STREAM_START_TIMEOUT_MS)
18
+ }).default({
19
+ stickyConversationSession: false,
20
+ streamTimeout: STREAM_START_TIMEOUT_MS
21
+ })
22
+ });
@@ -0,0 +1,13 @@
1
+ /*
2
+ Copyright 2025 Adobe. All rights reserved.
3
+ This file is licensed to you under the Apache License, Version 2.0 (the "License");
4
+ you may not use this file except in compliance with the License. You may obtain a copy
5
+ of the License at http://www.apache.org/licenses/LICENSE-2.0
6
+
7
+ Unless required by applicable law or agreed to in writing, software distributed under
8
+ the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR REPRESENTATIONS
9
+ OF ANY KIND, either express or implied. See the License for the specific language
10
+ governing permissions and limitations under the License.
11
+ */
12
+ export const BC_SESSION_COOKIE_NAME = "bc_session_id";
13
+ export const STREAM_START_TIMEOUT_MS = 10000;
@@ -0,0 +1,30 @@
1
+ /*
2
+ Copyright 2025 Adobe. All rights reserved.
3
+ This file is licensed to you under the Apache License, Version 2.0 (the "License");
4
+ you may not use this file except in compliance with the License. You may obtain a copy
5
+ of the License at http://www.apache.org/licenses/LICENSE-2.0
6
+
7
+ Unless required by applicable law or agreed to in writing, software distributed under
8
+ the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR REPRESENTATIONS
9
+ OF ANY KIND, either express or implied. See the License for the specific language
10
+ governing permissions and limitations under the License.
11
+ */
12
+
13
+ export default ({
14
+ queryString
15
+ }) => {
16
+ return ({
17
+ edgeDomain,
18
+ request,
19
+ datastreamId
20
+ }) => {
21
+ const params = request.getRequestParams();
22
+ const configId = request.getDatastreamIdOverride() || datastreamId;
23
+ params.requestId = request.getId();
24
+ params.configId = configId;
25
+ const stringifiedRequestParams = queryString.stringify({
26
+ ...params
27
+ });
28
+ return `https://${edgeDomain}${request.getEdgeSubPath()}/${request.getAction()}?${stringifiedRequestParams}`;
29
+ };
30
+ };
@@ -0,0 +1,31 @@
1
+ /*
2
+ Copyright 2023 Adobe. All rights reserved.
3
+ This file is licensed to you under the Apache License, Version 2.0 (the "License");
4
+ you may not use this file except in compliance with the License. You may obtain a copy
5
+ of the License at http://www.apache.org/licenses/LICENSE-2.0
6
+
7
+ Unless required by applicable law or agreed to in writing, software distributed under
8
+ the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR REPRESENTATIONS
9
+ OF ANY KIND, either express or implied. See the License for the specific language
10
+ governing permissions and limitations under the License.
11
+ */
12
+ import { createRequest } from "../../utils/request/index.js";
13
+ export default ({
14
+ payload,
15
+ action = "conversations",
16
+ sessionId
17
+ }) => {
18
+ return createRequest({
19
+ payload: payload,
20
+ edgeSubPath: "/brand-concierge",
21
+ requestParams: {
22
+ sessionId
23
+ },
24
+ getAction() {
25
+ return action;
26
+ },
27
+ getUseSendBeacon() {
28
+ return false;
29
+ }
30
+ });
31
+ };
@@ -0,0 +1,144 @@
1
+ /*
2
+ Copyright 2025 Adobe. All rights reserved.
3
+ This file is licensed to you under the Apache License, Version 2.0 (the "License");
4
+ you may not use this file except in compliance with the License. You may obtain a copy
5
+ of the License at http://www.apache.org/licenses/LICENSE-2.0
6
+
7
+ Unless required by applicable law or agreed to in writing, software distributed under
8
+ the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR REPRESENTATIONS
9
+ OF ANY KIND, either express or implied. See the License for the specific language
10
+ governing permissions and limitations under the License.
11
+ */
12
+ import { createDataCollectionRequestPayload } from "../../utils/request/index.js";
13
+ import createConversationServiceRequest from "./createConversationServiceRequest.js";
14
+ import { getConciergeSessionCookie, getPageSurface } from "./utils.js";
15
+ import uuid from "../../utils/uuid.js";
16
+ import createStreamParser from "./createStreamParser.js";
17
+ import createTimeoutWrapper from "./createTimeoutWrapper.js";
18
+ export default ({
19
+ eventManager,
20
+ loggingCookieJar,
21
+ config,
22
+ logger,
23
+ sendConversationServiceRequest,
24
+ buildEndpointUrl,
25
+ cookieTransfer,
26
+ createResponse,
27
+ decodeKndctrCookie,
28
+ lifecycle,
29
+ consent
30
+ }) => {
31
+ const {
32
+ edgeDomain,
33
+ edgeBasePath,
34
+ datastreamId,
35
+ onBeforeEventSend,
36
+ conversation
37
+ } = config;
38
+ return options => {
39
+ let streamingEnabled = false;
40
+ const {
41
+ message,
42
+ onStreamResponse,
43
+ xdm,
44
+ data
45
+ } = options;
46
+ const sessionId = getConciergeSessionCookie({
47
+ loggingCookieJar,
48
+ config
49
+ }) || uuid();
50
+ const payload = createDataCollectionRequestPayload();
51
+ const request = createConversationServiceRequest({
52
+ payload,
53
+ sessionId: sessionId
54
+ });
55
+ const event = eventManager.createEvent();
56
+ if (message || data) {
57
+ const pageSurface = getPageSurface();
58
+ event.mergeQuery({
59
+ conversation: {
60
+ surfaces: [pageSurface],
61
+ message,
62
+ data
63
+ }
64
+ });
65
+ }
66
+ const {
67
+ state
68
+ } = consent.current();
69
+ event.mergeMeta({
70
+ consent: {
71
+ state: state
72
+ }
73
+ });
74
+ const ecid = decodeKndctrCookie();
75
+ event.mergeXdm({
76
+ identityMap: {
77
+ ECID: [{
78
+ id: ecid
79
+ }]
80
+ }
81
+ });
82
+ event.mergeXdm({
83
+ ...xdm
84
+ });
85
+ if (message || data) {
86
+ streamingEnabled = true;
87
+ }
88
+ const url = buildEndpointUrl({
89
+ edgeDomain,
90
+ edgeBasePath,
91
+ datastreamId,
92
+ request
93
+ });
94
+ return lifecycle.onBeforeEvent({
95
+ event
96
+ }).then(() => {
97
+ try {
98
+ // NOTE: this calls onBeforeEventSend callback (if configured)
99
+ event.finalize(onBeforeEventSend);
100
+ } catch (error) {
101
+ onStreamResponse({
102
+ error
103
+ });
104
+ throw error;
105
+ }
106
+ payload.addEvent(event);
107
+ cookieTransfer.cookiesToPayload(payload, edgeDomain);
108
+ return sendConversationServiceRequest({
109
+ requestId: uuid(),
110
+ url,
111
+ request,
112
+ onStreamResponse,
113
+ streamingEnabled
114
+ }).then(response => {
115
+ if (response.status === 204) {
116
+ return;
117
+ }
118
+ const onStreamResponseCallback = event => {
119
+ if (event.error) {
120
+ logger.error("Stream error occurred", event.error);
121
+ onStreamResponse({
122
+ error: event.error
123
+ });
124
+ return;
125
+ }
126
+ const substr = event.data.replace("data: ", "");
127
+ const responseJson = JSON.parse(substr);
128
+ const response = createResponse({
129
+ content: responseJson
130
+ });
131
+ cookieTransfer.responseToCookies(response);
132
+ logger.info("onStreamResponse callback called with", response.getPayloadsByType("brand-concierge:conversation"));
133
+ onStreamResponse(response.getPayloadsByType("brand-concierge:conversation"));
134
+ };
135
+ const timeoutWrapper = createTimeoutWrapper({
136
+ onStreamResponseCallback,
137
+ streamTimeout: conversation.streamTimeout
138
+ });
139
+ const streamParser = createStreamParser();
140
+ streamParser(response.body, timeoutWrapper);
141
+ });
142
+ });
143
+ };
144
+ };
@@ -0,0 +1,81 @@
1
+ /*
2
+ Copyright 2025 Adobe. All rights reserved.
3
+ This file is licensed to you under the Apache License, Version 2.0 (the "License");
4
+ you may not use this file except in compliance with the License. You may obtain a copy
5
+ of the License at http://www.apache.org/licenses/LICENSE-2.0
6
+
7
+ Unless required by applicable law or agreed to in writing, software distributed under
8
+ the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR REPRESENTATIONS
9
+ OF ANY KIND, either express or implied. See the License for the specific language
10
+ governing permissions and limitations under the License.
11
+ */
12
+ import { stackError } from "../../utils/index.js";
13
+ export default ({
14
+ logger,
15
+ fetch
16
+ }) => {
17
+ return async ({
18
+ requestId,
19
+ url,
20
+ request,
21
+ streamingEnabled = true
22
+ }) => {
23
+ const payload = request.getPayload();
24
+ const stringifiedPayload = JSON.stringify(payload);
25
+ const parsedPayload = JSON.parse(stringifiedPayload);
26
+ const headers = {
27
+ "Content-Type": "text/plain"
28
+ };
29
+ if (streamingEnabled) {
30
+ headers.Accept = "text/event-stream";
31
+ } else {
32
+ headers.Accept = "text/plain";
33
+ }
34
+ logger.logOnBeforeNetworkRequest({
35
+ url,
36
+ requestId,
37
+ payload: parsedPayload
38
+ });
39
+ const fetchWithRetries = async (attemptNumber = 1) => {
40
+ const maxAttempts = 4;
41
+ const retryDelays = [2000, 3000, 5000];
42
+ try {
43
+ const response = await fetch(url, {
44
+ method: "POST",
45
+ headers: headers,
46
+ body: stringifiedPayload
47
+ });
48
+ if (!response.ok) {
49
+ throw new Error(`Request failed with status ${response.status}`);
50
+ }
51
+ return response;
52
+ } catch (error) {
53
+ if (attemptNumber < maxAttempts) {
54
+ const delay = retryDelays[attemptNumber - 1];
55
+ logger.logOnNetworkError({
56
+ requestId,
57
+ url,
58
+ payload: parsedPayload,
59
+ error: new Error(`Attempt ${attemptNumber} failed, retrying in ${delay}ms: ${error.message}`)
60
+ });
61
+ await new Promise(resolve => setTimeout(resolve, delay));
62
+ return fetchWithRetries(attemptNumber + 1);
63
+ }
64
+ logger.logOnNetworkError({
65
+ requestId,
66
+ url,
67
+ payload: parsedPayload,
68
+ error
69
+ });
70
+ throw stackError({
71
+ error,
72
+ message: "Network request failed after all retries."
73
+ });
74
+ }
75
+ };
76
+ const executeRequest = async () => {
77
+ return fetchWithRetries();
78
+ };
79
+ return executeRequest();
80
+ };
81
+ };
@@ -0,0 +1,127 @@
1
+ /*
2
+ Copyright 2024 Adobe. All rights reserved.
3
+ This file is licensed to you under the Apache License, Version 2.0 (the "License");
4
+ you may not use this file except in compliance with the License. You may obtain a copy
5
+ of the License at http://www.apache.org/licenses/LICENSE-2.0
6
+
7
+ Unless required by applicable law or agreed to in writing, software distributed under
8
+ the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR REPRESENTATIONS
9
+ OF ANY KIND, either express or implied. See the License for the specific language
10
+ governing permissions and limitations under the License.
11
+ */
12
+ export default () => {
13
+ // SSE streams are always UTF-8 encoded per specification
14
+ const ENCODING = "utf-8";
15
+ // SSE spec allows three line ending styles: CRLF (\r\n), LF (\n), or CR (\r)
16
+ const LINE_ENDING_REGEX = /\r\n|\r|\n/;
17
+ // Events are separated by blank lines (double line endings)
18
+ const EVENT_SEPARATOR_REGEX = /\r\n\r\n|\n\n|\r\r/;
19
+ // Ping comment format: `: ping` (colon followed immediately by "ping")
20
+ const PING_COMMENT = ": ping";
21
+
22
+ /**
23
+ * Check if an event block is a ping comment.
24
+ * Ping comments are SSE comments in the format `:ping`
25
+ *
26
+ * @param {string} eventData - Raw event data
27
+ * @returns {boolean} - True if this is a ping comment
28
+ */
29
+ const isPingComment = eventData => {
30
+ const trimmed = eventData.trim();
31
+ return trimmed.startsWith(PING_COMMENT);
32
+ };
33
+
34
+ /**
35
+ * Parse a single SSE event from raw event data.
36
+ * Follows the Server-Sent Events specification (https://html.spec.whatwg.org/multipage/server-sent-events.html)
37
+ *
38
+ * @param {string} eventData - Raw event data (multi-line string containing SSE fields)
39
+ * @returns {Object|null} - Parsed SSE event with structure { type, data, id } or null if invalid
40
+ */
41
+ const parseEventFromBuffer = eventData => {
42
+ const lines = eventData.split(LINE_ENDING_REGEX);
43
+ const parsedEvent = {};
44
+ for (const line of lines) {
45
+ const trimmedLine = line.trim();
46
+ if (!trimmedLine) {
47
+ continue;
48
+ }
49
+ const colonIndex = trimmedLine.indexOf(":");
50
+ if (colonIndex === -1) {
51
+ continue;
52
+ }
53
+ const field = trimmedLine.substring(0, colonIndex).trim();
54
+ const value = trimmedLine.substring(colonIndex + 1).trim();
55
+ if (field === "data") {
56
+ parsedEvent.data = (parsedEvent.data || "") + value;
57
+ } else if (field === "event") {
58
+ parsedEvent.type = value;
59
+ } else if (field === "id") {
60
+ parsedEvent.id = value;
61
+ }
62
+ }
63
+ return parsedEvent.data ? parsedEvent : null;
64
+ };
65
+
66
+ /**
67
+ * Parse SSE stream using callbacks.
68
+ * Uses modern async iteration (for await...of) for clean, performant stream processing.
69
+ *
70
+ * @param {ReadableStream} stream - The readable stream from fetch response
71
+ * @param {Object} callbacks - Callback functions for stream events
72
+ * @param {Function} callbacks.onEvent - Callback function called for each parsed event
73
+ * @param {Function} callbacks.onPing - Callback function called for ping comments
74
+ * @param {Function} callbacks.onComplete - Callback function called when stream ends
75
+ */
76
+ return async (stream, {
77
+ onEvent,
78
+ onPing,
79
+ onComplete
80
+ }) => {
81
+ const decoder = new TextDecoder(ENCODING);
82
+ let buffer = "";
83
+ try {
84
+ for await (const chunk of stream) {
85
+ buffer += decoder.decode(chunk, {
86
+ stream: true
87
+ });
88
+ const events = buffer.split(EVENT_SEPARATOR_REGEX);
89
+ buffer = events.pop() || "";
90
+ for (const event of events) {
91
+ const trimmedEvent = event.trim();
92
+ if (!trimmedEvent) {
93
+ continue;
94
+ }
95
+ if (isPingComment(trimmedEvent)) {
96
+ onPing();
97
+ continue;
98
+ }
99
+ const parsedEvent = parseEventFromBuffer(trimmedEvent);
100
+ if (parsedEvent !== null) {
101
+ onEvent(parsedEvent);
102
+ }
103
+ }
104
+ }
105
+ const trimmedBuffer = buffer.trim();
106
+ if (!trimmedBuffer) {
107
+ onComplete();
108
+ return;
109
+ }
110
+ if (isPingComment(trimmedBuffer)) {
111
+ onPing();
112
+ onComplete();
113
+ return;
114
+ }
115
+ const event = parseEventFromBuffer(trimmedBuffer);
116
+ if (event !== null) {
117
+ onEvent(event);
118
+ }
119
+ onComplete();
120
+ } catch (error) {
121
+ onEvent({
122
+ error
123
+ });
124
+ onComplete();
125
+ }
126
+ };
127
+ };
@@ -0,0 +1,76 @@
1
+ /*
2
+ Copyright 2025 Adobe. All rights reserved.
3
+ This file is licensed to you under the Apache License, Version 2.0 (the "License");
4
+ you may not use this file except in compliance with the License. You may obtain a copy
5
+ of the License at http://www.apache.org/licenses/LICENSE-2.0
6
+
7
+ Unless required by applicable law or agreed to in writing, software distributed under
8
+ the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR REPRESENTATIONS
9
+ OF ANY KIND, either express or implied. See the License for the specific language
10
+ governing permissions and limitations under the License.
11
+ */
12
+
13
+ /**
14
+ * Creates a wrapper around a callback that implements a rolling timeout.
15
+ * The timeout resets on every data event or ping. If no activity occurs
16
+ * within the timeout period, an error is passed to the callback.
17
+ * After timeout fires, all subsequent calls are ignored.
18
+ *
19
+ * @param {Object} options - Configuration options
20
+ * @param {Function} options.onStreamResponseCallback - The callback function to wrap
21
+ * @param {number} options.streamTimeout - Timeout duration in milliseconds
22
+ * @returns {Object} Object with onEvent, onPing, and onComplete handler functions
23
+ */
24
+ export default ({
25
+ onStreamResponseCallback,
26
+ streamTimeout
27
+ }) => {
28
+ let timedOut = false;
29
+ let timeoutId;
30
+ const resetTimeout = () => {
31
+ clearTimeout(timeoutId);
32
+ timeoutId = setTimeout(() => {
33
+ timedOut = true;
34
+ onStreamResponseCallback({
35
+ error: {
36
+ message: "Stream timeout: No data received within 10 seconds"
37
+ }
38
+ });
39
+ }, streamTimeout);
40
+ };
41
+
42
+ // Start initial timeout
43
+ resetTimeout();
44
+ return {
45
+ /**
46
+ * Handle data events from the stream parser.
47
+ * Resets the timeout and forwards the event to the callback.
48
+ *
49
+ * @param {Object} event - The parsed SSE event
50
+ */
51
+ onEvent: event => {
52
+ if (timedOut) {
53
+ return;
54
+ }
55
+ resetTimeout();
56
+ onStreamResponseCallback(event);
57
+ },
58
+ /**
59
+ * Handle ping events from the stream parser.
60
+ * Resets the timeout but does not forward anything to the callback.
61
+ */
62
+ onPing: () => {
63
+ if (timedOut) {
64
+ return;
65
+ }
66
+ resetTimeout();
67
+ },
68
+ /**
69
+ * Handle stream completion.
70
+ * Clears the timeout since the stream has ended successfully.
71
+ */
72
+ onComplete: () => {
73
+ clearTimeout(timeoutId);
74
+ }
75
+ };
76
+ };