Skip to content

Commit

Permalink
Fix logs, flags, code, methods
Browse files Browse the repository at this point in the history
  • Loading branch information
swamu committed Jan 17, 2025
1 parent b1351a6 commit f70653b
Show file tree
Hide file tree
Showing 6 changed files with 159 additions and 85 deletions.
59 changes: 37 additions & 22 deletions libs/features/personalization/personalization.js
Original file line number Diff line number Diff line change
@@ -1,9 +1,8 @@
/* eslint-disable default-param-last */
/* eslint-disable no-underscore-dangle */
/* eslint-disable no-console */

import {
createTag, getConfig, loadLink, loadScript, localizeLink, enablePersonalizationV2,
} from '../../utils/utils.js';
import { createTag, getConfig, loadLink, loadScript, localizeLink } from '../../utils/utils.js';
import { getFederatedUrl } from '../../utils/federated.js';

/* c8 ignore start */
Expand Down Expand Up @@ -763,7 +762,12 @@ export const getEntitlements = async (data) => {
});
};

async function getPersonalizationVariant(manifestPath, variantNames = [], variantLabel = null) {
async function getPersonalizationVariant(
manifestPath,
variantNames = [],
variantLabel = null,
enablePersV2,
) {
const config = getConfig();
if (config.mep?.variantOverride?.[manifestPath]) {
return config.mep.variantOverride[manifestPath];
Expand All @@ -776,7 +780,7 @@ async function getPersonalizationVariant(manifestPath, variantNames = [], varian

let userEntitlements = [];
if (hasEntitlementTag) {
if (enablePersonalizationV2()) {
if (enablePersV2) {
userEntitlements = [];
} else {
userEntitlements = await config.entitlements();
Expand Down Expand Up @@ -834,7 +838,7 @@ export const addMepAnalytics = (config, header) => {
}
});
};
export async function getManifestConfig(info = {}, variantOverride = false) {
export async function getManifestConfig(info = {}, variantOverride = false, enablePersV2 = false) {
const {
name,
manifestData,
Expand Down Expand Up @@ -904,6 +908,7 @@ export async function getManifestConfig(info = {}, variantOverride = false) {
manifestConfig.manifestPath,
manifestConfig.variantNames,
variantLabel,
enablePersV2,
);

manifestConfig.placeholderData = manifestPlaceholders || data?.placeholders?.data;
Expand Down Expand Up @@ -1040,12 +1045,16 @@ export function parseNestedPlaceholders({ placeholders }) {
});
}

export async function applyPers(manifests) {
export async function applyPers({ manifests, enablePersV2 }) {
if (!manifests?.length) return;
let experiments = manifests;
const config = getConfig();
for (let i = 0; i < experiments.length; i += 1) {
experiments[i] = await getManifestConfig(experiments[i], config.mep?.variantOverride);
experiments[i] = await getManifestConfig(
experiments[i],
config.mep?.variantOverride,
enablePersV2,
);
}

experiments = cleanAndSortManifestList(experiments);
Expand Down Expand Up @@ -1121,12 +1130,14 @@ export const combineMepSources = async (persEnabled, promoEnabled, mepParam) =>
return persManifests;
};

async function updateManifestsAndPropositions({ config, targetManifests, targetPropositions }) {
async function updateManifestsAndPropositions(
{ config, targetManifests, targetPropositions, enablePersV2 },
) {
targetManifests.forEach((manifest) => {
manifest.source = ['target'];
});
config.mep.targetManifests = targetManifests;
if (enablePersonalizationV2()) {
if (enablePersV2) {
window.addEventListener('alloy_sendEvent', () => {
if (targetPropositions?.length && window._satellite) {
window._satellite.track('propositionDisplay', targetPropositions);
Expand Down Expand Up @@ -1195,11 +1206,11 @@ const handleAlloyResponse = (response) => ((response.propositions || response.de
?.filter(Boolean) ?? [];

async function handleMartechTargetInteraction(
{ config, targetInteractionPromise, calculatedTimeout },
{ config, targetInteractionPromise, calculatedTimeout, enablePersV2 },
) {
let targetManifests = [];
let targetPropositions = [];
if (enablePersonalizationV2() && targetInteractionPromise) {
if (enablePersV2 && targetInteractionPromise) {
try {
const { targetInteractionData, respTime, respStartTime } = await targetInteractionPromise;
sendTargetResponseAnalytics(false, respStartTime, calculatedTimeout);
Expand All @@ -1220,7 +1231,9 @@ async function handleMartechTargetInteraction(
}
}

return updateManifestsAndPropositions({ config, targetManifests, targetPropositions });
return updateManifestsAndPropositions(
{ config, targetManifests, targetPropositions, enablePersV2 },
);
}

async function callMartech(config) {
Expand All @@ -1229,7 +1242,9 @@ async function callMartech(config) {
targetManifests,
targetPropositions,
} = await getTargetPersonalization({ handleAlloyResponse, sendTargetResponseAnalytics });
return updateManifestsAndPropositions({ config, targetManifests, targetPropositions });
return updateManifestsAndPropositions(
{ config, targetManifests, targetPropositions, enablePersV2: false },
);
}

const awaitMartech = () => new Promise((resolve) => {
Expand All @@ -1240,7 +1255,7 @@ const awaitMartech = () => new Promise((resolve) => {
export async function init(enablements = {}) {
let manifests = [];
const {
mepParam, mepHighlight, mepButton, pzn, promo,
mepParam, mepHighlight, mepButton, pzn, promo, enablePersV2,
target, targetInteractionPromise, calculatedTimeout, postLCP,
} = enablements;
const config = getConfig();
Expand All @@ -1266,20 +1281,20 @@ export async function init(enablements = {}) {
if (pzn) loadLink(getXLGListURL(config), { as: 'fetch', crossorigin: 'anonymous', rel: 'preload' });
}

if (enablePersonalizationV2()) {
if (enablePersV2 && target === true) {
manifests = manifests.concat(await handleMartechTargetInteraction(
{ config, targetInteractionPromise, calculatedTimeout },
{ config, targetInteractionPromise, calculatedTimeout, enablePersV2 },
));
} else {
if (target === true) manifests = manifests.concat(await callMartech(config));
if (target === 'postlcp') callMartech(config);
if (postLCP) {
if (!config.mep.targetManifests) await awaitMartech();
manifests = config.mep.targetManifests;
}
}
if (postLCP) {
if (!config.mep.targetManifests) await awaitMartech();
manifests = config.mep.targetManifests;
}
try {
if (manifests?.length) await applyPers(manifests);
if (manifests?.length) await applyPers({ manifests, enablePersV2 });
if (config.mep?.preview) await import('./preview.js').then(({ saveToMmm }) => saveToMmm());
} catch (e) {
log(`MEP Error: ${e.toString()}`);
Expand Down
51 changes: 31 additions & 20 deletions libs/martech/helpers.js
Original file line number Diff line number Diff line change
@@ -1,4 +1,8 @@
const AMCV_COOKIE = 'AMCV_9E1005A551ED61CA0A490D45@AdobeOrg';
const KNDCTR_COOKIE_KEYS = [
'kndctr_9E1005A551ED61CA0A490D45_AdobeOrg_identity',
'kndctr_9E1005A551ED61CA0A490D45_AdobeOrg_cluster',
];

/**
* Generates a random UUIDv4 using cryptographically secure random values.
Expand Down Expand Up @@ -211,16 +215,10 @@ function getUpdatedContext({
* @returns {Array<Object>} List of MarTech cookies with each
* object containing 'key' and 'value' properties.
*/
const getMarctechCookies = () => {
const KNDCTR_COOKIE_KEYS = [
'kndctr_9E1005A551ED61CA0A490D45_AdobeOrg_identity',
'kndctr_9E1005A551ED61CA0A490D45_AdobeOrg_cluster',
];
return document.cookie.split(';')
.map((x) => x.trim().split('='))
.filter(([key]) => KNDCTR_COOKIE_KEYS.includes(key))
.map(([key, value]) => ({ key, value }));
};
const getMartechCookies = () => document.cookie.split(';')
.map((x) => x.trim().split('='))
.filter(([key]) => KNDCTR_COOKIE_KEYS.includes(key))
.map(([key, value]) => ({ key, value }));

/**
* Creates the request payload for Adobe Analytics and Target.
Expand Down Expand Up @@ -300,24 +298,28 @@ function createRequestPayload({ updatedContext, pageName, locale, env }) {
com_adobe_target: { propertyToken: AT_PROPERTY_VAL },
},
state: {
domain: 'localhost',
domain: (new URL(window.location.origin)).hostname,
cookiesEnabled: true,
entries: getMarctechCookies(),
entries: getMartechCookies(),
},
},
};
}

/**
* Extracts the ECID (Experience Cloud ID) from the API response data.
* Updates the specified cookies with new values if they don't already exist.
*
* @param {Array<Object>} cookieData - An array of objects containing
* `key` and `value` pairs for the cookies.
*
* @param {Object} data - The response data from the API.
* @returns {string|null} The ECID value, or null if not found.
*/
function extractECIDFromResp(data) {
return data.handle
.flatMap((item) => item.payload)
.find((p) => p.namespace?.code === 'ECID')?.id || null;
function updateMartechCookies(cookieData) {
cookieData?.forEach(({ key, value }) => {
const currentCookie = getCookie(key);
if (!currentCookie) {
setCookie(encodeURIComponent(key), value);
}
});
}

/**
Expand Down Expand Up @@ -425,11 +427,20 @@ export const loadAnalyticsAndInteractionData = async ({ locale, env, calculatedT
throw new Error('Failed to fetch interact call');
}
const targetRespJson = await targetResp.json();
const ECID = extractECIDFromResp(targetRespJson);
const ECID = targetRespJson.handle
.flatMap((item) => item.payload)
.find((p) => p.namespace?.code === 'ECID')?.id || null;

// Update the AMCV cookie with ECID
updateAMCVCookie(ECID);

const stateStorePayload = targetRespJson?.handle?.find((item) => item.type === 'state:store')?.payload;
const extractedData = stateStorePayload?.map((item) => ({
key: item.key,
value: item.value,
}));
updateMartechCookies(extractedData);

// Resolve or reject based on propositions
const resultPayload = targetRespJson?.handle?.find((d) => d.type === 'personalization:decisions')?.payload;
if (resultPayload.length === 0) throw new Error('No propositions found');
Expand Down
48 changes: 18 additions & 30 deletions libs/utils/utils.js
Original file line number Diff line number Diff line change
Expand Up @@ -150,6 +150,7 @@ const PAGE_URL = new URL(window.location.href);
export const SLD = PAGE_URL.hostname.includes('.aem.') ? 'aem' : 'hlx';

const PROMO_PARAM = 'promo';
let isMartechLoaded = false;

export function getEnv(conf) {
const { host } = window.location;
Expand Down Expand Up @@ -1070,6 +1071,7 @@ export async function loadMartech({

const { default: initMartech } = await import('../martech/martech.js');
await initMartech({ persEnabled, persManifests, postLCP });
isMartechLoaded = true;

return true;
}
Expand Down Expand Up @@ -1106,6 +1108,7 @@ async function checkForPageMods() {
martech,
} = Object.fromEntries(PAGE_URL.searchParams);
let targetInteractionPromise = null;
let calculatedTimeout = null;
if (mepParam === 'off') return;
const pzn = getMepEnablement('personalization');
const promo = getMepEnablement('manifestnames', PROMO_PARAM);
Expand All @@ -1118,7 +1121,7 @@ async function checkForPageMods() {
const enablePersV2 = enablePersonalizationV2();
if ((target || xlg) && enablePersV2) {
const params = new URL(window.location.href).searchParams;
const calculatedTimeout = parseInt(params.get('target-timeout'), 10)
calculatedTimeout = parseInt(params.get('target-timeout'), 10)
|| parseInt(getMetadata('target-timeout'), 10)
|| TARGET_TIMEOUT_MS;

Expand All @@ -1136,34 +1139,27 @@ async function checkForPageMods() {

return { targetInteractionData: data, respTime, respStartTime: now };
})();

const { init } = await import('../features/personalization/personalization.js');
await init({
mepParam,
mepHighlight,
mepButton,
pzn,
promo,
target,
targetInteractionPromise,
calculatedTimeout,
});
return;
}
if (target || xlg) {
loadMartech();
} else if (pzn && martech !== 'off') {
} else if ((target || xlg) && !isMartechLoaded) loadMartech();
else if (pzn && martech !== 'off') {
loadIms()
.then(() => {
/* c8 ignore next */
if (window.adobeIMS?.isSignedInUser()) loadMartech();
if (window.adobeIMS?.isSignedInUser() && !isMartechLoaded) loadMartech();
})
.catch((e) => { console.log('Unable to load IMS:', e); });
}

const { init } = await import('../features/personalization/personalization.js');
await init({
mepParam, mepHighlight, mepButton, pzn, promo, target, targetInteractionPromise,
mepParam,
mepHighlight,
mepButton,
pzn,
promo,
target,
targetInteractionPromise,
calculatedTimeout,
enablePersV2,
});
}

Expand All @@ -1175,12 +1171,8 @@ async function loadPostLCP(config) {
/* c8 ignore next 2 */
const { init } = await import('../features/personalization/personalization.js');
await init({ postLCP: true });
if (enablePersonalizationV2()) {
loadMartech();
}
} else {
loadMartech();
}
if (enablePersonalizationV2() && !isMartechLoaded) loadMartech();
} else if (!isMartechLoaded) loadMartech();

const georouting = getMetadata('georouting') || config.geoRouting;
if (georouting === 'on') {
Expand Down Expand Up @@ -1430,10 +1422,6 @@ export async function loadArea(area = document) {
await loadDeferred(area, areaBlocks, config);
}

export function loadDelayed() {
// TODO: remove after all consumers have stopped calling this method
}

export const utf8ToB64 = (str) => window.btoa(unescape(encodeURIComponent(str)));
export const b64ToUtf8 = (str) => decodeURIComponent(escape(window.atob(str)));

Expand Down
4 changes: 2 additions & 2 deletions test/features/personalization/personalization.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -110,7 +110,7 @@ describe('Functional Test', () => {
manifestJson = JSON.parse(manifestJson);
setFetchResponse(manifestJson);
expect(document.querySelector('a[href="/test/features/personalization/mocks/fragments/insertafter3"]')).to.be.null;
await applyPers(promoMepSettings);
await applyPers({ manifests: promoMepSettings });

const fragment = document.querySelector('a[href="/test/features/personalization/mocks/fragments/insertafter3"]');
expect(fragment).to.not.be.null;
Expand All @@ -137,7 +137,7 @@ describe('Functional Test', () => {
];
await loadManifestAndSetResponse('./mocks/manifestScheduledInactive.json');
expect(document.querySelector('a[href="/fragments/insertafter4"]')).to.be.null;
await applyPers(promoMepSettings);
await applyPers({ manifests: promoMepSettings });

const fragment = document.querySelector('a[href="/fragments/insertafter4"]');
expect(fragment).to.be.null;
Expand Down
Loading

0 comments on commit f70653b

Please sign in to comment.