@coframe/sdk 1.1.4 → 1.1.5
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/pkg/cf.cjs.js +320 -119
- package/dist/pkg/cf.esm.mjs +320 -119
- package/package.json +1 -1
package/dist/pkg/cf.cjs.js
CHANGED
|
@@ -2579,6 +2579,220 @@ function rebindMetrics(coframe, logger, metrics, nonce) {
|
|
|
2579
2579
|
}
|
|
2580
2580
|
}
|
|
2581
2581
|
|
|
2582
|
+
function getActivePreviewModes(sessionPreview) {
|
|
2583
|
+
if (!sessionPreview.isSessionPreviewActive ||
|
|
2584
|
+
!sessionPreview.previewVariantId) {
|
|
2585
|
+
return [];
|
|
2586
|
+
}
|
|
2587
|
+
return [
|
|
2588
|
+
{
|
|
2589
|
+
id: 'session-preview',
|
|
2590
|
+
label: 'Preview on',
|
|
2591
|
+
title: `Session preview is active for ${sessionPreview.previewVariantId}`,
|
|
2592
|
+
variantIds: sessionPreview.previewVariantId
|
|
2593
|
+
.split(',')
|
|
2594
|
+
.map((id) => id.trim())
|
|
2595
|
+
.filter(Boolean),
|
|
2596
|
+
},
|
|
2597
|
+
];
|
|
2598
|
+
}
|
|
2599
|
+
|
|
2600
|
+
const PREVIEW_UI_PROTOCOL_VERSION = 1;
|
|
2601
|
+
|
|
2602
|
+
const SESSION_VARIANT_KEY = 'coframe.preview_variant';
|
|
2603
|
+
const PREVIEW_VARIANT_QUERY_PARAM = 'coframe_variant_id';
|
|
2604
|
+
const KEEP_PREVIEW_FOR_SESSION_QUERY_PARAM = 'keep_preview_for_session';
|
|
2605
|
+
let previewDismissed = false;
|
|
2606
|
+
function dismissSessionPreview() {
|
|
2607
|
+
previewDismissed = true;
|
|
2608
|
+
clearPreviewVariantId();
|
|
2609
|
+
const url = new URL(window.location.href);
|
|
2610
|
+
url.searchParams.delete(PREVIEW_VARIANT_QUERY_PARAM);
|
|
2611
|
+
url.searchParams.delete(KEEP_PREVIEW_FOR_SESSION_QUERY_PARAM);
|
|
2612
|
+
window.history.replaceState(window.history.state, '', url);
|
|
2613
|
+
window.location.reload();
|
|
2614
|
+
}
|
|
2615
|
+
function normalizeVariantIds(raw) {
|
|
2616
|
+
if (!raw)
|
|
2617
|
+
return null;
|
|
2618
|
+
const ids = raw
|
|
2619
|
+
.split(',')
|
|
2620
|
+
.map((id) => id.trim())
|
|
2621
|
+
.filter(Boolean);
|
|
2622
|
+
return ids.length > 0 ? ids.join(',') : null;
|
|
2623
|
+
}
|
|
2624
|
+
function readPreviewVariantId() {
|
|
2625
|
+
try {
|
|
2626
|
+
return sessionStorage.getItem(SESSION_VARIANT_KEY);
|
|
2627
|
+
}
|
|
2628
|
+
catch (_a) {
|
|
2629
|
+
return null;
|
|
2630
|
+
}
|
|
2631
|
+
}
|
|
2632
|
+
function persistPreviewVariantId(variantId) {
|
|
2633
|
+
const normalized = normalizeVariantIds(variantId);
|
|
2634
|
+
if (!normalized)
|
|
2635
|
+
return;
|
|
2636
|
+
try {
|
|
2637
|
+
sessionStorage.setItem(SESSION_VARIANT_KEY, normalized);
|
|
2638
|
+
}
|
|
2639
|
+
catch (_a) {
|
|
2640
|
+
}
|
|
2641
|
+
}
|
|
2642
|
+
function clearPreviewVariantId() {
|
|
2643
|
+
try {
|
|
2644
|
+
sessionStorage.removeItem(SESSION_VARIANT_KEY);
|
|
2645
|
+
}
|
|
2646
|
+
catch (_a) {
|
|
2647
|
+
}
|
|
2648
|
+
}
|
|
2649
|
+
function resolvePreviewSource(urlParams = getCurrentUrlSearchParams()) {
|
|
2650
|
+
return {
|
|
2651
|
+
urlVariantId: urlParams.get(PREVIEW_VARIANT_QUERY_PARAM),
|
|
2652
|
+
storedVariantId: readPreviewVariantId(),
|
|
2653
|
+
keepForSession: urlParams.get(KEEP_PREVIEW_FOR_SESSION_QUERY_PARAM) === 'true',
|
|
2654
|
+
};
|
|
2655
|
+
}
|
|
2656
|
+
function resolveSessionPreviewState() {
|
|
2657
|
+
if (previewDismissed) {
|
|
2658
|
+
return { isSessionPreviewActive: false, previewVariantId: null };
|
|
2659
|
+
}
|
|
2660
|
+
const previewSource = resolvePreviewSource();
|
|
2661
|
+
const urlVariantId = normalizeVariantIds(previewSource.urlVariantId);
|
|
2662
|
+
if (urlVariantId && previewSource.keepForSession) {
|
|
2663
|
+
return {
|
|
2664
|
+
isSessionPreviewActive: true,
|
|
2665
|
+
previewVariantId: urlVariantId,
|
|
2666
|
+
};
|
|
2667
|
+
}
|
|
2668
|
+
if (urlVariantId) {
|
|
2669
|
+
return { isSessionPreviewActive: false, previewVariantId: null };
|
|
2670
|
+
}
|
|
2671
|
+
const storedVariantId = normalizeVariantIds(previewSource.storedVariantId);
|
|
2672
|
+
return {
|
|
2673
|
+
isSessionPreviewActive: !!storedVariantId,
|
|
2674
|
+
previewVariantId: storedVariantId,
|
|
2675
|
+
};
|
|
2676
|
+
}
|
|
2677
|
+
|
|
2678
|
+
const PREVIEW_UI_SCRIPT_ID = 'coframe-preview-ui-script';
|
|
2679
|
+
const PREVIEW_UI_URL = "https://edge.cofra.me/preview-ui/latest.js";
|
|
2680
|
+
let loadPromise = null;
|
|
2681
|
+
let latestState = { modes: [] };
|
|
2682
|
+
let nonce;
|
|
2683
|
+
let logger;
|
|
2684
|
+
let mounted = false;
|
|
2685
|
+
function reportError(message, error) {
|
|
2686
|
+
const errorMessage = error instanceof Error ? error.message : String(error);
|
|
2687
|
+
if (logger) {
|
|
2688
|
+
logger.warn(message, 'preview_ui_unavailable', { error: errorMessage });
|
|
2689
|
+
return;
|
|
2690
|
+
}
|
|
2691
|
+
console.warn(`[Coframe] ${message}`, error);
|
|
2692
|
+
}
|
|
2693
|
+
function getPreviewUI() {
|
|
2694
|
+
const api = window.CoframePreviewUI;
|
|
2695
|
+
return (api === null || api === void 0 ? void 0 : api.protocolVersion) === PREVIEW_UI_PROTOCOL_VERSION ? api : undefined;
|
|
2696
|
+
}
|
|
2697
|
+
function loadPreviewUI() {
|
|
2698
|
+
const existing = getPreviewUI();
|
|
2699
|
+
if (existing)
|
|
2700
|
+
return Promise.resolve(existing);
|
|
2701
|
+
if (loadPromise)
|
|
2702
|
+
return loadPromise;
|
|
2703
|
+
loadPromise = new Promise((resolve, reject) => {
|
|
2704
|
+
const script = document.createElement('script');
|
|
2705
|
+
script.id = PREVIEW_UI_SCRIPT_ID;
|
|
2706
|
+
script.async = true;
|
|
2707
|
+
script.src = PREVIEW_UI_URL;
|
|
2708
|
+
if (nonce)
|
|
2709
|
+
script.nonce = nonce;
|
|
2710
|
+
script.onload = () => {
|
|
2711
|
+
const api = getPreviewUI();
|
|
2712
|
+
if (!api) {
|
|
2713
|
+
reject(new Error('Preview UI protocol is missing or incompatible'));
|
|
2714
|
+
return;
|
|
2715
|
+
}
|
|
2716
|
+
resolve(api);
|
|
2717
|
+
};
|
|
2718
|
+
script.onerror = () => {
|
|
2719
|
+
reject(new Error('Preview UI script failed to load'));
|
|
2720
|
+
};
|
|
2721
|
+
document.head.appendChild(script);
|
|
2722
|
+
});
|
|
2723
|
+
return loadPromise;
|
|
2724
|
+
}
|
|
2725
|
+
function renderPreviewUI(api) {
|
|
2726
|
+
try {
|
|
2727
|
+
if (latestState.modes.length === 0) {
|
|
2728
|
+
api.unmount();
|
|
2729
|
+
mounted = false;
|
|
2730
|
+
}
|
|
2731
|
+
else if (mounted) {
|
|
2732
|
+
api.update(latestState);
|
|
2733
|
+
}
|
|
2734
|
+
else {
|
|
2735
|
+
api.mount({ state: latestState, nonce, onDismiss: dismissPreviewPanel });
|
|
2736
|
+
mounted = true;
|
|
2737
|
+
}
|
|
2738
|
+
}
|
|
2739
|
+
catch (error) {
|
|
2740
|
+
reportError('Preview UI could not be rendered', error);
|
|
2741
|
+
}
|
|
2742
|
+
}
|
|
2743
|
+
function dismissPreviewPanel() {
|
|
2744
|
+
dismissSessionPreview();
|
|
2745
|
+
latestState = { modes: [] };
|
|
2746
|
+
const api = getPreviewUI();
|
|
2747
|
+
if (api)
|
|
2748
|
+
renderPreviewUI(api);
|
|
2749
|
+
}
|
|
2750
|
+
function modesWithVariants(sessionPreview, variantsAndElements, applied = true) {
|
|
2751
|
+
const activeModes = getActivePreviewModes(sessionPreview);
|
|
2752
|
+
if (activeModes.length === 0)
|
|
2753
|
+
return [];
|
|
2754
|
+
const currentPageVariantIds = new Set((variantsAndElements === null || variantsAndElements === void 0 ? void 0 : variantsAndElements.map(({ variant }) => variant.id)) || []);
|
|
2755
|
+
const slugById = new Map((variantsAndElements === null || variantsAndElements === void 0 ? void 0 : variantsAndElements.map(({ variant }) => [variant.id, variant.slug])) || []);
|
|
2756
|
+
return activeModes.map((mode) => ({
|
|
2757
|
+
id: mode.id,
|
|
2758
|
+
label: mode.label,
|
|
2759
|
+
title: mode.title,
|
|
2760
|
+
variants: mode.variantIds.map((id) => ({
|
|
2761
|
+
id,
|
|
2762
|
+
slug: slugById.get(id) || null,
|
|
2763
|
+
status: variantsAndElements
|
|
2764
|
+
? applied && currentPageVariantIds.has(id)
|
|
2765
|
+
? 'active'
|
|
2766
|
+
: 'inactive'
|
|
2767
|
+
: 'pending',
|
|
2768
|
+
})),
|
|
2769
|
+
}));
|
|
2770
|
+
}
|
|
2771
|
+
function resolveSessionPreviewPanel(sessionPreview, previewNonce, previewLogger) {
|
|
2772
|
+
const modes = modesWithVariants(sessionPreview);
|
|
2773
|
+
if (modes.length === 0)
|
|
2774
|
+
return;
|
|
2775
|
+
nonce = previewNonce;
|
|
2776
|
+
logger = previewLogger;
|
|
2777
|
+
latestState = { modes };
|
|
2778
|
+
const existing = getPreviewUI();
|
|
2779
|
+
if (existing) {
|
|
2780
|
+
renderPreviewUI(existing);
|
|
2781
|
+
return;
|
|
2782
|
+
}
|
|
2783
|
+
void loadPreviewUI()
|
|
2784
|
+
.then(renderPreviewUI)
|
|
2785
|
+
.catch((error) => reportError('Preview UI could not be loaded', error));
|
|
2786
|
+
}
|
|
2787
|
+
function updatePreviewPanel(variantsAndElements, sessionPreview, applied = true) {
|
|
2788
|
+
latestState = {
|
|
2789
|
+
modes: modesWithVariants(sessionPreview, variantsAndElements, applied),
|
|
2790
|
+
};
|
|
2791
|
+
const api = getPreviewUI();
|
|
2792
|
+
if (api)
|
|
2793
|
+
renderPreviewUI(api);
|
|
2794
|
+
}
|
|
2795
|
+
|
|
2582
2796
|
let lastUrl = null;
|
|
2583
2797
|
function observeUrlChanges(baseUrlMatch, onUrlChange) {
|
|
2584
2798
|
const tryTrack = () => {
|
|
@@ -2605,125 +2819,6 @@ function observeUrlChanges(baseUrlMatch, onUrlChange) {
|
|
|
2605
2819
|
patchHistoryMethod('replaceState');
|
|
2606
2820
|
}
|
|
2607
2821
|
|
|
2608
|
-
const TIMEOUT_MAX_MS = 5000;
|
|
2609
|
-
function getFeatureFlagValue(cmd) {
|
|
2610
|
-
if (cmd.featureFlagSet !== undefined)
|
|
2611
|
-
return cmd.featureFlagSet;
|
|
2612
|
-
if (typeof cmd.emit === 'object' &&
|
|
2613
|
-
cmd.emit !== null &&
|
|
2614
|
-
'featureFlagSet' in cmd.emit) {
|
|
2615
|
-
return cmd.emit.featureFlagSet;
|
|
2616
|
-
}
|
|
2617
|
-
return undefined;
|
|
2618
|
-
}
|
|
2619
|
-
async function resolveFeatureFlag(Coframe, timeoutMs) {
|
|
2620
|
-
const cmd = await waitForCmd((cmd) => typeof getFeatureFlagValue(cmd) === 'boolean', Coframe, timeoutMs);
|
|
2621
|
-
if (!cmd)
|
|
2622
|
-
return undefined;
|
|
2623
|
-
return getFeatureFlagValue(cmd);
|
|
2624
|
-
}
|
|
2625
|
-
async function resolveConfig(Coframe, revealPage) {
|
|
2626
|
-
const logger = Coframe.logger;
|
|
2627
|
-
const configCmd = await waitForCmd((cmd) => !!cmd.config, Coframe);
|
|
2628
|
-
if (!configCmd) {
|
|
2629
|
-
logger.error('Failed to wait for config cmd', 'wait_for_cmd_timeout');
|
|
2630
|
-
return null;
|
|
2631
|
-
}
|
|
2632
|
-
const config = configCmd.config;
|
|
2633
|
-
const timeoutMs = (config === null || config === void 0 ? void 0 : config.timeoutMs)
|
|
2634
|
-
? Math.min(config.timeoutMs, TIMEOUT_MAX_MS)
|
|
2635
|
-
: TIMEOUT_MAX_MS;
|
|
2636
|
-
const integrationStartTime = (config === null || config === void 0 ? void 0 : config.startTime)
|
|
2637
|
-
? new Date(config.startTime)
|
|
2638
|
-
: null;
|
|
2639
|
-
const executionStartTime = new Date();
|
|
2640
|
-
Coframe.batchSize = config.batchSize || 32;
|
|
2641
|
-
const gracefulExit = (msg) => {
|
|
2642
|
-
console.warn(`[Coframe] ${msg}`);
|
|
2643
|
-
revealPage();
|
|
2644
|
-
return null;
|
|
2645
|
-
};
|
|
2646
|
-
if (config.waitForFeatureFlag) {
|
|
2647
|
-
const flag = await resolveFeatureFlag(Coframe, timeoutMs);
|
|
2648
|
-
if (flag === undefined) {
|
|
2649
|
-
return gracefulExit('Feature flag was not set after timeout, graceful exit');
|
|
2650
|
-
}
|
|
2651
|
-
if (flag === false) {
|
|
2652
|
-
return gracefulExit('Feature flag is set to false, graceful exit');
|
|
2653
|
-
}
|
|
2654
|
-
}
|
|
2655
|
-
const projectId = config === null || config === void 0 ? void 0 : config.projectId;
|
|
2656
|
-
const warnMissingVariant = () => {
|
|
2657
|
-
if (applyVariantChangesStarted) {
|
|
2658
|
-
logger.warn('Failed to wait for variant rendered command', 'missing_variant_rendered');
|
|
2659
|
-
}
|
|
2660
|
-
};
|
|
2661
|
-
waitForCmd((cmd) => cmd.variantRendered === true || cmd.emit === 'variantRendered', Coframe, timeoutMs)
|
|
2662
|
-
.then((cmd) => {
|
|
2663
|
-
if (!cmd) {
|
|
2664
|
-
warnMissingVariant();
|
|
2665
|
-
}
|
|
2666
|
-
})
|
|
2667
|
-
.finally(() => {
|
|
2668
|
-
revealPage();
|
|
2669
|
-
});
|
|
2670
|
-
if (!projectId) {
|
|
2671
|
-
logger.error('No project ID', 'no_project_id', {
|
|
2672
|
-
description: 'No Coframe Page ID',
|
|
2673
|
-
});
|
|
2674
|
-
variantRendered();
|
|
2675
|
-
return null;
|
|
2676
|
-
}
|
|
2677
|
-
Coframe.projectId = projectId;
|
|
2678
|
-
const urlParams = getCurrentUrlSearchParams();
|
|
2679
|
-
const urlVariantId = urlParams.get('coframe_variant_id');
|
|
2680
|
-
const shouldSendEventsParam = urlParams.get('coframe_should_send_events');
|
|
2681
|
-
const keepForSession = urlParams.get('keep_preview_for_session') === 'true';
|
|
2682
|
-
let previewVariantId = null;
|
|
2683
|
-
let isSessionVariant = false;
|
|
2684
|
-
if (urlVariantId) {
|
|
2685
|
-
previewVariantId = urlVariantId;
|
|
2686
|
-
if (keepForSession) {
|
|
2687
|
-
persistPreviewVariantId(urlVariantId);
|
|
2688
|
-
}
|
|
2689
|
-
}
|
|
2690
|
-
else {
|
|
2691
|
-
const stored = readPreviewVariantId();
|
|
2692
|
-
if (stored) {
|
|
2693
|
-
previewVariantId = stored;
|
|
2694
|
-
isSessionVariant = true;
|
|
2695
|
-
}
|
|
2696
|
-
}
|
|
2697
|
-
setForceSendEvents(shouldSendEventsParam === 'true');
|
|
2698
|
-
setIsPreviewVariant(!!previewVariantId);
|
|
2699
|
-
setWaitingForCookies(!!config.waitForCookiesEnabled);
|
|
2700
|
-
return {
|
|
2701
|
-
config,
|
|
2702
|
-
timeoutMs,
|
|
2703
|
-
projectId,
|
|
2704
|
-
previewVariantId,
|
|
2705
|
-
isSessionVariant,
|
|
2706
|
-
integrationStartTime,
|
|
2707
|
-
executionStartTime,
|
|
2708
|
-
};
|
|
2709
|
-
}
|
|
2710
|
-
const SESSION_VARIANT_KEY = 'coframe.preview_variant';
|
|
2711
|
-
function readPreviewVariantId() {
|
|
2712
|
-
try {
|
|
2713
|
-
return sessionStorage.getItem(SESSION_VARIANT_KEY);
|
|
2714
|
-
}
|
|
2715
|
-
catch (_a) {
|
|
2716
|
-
return null;
|
|
2717
|
-
}
|
|
2718
|
-
}
|
|
2719
|
-
function persistPreviewVariantId(variantId) {
|
|
2720
|
-
try {
|
|
2721
|
-
sessionStorage.setItem(SESSION_VARIANT_KEY, variantId);
|
|
2722
|
-
}
|
|
2723
|
-
catch (_a) {
|
|
2724
|
-
}
|
|
2725
|
-
}
|
|
2726
|
-
|
|
2727
2822
|
function startSession(Coframe, cookiesEnabled, executionStartTime, personalizationHeaders) {
|
|
2728
2823
|
const sessionPayload = [
|
|
2729
2824
|
Coframe,
|
|
@@ -3182,6 +3277,8 @@ function createApplyVariants(Coframe, config, previewVariantId, isSessionVariant
|
|
|
3182
3277
|
Coframe.experimentInfo = experimentsInfo;
|
|
3183
3278
|
Coframe.variantsAndElements = variantsAndElements;
|
|
3184
3279
|
setFrameActivated(hasActivatedFrames);
|
|
3280
|
+
const sessionPreview = resolveSessionPreviewState();
|
|
3281
|
+
updatePreviewPanel(variantsAndElements, sessionPreview, !config.trackingOnly);
|
|
3185
3282
|
if (Coframe.debug) {
|
|
3186
3283
|
Coframe.debug.project = pageProject;
|
|
3187
3284
|
Coframe.debug.frames = pageProject.frames;
|
|
@@ -3201,6 +3298,11 @@ function createApplyVariants(Coframe, config, previewVariantId, isSessionVariant
|
|
|
3201
3298
|
async function modifyPage(Coframe, configResult, projectResult, analytics) {
|
|
3202
3299
|
const { config, timeoutMs, previewVariantId, isSessionVariant, integrationStartTime, executionStartTime, } = configResult;
|
|
3203
3300
|
const { project: cdnProject, personalizationHeaders } = projectResult;
|
|
3301
|
+
if (resolveSessionPreviewState().isSessionPreviewActive) {
|
|
3302
|
+
waitForBody(timeoutMs)
|
|
3303
|
+
.then(() => resolveSessionPreviewPanel(resolveSessionPreviewState(), config.nonce, Coframe.logger))
|
|
3304
|
+
.catch(() => { });
|
|
3305
|
+
}
|
|
3204
3306
|
if (!(await awaitHydration(config, Coframe, cdnProject)))
|
|
3205
3307
|
return;
|
|
3206
3308
|
if (cdnProject.tags) {
|
|
@@ -3222,6 +3324,105 @@ async function modifyPage(Coframe, configResult, projectResult, analytics) {
|
|
|
3222
3324
|
setupFlushInterval(Coframe.projectId);
|
|
3223
3325
|
}
|
|
3224
3326
|
|
|
3327
|
+
const TIMEOUT_MAX_MS = 5000;
|
|
3328
|
+
function getFeatureFlagValue(cmd) {
|
|
3329
|
+
if (cmd.featureFlagSet !== undefined)
|
|
3330
|
+
return cmd.featureFlagSet;
|
|
3331
|
+
if (typeof cmd.emit === 'object' &&
|
|
3332
|
+
cmd.emit !== null &&
|
|
3333
|
+
'featureFlagSet' in cmd.emit) {
|
|
3334
|
+
return cmd.emit.featureFlagSet;
|
|
3335
|
+
}
|
|
3336
|
+
return undefined;
|
|
3337
|
+
}
|
|
3338
|
+
async function resolveFeatureFlag(Coframe, timeoutMs) {
|
|
3339
|
+
const cmd = await waitForCmd((cmd) => typeof getFeatureFlagValue(cmd) === 'boolean', Coframe, timeoutMs);
|
|
3340
|
+
if (!cmd)
|
|
3341
|
+
return undefined;
|
|
3342
|
+
return getFeatureFlagValue(cmd);
|
|
3343
|
+
}
|
|
3344
|
+
async function resolveConfig(Coframe, revealPage) {
|
|
3345
|
+
const logger = Coframe.logger;
|
|
3346
|
+
const configCmd = await waitForCmd((cmd) => !!cmd.config, Coframe);
|
|
3347
|
+
if (!configCmd) {
|
|
3348
|
+
logger.error('Failed to wait for config cmd', 'wait_for_cmd_timeout');
|
|
3349
|
+
return null;
|
|
3350
|
+
}
|
|
3351
|
+
const config = configCmd.config;
|
|
3352
|
+
const timeoutMs = (config === null || config === void 0 ? void 0 : config.timeoutMs)
|
|
3353
|
+
? Math.min(config.timeoutMs, TIMEOUT_MAX_MS)
|
|
3354
|
+
: TIMEOUT_MAX_MS;
|
|
3355
|
+
const integrationStartTime = (config === null || config === void 0 ? void 0 : config.startTime)
|
|
3356
|
+
? new Date(config.startTime)
|
|
3357
|
+
: null;
|
|
3358
|
+
const executionStartTime = new Date();
|
|
3359
|
+
Coframe.batchSize = config.batchSize || 32;
|
|
3360
|
+
const gracefulExit = (msg) => {
|
|
3361
|
+
console.warn(`[Coframe] ${msg}`);
|
|
3362
|
+
revealPage();
|
|
3363
|
+
return null;
|
|
3364
|
+
};
|
|
3365
|
+
if (config.waitForFeatureFlag) {
|
|
3366
|
+
const flag = await resolveFeatureFlag(Coframe, timeoutMs);
|
|
3367
|
+
if (flag === undefined) {
|
|
3368
|
+
return gracefulExit('Feature flag was not set after timeout, graceful exit');
|
|
3369
|
+
}
|
|
3370
|
+
if (flag === false) {
|
|
3371
|
+
return gracefulExit('Feature flag is set to false, graceful exit');
|
|
3372
|
+
}
|
|
3373
|
+
}
|
|
3374
|
+
const projectId = config === null || config === void 0 ? void 0 : config.projectId;
|
|
3375
|
+
const warnMissingVariant = () => {
|
|
3376
|
+
if (applyVariantChangesStarted) {
|
|
3377
|
+
logger.warn('Failed to wait for variant rendered command', 'missing_variant_rendered');
|
|
3378
|
+
}
|
|
3379
|
+
};
|
|
3380
|
+
waitForCmd((cmd) => cmd.variantRendered === true || cmd.emit === 'variantRendered', Coframe, timeoutMs)
|
|
3381
|
+
.then((cmd) => {
|
|
3382
|
+
if (!cmd) {
|
|
3383
|
+
warnMissingVariant();
|
|
3384
|
+
}
|
|
3385
|
+
})
|
|
3386
|
+
.finally(() => {
|
|
3387
|
+
revealPage();
|
|
3388
|
+
});
|
|
3389
|
+
if (!projectId) {
|
|
3390
|
+
logger.error('No project ID', 'no_project_id', {
|
|
3391
|
+
description: 'No Coframe Page ID',
|
|
3392
|
+
});
|
|
3393
|
+
variantRendered();
|
|
3394
|
+
return null;
|
|
3395
|
+
}
|
|
3396
|
+
Coframe.projectId = projectId;
|
|
3397
|
+
const urlParams = getCurrentUrlSearchParams();
|
|
3398
|
+
const previewSource = resolvePreviewSource(urlParams);
|
|
3399
|
+
const shouldSendEventsParam = urlParams.get('coframe_should_send_events');
|
|
3400
|
+
let previewVariantId = null;
|
|
3401
|
+
let isSessionVariant = false;
|
|
3402
|
+
if (previewSource.urlVariantId) {
|
|
3403
|
+
previewVariantId = previewSource.urlVariantId;
|
|
3404
|
+
if (previewSource.keepForSession) {
|
|
3405
|
+
persistPreviewVariantId(previewSource.urlVariantId);
|
|
3406
|
+
}
|
|
3407
|
+
}
|
|
3408
|
+
else if (previewSource.storedVariantId) {
|
|
3409
|
+
previewVariantId = previewSource.storedVariantId;
|
|
3410
|
+
isSessionVariant = true;
|
|
3411
|
+
}
|
|
3412
|
+
setForceSendEvents(shouldSendEventsParam === 'true');
|
|
3413
|
+
setIsPreviewVariant(!!previewVariantId);
|
|
3414
|
+
setWaitingForCookies(!!config.waitForCookiesEnabled);
|
|
3415
|
+
return {
|
|
3416
|
+
config,
|
|
3417
|
+
timeoutMs,
|
|
3418
|
+
projectId,
|
|
3419
|
+
previewVariantId,
|
|
3420
|
+
isSessionVariant,
|
|
3421
|
+
integrationStartTime,
|
|
3422
|
+
executionStartTime,
|
|
3423
|
+
};
|
|
3424
|
+
}
|
|
3425
|
+
|
|
3225
3426
|
async function resolveIdentity(config, Coframe, timeoutMs, gracefulExit) {
|
|
3226
3427
|
const logger = Coframe.logger;
|
|
3227
3428
|
let userToken;
|
package/dist/pkg/cf.esm.mjs
CHANGED
|
@@ -2577,6 +2577,220 @@ function rebindMetrics(coframe, logger, metrics, nonce) {
|
|
|
2577
2577
|
}
|
|
2578
2578
|
}
|
|
2579
2579
|
|
|
2580
|
+
function getActivePreviewModes(sessionPreview) {
|
|
2581
|
+
if (!sessionPreview.isSessionPreviewActive ||
|
|
2582
|
+
!sessionPreview.previewVariantId) {
|
|
2583
|
+
return [];
|
|
2584
|
+
}
|
|
2585
|
+
return [
|
|
2586
|
+
{
|
|
2587
|
+
id: 'session-preview',
|
|
2588
|
+
label: 'Preview on',
|
|
2589
|
+
title: `Session preview is active for ${sessionPreview.previewVariantId}`,
|
|
2590
|
+
variantIds: sessionPreview.previewVariantId
|
|
2591
|
+
.split(',')
|
|
2592
|
+
.map((id) => id.trim())
|
|
2593
|
+
.filter(Boolean),
|
|
2594
|
+
},
|
|
2595
|
+
];
|
|
2596
|
+
}
|
|
2597
|
+
|
|
2598
|
+
const PREVIEW_UI_PROTOCOL_VERSION = 1;
|
|
2599
|
+
|
|
2600
|
+
const SESSION_VARIANT_KEY = 'coframe.preview_variant';
|
|
2601
|
+
const PREVIEW_VARIANT_QUERY_PARAM = 'coframe_variant_id';
|
|
2602
|
+
const KEEP_PREVIEW_FOR_SESSION_QUERY_PARAM = 'keep_preview_for_session';
|
|
2603
|
+
let previewDismissed = false;
|
|
2604
|
+
function dismissSessionPreview() {
|
|
2605
|
+
previewDismissed = true;
|
|
2606
|
+
clearPreviewVariantId();
|
|
2607
|
+
const url = new URL(window.location.href);
|
|
2608
|
+
url.searchParams.delete(PREVIEW_VARIANT_QUERY_PARAM);
|
|
2609
|
+
url.searchParams.delete(KEEP_PREVIEW_FOR_SESSION_QUERY_PARAM);
|
|
2610
|
+
window.history.replaceState(window.history.state, '', url);
|
|
2611
|
+
window.location.reload();
|
|
2612
|
+
}
|
|
2613
|
+
function normalizeVariantIds(raw) {
|
|
2614
|
+
if (!raw)
|
|
2615
|
+
return null;
|
|
2616
|
+
const ids = raw
|
|
2617
|
+
.split(',')
|
|
2618
|
+
.map((id) => id.trim())
|
|
2619
|
+
.filter(Boolean);
|
|
2620
|
+
return ids.length > 0 ? ids.join(',') : null;
|
|
2621
|
+
}
|
|
2622
|
+
function readPreviewVariantId() {
|
|
2623
|
+
try {
|
|
2624
|
+
return sessionStorage.getItem(SESSION_VARIANT_KEY);
|
|
2625
|
+
}
|
|
2626
|
+
catch (_a) {
|
|
2627
|
+
return null;
|
|
2628
|
+
}
|
|
2629
|
+
}
|
|
2630
|
+
function persistPreviewVariantId(variantId) {
|
|
2631
|
+
const normalized = normalizeVariantIds(variantId);
|
|
2632
|
+
if (!normalized)
|
|
2633
|
+
return;
|
|
2634
|
+
try {
|
|
2635
|
+
sessionStorage.setItem(SESSION_VARIANT_KEY, normalized);
|
|
2636
|
+
}
|
|
2637
|
+
catch (_a) {
|
|
2638
|
+
}
|
|
2639
|
+
}
|
|
2640
|
+
function clearPreviewVariantId() {
|
|
2641
|
+
try {
|
|
2642
|
+
sessionStorage.removeItem(SESSION_VARIANT_KEY);
|
|
2643
|
+
}
|
|
2644
|
+
catch (_a) {
|
|
2645
|
+
}
|
|
2646
|
+
}
|
|
2647
|
+
function resolvePreviewSource(urlParams = getCurrentUrlSearchParams()) {
|
|
2648
|
+
return {
|
|
2649
|
+
urlVariantId: urlParams.get(PREVIEW_VARIANT_QUERY_PARAM),
|
|
2650
|
+
storedVariantId: readPreviewVariantId(),
|
|
2651
|
+
keepForSession: urlParams.get(KEEP_PREVIEW_FOR_SESSION_QUERY_PARAM) === 'true',
|
|
2652
|
+
};
|
|
2653
|
+
}
|
|
2654
|
+
function resolveSessionPreviewState() {
|
|
2655
|
+
if (previewDismissed) {
|
|
2656
|
+
return { isSessionPreviewActive: false, previewVariantId: null };
|
|
2657
|
+
}
|
|
2658
|
+
const previewSource = resolvePreviewSource();
|
|
2659
|
+
const urlVariantId = normalizeVariantIds(previewSource.urlVariantId);
|
|
2660
|
+
if (urlVariantId && previewSource.keepForSession) {
|
|
2661
|
+
return {
|
|
2662
|
+
isSessionPreviewActive: true,
|
|
2663
|
+
previewVariantId: urlVariantId,
|
|
2664
|
+
};
|
|
2665
|
+
}
|
|
2666
|
+
if (urlVariantId) {
|
|
2667
|
+
return { isSessionPreviewActive: false, previewVariantId: null };
|
|
2668
|
+
}
|
|
2669
|
+
const storedVariantId = normalizeVariantIds(previewSource.storedVariantId);
|
|
2670
|
+
return {
|
|
2671
|
+
isSessionPreviewActive: !!storedVariantId,
|
|
2672
|
+
previewVariantId: storedVariantId,
|
|
2673
|
+
};
|
|
2674
|
+
}
|
|
2675
|
+
|
|
2676
|
+
const PREVIEW_UI_SCRIPT_ID = 'coframe-preview-ui-script';
|
|
2677
|
+
const PREVIEW_UI_URL = "https://edge.cofra.me/preview-ui/latest.js";
|
|
2678
|
+
let loadPromise = null;
|
|
2679
|
+
let latestState = { modes: [] };
|
|
2680
|
+
let nonce;
|
|
2681
|
+
let logger;
|
|
2682
|
+
let mounted = false;
|
|
2683
|
+
function reportError(message, error) {
|
|
2684
|
+
const errorMessage = error instanceof Error ? error.message : String(error);
|
|
2685
|
+
if (logger) {
|
|
2686
|
+
logger.warn(message, 'preview_ui_unavailable', { error: errorMessage });
|
|
2687
|
+
return;
|
|
2688
|
+
}
|
|
2689
|
+
console.warn(`[Coframe] ${message}`, error);
|
|
2690
|
+
}
|
|
2691
|
+
function getPreviewUI() {
|
|
2692
|
+
const api = window.CoframePreviewUI;
|
|
2693
|
+
return (api === null || api === void 0 ? void 0 : api.protocolVersion) === PREVIEW_UI_PROTOCOL_VERSION ? api : undefined;
|
|
2694
|
+
}
|
|
2695
|
+
function loadPreviewUI() {
|
|
2696
|
+
const existing = getPreviewUI();
|
|
2697
|
+
if (existing)
|
|
2698
|
+
return Promise.resolve(existing);
|
|
2699
|
+
if (loadPromise)
|
|
2700
|
+
return loadPromise;
|
|
2701
|
+
loadPromise = new Promise((resolve, reject) => {
|
|
2702
|
+
const script = document.createElement('script');
|
|
2703
|
+
script.id = PREVIEW_UI_SCRIPT_ID;
|
|
2704
|
+
script.async = true;
|
|
2705
|
+
script.src = PREVIEW_UI_URL;
|
|
2706
|
+
if (nonce)
|
|
2707
|
+
script.nonce = nonce;
|
|
2708
|
+
script.onload = () => {
|
|
2709
|
+
const api = getPreviewUI();
|
|
2710
|
+
if (!api) {
|
|
2711
|
+
reject(new Error('Preview UI protocol is missing or incompatible'));
|
|
2712
|
+
return;
|
|
2713
|
+
}
|
|
2714
|
+
resolve(api);
|
|
2715
|
+
};
|
|
2716
|
+
script.onerror = () => {
|
|
2717
|
+
reject(new Error('Preview UI script failed to load'));
|
|
2718
|
+
};
|
|
2719
|
+
document.head.appendChild(script);
|
|
2720
|
+
});
|
|
2721
|
+
return loadPromise;
|
|
2722
|
+
}
|
|
2723
|
+
function renderPreviewUI(api) {
|
|
2724
|
+
try {
|
|
2725
|
+
if (latestState.modes.length === 0) {
|
|
2726
|
+
api.unmount();
|
|
2727
|
+
mounted = false;
|
|
2728
|
+
}
|
|
2729
|
+
else if (mounted) {
|
|
2730
|
+
api.update(latestState);
|
|
2731
|
+
}
|
|
2732
|
+
else {
|
|
2733
|
+
api.mount({ state: latestState, nonce, onDismiss: dismissPreviewPanel });
|
|
2734
|
+
mounted = true;
|
|
2735
|
+
}
|
|
2736
|
+
}
|
|
2737
|
+
catch (error) {
|
|
2738
|
+
reportError('Preview UI could not be rendered', error);
|
|
2739
|
+
}
|
|
2740
|
+
}
|
|
2741
|
+
function dismissPreviewPanel() {
|
|
2742
|
+
dismissSessionPreview();
|
|
2743
|
+
latestState = { modes: [] };
|
|
2744
|
+
const api = getPreviewUI();
|
|
2745
|
+
if (api)
|
|
2746
|
+
renderPreviewUI(api);
|
|
2747
|
+
}
|
|
2748
|
+
function modesWithVariants(sessionPreview, variantsAndElements, applied = true) {
|
|
2749
|
+
const activeModes = getActivePreviewModes(sessionPreview);
|
|
2750
|
+
if (activeModes.length === 0)
|
|
2751
|
+
return [];
|
|
2752
|
+
const currentPageVariantIds = new Set((variantsAndElements === null || variantsAndElements === void 0 ? void 0 : variantsAndElements.map(({ variant }) => variant.id)) || []);
|
|
2753
|
+
const slugById = new Map((variantsAndElements === null || variantsAndElements === void 0 ? void 0 : variantsAndElements.map(({ variant }) => [variant.id, variant.slug])) || []);
|
|
2754
|
+
return activeModes.map((mode) => ({
|
|
2755
|
+
id: mode.id,
|
|
2756
|
+
label: mode.label,
|
|
2757
|
+
title: mode.title,
|
|
2758
|
+
variants: mode.variantIds.map((id) => ({
|
|
2759
|
+
id,
|
|
2760
|
+
slug: slugById.get(id) || null,
|
|
2761
|
+
status: variantsAndElements
|
|
2762
|
+
? applied && currentPageVariantIds.has(id)
|
|
2763
|
+
? 'active'
|
|
2764
|
+
: 'inactive'
|
|
2765
|
+
: 'pending',
|
|
2766
|
+
})),
|
|
2767
|
+
}));
|
|
2768
|
+
}
|
|
2769
|
+
function resolveSessionPreviewPanel(sessionPreview, previewNonce, previewLogger) {
|
|
2770
|
+
const modes = modesWithVariants(sessionPreview);
|
|
2771
|
+
if (modes.length === 0)
|
|
2772
|
+
return;
|
|
2773
|
+
nonce = previewNonce;
|
|
2774
|
+
logger = previewLogger;
|
|
2775
|
+
latestState = { modes };
|
|
2776
|
+
const existing = getPreviewUI();
|
|
2777
|
+
if (existing) {
|
|
2778
|
+
renderPreviewUI(existing);
|
|
2779
|
+
return;
|
|
2780
|
+
}
|
|
2781
|
+
void loadPreviewUI()
|
|
2782
|
+
.then(renderPreviewUI)
|
|
2783
|
+
.catch((error) => reportError('Preview UI could not be loaded', error));
|
|
2784
|
+
}
|
|
2785
|
+
function updatePreviewPanel(variantsAndElements, sessionPreview, applied = true) {
|
|
2786
|
+
latestState = {
|
|
2787
|
+
modes: modesWithVariants(sessionPreview, variantsAndElements, applied),
|
|
2788
|
+
};
|
|
2789
|
+
const api = getPreviewUI();
|
|
2790
|
+
if (api)
|
|
2791
|
+
renderPreviewUI(api);
|
|
2792
|
+
}
|
|
2793
|
+
|
|
2580
2794
|
let lastUrl = null;
|
|
2581
2795
|
function observeUrlChanges(baseUrlMatch, onUrlChange) {
|
|
2582
2796
|
const tryTrack = () => {
|
|
@@ -2603,125 +2817,6 @@ function observeUrlChanges(baseUrlMatch, onUrlChange) {
|
|
|
2603
2817
|
patchHistoryMethod('replaceState');
|
|
2604
2818
|
}
|
|
2605
2819
|
|
|
2606
|
-
const TIMEOUT_MAX_MS = 5000;
|
|
2607
|
-
function getFeatureFlagValue(cmd) {
|
|
2608
|
-
if (cmd.featureFlagSet !== undefined)
|
|
2609
|
-
return cmd.featureFlagSet;
|
|
2610
|
-
if (typeof cmd.emit === 'object' &&
|
|
2611
|
-
cmd.emit !== null &&
|
|
2612
|
-
'featureFlagSet' in cmd.emit) {
|
|
2613
|
-
return cmd.emit.featureFlagSet;
|
|
2614
|
-
}
|
|
2615
|
-
return undefined;
|
|
2616
|
-
}
|
|
2617
|
-
async function resolveFeatureFlag(Coframe, timeoutMs) {
|
|
2618
|
-
const cmd = await waitForCmd((cmd) => typeof getFeatureFlagValue(cmd) === 'boolean', Coframe, timeoutMs);
|
|
2619
|
-
if (!cmd)
|
|
2620
|
-
return undefined;
|
|
2621
|
-
return getFeatureFlagValue(cmd);
|
|
2622
|
-
}
|
|
2623
|
-
async function resolveConfig(Coframe, revealPage) {
|
|
2624
|
-
const logger = Coframe.logger;
|
|
2625
|
-
const configCmd = await waitForCmd((cmd) => !!cmd.config, Coframe);
|
|
2626
|
-
if (!configCmd) {
|
|
2627
|
-
logger.error('Failed to wait for config cmd', 'wait_for_cmd_timeout');
|
|
2628
|
-
return null;
|
|
2629
|
-
}
|
|
2630
|
-
const config = configCmd.config;
|
|
2631
|
-
const timeoutMs = (config === null || config === void 0 ? void 0 : config.timeoutMs)
|
|
2632
|
-
? Math.min(config.timeoutMs, TIMEOUT_MAX_MS)
|
|
2633
|
-
: TIMEOUT_MAX_MS;
|
|
2634
|
-
const integrationStartTime = (config === null || config === void 0 ? void 0 : config.startTime)
|
|
2635
|
-
? new Date(config.startTime)
|
|
2636
|
-
: null;
|
|
2637
|
-
const executionStartTime = new Date();
|
|
2638
|
-
Coframe.batchSize = config.batchSize || 32;
|
|
2639
|
-
const gracefulExit = (msg) => {
|
|
2640
|
-
console.warn(`[Coframe] ${msg}`);
|
|
2641
|
-
revealPage();
|
|
2642
|
-
return null;
|
|
2643
|
-
};
|
|
2644
|
-
if (config.waitForFeatureFlag) {
|
|
2645
|
-
const flag = await resolveFeatureFlag(Coframe, timeoutMs);
|
|
2646
|
-
if (flag === undefined) {
|
|
2647
|
-
return gracefulExit('Feature flag was not set after timeout, graceful exit');
|
|
2648
|
-
}
|
|
2649
|
-
if (flag === false) {
|
|
2650
|
-
return gracefulExit('Feature flag is set to false, graceful exit');
|
|
2651
|
-
}
|
|
2652
|
-
}
|
|
2653
|
-
const projectId = config === null || config === void 0 ? void 0 : config.projectId;
|
|
2654
|
-
const warnMissingVariant = () => {
|
|
2655
|
-
if (applyVariantChangesStarted) {
|
|
2656
|
-
logger.warn('Failed to wait for variant rendered command', 'missing_variant_rendered');
|
|
2657
|
-
}
|
|
2658
|
-
};
|
|
2659
|
-
waitForCmd((cmd) => cmd.variantRendered === true || cmd.emit === 'variantRendered', Coframe, timeoutMs)
|
|
2660
|
-
.then((cmd) => {
|
|
2661
|
-
if (!cmd) {
|
|
2662
|
-
warnMissingVariant();
|
|
2663
|
-
}
|
|
2664
|
-
})
|
|
2665
|
-
.finally(() => {
|
|
2666
|
-
revealPage();
|
|
2667
|
-
});
|
|
2668
|
-
if (!projectId) {
|
|
2669
|
-
logger.error('No project ID', 'no_project_id', {
|
|
2670
|
-
description: 'No Coframe Page ID',
|
|
2671
|
-
});
|
|
2672
|
-
variantRendered();
|
|
2673
|
-
return null;
|
|
2674
|
-
}
|
|
2675
|
-
Coframe.projectId = projectId;
|
|
2676
|
-
const urlParams = getCurrentUrlSearchParams();
|
|
2677
|
-
const urlVariantId = urlParams.get('coframe_variant_id');
|
|
2678
|
-
const shouldSendEventsParam = urlParams.get('coframe_should_send_events');
|
|
2679
|
-
const keepForSession = urlParams.get('keep_preview_for_session') === 'true';
|
|
2680
|
-
let previewVariantId = null;
|
|
2681
|
-
let isSessionVariant = false;
|
|
2682
|
-
if (urlVariantId) {
|
|
2683
|
-
previewVariantId = urlVariantId;
|
|
2684
|
-
if (keepForSession) {
|
|
2685
|
-
persistPreviewVariantId(urlVariantId);
|
|
2686
|
-
}
|
|
2687
|
-
}
|
|
2688
|
-
else {
|
|
2689
|
-
const stored = readPreviewVariantId();
|
|
2690
|
-
if (stored) {
|
|
2691
|
-
previewVariantId = stored;
|
|
2692
|
-
isSessionVariant = true;
|
|
2693
|
-
}
|
|
2694
|
-
}
|
|
2695
|
-
setForceSendEvents(shouldSendEventsParam === 'true');
|
|
2696
|
-
setIsPreviewVariant(!!previewVariantId);
|
|
2697
|
-
setWaitingForCookies(!!config.waitForCookiesEnabled);
|
|
2698
|
-
return {
|
|
2699
|
-
config,
|
|
2700
|
-
timeoutMs,
|
|
2701
|
-
projectId,
|
|
2702
|
-
previewVariantId,
|
|
2703
|
-
isSessionVariant,
|
|
2704
|
-
integrationStartTime,
|
|
2705
|
-
executionStartTime,
|
|
2706
|
-
};
|
|
2707
|
-
}
|
|
2708
|
-
const SESSION_VARIANT_KEY = 'coframe.preview_variant';
|
|
2709
|
-
function readPreviewVariantId() {
|
|
2710
|
-
try {
|
|
2711
|
-
return sessionStorage.getItem(SESSION_VARIANT_KEY);
|
|
2712
|
-
}
|
|
2713
|
-
catch (_a) {
|
|
2714
|
-
return null;
|
|
2715
|
-
}
|
|
2716
|
-
}
|
|
2717
|
-
function persistPreviewVariantId(variantId) {
|
|
2718
|
-
try {
|
|
2719
|
-
sessionStorage.setItem(SESSION_VARIANT_KEY, variantId);
|
|
2720
|
-
}
|
|
2721
|
-
catch (_a) {
|
|
2722
|
-
}
|
|
2723
|
-
}
|
|
2724
|
-
|
|
2725
2820
|
function startSession(Coframe, cookiesEnabled, executionStartTime, personalizationHeaders) {
|
|
2726
2821
|
const sessionPayload = [
|
|
2727
2822
|
Coframe,
|
|
@@ -3180,6 +3275,8 @@ function createApplyVariants(Coframe, config, previewVariantId, isSessionVariant
|
|
|
3180
3275
|
Coframe.experimentInfo = experimentsInfo;
|
|
3181
3276
|
Coframe.variantsAndElements = variantsAndElements;
|
|
3182
3277
|
setFrameActivated(hasActivatedFrames);
|
|
3278
|
+
const sessionPreview = resolveSessionPreviewState();
|
|
3279
|
+
updatePreviewPanel(variantsAndElements, sessionPreview, !config.trackingOnly);
|
|
3183
3280
|
if (Coframe.debug) {
|
|
3184
3281
|
Coframe.debug.project = pageProject;
|
|
3185
3282
|
Coframe.debug.frames = pageProject.frames;
|
|
@@ -3199,6 +3296,11 @@ function createApplyVariants(Coframe, config, previewVariantId, isSessionVariant
|
|
|
3199
3296
|
async function modifyPage(Coframe, configResult, projectResult, analytics) {
|
|
3200
3297
|
const { config, timeoutMs, previewVariantId, isSessionVariant, integrationStartTime, executionStartTime, } = configResult;
|
|
3201
3298
|
const { project: cdnProject, personalizationHeaders } = projectResult;
|
|
3299
|
+
if (resolveSessionPreviewState().isSessionPreviewActive) {
|
|
3300
|
+
waitForBody(timeoutMs)
|
|
3301
|
+
.then(() => resolveSessionPreviewPanel(resolveSessionPreviewState(), config.nonce, Coframe.logger))
|
|
3302
|
+
.catch(() => { });
|
|
3303
|
+
}
|
|
3202
3304
|
if (!(await awaitHydration(config, Coframe, cdnProject)))
|
|
3203
3305
|
return;
|
|
3204
3306
|
if (cdnProject.tags) {
|
|
@@ -3220,6 +3322,105 @@ async function modifyPage(Coframe, configResult, projectResult, analytics) {
|
|
|
3220
3322
|
setupFlushInterval(Coframe.projectId);
|
|
3221
3323
|
}
|
|
3222
3324
|
|
|
3325
|
+
const TIMEOUT_MAX_MS = 5000;
|
|
3326
|
+
function getFeatureFlagValue(cmd) {
|
|
3327
|
+
if (cmd.featureFlagSet !== undefined)
|
|
3328
|
+
return cmd.featureFlagSet;
|
|
3329
|
+
if (typeof cmd.emit === 'object' &&
|
|
3330
|
+
cmd.emit !== null &&
|
|
3331
|
+
'featureFlagSet' in cmd.emit) {
|
|
3332
|
+
return cmd.emit.featureFlagSet;
|
|
3333
|
+
}
|
|
3334
|
+
return undefined;
|
|
3335
|
+
}
|
|
3336
|
+
async function resolveFeatureFlag(Coframe, timeoutMs) {
|
|
3337
|
+
const cmd = await waitForCmd((cmd) => typeof getFeatureFlagValue(cmd) === 'boolean', Coframe, timeoutMs);
|
|
3338
|
+
if (!cmd)
|
|
3339
|
+
return undefined;
|
|
3340
|
+
return getFeatureFlagValue(cmd);
|
|
3341
|
+
}
|
|
3342
|
+
async function resolveConfig(Coframe, revealPage) {
|
|
3343
|
+
const logger = Coframe.logger;
|
|
3344
|
+
const configCmd = await waitForCmd((cmd) => !!cmd.config, Coframe);
|
|
3345
|
+
if (!configCmd) {
|
|
3346
|
+
logger.error('Failed to wait for config cmd', 'wait_for_cmd_timeout');
|
|
3347
|
+
return null;
|
|
3348
|
+
}
|
|
3349
|
+
const config = configCmd.config;
|
|
3350
|
+
const timeoutMs = (config === null || config === void 0 ? void 0 : config.timeoutMs)
|
|
3351
|
+
? Math.min(config.timeoutMs, TIMEOUT_MAX_MS)
|
|
3352
|
+
: TIMEOUT_MAX_MS;
|
|
3353
|
+
const integrationStartTime = (config === null || config === void 0 ? void 0 : config.startTime)
|
|
3354
|
+
? new Date(config.startTime)
|
|
3355
|
+
: null;
|
|
3356
|
+
const executionStartTime = new Date();
|
|
3357
|
+
Coframe.batchSize = config.batchSize || 32;
|
|
3358
|
+
const gracefulExit = (msg) => {
|
|
3359
|
+
console.warn(`[Coframe] ${msg}`);
|
|
3360
|
+
revealPage();
|
|
3361
|
+
return null;
|
|
3362
|
+
};
|
|
3363
|
+
if (config.waitForFeatureFlag) {
|
|
3364
|
+
const flag = await resolveFeatureFlag(Coframe, timeoutMs);
|
|
3365
|
+
if (flag === undefined) {
|
|
3366
|
+
return gracefulExit('Feature flag was not set after timeout, graceful exit');
|
|
3367
|
+
}
|
|
3368
|
+
if (flag === false) {
|
|
3369
|
+
return gracefulExit('Feature flag is set to false, graceful exit');
|
|
3370
|
+
}
|
|
3371
|
+
}
|
|
3372
|
+
const projectId = config === null || config === void 0 ? void 0 : config.projectId;
|
|
3373
|
+
const warnMissingVariant = () => {
|
|
3374
|
+
if (applyVariantChangesStarted) {
|
|
3375
|
+
logger.warn('Failed to wait for variant rendered command', 'missing_variant_rendered');
|
|
3376
|
+
}
|
|
3377
|
+
};
|
|
3378
|
+
waitForCmd((cmd) => cmd.variantRendered === true || cmd.emit === 'variantRendered', Coframe, timeoutMs)
|
|
3379
|
+
.then((cmd) => {
|
|
3380
|
+
if (!cmd) {
|
|
3381
|
+
warnMissingVariant();
|
|
3382
|
+
}
|
|
3383
|
+
})
|
|
3384
|
+
.finally(() => {
|
|
3385
|
+
revealPage();
|
|
3386
|
+
});
|
|
3387
|
+
if (!projectId) {
|
|
3388
|
+
logger.error('No project ID', 'no_project_id', {
|
|
3389
|
+
description: 'No Coframe Page ID',
|
|
3390
|
+
});
|
|
3391
|
+
variantRendered();
|
|
3392
|
+
return null;
|
|
3393
|
+
}
|
|
3394
|
+
Coframe.projectId = projectId;
|
|
3395
|
+
const urlParams = getCurrentUrlSearchParams();
|
|
3396
|
+
const previewSource = resolvePreviewSource(urlParams);
|
|
3397
|
+
const shouldSendEventsParam = urlParams.get('coframe_should_send_events');
|
|
3398
|
+
let previewVariantId = null;
|
|
3399
|
+
let isSessionVariant = false;
|
|
3400
|
+
if (previewSource.urlVariantId) {
|
|
3401
|
+
previewVariantId = previewSource.urlVariantId;
|
|
3402
|
+
if (previewSource.keepForSession) {
|
|
3403
|
+
persistPreviewVariantId(previewSource.urlVariantId);
|
|
3404
|
+
}
|
|
3405
|
+
}
|
|
3406
|
+
else if (previewSource.storedVariantId) {
|
|
3407
|
+
previewVariantId = previewSource.storedVariantId;
|
|
3408
|
+
isSessionVariant = true;
|
|
3409
|
+
}
|
|
3410
|
+
setForceSendEvents(shouldSendEventsParam === 'true');
|
|
3411
|
+
setIsPreviewVariant(!!previewVariantId);
|
|
3412
|
+
setWaitingForCookies(!!config.waitForCookiesEnabled);
|
|
3413
|
+
return {
|
|
3414
|
+
config,
|
|
3415
|
+
timeoutMs,
|
|
3416
|
+
projectId,
|
|
3417
|
+
previewVariantId,
|
|
3418
|
+
isSessionVariant,
|
|
3419
|
+
integrationStartTime,
|
|
3420
|
+
executionStartTime,
|
|
3421
|
+
};
|
|
3422
|
+
}
|
|
3423
|
+
|
|
3223
3424
|
async function resolveIdentity(config, Coframe, timeoutMs, gracefulExit) {
|
|
3224
3425
|
const logger = Coframe.logger;
|
|
3225
3426
|
let userToken;
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@coframe/sdk",
|
|
3
|
-
"version": "1.1.
|
|
3
|
+
"version": "1.1.5",
|
|
4
4
|
"description": "Coframe optimizes your website using generative AI to deliver maximum impact to your audience and allow your site to improve itself as you sleep. Learn more at coframe.com.",
|
|
5
5
|
"main": "dist/pkg/cf.cjs.js",
|
|
6
6
|
"module": "dist/pkg/cf.esm.mjs",
|