@adobe/alloy 2.35.1-beta.0 → 2.35.1
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/dist/alloy.js +193 -46
- package/dist/alloy.min.js +2 -2
- package/dist/types/core/src/components/BrandConcierge/createSendConversationEvent.d.ts +2 -1
- package/dist/types/core/src/components/BrandConcierge/index.d.ts +16 -1
- package/dist/types/core/src/constants/legacyCookies.d.ts +1 -0
- package/dist/types/core/src/core/createCookieTransfer.d.ts +1 -1
- package/dist/types/core/src/index.d.ts +1 -0
- package/package.json +2 -2
- package/src/components/Personalization/dom-actions/scripts.js +147 -23
|
@@ -1,10 +1,11 @@
|
|
|
1
|
-
declare function _default({ eventManager, config, logger, sendConversationServiceRequest, buildEndpointUrl, cookieTransfer, createResponse, decodeKndctrCookie, lifecycle, consent, session, getPageLocation, }: {
|
|
1
|
+
declare function _default({ eventManager, config, logger, sendConversationServiceRequest, buildEndpointUrl, cookieTransfer, alwaysTransferCookies, createResponse, decodeKndctrCookie, lifecycle, consent, session, getPageLocation, }: {
|
|
2
2
|
eventManager: any;
|
|
3
3
|
config: any;
|
|
4
4
|
logger: any;
|
|
5
5
|
sendConversationServiceRequest: any;
|
|
6
6
|
buildEndpointUrl: any;
|
|
7
7
|
cookieTransfer: any;
|
|
8
|
+
alwaysTransferCookies?: never[] | undefined;
|
|
8
9
|
createResponse: any;
|
|
9
10
|
decodeKndctrCookie: any;
|
|
10
11
|
lifecycle: any;
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
export default createConciergeComponent;
|
|
2
|
-
declare function createConciergeComponent({ loggingCookieJar, logger, eventManager, consent, instanceName, sendEdgeNetworkRequest, config, lifecycle, cookieTransfer, createResponse, platformServices, }: {
|
|
2
|
+
declare function createConciergeComponent({ loggingCookieJar, logger, eventManager, consent, instanceName, sendEdgeNetworkRequest, config, lifecycle, cookieTransfer, createResponse, platformServices, createSendConversationEvent: createSendConversationEventFactory, }: {
|
|
3
3
|
loggingCookieJar: any;
|
|
4
4
|
logger: any;
|
|
5
5
|
eventManager: any;
|
|
@@ -11,6 +11,21 @@ declare function createConciergeComponent({ loggingCookieJar, logger, eventManag
|
|
|
11
11
|
cookieTransfer: any;
|
|
12
12
|
createResponse: any;
|
|
13
13
|
platformServices: any;
|
|
14
|
+
createSendConversationEvent?: (({ eventManager, config, logger, sendConversationServiceRequest, buildEndpointUrl, cookieTransfer, alwaysTransferCookies, createResponse, decodeKndctrCookie, lifecycle, consent, session, getPageLocation, }: {
|
|
15
|
+
eventManager: any;
|
|
16
|
+
config: any;
|
|
17
|
+
logger: any;
|
|
18
|
+
sendConversationServiceRequest: any;
|
|
19
|
+
buildEndpointUrl: any;
|
|
20
|
+
cookieTransfer: any;
|
|
21
|
+
alwaysTransferCookies?: never[] | undefined;
|
|
22
|
+
createResponse: any;
|
|
23
|
+
decodeKndctrCookie: any;
|
|
24
|
+
lifecycle: any;
|
|
25
|
+
consent: any;
|
|
26
|
+
session: any;
|
|
27
|
+
getPageLocation: any;
|
|
28
|
+
}) => (options: any) => any) | undefined;
|
|
14
29
|
}): {
|
|
15
30
|
lifecycle: {
|
|
16
31
|
onBeforeEvent({ event }: {
|
|
@@ -9,7 +9,7 @@ declare function _default({ cookieJar, shouldTransferCookie, apexDomain, datePro
|
|
|
9
9
|
* access first-party cookies, therefore we transfer cookies into
|
|
10
10
|
* the request body so they can be read by the server.
|
|
11
11
|
*/
|
|
12
|
-
cookiesToPayload(payload: any, endpointDomain: any): void;
|
|
12
|
+
cookiesToPayload(payload: any, endpointDomain: any, extraCookieNames?: any[]): void;
|
|
13
13
|
/**
|
|
14
14
|
* When receiving from a third-party endpoint, the endpoint won't be able to
|
|
15
15
|
* write first-party cookies, therefore we write first-party cookies
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
export { default as createCoreConfigs } from "./core/config/createCoreConfigs.js";
|
|
2
|
+
export { default as consent } from "./components/Consent/index.js";
|
|
2
3
|
export function createCustomInstance(options?: {
|
|
3
4
|
name?: string | undefined;
|
|
4
5
|
monitors?: import("./core/types.js").AlloyMonitor[] | undefined;
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@adobe/alloy",
|
|
3
|
-
"version": "2.35.1
|
|
3
|
+
"version": "2.35.1",
|
|
4
4
|
"description": "Adobe Experience Platform Web SDK",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"repository": {
|
|
@@ -69,7 +69,7 @@
|
|
|
69
69
|
"commander": "^14.0.2",
|
|
70
70
|
"rollup": "^4.60.3",
|
|
71
71
|
"rollup-plugin-license": "^3.7.1",
|
|
72
|
-
"@adobe/alloy-core": "^1.2.3
|
|
72
|
+
"@adobe/alloy-core": "^1.2.3"
|
|
73
73
|
},
|
|
74
74
|
"devDependencies": {
|
|
75
75
|
"glob": "^13.0.6",
|
|
@@ -14,6 +14,55 @@ import { SCRIPT } from "@adobe/alloy-core/constants/tagName.js";
|
|
|
14
14
|
import { SRC } from "@adobe/alloy-core/constants/elementAttribute.js";
|
|
15
15
|
import { getAttribute, getNonce } from "./dom/index.js";
|
|
16
16
|
|
|
17
|
+
const TYPE = "type";
|
|
18
|
+
const MODULE = "module";
|
|
19
|
+
const NONCE = "nonce";
|
|
20
|
+
const NOMODULE = "nomodule";
|
|
21
|
+
|
|
22
|
+
// Per the HTML spec, a <script> only ever executes if its type is absent/
|
|
23
|
+
// empty, "module", or one of these recognized JavaScript MIME type essences
|
|
24
|
+
// (https://mimesniff.spec.whatwg.org/#javascript-mime-type). Any other type
|
|
25
|
+
// (e.g. "importmap", "application/json", a templating library's custom type)
|
|
26
|
+
// makes the element a data block: the browser never executes it, regardless
|
|
27
|
+
// of whether it's parsed from HTML, inserted via innerHTML, or appended with
|
|
28
|
+
// appendChild. Such elements are left untouched by this module — extracting
|
|
29
|
+
// and re-inserting them would be pointless at best, and at worst (if `type`
|
|
30
|
+
// were dropped along the way) would turn inert data into code that runs.
|
|
31
|
+
const JAVASCRIPT_MIME_TYPES = new Set([
|
|
32
|
+
"application/ecmascript",
|
|
33
|
+
"application/javascript",
|
|
34
|
+
"application/x-ecmascript",
|
|
35
|
+
"application/x-javascript",
|
|
36
|
+
"text/ecmascript",
|
|
37
|
+
"text/javascript",
|
|
38
|
+
"text/javascript1.0",
|
|
39
|
+
"text/javascript1.1",
|
|
40
|
+
"text/javascript1.2",
|
|
41
|
+
"text/javascript1.3",
|
|
42
|
+
"text/javascript1.4",
|
|
43
|
+
"text/javascript1.5",
|
|
44
|
+
"text/jscript",
|
|
45
|
+
"text/livescript",
|
|
46
|
+
"text/x-ecmascript",
|
|
47
|
+
"text/x-javascript",
|
|
48
|
+
]);
|
|
49
|
+
|
|
50
|
+
// Attributes that affect how the script executes/fetches (as opposed to
|
|
51
|
+
// identity/presentation attributes like id, class, and data-*, which are
|
|
52
|
+
// intentionally not copied — see loadScript below). `src` is handled
|
|
53
|
+
// separately since it needs different treatment for inline vs. remote
|
|
54
|
+
// scripts, and `nonce` is copied here as a fallback but then overridden
|
|
55
|
+
// below with the page's current CSP nonce when one is found.
|
|
56
|
+
const COPIED_ATTRIBUTES = [
|
|
57
|
+
TYPE,
|
|
58
|
+
NONCE,
|
|
59
|
+
"crossorigin",
|
|
60
|
+
"integrity",
|
|
61
|
+
"referrerpolicy",
|
|
62
|
+
"fetchpriority",
|
|
63
|
+
"nomodule",
|
|
64
|
+
];
|
|
65
|
+
|
|
17
66
|
const getPromise = (url, script) => {
|
|
18
67
|
return new Promise((resolve, reject) => {
|
|
19
68
|
script.onload = () => {
|
|
@@ -24,24 +73,45 @@ const getPromise = (url, script) => {
|
|
|
24
73
|
};
|
|
25
74
|
});
|
|
26
75
|
};
|
|
76
|
+
|
|
77
|
+
// Re-creates a script in <head> so the browser executes it (scripts inserted via
|
|
78
|
+
// innerHTML never run). Handles both remote scripts (with a src) and inline
|
|
79
|
+
// module scripts: an inline `type="module"` executes asynchronously and belongs
|
|
80
|
+
// with the head-loaded scripts rather than the synchronously-run inline path.
|
|
27
81
|
const loadScript = (source) => {
|
|
28
82
|
const url = getAttribute(source, SRC);
|
|
29
83
|
const script = document.createElement("script");
|
|
30
|
-
//
|
|
31
|
-
//
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
84
|
+
// Only carry the attributes required to execute the script correctly:
|
|
85
|
+
// `src` (below) and COPIED_ATTRIBUTES. Author attributes such as `id`,
|
|
86
|
+
// `class`, and `data-*` are intentionally NOT copied: the original offer
|
|
87
|
+
// <script> is left in the page (inert), so copying its id/class onto this
|
|
88
|
+
// executed element would create duplicate matches for
|
|
89
|
+
// document.getElementById / querySelector.
|
|
90
|
+
COPIED_ATTRIBUTES.forEach((name) => {
|
|
91
|
+
const value = getAttribute(source, name);
|
|
92
|
+
if (value !== null) {
|
|
93
|
+
script.setAttribute(name, value);
|
|
94
|
+
}
|
|
95
|
+
});
|
|
96
|
+
// The page's current CSP nonce takes priority over whatever nonce (if any)
|
|
97
|
+
// was written into the source markup, since that's the one the browser
|
|
98
|
+
// will actually check against the CSP header for this page load.
|
|
38
99
|
const nonce = getNonce();
|
|
39
100
|
if (nonce) {
|
|
40
|
-
script.setAttribute(
|
|
101
|
+
script.setAttribute(NONCE, nonce);
|
|
41
102
|
}
|
|
103
|
+
|
|
104
|
+
if (!url) {
|
|
105
|
+
// Inline module script: carry the code across and let it execute in <head>.
|
|
106
|
+
// Inline scripts emit no load event, so completion cannot be tracked; we
|
|
107
|
+
// resolve immediately and rely on the browser's deferred module execution.
|
|
108
|
+
script.textContent = source.textContent;
|
|
109
|
+
document.head.appendChild(script);
|
|
110
|
+
return Promise.resolve(script);
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
script.src = url;
|
|
42
114
|
script.async = true;
|
|
43
|
-
// Assign load handlers after copying attributes so a copied inline
|
|
44
|
-
// onload/onerror attribute can't break load-completion tracking.
|
|
45
115
|
const promise = getPromise(url, script);
|
|
46
116
|
document.head.appendChild(script);
|
|
47
117
|
return promise;
|
|
@@ -50,11 +120,59 @@ const loadScript = (source) => {
|
|
|
50
120
|
export const is = (element, tagName) =>
|
|
51
121
|
!!element && element.tagName === tagName;
|
|
52
122
|
|
|
53
|
-
|
|
54
|
-
|
|
123
|
+
// Normalizes away casing/whitespace/parameters (e.g. "TEXT/JAVASCRIPT ;
|
|
124
|
+
// charset=utf-8") so it can be compared against MODULE/JAVASCRIPT_MIME_TYPES.
|
|
125
|
+
const getNormalizedType = (element) => {
|
|
126
|
+
const type = getAttribute(element, TYPE);
|
|
127
|
+
return type ? type.split(";")[0].trim().toLowerCase() : "";
|
|
128
|
+
};
|
|
55
129
|
|
|
56
|
-
const
|
|
57
|
-
|
|
130
|
+
const isModule = (element) => getNormalizedType(element) === MODULE;
|
|
131
|
+
|
|
132
|
+
// An empty src (`<script src="">`) is treated as "no src" — it points nowhere,
|
|
133
|
+
// so the script is handled on the inline path rather than fetched.
|
|
134
|
+
const hasSrc = (element) => !!getAttribute(element, SRC);
|
|
135
|
+
|
|
136
|
+
// A <script> the browser would actually execute: a classic script (type is
|
|
137
|
+
// absent/empty or a recognized JavaScript MIME type) or an ES module. Any other
|
|
138
|
+
// type is a data block (e.g. "importmap", "application/json", a templating
|
|
139
|
+
// library's custom type) that never runs — see JAVASCRIPT_MIME_TYPES above.
|
|
140
|
+
// Only executable scripts are extracted and re-inserted; the rest are left
|
|
141
|
+
// untouched, since forcing them to run was never the intent.
|
|
142
|
+
const isExecutableScript = (element) => {
|
|
143
|
+
if (!is(element, SCRIPT)) {
|
|
144
|
+
return false;
|
|
145
|
+
}
|
|
146
|
+
const type = getNormalizedType(element);
|
|
147
|
+
return type === "" || type === MODULE || JAVASCRIPT_MIME_TYPES.has(type);
|
|
148
|
+
};
|
|
149
|
+
|
|
150
|
+
// How a given <script> must be re-created for the browser to run it:
|
|
151
|
+
// HEAD_SCRIPT – re-created in <head>: any remote script (with a src), plus
|
|
152
|
+
// inline ES modules. An inline `type="module"` executes
|
|
153
|
+
// asynchronously, so it belongs with the head scripts rather
|
|
154
|
+
// than the synchronous inline path.
|
|
155
|
+
// INLINE_SCRIPT – classic inline script: re-created and run synchronously in
|
|
156
|
+
// the offer container.
|
|
157
|
+
const HEAD_SCRIPT = "head";
|
|
158
|
+
const INLINE_SCRIPT = "inline";
|
|
159
|
+
|
|
160
|
+
// Classifies a <script>, or returns null when there's nothing to run: either a
|
|
161
|
+
// data block the browser would never execute (left untouched), or an inline
|
|
162
|
+
// script with no code. `src`-less inline scripts need code to be worth running;
|
|
163
|
+
// a remote script's code lives at its `src`, so it always qualifies.
|
|
164
|
+
const classifyScript = (element) => {
|
|
165
|
+
if (!isExecutableScript(element)) {
|
|
166
|
+
return null;
|
|
167
|
+
}
|
|
168
|
+
if (hasSrc(element)) {
|
|
169
|
+
return HEAD_SCRIPT;
|
|
170
|
+
}
|
|
171
|
+
if (!element.textContent) {
|
|
172
|
+
return null;
|
|
173
|
+
}
|
|
174
|
+
return isModule(element) ? HEAD_SCRIPT : INLINE_SCRIPT;
|
|
175
|
+
};
|
|
58
176
|
|
|
59
177
|
export const getInlineScripts = (fragment) => {
|
|
60
178
|
const scripts = selectNodes(SCRIPT, fragment);
|
|
@@ -68,17 +186,24 @@ export const getInlineScripts = (fragment) => {
|
|
|
68
186
|
for (let i = 0; i < length; i += 1) {
|
|
69
187
|
const element = scripts[i];
|
|
70
188
|
|
|
71
|
-
if (
|
|
189
|
+
if (classifyScript(element) !== INLINE_SCRIPT) {
|
|
72
190
|
continue;
|
|
73
191
|
}
|
|
74
192
|
|
|
75
193
|
const { textContent } = element;
|
|
76
194
|
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
195
|
+
// `nomodule` is preserved even though this element is force-executed via
|
|
196
|
+
// appendChild: without it, a classic script the author intended as a
|
|
197
|
+
// legacy fallback (skipped in module-supporting browsers) would run
|
|
198
|
+
// where it otherwise wouldn't have.
|
|
199
|
+
const nomodule = getAttribute(element, NOMODULE);
|
|
200
|
+
result.push(
|
|
201
|
+
createNode(
|
|
202
|
+
SCRIPT,
|
|
203
|
+
{ ...attributes, ...(nomodule !== null && { nomodule }) },
|
|
204
|
+
{ textContent },
|
|
205
|
+
),
|
|
206
|
+
);
|
|
82
207
|
}
|
|
83
208
|
|
|
84
209
|
return result;
|
|
@@ -92,8 +217,7 @@ export const getRemoteScripts = (fragment) => {
|
|
|
92
217
|
for (let i = 0; i < length; i += 1) {
|
|
93
218
|
const element = scripts[i];
|
|
94
219
|
|
|
95
|
-
|
|
96
|
-
if (!isRemoteScript(element)) {
|
|
220
|
+
if (classifyScript(element) !== HEAD_SCRIPT) {
|
|
97
221
|
continue;
|
|
98
222
|
}
|
|
99
223
|
|