@adobe/alloy 2.30.1-beta.12 → 2.30.1-beta.13
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.
- package/libEs5/components/BrandConcierge/constants.js +15 -0
- package/libEs5/components/BrandConcierge/createBuildEndpointUrl.js +33 -0
- package/libEs5/components/BrandConcierge/createConversationServiceRequest.js +35 -0
- package/libEs5/components/BrandConcierge/createSendConversationEvent.js +132 -0
- package/libEs5/components/BrandConcierge/createSendConversationServiceRequest.js +85 -0
- package/libEs5/components/BrandConcierge/createStreamParser.js +96 -0
- package/libEs5/components/BrandConcierge/index.js +104 -0
- package/libEs5/components/BrandConcierge/utils.js +33 -0
- package/libEs5/components/BrandConcierge/validateMessage.js +41 -0
- package/libEs5/components/Personalization/createPersonalizationDetails.js +1 -1
- package/libEs5/components/Personalization/index.js +1 -1
- package/libEs5/constants/libraryVersion.js +1 -1
- package/libEs5/constants/surface.js +19 -0
- package/libEs5/core/componentCreators.js +8 -1
- package/libEs5/core/index.js +5 -1
- package/libEs5/utils/dom/createGetPageLocation.js +20 -0
- package/libEs5/utils/index.js +8 -1
- package/libEs5/utils/request/createRequest.js +5 -1
- package/libEs5/utils/surfaceUtils.js +82 -0
- package/libEs6/components/BrandConcierge/constants.js +12 -0
- package/libEs6/components/BrandConcierge/createBuildEndpointUrl.js +30 -0
- package/libEs6/components/BrandConcierge/createConversationServiceRequest.js +31 -0
- package/libEs6/components/BrandConcierge/createSendConversationEvent.js +128 -0
- package/libEs6/components/BrandConcierge/createSendConversationServiceRequest.js +81 -0
- package/libEs6/components/BrandConcierge/createStreamParser.js +92 -0
- package/libEs6/components/BrandConcierge/index.js +100 -0
- package/libEs6/components/BrandConcierge/utils.js +27 -0
- package/libEs6/components/BrandConcierge/validateMessage.js +37 -0
- package/libEs6/components/Personalization/createPersonalizationDetails.js +1 -1
- package/libEs6/components/Personalization/index.js +1 -1
- package/libEs6/constants/libraryVersion.js +1 -1
- package/libEs6/constants/surface.js +16 -0
- package/libEs6/core/componentCreators.js +2 -1
- package/libEs6/core/index.js +5 -1
- package/libEs6/utils/dom/createGetPageLocation.js +17 -0
- package/libEs6/utils/index.js +2 -1
- package/libEs6/utils/request/createRequest.js +5 -1
- package/libEs6/utils/surfaceUtils.js +76 -0
- package/package.json +1 -1
- package/types/components/BrandConcierge/constants.d.ts +2 -0
- package/types/components/BrandConcierge/constants.d.ts.map +1 -0
- package/types/components/BrandConcierge/createBuildEndpointUrl.d.ts +9 -0
- package/types/components/BrandConcierge/createBuildEndpointUrl.d.ts.map +1 -0
- package/types/components/BrandConcierge/createConversationServiceRequest.d.ts +7 -0
- package/types/components/BrandConcierge/createConversationServiceRequest.d.ts.map +1 -0
- package/types/components/BrandConcierge/createSendConversationEvent.d.ts +14 -0
- package/types/components/BrandConcierge/createSendConversationEvent.d.ts.map +1 -0
- package/types/components/BrandConcierge/createSendConversationServiceRequest.d.ts +11 -0
- package/types/components/BrandConcierge/createSendConversationServiceRequest.d.ts.map +1 -0
- package/types/components/BrandConcierge/createStreamParser.d.ts +3 -0
- package/types/components/BrandConcierge/createStreamParser.d.ts.map +1 -0
- package/types/components/BrandConcierge/index.d.ts +31 -0
- package/types/components/BrandConcierge/index.d.ts.map +1 -0
- package/types/components/BrandConcierge/utils.d.ts +6 -0
- package/types/components/BrandConcierge/utils.d.ts.map +1 -0
- package/types/components/BrandConcierge/validateMessage.d.ts +5 -0
- package/types/components/BrandConcierge/validateMessage.d.ts.map +1 -0
- package/types/components/Personalization/createPersonalizationDetails.d.ts.map +1 -1
- package/types/constants/surface.d.ts +5 -0
- package/types/constants/surface.d.ts.map +1 -0
- package/types/core/componentCreators.d.ts +1 -0
- package/types/core/index.d.ts.map +1 -1
- package/types/utils/dom/createGetPageLocation.d.ts +5 -0
- package/types/utils/dom/createGetPageLocation.d.ts.map +1 -0
- package/types/utils/index.d.ts +1 -0
- package/types/utils/request/createRequest.d.ts.map +1 -1
- package/types/utils/surfaceUtils.d.ts +4 -0
- package/types/utils/surfaceUtils.d.ts.map +1 -0
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
|
|
3
|
+
exports.default = void 0;
|
|
4
|
+
/*
|
|
5
|
+
Copyright 2022 Adobe. All rights reserved.
|
|
6
|
+
This file is licensed to you under the Apache License, Version 2.0 (the "License");
|
|
7
|
+
you may not use this file except in compliance with the License. You may obtain a copy
|
|
8
|
+
of the License at http://www.apache.org/licenses/LICENSE-2.0
|
|
9
|
+
|
|
10
|
+
Unless required by applicable law or agreed to in writing, software distributed under
|
|
11
|
+
the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR REPRESENTATIONS
|
|
12
|
+
OF ANY KIND, either express or implied. See the License for the specific language
|
|
13
|
+
governing permissions and limitations under the License.
|
|
14
|
+
*/
|
|
15
|
+
var _default = ({
|
|
16
|
+
window
|
|
17
|
+
}) => () => {
|
|
18
|
+
return window.location;
|
|
19
|
+
};
|
|
20
|
+
exports.default = _default;
|
package/libEs5/utils/index.js
CHANGED
|
@@ -36,6 +36,12 @@ Object.defineProperty(exports, "createCallbackAggregator", {
|
|
|
36
36
|
return _createCallbackAggregator.default;
|
|
37
37
|
}
|
|
38
38
|
});
|
|
39
|
+
Object.defineProperty(exports, "createGetPageLocation", {
|
|
40
|
+
enumerable: true,
|
|
41
|
+
get: function () {
|
|
42
|
+
return _createGetPageLocation.default;
|
|
43
|
+
}
|
|
44
|
+
});
|
|
39
45
|
Object.defineProperty(exports, "createLoggingCookieJar", {
|
|
40
46
|
enumerable: true,
|
|
41
47
|
get: function () {
|
|
@@ -362,4 +368,5 @@ var _toISOStringLocal = require("./toISOStringLocal.js");
|
|
|
362
368
|
var _uuid = require("./uuid.js");
|
|
363
369
|
var _updateErrorMessage = require("./updateErrorMessage.js");
|
|
364
370
|
var _validateIdentityMap = require("./validateIdentityMap.js");
|
|
365
|
-
var _validateConfigOverride = require("./validateConfigOverride.js");
|
|
371
|
+
var _validateConfigOverride = require("./validateConfigOverride.js");
|
|
372
|
+
var _createGetPageLocation = require("./dom/createGetPageLocation.js");
|
|
@@ -47,7 +47,8 @@ var _default = options => {
|
|
|
47
47
|
getAction,
|
|
48
48
|
getUseSendBeacon,
|
|
49
49
|
datastreamIdOverride,
|
|
50
|
-
edgeSubPath
|
|
50
|
+
edgeSubPath,
|
|
51
|
+
requestParams = {}
|
|
51
52
|
} = options;
|
|
52
53
|
const id = (0, _index.uuid)();
|
|
53
54
|
let shouldUseThirdPartyDomain = false;
|
|
@@ -86,6 +87,9 @@ var _default = options => {
|
|
|
86
87
|
},
|
|
87
88
|
setIsIdentityEstablished() {
|
|
88
89
|
isIdentityEstablished = true;
|
|
90
|
+
},
|
|
91
|
+
getRequestParams() {
|
|
92
|
+
return requestParams;
|
|
89
93
|
}
|
|
90
94
|
};
|
|
91
95
|
};
|
|
@@ -0,0 +1,82 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
|
|
3
|
+
exports.normalizeSurfaces = exports.isPageWideSurface = exports.buildPageSurface = void 0;
|
|
4
|
+
var _surface = require("../constants/surface.js");
|
|
5
|
+
var _index = require("./index.js");
|
|
6
|
+
/*
|
|
7
|
+
Copyright 2022 Adobe. All rights reserved.
|
|
8
|
+
This file is licensed to you under the Apache License, Version 2.0 (the "License");
|
|
9
|
+
you may not use this file except in compliance with the License. You may obtain a copy
|
|
10
|
+
of the License at http://www.apache.org/licenses/LICENSE-2.0
|
|
11
|
+
|
|
12
|
+
Unless required by applicable law or agreed to in writing, software distributed under
|
|
13
|
+
the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR REPRESENTATIONS
|
|
14
|
+
OF ANY KIND, either express or implied. See the License for the specific language
|
|
15
|
+
governing permissions and limitations under the License.
|
|
16
|
+
*/
|
|
17
|
+
|
|
18
|
+
const SURFACE_REGEX = /^(\w+):\/\/([^/#]+)(\/[^#]*)?(#.*)?$/;
|
|
19
|
+
const AUTHORITY_REGEX = /^(?:.*@)?(?:[a-z\d\u00a1-\uffff.-]+|\[[a-f\d:]+])(?::\d+)?$/;
|
|
20
|
+
const PATH_REGEX = /^\/(?:[/\w\u00a1-\uffff-.~]|%[a-fA-F\d]{2})*$/;
|
|
21
|
+
const FRAGMENT_REGEX = /^#(?:[/\w\u00a1-\uffff-.~]|%[a-fA-F\d]{2})+$/;
|
|
22
|
+
const normalizePath = (path = "/") => {
|
|
23
|
+
let end = path.length;
|
|
24
|
+
while (end > 0 && "/".indexOf(path.charAt(end - 1)) !== -1) {
|
|
25
|
+
end -= 1;
|
|
26
|
+
}
|
|
27
|
+
return path.substring(0, end) || "/";
|
|
28
|
+
};
|
|
29
|
+
const getSurfaceType = surfaceTypeMatch => (0, _index.isNonEmptyString)(surfaceTypeMatch) ? surfaceTypeMatch.toLowerCase() : "";
|
|
30
|
+
const getAuthority = authorityMatch => (0, _index.isNonEmptyString)(authorityMatch) ? authorityMatch.toLowerCase() : "";
|
|
31
|
+
const getPath = pathMatch => (0, _index.isNonEmptyString)(pathMatch) ? normalizePath(pathMatch) : "/";
|
|
32
|
+
const parseSurface = surfaceString => {
|
|
33
|
+
const matched = surfaceString.match(SURFACE_REGEX);
|
|
34
|
+
return matched ? {
|
|
35
|
+
surfaceType: getSurfaceType(matched[1]),
|
|
36
|
+
authority: getAuthority(matched[2]),
|
|
37
|
+
path: getPath(matched[3]),
|
|
38
|
+
fragment: matched[4]
|
|
39
|
+
} : null;
|
|
40
|
+
};
|
|
41
|
+
const stringifySurface = surface => "" + surface.surfaceType + _surface.SURFACE_TYPE_DELIMITER + surface.authority + (surface.path || "") + (surface.fragment || "");
|
|
42
|
+
const buildPageSurface = getPageLocation => {
|
|
43
|
+
const location = getPageLocation();
|
|
44
|
+
const host = location.host.toLowerCase();
|
|
45
|
+
const path = location.pathname;
|
|
46
|
+
return _surface.WEB + _surface.SURFACE_TYPE_DELIMITER + host + normalizePath(path);
|
|
47
|
+
};
|
|
48
|
+
exports.buildPageSurface = buildPageSurface;
|
|
49
|
+
const expandFragmentSurface = (surface, getPageLocation) => surface.startsWith(_surface.FRAGMENT_DELIMITER) ? buildPageSurface(getPageLocation) + surface : surface;
|
|
50
|
+
const validateSurface = (surface, getPageLocation, logger) => {
|
|
51
|
+
const invalidateSurface = validationError => {
|
|
52
|
+
logger.warn(validationError);
|
|
53
|
+
return null;
|
|
54
|
+
};
|
|
55
|
+
if (!(0, _index.isNonEmptyString)(surface)) {
|
|
56
|
+
return invalidateSurface("Invalid surface: " + surface);
|
|
57
|
+
}
|
|
58
|
+
const expanded = expandFragmentSurface(surface, getPageLocation);
|
|
59
|
+
const parsed = parseSurface(expanded);
|
|
60
|
+
if (parsed === null) {
|
|
61
|
+
return invalidateSurface("Invalid surface: " + surface);
|
|
62
|
+
}
|
|
63
|
+
if (![_surface.WEB, _surface.WEBAPP].includes(parsed.surfaceType)) {
|
|
64
|
+
return invalidateSurface("Unsupported surface type " + parsed.surfaceType + " in surface: " + surface);
|
|
65
|
+
}
|
|
66
|
+
if (!parsed.authority || !AUTHORITY_REGEX.test(parsed.authority)) {
|
|
67
|
+
return invalidateSurface("Invalid authority " + parsed.authority + " in surface: " + surface);
|
|
68
|
+
}
|
|
69
|
+
if (parsed.path && !PATH_REGEX.test(parsed.path)) {
|
|
70
|
+
return invalidateSurface("Invalid path " + parsed.path + " in surface: " + surface);
|
|
71
|
+
}
|
|
72
|
+
if (parsed.fragment && !FRAGMENT_REGEX.test(parsed.fragment)) {
|
|
73
|
+
return invalidateSurface("Invalid fragment " + parsed.fragment + " in surface: " + surface);
|
|
74
|
+
}
|
|
75
|
+
return parsed;
|
|
76
|
+
};
|
|
77
|
+
const isPageWideSurface = scope => !!scope && scope.indexOf(_surface.WEB + _surface.SURFACE_TYPE_DELIMITER) === 0 && scope.indexOf(_surface.FRAGMENT_DELIMITER) === -1;
|
|
78
|
+
|
|
79
|
+
// eslint-disable-next-line default-param-last
|
|
80
|
+
exports.isPageWideSurface = isPageWideSurface;
|
|
81
|
+
const normalizeSurfaces = (surfaces = [], getPageLocation, logger) => surfaces.map(surface => validateSurface(surface, getPageLocation, logger)).filter(surface => !(0, _index.isNil)(surface)).map(stringifySurface);
|
|
82
|
+
exports.normalizeSurfaces = normalizeSurfaces;
|
|
@@ -0,0 +1,12 @@
|
|
|
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";
|
|
@@ -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,128 @@
|
|
|
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
|
+
export default ({
|
|
18
|
+
eventManager,
|
|
19
|
+
loggingCookieJar,
|
|
20
|
+
config,
|
|
21
|
+
logger,
|
|
22
|
+
sendConversationServiceRequest,
|
|
23
|
+
buildEndpointUrl,
|
|
24
|
+
cookieTransfer,
|
|
25
|
+
createResponse,
|
|
26
|
+
decodeKndctrCookie,
|
|
27
|
+
lifecycle
|
|
28
|
+
}) => {
|
|
29
|
+
const {
|
|
30
|
+
edgeDomain,
|
|
31
|
+
edgeBasePath,
|
|
32
|
+
datastreamId,
|
|
33
|
+
onBeforeEventSend
|
|
34
|
+
} = config;
|
|
35
|
+
return options => {
|
|
36
|
+
let streamingEnabled = false;
|
|
37
|
+
const {
|
|
38
|
+
message,
|
|
39
|
+
onStreamResponse,
|
|
40
|
+
xdm,
|
|
41
|
+
data
|
|
42
|
+
} = options;
|
|
43
|
+
const sessionId = getConciergeSessionCookie({
|
|
44
|
+
loggingCookieJar,
|
|
45
|
+
config
|
|
46
|
+
}) || uuid();
|
|
47
|
+
const payload = createDataCollectionRequestPayload();
|
|
48
|
+
const request = createConversationServiceRequest({
|
|
49
|
+
payload,
|
|
50
|
+
sessionId: sessionId
|
|
51
|
+
});
|
|
52
|
+
const event = eventManager.createEvent();
|
|
53
|
+
if (message || data) {
|
|
54
|
+
const pageSurface = getPageSurface();
|
|
55
|
+
event.mergeQuery({
|
|
56
|
+
conversation: {
|
|
57
|
+
surfaces: [pageSurface],
|
|
58
|
+
message,
|
|
59
|
+
data
|
|
60
|
+
}
|
|
61
|
+
});
|
|
62
|
+
}
|
|
63
|
+
const ecid = decodeKndctrCookie();
|
|
64
|
+
event.mergeXdm({
|
|
65
|
+
identityMap: {
|
|
66
|
+
ECID: [{
|
|
67
|
+
id: ecid
|
|
68
|
+
}]
|
|
69
|
+
}
|
|
70
|
+
});
|
|
71
|
+
event.mergeXdm({
|
|
72
|
+
...xdm
|
|
73
|
+
});
|
|
74
|
+
if (message || data) {
|
|
75
|
+
streamingEnabled = true;
|
|
76
|
+
}
|
|
77
|
+
const url = buildEndpointUrl({
|
|
78
|
+
edgeDomain,
|
|
79
|
+
edgeBasePath,
|
|
80
|
+
datastreamId,
|
|
81
|
+
request
|
|
82
|
+
});
|
|
83
|
+
return lifecycle.onBeforeEvent({
|
|
84
|
+
event
|
|
85
|
+
}).then(() => {
|
|
86
|
+
try {
|
|
87
|
+
// NOTE: this calls onBeforeEventSend callback (if configured)
|
|
88
|
+
event.finalize(onBeforeEventSend);
|
|
89
|
+
} catch (error) {
|
|
90
|
+
onStreamResponse({
|
|
91
|
+
error
|
|
92
|
+
});
|
|
93
|
+
throw error;
|
|
94
|
+
}
|
|
95
|
+
payload.addEvent(event);
|
|
96
|
+
cookieTransfer.cookiesToPayload(payload, edgeDomain);
|
|
97
|
+
return sendConversationServiceRequest({
|
|
98
|
+
requestId: uuid(),
|
|
99
|
+
url,
|
|
100
|
+
request,
|
|
101
|
+
onStreamResponse,
|
|
102
|
+
streamingEnabled
|
|
103
|
+
}).then(response => {
|
|
104
|
+
if (response.status === 204) {
|
|
105
|
+
return;
|
|
106
|
+
}
|
|
107
|
+
const onStreamResponseCallback = event => {
|
|
108
|
+
if (event.error) {
|
|
109
|
+
onStreamResponse({
|
|
110
|
+
error: event.error
|
|
111
|
+
});
|
|
112
|
+
return;
|
|
113
|
+
}
|
|
114
|
+
const substr = event.data.replace("data: ", "");
|
|
115
|
+
const responseJson = JSON.parse(substr);
|
|
116
|
+
const response = createResponse({
|
|
117
|
+
content: responseJson
|
|
118
|
+
});
|
|
119
|
+
cookieTransfer.responseToCookies(response);
|
|
120
|
+
logger.info("onStreamResponse callback called with", response.getPayloadsByType("brand-concierge:conversation"));
|
|
121
|
+
onStreamResponse(response.getPayloadsByType("brand-concierge:conversation"));
|
|
122
|
+
};
|
|
123
|
+
const streamParser = createStreamParser();
|
|
124
|
+
streamParser(response.body, onStreamResponseCallback);
|
|
125
|
+
});
|
|
126
|
+
});
|
|
127
|
+
};
|
|
128
|
+
};
|
|
@@ -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,92 @@
|
|
|
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
|
+
|
|
20
|
+
/**
|
|
21
|
+
* Parse a single SSE event from raw event data.
|
|
22
|
+
* Follows the Server-Sent Events specification (https://html.spec.whatwg.org/multipage/server-sent-events.html)
|
|
23
|
+
*
|
|
24
|
+
* @param {string} eventData - Raw event data (multi-line string containing SSE fields)
|
|
25
|
+
* @returns {Object|null} - Parsed SSE event with structure { type, data, id } or null if invalid
|
|
26
|
+
*/
|
|
27
|
+
const parseEventFromBuffer = eventData => {
|
|
28
|
+
const lines = eventData.split(LINE_ENDING_REGEX);
|
|
29
|
+
const parsedEvent = {};
|
|
30
|
+
for (const line of lines) {
|
|
31
|
+
const trimmedLine = line.trim();
|
|
32
|
+
if (!trimmedLine) {
|
|
33
|
+
continue;
|
|
34
|
+
}
|
|
35
|
+
const colonIndex = trimmedLine.indexOf(":");
|
|
36
|
+
if (colonIndex === -1) {
|
|
37
|
+
continue;
|
|
38
|
+
}
|
|
39
|
+
const field = trimmedLine.substring(0, colonIndex).trim();
|
|
40
|
+
const value = trimmedLine.substring(colonIndex + 1).trim();
|
|
41
|
+
if (field === "data") {
|
|
42
|
+
parsedEvent.data = (parsedEvent.data || "") + value;
|
|
43
|
+
} else if (field === "event") {
|
|
44
|
+
parsedEvent.type = value;
|
|
45
|
+
} else if (field === "id") {
|
|
46
|
+
parsedEvent.id = value;
|
|
47
|
+
}
|
|
48
|
+
}
|
|
49
|
+
return parsedEvent.data ? parsedEvent : null;
|
|
50
|
+
};
|
|
51
|
+
|
|
52
|
+
/**
|
|
53
|
+
* Parse SSE stream using callbacks.
|
|
54
|
+
* Uses modern async iteration (for await...of) for clean, performant stream processing.
|
|
55
|
+
*
|
|
56
|
+
* @param {ReadableStream} stream - The readable stream from fetch response
|
|
57
|
+
* @param {Function} onEvent - Callback function called for each parsed event
|
|
58
|
+
*/
|
|
59
|
+
return async (stream, onEvent) => {
|
|
60
|
+
const decoder = new TextDecoder(ENCODING);
|
|
61
|
+
let buffer = "";
|
|
62
|
+
try {
|
|
63
|
+
for await (const chunk of stream) {
|
|
64
|
+
buffer += decoder.decode(chunk, {
|
|
65
|
+
stream: true
|
|
66
|
+
});
|
|
67
|
+
const events = buffer.split(EVENT_SEPARATOR_REGEX);
|
|
68
|
+
buffer = events.pop() || "";
|
|
69
|
+
for (const eventData of events) {
|
|
70
|
+
const trimmedEvent = eventData.trim();
|
|
71
|
+
if (trimmedEvent) {
|
|
72
|
+
const event = parseEventFromBuffer(trimmedEvent);
|
|
73
|
+
if (event !== null) {
|
|
74
|
+
onEvent(event);
|
|
75
|
+
}
|
|
76
|
+
}
|
|
77
|
+
}
|
|
78
|
+
}
|
|
79
|
+
const trimmedBuffer = buffer.trim();
|
|
80
|
+
if (trimmedBuffer) {
|
|
81
|
+
const event = parseEventFromBuffer(trimmedBuffer);
|
|
82
|
+
if (event !== null) {
|
|
83
|
+
onEvent(event);
|
|
84
|
+
}
|
|
85
|
+
}
|
|
86
|
+
} catch (error) {
|
|
87
|
+
onEvent({
|
|
88
|
+
error
|
|
89
|
+
});
|
|
90
|
+
}
|
|
91
|
+
};
|
|
92
|
+
};
|
|
@@ -0,0 +1,100 @@
|
|
|
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
|
+
import validateMessage from "./validateMessage.js";
|
|
13
|
+
import createSendConversationEvent from "./createSendConversationEvent.js";
|
|
14
|
+
import createBuildEndpointUrl from "./createBuildEndpointUrl.js";
|
|
15
|
+
import queryString from "@adobe/reactor-query-string";
|
|
16
|
+
import { getNamespacedCookieName } from "../../utils/index.js";
|
|
17
|
+
import { BC_SESSION_COOKIE_NAME } from "./constants.js";
|
|
18
|
+
import { boolean, objectOf } from "../../utils/validation/index.js";
|
|
19
|
+
import createGetEcidFromCookie from "../../utils/createDecodeKndctrCookie.js";
|
|
20
|
+
import createSendConversationServiceRequest from "./createSendConversationServiceRequest.js";
|
|
21
|
+
const createConciergeComponent = ({
|
|
22
|
+
loggingCookieJar,
|
|
23
|
+
logger,
|
|
24
|
+
eventManager,
|
|
25
|
+
consent,
|
|
26
|
+
instanceName,
|
|
27
|
+
sendEdgeNetworkRequest,
|
|
28
|
+
config,
|
|
29
|
+
lifecycle,
|
|
30
|
+
cookieTransfer,
|
|
31
|
+
createResponse,
|
|
32
|
+
apexDomain
|
|
33
|
+
}) => {
|
|
34
|
+
const {
|
|
35
|
+
fetch
|
|
36
|
+
} = window;
|
|
37
|
+
if (!config.stickyConversationSession) {
|
|
38
|
+
loggingCookieJar.remove(getNamespacedCookieName(config.orgId, BC_SESSION_COOKIE_NAME), {
|
|
39
|
+
domain: apexDomain
|
|
40
|
+
});
|
|
41
|
+
}
|
|
42
|
+
const buildEndpointUrl = createBuildEndpointUrl({
|
|
43
|
+
queryString
|
|
44
|
+
});
|
|
45
|
+
const sendConversationServiceRequest = createSendConversationServiceRequest({
|
|
46
|
+
logger,
|
|
47
|
+
fetch,
|
|
48
|
+
config
|
|
49
|
+
});
|
|
50
|
+
const decodeKndctrCookie = createGetEcidFromCookie({
|
|
51
|
+
orgId: config.orgId,
|
|
52
|
+
cookieJar: loggingCookieJar,
|
|
53
|
+
logger
|
|
54
|
+
});
|
|
55
|
+
const sendConversationEvent = createSendConversationEvent({
|
|
56
|
+
loggingCookieJar,
|
|
57
|
+
logger,
|
|
58
|
+
eventManager,
|
|
59
|
+
consent,
|
|
60
|
+
instanceName,
|
|
61
|
+
sendEdgeNetworkRequest,
|
|
62
|
+
config,
|
|
63
|
+
buildEndpointUrl,
|
|
64
|
+
lifecycle,
|
|
65
|
+
cookieTransfer,
|
|
66
|
+
createResponse,
|
|
67
|
+
sendConversationServiceRequest,
|
|
68
|
+
decodeKndctrCookie
|
|
69
|
+
});
|
|
70
|
+
return {
|
|
71
|
+
lifecycle: {
|
|
72
|
+
onBeforeEvent({
|
|
73
|
+
event
|
|
74
|
+
}) {
|
|
75
|
+
const parsedParams = queryString.parse(window.location.search);
|
|
76
|
+
if (parsedParams.source) {
|
|
77
|
+
const source = parsedParams.source;
|
|
78
|
+
event.mergeXdm({
|
|
79
|
+
channel: {
|
|
80
|
+
referringSource: source
|
|
81
|
+
}
|
|
82
|
+
});
|
|
83
|
+
}
|
|
84
|
+
}
|
|
85
|
+
},
|
|
86
|
+
commands: {
|
|
87
|
+
sendConversationEvent: {
|
|
88
|
+
optionsValidator: options => validateMessage({
|
|
89
|
+
options
|
|
90
|
+
}),
|
|
91
|
+
run: sendConversationEvent
|
|
92
|
+
}
|
|
93
|
+
}
|
|
94
|
+
};
|
|
95
|
+
};
|
|
96
|
+
createConciergeComponent.namespace = "BrandConcierge";
|
|
97
|
+
createConciergeComponent.configValidators = objectOf({
|
|
98
|
+
stickyConversationSession: boolean().default(false)
|
|
99
|
+
});
|
|
100
|
+
export default createConciergeComponent;
|
|
@@ -0,0 +1,27 @@
|
|
|
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 { getNamespacedCookieName, createGetPageLocation } from "../../utils/index.js";
|
|
13
|
+
import { buildPageSurface } from "../../utils/surfaceUtils.js";
|
|
14
|
+
import { BC_SESSION_COOKIE_NAME } from "./constants.js";
|
|
15
|
+
export const getPageSurface = () => {
|
|
16
|
+
const pageLocation = createGetPageLocation({
|
|
17
|
+
window: window
|
|
18
|
+
});
|
|
19
|
+
return buildPageSurface(pageLocation);
|
|
20
|
+
};
|
|
21
|
+
export const getConciergeSessionCookie = ({
|
|
22
|
+
loggingCookieJar,
|
|
23
|
+
config
|
|
24
|
+
}) => {
|
|
25
|
+
const cookieName = getNamespacedCookieName(config.orgId, BC_SESSION_COOKIE_NAME);
|
|
26
|
+
return loggingCookieJar.get(cookieName);
|
|
27
|
+
};
|