diff --git a/libs/features/mep/addons/event.js b/libs/features/mep/addons/event.js
index 1e1bcd9e2db..59fda6c29e8 100644
--- a/libs/features/mep/addons/event.js
+++ b/libs/features/mep/addons/event.js
@@ -1,49 +1,110 @@
-import { isSignedOut, getConfig, getMepEnablement, loadIms } from '../../../utils/utils.js';
-import { getCookie } from '../../../martech/helpers.js';
+import { isSignedOut, getConfig, getMepEnablement, loadIms, getCookie } from '../../../utils/utils.js';
+
+const defaultReturn = { isRegistered: false };
+
+// Persist only what personalization reads; never the RF authToken/userKey.
+const store = window.localStorage;
+const TTL_REGISTERED = 24 * 60 * 60 * 1000;
+const TTL_UNREGISTERED = 3 * 60 * 1000;
+const cacheKey = (eventCode, userId) => `mep-event:${eventCode}:${userId}`;
+
+// TODO(MWPW-199051): enable once VEAL confirms the redirect-cookie name/domain.
+// When enabling, clearRegisteredFlag must set domain= to match — a host-only
+// delete won't clear a .adobe.com cookie, leaving the flag stuck.
+const REDIRECT_INVALIDATION_ENABLED = false;
+const justRegistered = (eventCode) => REDIRECT_INVALIDATION_ENABLED
+ && getCookie(`feds_${eventCode}_registeredByRedirect`) === 'true';
+/* c8 ignore next 3 */
+const clearRegisteredFlag = (eventCode) => {
+ document.cookie = `feds_${eventCode}_registeredByRedirect=; Max-Age=0; path=/`;
+};
+
+function readCache(eventCode, userId) {
+ try {
+ const raw = store.getItem(cacheKey(eventCode, userId));
+ if (!raw) return null;
+ const { isRegistered, inPersonAttendee, exp } = JSON.parse(raw);
+ if (!exp || Date.now() > exp) return null;
+ return { isRegistered, inPersonAttendee };
+ } catch {
+ return null;
+ }
+}
+
+function writeCache(eventCode, userId, data) {
+ try {
+ const ttl = data.isRegistered ? TTL_REGISTERED : TTL_UNREGISTERED;
+ store.setItem(cacheKey(eventCode, userId), JSON.stringify({
+ isRegistered: !!data.isRegistered,
+ inPersonAttendee: !!data.inPersonAttendee,
+ exp: Date.now() + ttl,
+ }));
+ } catch {
+ // storage unavailable — non-fatal
+ }
+}
async function getUserId() {
- if (isSignedOut() && !getMepEnablement('signedIn')) return false;
- if (getMepEnablement('userId') !== 'undefined') return getMepEnablement('userId');
- /* c8 ignore next 3 */
- await loadIms();
- const { userId } = await window.adobeIMS.getProfile();
- return userId;
+ const signedInEnable = getMepEnablement('signedIn') || getMepEnablement('signedin');
+ if (isSignedOut() && !signedInEnable) return false;
+ const userIdEnable = getMepEnablement('userId') || getMepEnablement('userid');
+ if (userIdEnable && userIdEnable !== 'undefined') return userIdEnable;
+ /* c8 ignore start */
+ try {
+ await loadIms();
+ const { userId } = await window.adobeIMS.getProfile();
+ return userId;
+ } catch {
+ return false;
+ }
+ /* c8 ignore stop */
}
-async function fetchFromRainfocus(eventId) {
+
+async function fetchFromRainfocus(eventCode) {
const userId = await getUserId();
- if (!userId) return {};
+ if (!userId) return defaultReturn;
+
+ /* c8 ignore next 3 */
+ if (justRegistered(eventCode)) {
+ store.removeItem(cacheKey(eventCode, userId));
+ clearRegisteredFlag(eventCode);
+ } else {
+ const cached = readCache(eventCode, userId);
+ if (cached) return cached;
+ }
const accessToken = window.adobeIMS.getAccessToken()?.token;
- if (!accessToken) return {};
+ if (!accessToken) return defaultReturn;
const domainSuffix = getConfig()?.env?.name === 'prod' ? '' : '.stage';
- const url = `https://www${domainSuffix}.adobe.com/events/api/rf-auth-seq-generic/${eventId}?user_id=${encodeURIComponent(userId)}`;
+ const url = `https://www${domainSuffix}.adobe.com/events/api/rf-auth-seq-generic/${eventCode}?user_id=${encodeURIComponent(userId)}`;
try {
const response = await fetch(url, {
method: 'GET',
headers: { Authorization: `Bearer ${accessToken}` },
credentials: 'same-origin',
});
- if (response.ok) return response.json();
+ if (response.ok) {
+ // RF returns {} (not { isRegistered: false }) when not registered.
+ const data = { isRegistered: false, ...(await response.json()) };
+ writeCache(eventCode, userId, data);
+ return data;
+ }
window.lana?.log(`Unable to fetch from Rainfocus: ${response.statusText}`, {
tags: 'mep-event',
severity: 'error',
});
- return {};
+ return defaultReturn;
} catch (e) {
window.lana?.log(`Unable to fetch from Rainfocus: ${e.toString()}`, {
tags: 'mep-event',
severity: 'error',
});
- return {};
+ return defaultReturn;
}
}
-export default async function init(eventId) {
- if (eventId === true) return eventId;
-
- const consentCookieValue = getCookie('OptanonConsent');
- if (consentCookieValue?.includes('C0002:0')) return false;
- const eventDetails = await fetchFromRainfocus(eventId);
- return eventDetails?.isRegistered === true;
+export default async function init(eventCode) {
+ if (eventCode === true) return { isRegistered: eventCode };
+ return fetchFromRainfocus(eventCode);
}
diff --git a/libs/features/personalization/personalization.js b/libs/features/personalization/personalization.js
index 94a2bd5d6ac..af471cdf2f1 100644
--- a/libs/features/personalization/personalization.js
+++ b/libs/features/personalization/personalization.js
@@ -1093,7 +1093,7 @@ async function getPersonalizationVariant(
if (userEntitlements?.includes(name)) return true;
const { lob, event } = config.mep.promises;
if (lob && lob === name.split('lob-')[1]?.toLowerCase()) return true;
- if (name === 'registered' && event) return true;
+ if (name === 'registered' && event?.isRegistered) return true;
return PERSONALIZATION_KEYS.includes(name) && PERSONALIZATION_TAGS[name]();
};
diff --git a/libs/utils/utils.js b/libs/utils/utils.js
index fe7f90cb39c..94dc5d6bcbb 100644
--- a/libs/utils/utils.js
+++ b/libs/utils/utils.js
@@ -2119,7 +2119,7 @@ export function enablePersonalizationV2() {
}
export function loadMepAddons() {
- const mepAddons = ['lob', 'event-id'];
+ const mepAddons = ['lob', 'event-code'];
const promises = {};
mepAddons.forEach((addon) => {
const enablement = getMepEnablement(addon);
diff --git a/test/features/mep/addons/event.test.js b/test/features/mep/addons/event.test.js
index 357d4ad05f4..062e5acedd3 100644
--- a/test/features/mep/addons/event.test.js
+++ b/test/features/mep/addons/event.test.js
@@ -27,34 +27,36 @@ const setMetadata = (name, content) => {
describe('event', () => {
beforeEach(() => {
document.head.innerHTML = '';
+ localStorage.clear();
setMetadata('signedIn', 'on');
setCookie('OptanonConsent', 'C0002:1');
window.adobeIMS = { getAccessToken: () => ({ token: '1234567890' }) };
});
+ afterEach(() => {
+ setCookie('feds_adobe-max-2025_registeredByRedirect', '; Max-Age=0');
+ });
it('should return true when sending true into init', async () => {
const event = await init(true);
- expect(event).to.equal(true);
- });
- it('should return false when consent cookie is set to C0002:0', async () => {
- setCookie('OptanonConsent', 'C0002:0');
- const event = await init('adobe-max-2025');
- expect(event).to.equal(false);
+ expect(event.isRegistered).to.equal(true);
});
it('should return false when the user is signed out', async () => {
document.head.innerHTML = '';
const event = await init('adobe-max-2025');
- expect(event).to.equal(false);
+ expect(event.isRegistered).to.equal(false);
});
- it('should return false when userId is set to off', async () => {
- setMetadata('userId', 'off');
+ it('should read enablements from lowercase DA metadata', async () => {
+ document.head.innerHTML = '';
+ setMetadata('signedin', 'on');
+ setMetadata('userid', '1234567890');
+ setFetchResponse({ ok: true, isRegistered: true });
const event = await init('adobe-max-2025');
- expect(event).to.equal(false);
+ expect(event.isRegistered).to.equal(true);
});
it('should return false when getAccessToken returns an empty object', async () => {
setMetadata('userId', '1234567890');
window.adobeIMS.getAccessToken = () => Promise.resolve({});
const event = await init('adobe-max-2025');
- expect(event).to.equal(false);
+ expect(event.isRegistered).to.equal(false);
});
it('should return false when api returns false', async () => {
setMetadata('userId', '1234567890');
@@ -63,7 +65,7 @@ describe('event', () => {
isRegistered: false,
});
const event = await init('adobe-max-2025');
- expect(event).to.equal(false);
+ expect(event.isRegistered).to.equal(false);
});
it('should return true when api returns true', async () => {
setMetadata('userId', '1234567890');
@@ -72,6 +74,32 @@ describe('event', () => {
isRegistered: true,
});
const event = await init('adobe-max-2025');
- expect(event).to.equal(true);
+ expect(event.isRegistered).to.equal(true);
+ });
+ it('should serve a cached result without re-calling the API', async () => {
+ setMetadata('userId', '1234567890');
+ setFetchResponse({ ok: true, isRegistered: true });
+ const first = await init('adobe-max-2025');
+ expect(first.isRegistered).to.equal(true);
+ // A cache hit must ignore a now-changed API response.
+ setFetchResponse({ ok: true, isRegistered: false });
+ const second = await init('adobe-max-2025');
+ expect(second.isRegistered).to.equal(true);
+ });
+ it('should normalize an empty API response to isRegistered false', async () => {
+ setMetadata('userId', '1234567890');
+ setFetchResponse({});
+ const event = await init('adobe-max-2025');
+ expect(event.isRegistered).to.equal(false);
+ });
+ // Un-skip when REDIRECT_INVALIDATION_ENABLED flips on (MWPW-199051).
+ it.skip('should bypass the cache when the registration-redirect cookie is set', async () => {
+ setMetadata('userId', '1234567890');
+ setFetchResponse({ ok: true, isRegistered: false });
+ await init('adobe-max-2025');
+ setCookie('feds_adobe-max-2025_registeredByRedirect', 'true');
+ setFetchResponse({ ok: true, isRegistered: true });
+ const event = await init('adobe-max-2025');
+ expect(event.isRegistered).to.equal(true);
});
});
diff --git a/test/utils/utils-mep.test.js b/test/utils/utils-mep.test.js
index 935fa1c0b6d..7abde7ac304 100644
--- a/test/utils/utils-mep.test.js
+++ b/test/utils/utils-mep.test.js
@@ -120,6 +120,16 @@ describe('MEP Utils', () => {
console.log(promises);
expect(promises.lob).to.be.a('promise');
});
+ it('loads event from event-code metadata', async () => {
+ document.head.innerHTML = '';
+ const promises = loadMepAddons();
+ expect(promises.event).to.be.a('promise');
+ });
+ it('does not load event from the legacy event-id metadata', async () => {
+ document.head.innerHTML = '';
+ const promises = loadMepAddons();
+ expect(promises.event).to.be.undefined;
+ });
afterEach(() => {
document.head.innerHTML = '';
});