@adobe/alloy 2.35.1 → 2.36.0-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
@@ -2000,6 +2000,43 @@
2000
2000
  var reactorQueryStringExports = requireReactorQueryString();
2001
2001
  var queryString = /*@__PURE__*/getDefaultExportFromCjs(reactorQueryStringExports);
2002
2002
 
2003
+ /*
2004
+ Copyright 2026 Adobe. All rights reserved.
2005
+ This file is licensed to you under the Apache License, Version 2.0 (the "License");
2006
+ you may not use this file except in compliance with the License. You may obtain a copy
2007
+ of the License at http://www.apache.org/licenses/LICENSE-2.0
2008
+
2009
+ Unless required by applicable law or agreed to in writing, software distributed under
2010
+ the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR REPRESENTATIONS
2011
+ OF ANY KIND, either express or implied. See the License for the specific language
2012
+ governing permissions and limitations under the License.
2013
+ */
2014
+
2015
+ /**
2016
+ * Returns `value` unchanged unless it has an `edgeCredentials.clientSecret`,
2017
+ * in which case it returns a shallow copy with that one value replaced by
2018
+ * `"[REDACTED]"`. Deliberately not a deep clone, so anything else on
2019
+ * `value` (including functions like `onBeforeEventSend`) survives as the
2020
+ * exact same reference.
2021
+ * @param {*} value
2022
+ * @returns {any}
2023
+ */
2024
+ var redactEdgeCredentials = (value) => {
2025
+ if (
2026
+ !value?.edgeCredentials ||
2027
+ !Object.prototype.hasOwnProperty.call(value.edgeCredentials, "clientSecret")
2028
+ ) {
2029
+ return value;
2030
+ }
2031
+ return {
2032
+ ...value,
2033
+ edgeCredentials: {
2034
+ ...value.edgeCredentials,
2035
+ clientSecret: "[REDACTED]",
2036
+ },
2037
+ };
2038
+ };
2039
+
2003
2040
  /*
2004
2041
  Copyright 2025 Adobe. All rights reserved.
2005
2042
  This file is licensed to you under the Apache License, Version 2.0 (the "License");
@@ -3713,7 +3750,7 @@
3713
3750
  /**
3714
3751
  * Send a network request and returns details about the response.
3715
3752
  */
3716
- return ({ requestId, url, payload, useSendBeacon }) => {
3753
+ return ({ requestId, url, payload, useSendBeacon, headers }) => {
3717
3754
  // We want to log raw payload and event data rather than
3718
3755
  // our fancy wrapper objects. Calling payload.toJSON() is
3719
3756
  // insufficient to get all the nested raw data, because it's
@@ -3731,52 +3768,56 @@
3731
3768
  });
3732
3769
 
3733
3770
  const executeRequest = (retriesAttempted = 0) => {
3734
- const requestMethod = useSendBeacon
3735
- ? sendBeaconRequest
3736
- : sendFetchRequest;
3737
-
3738
- return requestMethod(url, stringifiedPayload).then((response) => {
3739
- const requestIsRetryable = isRequestRetryable({
3740
- response,
3741
- retriesAttempted,
3742
- });
3743
-
3744
- if (requestIsRetryable) {
3745
- const requestRetryDelay = getRequestRetryDelay({
3771
+ // navigator.sendBeacon() has no way to attach custom headers, so a
3772
+ // request that needs any (e.g. authenticated Server API requests)
3773
+ // must always go through fetch, regardless of useSendBeacon.
3774
+ const requestMethod =
3775
+ useSendBeacon && !headers ? sendBeaconRequest : sendFetchRequest;
3776
+
3777
+ return requestMethod(url, stringifiedPayload, headers).then(
3778
+ (response) => {
3779
+ const requestIsRetryable = isRequestRetryable({
3746
3780
  response,
3747
3781
  retriesAttempted,
3748
3782
  });
3749
- return new Promise((resolve) => {
3750
- setTimeout(() => {
3751
- resolve(executeRequest(retriesAttempted + 1));
3752
- }, requestRetryDelay);
3753
- });
3754
- }
3755
3783
 
3756
- let parsedBody;
3784
+ if (requestIsRetryable) {
3785
+ const requestRetryDelay = getRequestRetryDelay({
3786
+ response,
3787
+ retriesAttempted,
3788
+ });
3789
+ return new Promise((resolve) => {
3790
+ setTimeout(() => {
3791
+ resolve(executeRequest(retriesAttempted + 1));
3792
+ }, requestRetryDelay);
3793
+ });
3794
+ }
3757
3795
 
3758
- try {
3759
- parsedBody = JSON.parse(response.body);
3760
- } catch {
3761
- // Non-JSON. Something went wrong.
3762
- }
3796
+ let parsedBody;
3763
3797
 
3764
- logger.logOnNetworkResponse({
3765
- requestId,
3766
- url,
3767
- payload: parsedPayload,
3768
- ...response,
3769
- parsedBody,
3770
- retriesAttempted,
3771
- });
3798
+ try {
3799
+ parsedBody = JSON.parse(response.body);
3800
+ } catch {
3801
+ // Non-JSON. Something went wrong.
3802
+ }
3772
3803
 
3773
- return {
3774
- statusCode: response.statusCode,
3775
- body: response.body,
3776
- parsedBody,
3777
- getHeader: response.getHeader,
3778
- };
3779
- });
3804
+ logger.logOnNetworkResponse({
3805
+ requestId,
3806
+ url,
3807
+ payload: parsedPayload,
3808
+ ...response,
3809
+ parsedBody,
3810
+ retriesAttempted,
3811
+ });
3812
+
3813
+ return {
3814
+ statusCode: response.statusCode,
3815
+ body: response.body,
3816
+ parsedBody,
3817
+ getHeader: response.getHeader,
3818
+ };
3819
+ },
3820
+ );
3780
3821
  };
3781
3822
 
3782
3823
  return executeRequest().catch((error) => {
@@ -5021,6 +5062,10 @@
5021
5062
 
5022
5063
  const EDGE = "edge.adobedc.net";
5023
5064
  const ID_THIRD_PARTY = "adobedc.demdex.net";
5065
+ // The authenticated Edge Network Server API — a different domain
5066
+ // entirely from EDGE, used only when edgeCredentials are configured.
5067
+ const SERVER = "server.adobedc.net";
5068
+ const DEFAULT_IMS_HOST = "ims-na1.adobelogin.com";
5024
5069
 
5025
5070
  /*
5026
5071
  Copyright 2023 Adobe. All rights reserved.
@@ -5057,6 +5102,14 @@
5057
5102
  orgId: boundString().unique().required(),
5058
5103
  onBeforeEventSend: boundCallback().default(noop),
5059
5104
  edgeConfigOverrides: validateConfigOverride,
5105
+ // Opt-in OAuth Server-to-Server credentials — when present, requests
5106
+ // use the authenticated Server API (v2) instead of v1.
5107
+ edgeCredentials: boundObjectOf({
5108
+ clientId: boundString().nonEmpty().required(),
5109
+ clientSecret: boundString().nonEmpty().required(),
5110
+ scopes: boundArrayOf(boundString().nonEmpty()).nonEmpty().required(),
5111
+ imsHost: boundString().domain().default(DEFAULT_IMS_HOST),
5112
+ }),
5060
5113
  }).renamed("edgeConfigId", boundString().unique(), "datastreamId");
5061
5114
 
5062
5115
  /*
@@ -5103,16 +5156,25 @@
5103
5156
  governing permissions and limitations under the License.
5104
5157
  */
5105
5158
 
5159
+
5106
5160
  var createLogger = ({ getDebugEnabled, console, getMonitors, context }) => {
5107
5161
  let prefix = `[${context.instanceName}]`;
5108
5162
  if (context.componentName) {
5109
5163
  prefix += ` [${context.componentName}]`;
5110
5164
  }
5111
5165
 
5166
+ // redactEdgeCredentials no-ops on anything without edgeCredentials, so
5167
+ // applying it here covers every call site (config, command options, ...)
5168
+ // without redacting each one individually.
5112
5169
  const notifyMonitors = (method, data) => {
5113
5170
  const monitors = getMonitors();
5114
5171
  if (monitors.length > 0) {
5115
- const dataWithContext = { ...context, ...data };
5172
+ const dataWithContext = {
5173
+ ...context,
5174
+ ...data,
5175
+ config: redactEdgeCredentials(data.config),
5176
+ options: redactEdgeCredentials(data.options),
5177
+ };
5116
5178
  monitors.forEach((monitor) => {
5117
5179
  if (monitor[method]) {
5118
5180
  monitor[method](dataWithContext);
@@ -5122,9 +5184,10 @@
5122
5184
  };
5123
5185
 
5124
5186
  const log = (level, ...rest) => {
5125
- notifyMonitors("onBeforeLog", { level, arguments: rest });
5187
+ const redactedRest = rest.map(redactEdgeCredentials);
5188
+ notifyMonitors("onBeforeLog", { level, arguments: redactedRest });
5126
5189
  if (getDebugEnabled()) {
5127
- console[level](prefix, ...rest);
5190
+ console[level](prefix, ...redactedRest);
5128
5191
  }
5129
5192
  };
5130
5193
 
@@ -6129,6 +6192,25 @@
6129
6192
  return request.getUseIdThirdPartyDomain() && isNetworkError(error);
6130
6193
  };
6131
6194
 
6195
+ // Confirmed against the real API: the Server API (v2) only exists for the
6196
+ // interact action — privacy/set-consent and identity/acquire both 404
6197
+ // under v2.
6198
+ const isServerApiEligible = (request) => request.getAction() === "interact";
6199
+
6200
+ // v2 expects a singular `event` object rather than v1's `events` array,
6201
+ // and requires an explicit primary identity in it (no browser cookie to
6202
+ // resolve identity from) — confirmed by testing against the real
6203
+ // endpoint; not documented anywhere we could find.
6204
+ const toServerApiPayloadJSON = (payload) => {
6205
+ const { events, ...rest } = payload.toJSON();
6206
+ if (!events || events.length !== 1) {
6207
+ throw new Error(
6208
+ `The authenticated Server API (v2) only supports exactly one event per request; got ${events ? events.length : 0}.`,
6209
+ );
6210
+ }
6211
+ return { ...rest, event: events[0] };
6212
+ };
6213
+
6132
6214
  /**
6133
6215
  * @function
6134
6216
  *
@@ -6141,7 +6223,7 @@
6141
6223
  * @param {function(object): void} options.processWarningsAndErrors
6142
6224
  * @param {function(): string|undefined} options.getLocationHint
6143
6225
  * @param {function(): string} options.getAssuranceValidationTokenParams
6144
-
6226
+ * @param {{ getAccessToken: () => Promise<string> }} [options.getImsAccessToken]
6145
6227
  *
6146
6228
  * @returns {EdgeRequestExecutor} A function that sends edge network requests with lifecycle management
6147
6229
  */
@@ -6154,18 +6236,26 @@
6154
6236
  processWarningsAndErrors,
6155
6237
  getLocationHint,
6156
6238
  getAssuranceValidationTokenParams,
6239
+ getImsAccessToken,
6157
6240
  }) => {
6158
- const { edgeDomain, edgeBasePath, datastreamId } = config;
6241
+ const { edgeDomain, edgeBasePath, datastreamId, orgId, edgeCredentials } =
6242
+ config;
6159
6243
  let hasDemdexFailed = false;
6160
6244
 
6161
- const buildEndpointUrl = (endpointDomain, request) => {
6162
- const locationHint = getLocationHint();
6245
+ // v2 differs from v1 in domain, version segment, and datastream query
6246
+ // param name — not just an extra header.
6247
+ const buildEndpointUrl = (endpointDomain, request, useServerApi) => {
6248
+ // The cluster location hint is a browser/v1 CDN-routing artifact —
6249
+ // confirmed against the real API that the Server API domain 404s if
6250
+ // it's included, even though a v1 response can still write the cookie.
6251
+ const locationHint = useServerApi ? undefined : getLocationHint();
6163
6252
  const edgeBasePathWithLocationHint = locationHint
6164
6253
  ? `${edgeBasePath}/${locationHint}${request.getEdgeSubPath()}`
6165
6254
  : `${edgeBasePath}${request.getEdgeSubPath()}`;
6166
- const configId = request.getDatastreamIdOverride() || datastreamId;
6255
+ const resolvedDatastreamId =
6256
+ request.getDatastreamIdOverride() || datastreamId;
6167
6257
 
6168
- if (configId !== datastreamId) {
6258
+ if (resolvedDatastreamId !== datastreamId) {
6169
6259
  request.getPayload().mergeMeta({
6170
6260
  sdkConfig: {
6171
6261
  datastream: {
@@ -6175,7 +6265,19 @@
6175
6265
  });
6176
6266
  }
6177
6267
 
6178
- return `https://${endpointDomain}/${edgeBasePathWithLocationHint}/${apiVersion}/${request.getAction()}?configId=${configId}&requestId=${request.getId()}${getAssuranceValidationTokenParams()}`;
6268
+ const version = useServerApi ? "v2" : apiVersion;
6269
+ const datastreamParamName = useServerApi ? "dataStreamId" : "configId";
6270
+
6271
+ return `https://${endpointDomain}/${edgeBasePathWithLocationHint}/${version}/${request.getAction()}?${datastreamParamName}=${resolvedDatastreamId}&requestId=${request.getId()}${getAssuranceValidationTokenParams()}`;
6272
+ };
6273
+
6274
+ const buildAuthHeaders = async () => {
6275
+ const accessToken = await getImsAccessToken.getAccessToken();
6276
+ return {
6277
+ Authorization: `Bearer ${accessToken}`,
6278
+ "x-api-key": edgeCredentials.clientId,
6279
+ "x-gw-ims-org-id": orgId,
6280
+ };
6179
6281
  };
6180
6282
 
6181
6283
  /**
@@ -6195,19 +6297,25 @@
6195
6297
  onRequestFailureCallbackAggregator.add(lifecycle.onRequestFailure);
6196
6298
  onRequestFailureCallbackAggregator.add(runOnRequestFailureCallbacks);
6197
6299
 
6300
+ const useServerApi = !!edgeCredentials && isServerApiEligible(request);
6301
+
6198
6302
  return lifecycle
6199
6303
  .onBeforeRequest({
6200
6304
  request,
6201
6305
  onResponse: onResponseCallbackAggregator.add,
6202
6306
  onRequestFailure: onRequestFailureCallbackAggregator.add,
6203
6307
  })
6204
- .then(() => {
6205
- const endpointDomain =
6206
- hasDemdexFailed || !request.getUseIdThirdPartyDomain()
6308
+ .then(async () => {
6309
+ // The demdex third-party-domain dance is a browser ITP/ad-blocker
6310
+ // workaround, not applicable to authenticated server-to-server
6311
+ // calls — those always go to the Server API domain instead.
6312
+ const endpointDomain = useServerApi
6313
+ ? SERVER
6314
+ : hasDemdexFailed || !request.getUseIdThirdPartyDomain()
6207
6315
  ? edgeDomain
6208
6316
  : ID_THIRD_PARTY;
6209
6317
 
6210
- const url = buildEndpointUrl(endpointDomain, request);
6318
+ const url = buildEndpointUrl(endpointDomain, request, useServerApi);
6211
6319
  const payload = request.getPayload();
6212
6320
 
6213
6321
  const queueTimeMillis = calculateQueueTimeMillis(payload);
@@ -6217,19 +6325,25 @@
6217
6325
 
6218
6326
  cookieTransfer.cookiesToPayload(payload, endpointDomain);
6219
6327
 
6328
+ const headers = useServerApi ? await buildAuthHeaders() : undefined;
6329
+ const outgoingPayload = useServerApi
6330
+ ? toServerApiPayloadJSON(payload)
6331
+ : payload;
6332
+
6220
6333
  return sendNetworkRequest({
6221
6334
  requestId: request.getId(),
6222
6335
  url,
6223
- payload,
6336
+ payload: outgoingPayload,
6224
6337
  useSendBeacon: request.getUseSendBeacon(),
6338
+ headers,
6225
6339
  });
6226
6340
  })
6227
6341
  .then((networkResponse) => {
6228
6342
  processWarningsAndErrors(networkResponse);
6229
6343
  return networkResponse;
6230
6344
  })
6231
- .catch((error) => {
6232
- if (isDemdexBlockedError(error, request)) {
6345
+ .catch(async (error) => {
6346
+ if (!useServerApi && isDemdexBlockedError(error, request)) {
6233
6347
  hasDemdexFailed = true;
6234
6348
  request.setUseIdThirdPartyDomain(false);
6235
6349
  const url = buildEndpointUrl(edgeDomain, request);
@@ -6264,6 +6378,92 @@
6264
6378
  };
6265
6379
  };
6266
6380
 
6381
+ /*
6382
+ Copyright 2026 Adobe. All rights reserved.
6383
+ This file is licensed to you under the Apache License, Version 2.0 (the "License");
6384
+ you may not use this file except in compliance with the License. You may obtain a copy
6385
+ of the License at http://www.apache.org/licenses/LICENSE-2.0
6386
+
6387
+ Unless required by applicable law or agreed to in writing, software distributed under
6388
+ the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR REPRESENTATIONS
6389
+ OF ANY KIND, either express or implied. See the License for the specific language
6390
+ governing permissions and limitations under the License.
6391
+ */
6392
+
6393
+ // Refresh this long before the real ~24h expiry (Adobe's own guidance is to
6394
+ // rotate at 23h), so a slow request never straddles the token's actual
6395
+ // expiration.
6396
+ const EXPIRY_SAFETY_MARGIN_MILLIS = 5 * 60 * 1000;
6397
+
6398
+ /**
6399
+ * Exchanges OAuth Server-to-Server credentials for an IMS access token,
6400
+ * caching it for reuse until shortly before it expires. Concurrent calls
6401
+ * while a fetch is already in flight share that same in-flight request
6402
+ * instead of each starting their own.
6403
+ *
6404
+ * Deliberately not tied to a single request/instance's lifetime — callers
6405
+ * that rebuild their core instance per request (e.g. Node's forRequest())
6406
+ * should create one of these once and reuse it across those rebuilds, or
6407
+ * every request would re-authenticate with IMS from scratch.
6408
+ *
6409
+ * @param {Object} params
6410
+ * @param {{ clientId: string, clientSecret: string, scopes: string[], imsHost: string }} params.edgeCredentials
6411
+ * @param {() => Date} [params.dateProvider]
6412
+ * @returns {{ getAccessToken: () => Promise<string> }}
6413
+ */
6414
+ var injectGetImsAccessToken = ({ edgeCredentials, dateProvider = () => new Date() }) => {
6415
+ /** @type {string | undefined} */
6416
+ let cachedToken;
6417
+ let expiresAt = 0;
6418
+ /** @type {Promise<string> | undefined} */
6419
+ let pendingFetch;
6420
+
6421
+ const fetchNewToken = async () => {
6422
+ const { clientId, clientSecret, scopes, imsHost } = edgeCredentials;
6423
+ const body = new URLSearchParams({
6424
+ grant_type: "client_credentials",
6425
+ client_id: clientId,
6426
+ client_secret: clientSecret,
6427
+ scope: scopes.join(","),
6428
+ });
6429
+
6430
+ const response = await fetch(`https://${imsHost}/ims/token/v3`, {
6431
+ method: "POST",
6432
+ headers: { "Content-Type": "application/x-www-form-urlencoded" },
6433
+ body: body.toString(),
6434
+ });
6435
+
6436
+ if (!response.ok) {
6437
+ throw new Error(
6438
+ `Failed to acquire an IMS access token: the server responded with a status code ${response.status} and response body: ${await response.text()}`,
6439
+ );
6440
+ }
6441
+
6442
+ const { access_token: accessToken, expires_in: expiresInSeconds } =
6443
+ await response.json();
6444
+ cachedToken = accessToken;
6445
+ expiresAt =
6446
+ dateProvider().getTime() +
6447
+ expiresInSeconds * 1000 -
6448
+ EXPIRY_SAFETY_MARGIN_MILLIS;
6449
+ return cachedToken;
6450
+ };
6451
+
6452
+ return {
6453
+ getAccessToken() {
6454
+ if (cachedToken && dateProvider().getTime() < expiresAt) {
6455
+ return Promise.resolve(cachedToken);
6456
+ }
6457
+ if (!pendingFetch) {
6458
+ pendingFetch = fetchNewToken().finally(() => {
6459
+ pendingFetch = undefined;
6460
+ });
6461
+ }
6462
+ return pendingFetch;
6463
+ },
6464
+ };
6465
+ };
6466
+
6267
6467
  /*
6268
6468
  Copyright 2020 Adobe. All rights reserved.
6269
6469
  This file is licensed to you under the Apache License, Version 2.0 (the "License");
@@ -7756,10 +7956,10 @@
7756
7956
  governing permissions and limitations under the License.
7757
7957
  */
7758
7958
 
7759
- // The 2.35.1 keyword will be replace at alloy build time with the package.json version.
7959
+ // The 2.36.0-beta.1 keyword will be replace at alloy build time with the package.json version.
7760
7960
  // see babel-plugin-version
7761
7961
 
7762
- var libraryVersion = "2.35.1";
7962
+ var libraryVersion = "2.36.0-beta.1";
7763
7963
 
7764
7964
  /*
7765
7965
  Copyright 2019 Adobe. All rights reserved.
@@ -7774,13 +7974,13 @@
7774
7974
  */
7775
7975
 
7776
7976
 
7777
- const prepareLibraryInfo = ({ config, componentRegistry }) => {
7977
+ const prepareLibraryInfo = ({ config, componentRegistry, libraryVersion }) => {
7778
7978
  const allCommands = [
7779
7979
  ...componentRegistry.getCommandNames(),
7780
7980
  CONFIGURE,
7781
7981
  SET_DEBUG,
7782
7982
  ].sort();
7783
- const resultConfig = { ...config };
7983
+ const resultConfig = { ...redactEdgeCredentials(config) };
7784
7984
  Object.keys(config).forEach((key) => {
7785
7985
  const value = config[key];
7786
7986
  if (typeof value !== "function") {
@@ -7797,13 +7997,21 @@
7797
7997
  };
7798
7998
  };
7799
7999
 
7800
- const createLibraryInfo = ({ config, componentRegistry }) => {
8000
+ const createLibraryInfo = ({ config, componentRegistry, platformServices }) => {
8001
+ // defaultLibraryVersion is a build-time placeholder the browser bundler
8002
+ // replaces; other runtimes (e.g. Node) override it via platformServices.
8003
+ const libraryVersion$1 =
8004
+ platformServices?.libraryVersionOverride ?? libraryVersion;
7801
8005
  return {
7802
8006
  commands: {
7803
8007
  getLibraryInfo: {
7804
8008
  run: () => {
7805
8009
  return {
7806
- libraryInfo: prepareLibraryInfo({ config, componentRegistry }),
8010
+ libraryInfo: prepareLibraryInfo({
8011
+ config,
8012
+ componentRegistry,
8013
+ libraryVersion: libraryVersion$1,
8014
+ }),
7807
8015
  };
7808
8016
  },
7809
8017
  },
@@ -7858,6 +8066,9 @@
7858
8066
  * @param {Array<Function>} params.components
7859
8067
  * @param {() => import('../services/index.js').PlatformServices} params.createPlatformServices
7860
8068
  * @param {ReturnType<typeof createCoreConfigs>} [params.coreConfigValidators]
8069
+ * @param {{ getAccessToken: () => Promise<string> }} [params.getImsAccessToken]
8070
+ * Shared token cache for repeated configure() calls — see
8071
+ * injectGetImsAccessToken.js. Defaults to a fresh one per call.
7861
8072
  */
7862
8073
  const createExecuteCommand = ({
7863
8074
  instanceName,
@@ -7865,6 +8076,7 @@
7865
8076
  components,
7866
8077
  createPlatformServices,
7867
8078
  coreConfigValidators = defaultCoreConfigValidators,
8079
+ getImsAccessToken: sharedGetImsAccessToken,
7868
8080
  }) => {
7869
8081
  const platformServices = createPlatformServices();
7870
8082
  const allMonitors = [...platformServices.globals.getMonitors(), ...monitors];
@@ -7959,6 +8171,10 @@
7959
8171
  orgId,
7960
8172
  cookieJar: platformServices.cookie,
7961
8173
  });
8174
+ const getImsAccessToken = config.edgeCredentials
8175
+ ? sharedGetImsAccessToken ||
8176
+ injectGetImsAccessToken({ edgeCredentials: config.edgeCredentials })
8177
+ : undefined;
7962
8178
  const sendEdgeNetworkRequest = injectSendEdgeNetworkRequest({
7963
8179
  config,
7964
8180
  lifecycle,
@@ -7968,6 +8184,7 @@
7968
8184
  processWarningsAndErrors,
7969
8185
  getLocationHint,
7970
8186
  getAssuranceValidationTokenParams,
8187
+ getImsAccessToken,
7971
8188
  });
7972
8189
 
7973
8190
  const applyResponse = injectApplyResponse({
@@ -12425,10 +12642,12 @@
12425
12642
  xdm: xdmValidator,
12426
12643
  onStreamResponse: boundCallback().default(noop),
12427
12644
  voiceEnabled: boundBoolean().default(false),
12645
+ surfaces: boundArrayOf(boundString()).uniqueItems(),
12428
12646
  }),
12429
12647
  boundObjectOf({
12430
12648
  xdm: xdmValidator,
12431
12649
  voiceEnabled: boundBoolean().default(false),
12650
+ surfaces: boundArrayOf(boundString()).uniqueItems(),
12432
12651
  }).required(),
12433
12652
  boundObjectOf({
12434
12653
  data: boundObjectOf({
@@ -12437,6 +12656,7 @@
12437
12656
  }).required(),
12438
12657
  onStreamResponse: boundCallback().default(noop),
12439
12658
  voiceEnabled: boundBoolean().default(false),
12659
+ surfaces: boundArrayOf(boundString()).uniqueItems(),
12440
12660
  }),
12441
12661
  ]);
12442
12662
 
@@ -12925,6 +13145,7 @@
12925
13145
  xdm,
12926
13146
  data,
12927
13147
  voiceEnabled = false,
13148
+ surfaces: requestSurfaces,
12928
13149
  } = options;
12929
13150
  const payload = createDataCollectionRequestPayload();
12930
13151
  const request = createConversationServiceRequest({
@@ -12936,10 +13157,14 @@
12936
13157
 
12937
13158
  const event = eventManager.createEvent();
12938
13159
  if (message || data) {
13160
+ const surfaces = [...(requestSurfaces || [])];
12939
13161
  const pageSurface = getPageSurface(getPageLocation);
13162
+ if (!surfaces.includes(pageSurface)) {
13163
+ surfaces.push(pageSurface);
13164
+ }
12940
13165
  event.mergeQuery({
12941
13166
  conversation: {
12942
- surfaces: [pageSurface],
13167
+ surfaces,
12943
13168
  message,
12944
13169
  data,
12945
13170
  },
@@ -13290,6 +13515,9 @@
13290
13515
  * load," since a page load resets module state); pass a fresh instance per
13291
13516
  * call if that assumption doesn't hold for your runtime (e.g. one Node
13292
13517
  * process handling many requests).
13518
+ * @param {ReturnType<typeof import('./core/edgeNetwork/injectGetImsAccessToken.js').default>} [getImsAccessToken]
13519
+ * Only relevant when `edgeCredentials` is configured — see
13520
+ * `createGetImsAccessToken` above.
13293
13521
  * @returns {(commandName: string, options?: Object) => Promise<any>} A callable Alloy instance.
13294
13522
  *
13295
13523
  * @see {@link https://experienceleague.adobe.com/en/docs/experience-platform/web-sdk/install/create-custom-build} for more details.
@@ -13298,6 +13526,7 @@
13298
13526
  options = {},
13299
13527
  createPlatformServices = undefined,
13300
13528
  coreConfigValidators = undefined,
13529
+ getImsAccessToken = undefined,
13301
13530
  ) => {
13302
13531
  const eventOptionsValidator = boundObjectOf({
13303
13532
  name: boundString().default("alloy"),
@@ -13313,6 +13542,7 @@
13313
13542
  components,
13314
13543
  createPlatformServices,
13315
13544
  coreConfigValidators,
13545
+ getImsAccessToken,
13316
13546
  });
13317
13547
  };
13318
13548
 
@@ -21888,13 +22118,14 @@
21888
22118
  */
21889
22119
 
21890
22120
  var injectSendFetchRequest = ({ fetch }) => {
21891
- return (url, body) => {
22121
+ return (url, body, headers) => {
21892
22122
  return fetch(url, {
21893
22123
  method: "POST",
21894
22124
  cache: "no-cache",
21895
22125
  credentials: "include", // To set the cookie header in the request.
21896
22126
  headers: {
21897
22127
  "Content-Type": "text/plain; charset=UTF-8",
22128
+ ...headers,
21898
22129
  },
21899
22130
  referrerPolicy: "no-referrer-when-downgrade",
21900
22131
  body,