@adobe/alloy 2.35.1-beta.0 → 2.35.1-beta.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 CHANGED
@@ -5828,6 +5828,8 @@
5828
5828
  OF ANY KIND, either express or implied. See the License for the specific language
5829
5829
  governing permissions and limitations under the License.
5830
5830
  */
5831
+
5832
+
5831
5833
  const STATE_STORE_HANDLE_TYPE = "state:store";
5832
5834
 
5833
5835
  var createCookieTransfer = ({
@@ -5842,7 +5844,7 @@
5842
5844
  * access first-party cookies, therefore we transfer cookies into
5843
5845
  * the request body so they can be read by the server.
5844
5846
  */
5845
- cookiesToPayload(payload, endpointDomain) {
5847
+ cookiesToPayload(payload, endpointDomain, extraCookieNames = []) {
5846
5848
  // localhost is a special case where the apexDomain is ""
5847
5849
  // We want to treat localhost as a third-party domain.
5848
5850
  const isEndpointFirstParty =
@@ -5855,20 +5857,22 @@
5855
5857
  // If the endpoint is first-party, there's no need to transfer cookies
5856
5858
  // to the payload since they'll be automatically passed through cookie
5857
5859
  // headers.
5858
- if (!isEndpointFirstParty) {
5860
+ if (!isEndpointFirstParty || isNonEmptyArray(extraCookieNames)) {
5859
5861
  const cookies = cookieJar.getAll();
5860
-
5861
- const entries = Object.keys(cookies)
5862
- .filter(shouldTransferCookie)
5863
- .map((qualifyingCookieName) => {
5864
- return {
5865
- key: qualifyingCookieName,
5866
- value: cookies[qualifyingCookieName],
5867
- };
5868
- });
5869
-
5870
- if (entries.length) {
5871
- state.entries = entries;
5862
+ const entriesByKey = new Map();
5863
+ const addEntry = (key) => {
5864
+ if (cookies[key] !== undefined && !entriesByKey.has(key)) {
5865
+ entriesByKey.set(key, { key, value: cookies[key] });
5866
+ }
5867
+ };
5868
+ if (!isEndpointFirstParty) {
5869
+ Object.keys(cookies).filter(shouldTransferCookie).forEach(addEntry);
5870
+ }
5871
+ if (isNonEmptyArray(extraCookieNames)) {
5872
+ extraCookieNames.forEach(addEntry);
5873
+ }
5874
+ if (entriesByKey.size) {
5875
+ state.entries = [...entriesByKey.values()];
5872
5876
  }
5873
5877
  }
5874
5878
 
@@ -5926,6 +5930,9 @@
5926
5930
  const MBOX_EDGE_CLUSTER = "mboxEdgeCluster";
5927
5931
  const AT_QA_MODE = "at_qa_mode";
5928
5932
  const MBOX = "mbox";
5933
+ // The cookie that Marketo (Munchkin) JS sets. It must be forwarded so the
5934
+ // server can resolve the visitor's Marketo identity for Marketo integrations.
5935
+ const MUNCHKIN = "_mkto_trk";
5929
5936
 
5930
5937
  /*
5931
5938
  Copyright 2022 Adobe. All rights reserved.
@@ -5946,10 +5953,13 @@
5946
5953
  // all cookies whose names are namespaced according to the
5947
5954
  // logic in isNamespacedCookieName as well as any legacy
5948
5955
  // cookie names (so that the server can handle migrating
5949
- // identities on websites previously using Visitor.js)
5956
+ // identities on websites previously using Visitor.js). The
5957
+ // Marketo Munchkin cookie is always forwarded so the server
5958
+ // can resolve the visitor's Marketo identity.
5950
5959
  return (
5951
5960
  isNamespacedCookieName(orgId, name) ||
5952
5961
  name === AT_QA_MODE ||
5962
+ name === MUNCHKIN ||
5953
5963
  (targetMigrationEnabled && name === MBOX)
5954
5964
  );
5955
5965
  };
@@ -7746,10 +7756,10 @@
7746
7756
  governing permissions and limitations under the License.
7747
7757
  */
7748
7758
 
7749
- // The 2.35.1-beta.0 keyword will be replace at alloy build time with the package.json version.
7759
+ // The 2.35.1-beta.1 keyword will be replace at alloy build time with the package.json version.
7750
7760
  // see babel-plugin-version
7751
7761
 
7752
- var libraryVersion = "2.35.1-beta.0";
7762
+ var libraryVersion = "2.35.1-beta.1";
7753
7763
 
7754
7764
  /*
7755
7765
  Copyright 2019 Adobe. All rights reserved.
@@ -10216,8 +10226,8 @@
10216
10226
  const ID = "id";
10217
10227
  const IAM_EVENT_TYPE = "iam.eventType";
10218
10228
  const EVENT_TYPE = "eventType";
10219
- const TYPE = "type";
10220
- const VALID_EVENT_TYPES = [IAM_EVENT_TYPE, EVENT_TYPE, TYPE];
10229
+ const TYPE$1 = "type";
10230
+ const VALID_EVENT_TYPES = [IAM_EVENT_TYPE, EVENT_TYPE, TYPE$1];
10221
10231
  const VALID_EVENT_IDS = [IAM_ID, ID];
10222
10232
  const checkForHistoricalMatcher = (eventCount, matcherKey, value) => {
10223
10233
  switch (matcherKey) {
@@ -12898,6 +12908,7 @@
12898
12908
  sendConversationServiceRequest,
12899
12909
  buildEndpointUrl,
12900
12910
  cookieTransfer,
12911
+ alwaysTransferCookies = [],
12901
12912
  createResponse,
12902
12913
  decodeKndctrCookie,
12903
12914
  lifecycle,
@@ -12978,9 +12989,11 @@
12978
12989
  }
12979
12990
 
12980
12991
  payload.addEvent(event);
12981
- if (config.conversation.stickyConversationSession === true) {
12982
- cookieTransfer.cookiesToPayload(payload, edgeDomain);
12983
- }
12992
+ cookieTransfer.cookiesToPayload(
12993
+ payload,
12994
+ edgeDomain,
12995
+ alwaysTransferCookies,
12996
+ );
12984
12997
  return sendConversationServiceRequest({
12985
12998
  requestId: v4(),
12986
12999
  url,
@@ -13151,10 +13164,14 @@
13151
13164
  .default(STREAM_START_TIMEOUT_MS),
13152
13165
  collectSources: boundBoolean().default(false),
13153
13166
  region: boundString().matches(/^[a-z]{2,4}[0-9]{1,2}$/i),
13167
+ // Additional first-party cookie names to always transfer into the
13168
+ // request meta.state object (on top of the ones transferred by default).
13169
+ transferCookies: boundArrayOf(boundString()).default([]),
13154
13170
  }).default({
13155
13171
  stickyConversationSession: false,
13156
13172
  streamTimeout: STREAM_START_TIMEOUT_MS,
13157
13173
  collectSources: false,
13174
+ transferCookies: [],
13158
13175
  }),
13159
13176
  });
13160
13177
 
@@ -13182,6 +13199,8 @@
13182
13199
  cookieTransfer,
13183
13200
  createResponse,
13184
13201
  platformServices,
13202
+ createSendConversationEvent:
13203
+ createSendConversationEventFactory = createSendConversationEvent,
13185
13204
  }) => {
13186
13205
  const session = {
13187
13206
  id: getConciergeSessionCookie({ loggingCookieJar, config }),
@@ -13199,14 +13218,18 @@
13199
13218
  cookieJar: loggingCookieJar,
13200
13219
  logger,
13201
13220
  });
13202
- const sendConversationEvent = createSendConversationEvent({
13221
+ const sendConversationEvent = createSendConversationEventFactory({
13222
+ loggingCookieJar,
13203
13223
  logger,
13204
13224
  eventManager,
13205
13225
  consent,
13226
+ instanceName,
13227
+ sendEdgeNetworkRequest,
13206
13228
  config,
13207
13229
  buildEndpointUrl,
13208
13230
  lifecycle,
13209
13231
  cookieTransfer,
13232
+ alwaysTransferCookies: config.conversation.transferCookies || [],
13210
13233
  createResponse,
13211
13234
  sendConversationServiceRequest,
13212
13235
  decodeKndctrCookie,
@@ -17229,6 +17252,55 @@
17229
17252
  governing permissions and limitations under the License.
17230
17253
  */
17231
17254
 
17255
+ const TYPE = "type";
17256
+ const MODULE = "module";
17257
+ const NONCE = "nonce";
17258
+ const NOMODULE = "nomodule";
17259
+
17260
+ // Per the HTML spec, a <script> only ever executes if its type is absent/
17261
+ // empty, "module", or one of these recognized JavaScript MIME type essences
17262
+ // (https://mimesniff.spec.whatwg.org/#javascript-mime-type). Any other type
17263
+ // (e.g. "importmap", "application/json", a templating library's custom type)
17264
+ // makes the element a data block: the browser never executes it, regardless
17265
+ // of whether it's parsed from HTML, inserted via innerHTML, or appended with
17266
+ // appendChild. Such elements are left untouched by this module — extracting
17267
+ // and re-inserting them would be pointless at best, and at worst (if `type`
17268
+ // were dropped along the way) would turn inert data into code that runs.
17269
+ const JAVASCRIPT_MIME_TYPES = new Set([
17270
+ "application/ecmascript",
17271
+ "application/javascript",
17272
+ "application/x-ecmascript",
17273
+ "application/x-javascript",
17274
+ "text/ecmascript",
17275
+ "text/javascript",
17276
+ "text/javascript1.0",
17277
+ "text/javascript1.1",
17278
+ "text/javascript1.2",
17279
+ "text/javascript1.3",
17280
+ "text/javascript1.4",
17281
+ "text/javascript1.5",
17282
+ "text/jscript",
17283
+ "text/livescript",
17284
+ "text/x-ecmascript",
17285
+ "text/x-javascript",
17286
+ ]);
17287
+
17288
+ // Attributes that affect how the script executes/fetches (as opposed to
17289
+ // identity/presentation attributes like id, class, and data-*, which are
17290
+ // intentionally not copied — see loadScript below). `src` is handled
17291
+ // separately since it needs different treatment for inline vs. remote
17292
+ // scripts, and `nonce` is copied here as a fallback but then overridden
17293
+ // below with the page's current CSP nonce when one is found.
17294
+ const COPIED_ATTRIBUTES = [
17295
+ TYPE,
17296
+ NONCE,
17297
+ "crossorigin",
17298
+ "integrity",
17299
+ "referrerpolicy",
17300
+ "fetchpriority",
17301
+ "nomodule",
17302
+ ];
17303
+
17232
17304
  const getPromise = (url, script) => {
17233
17305
  return new Promise((resolve, reject) => {
17234
17306
  script.onload = () => {
@@ -17239,24 +17311,45 @@
17239
17311
  };
17240
17312
  });
17241
17313
  };
17314
+
17315
+ // Re-creates a script in <head> so the browser executes it (scripts inserted via
17316
+ // innerHTML never run). Handles both remote scripts (with a src) and inline
17317
+ // module scripts: an inline `type="module"` executes asynchronously and belongs
17318
+ // with the head-loaded scripts rather than the synchronously-run inline path.
17242
17319
  const loadScript = (source) => {
17243
17320
  const url = getAttribute(source, SRC);
17244
17321
  const script = document.createElement("script");
17245
- // Preserve all author-supplied attributes (class, type, data-*, etc.) so
17246
- // consumers relying on them keep working.
17247
- const { attributes } = source;
17248
- for (let i = 0; i < attributes.length; i += 1) {
17249
- const { name, value } = attributes[i];
17250
- script.setAttribute(name, value);
17251
- }
17252
- // Override invariants last so they can't be clobbered by the source element.
17322
+ // Only carry the attributes required to execute the script correctly:
17323
+ // `src` (below) and COPIED_ATTRIBUTES. Author attributes such as `id`,
17324
+ // `class`, and `data-*` are intentionally NOT copied: the original offer
17325
+ // <script> is left in the page (inert), so copying its id/class onto this
17326
+ // executed element would create duplicate matches for
17327
+ // document.getElementById / querySelector.
17328
+ COPIED_ATTRIBUTES.forEach((name) => {
17329
+ const value = getAttribute(source, name);
17330
+ if (value !== null) {
17331
+ script.setAttribute(name, value);
17332
+ }
17333
+ });
17334
+ // The page's current CSP nonce takes priority over whatever nonce (if any)
17335
+ // was written into the source markup, since that's the one the browser
17336
+ // will actually check against the CSP header for this page load.
17253
17337
  const nonce = getNonce();
17254
17338
  if (nonce) {
17255
- script.setAttribute("nonce", nonce);
17339
+ script.setAttribute(NONCE, nonce);
17256
17340
  }
17341
+
17342
+ if (!url) {
17343
+ // Inline module script: carry the code across and let it execute in <head>.
17344
+ // Inline scripts emit no load event, so completion cannot be tracked; we
17345
+ // resolve immediately and rely on the browser's deferred module execution.
17346
+ script.textContent = source.textContent;
17347
+ document.head.appendChild(script);
17348
+ return Promise.resolve(script);
17349
+ }
17350
+
17351
+ script.src = url;
17257
17352
  script.async = true;
17258
- // Assign load handlers after copying attributes so a copied inline
17259
- // onload/onerror attribute can't break load-completion tracking.
17260
17353
  const promise = getPromise(url, script);
17261
17354
  document.head.appendChild(script);
17262
17355
  return promise;
@@ -17265,11 +17358,59 @@
17265
17358
  const is = (element, tagName) =>
17266
17359
  !!element && element.tagName === tagName;
17267
17360
 
17268
- const isInlineScript = (element) =>
17269
- is(element, SCRIPT) && !getAttribute(element, SRC);
17361
+ // Normalizes away casing/whitespace/parameters (e.g. "TEXT/JAVASCRIPT ;
17362
+ // charset=utf-8") so it can be compared against MODULE/JAVASCRIPT_MIME_TYPES.
17363
+ const getNormalizedType = (element) => {
17364
+ const type = getAttribute(element, TYPE);
17365
+ return type ? type.split(";")[0].trim().toLowerCase() : "";
17366
+ };
17367
+
17368
+ const isModule = (element) => getNormalizedType(element) === MODULE;
17369
+
17370
+ // An empty src (`<script src="">`) is treated as "no src" — it points nowhere,
17371
+ // so the script is handled on the inline path rather than fetched.
17372
+ const hasSrc = (element) => !!getAttribute(element, SRC);
17270
17373
 
17271
- const isRemoteScript = (element) =>
17272
- is(element, SCRIPT) && getAttribute(element, SRC);
17374
+ // A <script> the browser would actually execute: a classic script (type is
17375
+ // absent/empty or a recognized JavaScript MIME type) or an ES module. Any other
17376
+ // type is a data block (e.g. "importmap", "application/json", a templating
17377
+ // library's custom type) that never runs — see JAVASCRIPT_MIME_TYPES above.
17378
+ // Only executable scripts are extracted and re-inserted; the rest are left
17379
+ // untouched, since forcing them to run was never the intent.
17380
+ const isExecutableScript = (element) => {
17381
+ if (!is(element, SCRIPT)) {
17382
+ return false;
17383
+ }
17384
+ const type = getNormalizedType(element);
17385
+ return type === "" || type === MODULE || JAVASCRIPT_MIME_TYPES.has(type);
17386
+ };
17387
+
17388
+ // How a given <script> must be re-created for the browser to run it:
17389
+ // HEAD_SCRIPT – re-created in <head>: any remote script (with a src), plus
17390
+ // inline ES modules. An inline `type="module"` executes
17391
+ // asynchronously, so it belongs with the head scripts rather
17392
+ // than the synchronous inline path.
17393
+ // INLINE_SCRIPT – classic inline script: re-created and run synchronously in
17394
+ // the offer container.
17395
+ const HEAD_SCRIPT = "head";
17396
+ const INLINE_SCRIPT = "inline";
17397
+
17398
+ // Classifies a <script>, or returns null when there's nothing to run: either a
17399
+ // data block the browser would never execute (left untouched), or an inline
17400
+ // script with no code. `src`-less inline scripts need code to be worth running;
17401
+ // a remote script's code lives at its `src`, so it always qualifies.
17402
+ const classifyScript = (element) => {
17403
+ if (!isExecutableScript(element)) {
17404
+ return null;
17405
+ }
17406
+ if (hasSrc(element)) {
17407
+ return HEAD_SCRIPT;
17408
+ }
17409
+ if (!element.textContent) {
17410
+ return null;
17411
+ }
17412
+ return isModule(element) ? HEAD_SCRIPT : INLINE_SCRIPT;
17413
+ };
17273
17414
 
17274
17415
  const getInlineScripts = (fragment) => {
17275
17416
  const scripts = selectNodes(SCRIPT, fragment);
@@ -17283,17 +17424,24 @@
17283
17424
  for (let i = 0; i < length; i += 1) {
17284
17425
  const element = scripts[i];
17285
17426
 
17286
- if (!isInlineScript(element)) {
17427
+ if (classifyScript(element) !== INLINE_SCRIPT) {
17287
17428
  continue;
17288
17429
  }
17289
17430
 
17290
17431
  const { textContent } = element;
17291
17432
 
17292
- if (!textContent) {
17293
- continue;
17294
- }
17295
-
17296
- result.push(createNode(SCRIPT, attributes, { textContent }));
17433
+ // `nomodule` is preserved even though this element is force-executed via
17434
+ // appendChild: without it, a classic script the author intended as a
17435
+ // legacy fallback (skipped in module-supporting browsers) would run
17436
+ // where it otherwise wouldn't have.
17437
+ const nomodule = getAttribute(element, NOMODULE);
17438
+ result.push(
17439
+ createNode(
17440
+ SCRIPT,
17441
+ { ...attributes, ...(nomodule !== null && { nomodule }) },
17442
+ { textContent },
17443
+ ),
17444
+ );
17297
17445
  }
17298
17446
 
17299
17447
  return result;
@@ -17307,8 +17455,7 @@
17307
17455
  for (let i = 0; i < length; i += 1) {
17308
17456
  const element = scripts[i];
17309
17457
 
17310
- // isRemoteScript already requires a non-empty src attribute.
17311
- if (!isRemoteScript(element)) {
17458
+ if (classifyScript(element) !== HEAD_SCRIPT) {
17312
17459
  continue;
17313
17460
  }
17314
17461