@coframe/sdk 1.1.34 → 1.1.36
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 +146 -33
- package/dist/pkg/cf.esm.mjs +146 -33
- package/dist/pkg/types/index.d.ts +1 -0
- package/package.json +1 -1
package/dist/pkg/cf.cjs.js
CHANGED
|
@@ -539,6 +539,30 @@ const getElement = (selector, options) => {
|
|
|
539
539
|
}
|
|
540
540
|
return null;
|
|
541
541
|
};
|
|
542
|
+
const resolvedPathCache = new Map();
|
|
543
|
+
const selectorKey = (selector) => selector.fingerprint || JSON.stringify(selector);
|
|
544
|
+
const keepsIdentity = (document, element, selector) => {
|
|
545
|
+
if (element.tagName.toLowerCase() !== selector.t.toLowerCase())
|
|
546
|
+
return false;
|
|
547
|
+
const attrs = [
|
|
548
|
+
['id', selector.id],
|
|
549
|
+
['data-test-id', selector.dataTestId],
|
|
550
|
+
['aria-label', selector.ariaLabel],
|
|
551
|
+
];
|
|
552
|
+
for (const [name, value] of attrs) {
|
|
553
|
+
if (!value || element.getAttribute(name) === value)
|
|
554
|
+
continue;
|
|
555
|
+
try {
|
|
556
|
+
const carriers = document.querySelectorAll(`[${name}="${value.replace(/["\\]/g, '\\$&')}"]`);
|
|
557
|
+
if (carriers.length === 1 && carriers[0] !== element)
|
|
558
|
+
return false;
|
|
559
|
+
}
|
|
560
|
+
catch (_a) {
|
|
561
|
+
return false;
|
|
562
|
+
}
|
|
563
|
+
}
|
|
564
|
+
return true;
|
|
565
|
+
};
|
|
542
566
|
const getElementUniversal = (document, selector, debug) => {
|
|
543
567
|
var _a, _b, _c;
|
|
544
568
|
const debugList = [];
|
|
@@ -621,20 +645,34 @@ const getElementUniversal = (document, selector, debug) => {
|
|
|
621
645
|
}
|
|
622
646
|
return element;
|
|
623
647
|
};
|
|
648
|
+
const key = selectorKey(selector);
|
|
649
|
+
const remembered = resolvedPathCache.get(key);
|
|
650
|
+
if (remembered && !debug) {
|
|
651
|
+
const element = tryPath(remembered);
|
|
652
|
+
if (element && keepsIdentity(document, element, selector))
|
|
653
|
+
return { element };
|
|
654
|
+
resolvedPathCache.delete(key);
|
|
655
|
+
}
|
|
656
|
+
const tryPathAndCache = (pathSegments) => {
|
|
657
|
+
const element = tryPath(pathSegments);
|
|
658
|
+
if (element && !debug)
|
|
659
|
+
resolvedPathCache.set(key, pathSegments);
|
|
660
|
+
return element;
|
|
661
|
+
};
|
|
624
662
|
const naivePaths = generateNaivePaths(selector);
|
|
625
|
-
let element =
|
|
663
|
+
let element = tryPathAndCache(naivePaths[0]);
|
|
626
664
|
if (element && !debug)
|
|
627
665
|
return { element };
|
|
628
666
|
const [relativePaths, partialRelativePaths] = generateRelativePaths(selector, 10);
|
|
629
667
|
for (const relativePath of relativePaths) {
|
|
630
|
-
element =
|
|
668
|
+
element = tryPathAndCache(relativePath);
|
|
631
669
|
if (element && !debug)
|
|
632
670
|
return { element };
|
|
633
671
|
}
|
|
634
672
|
if (selector.text) {
|
|
635
673
|
const textPaths = generatePathsByText(selector.text, selector.t);
|
|
636
674
|
for (const textPath of textPaths) {
|
|
637
|
-
element =
|
|
675
|
+
element = tryPathAndCache(textPath);
|
|
638
676
|
if (element && !debug)
|
|
639
677
|
return { element };
|
|
640
678
|
}
|
|
@@ -648,7 +686,7 @@ const getElementUniversal = (document, selector, debug) => {
|
|
|
648
686
|
const descPath = (_a = generateRelativePaths(descendant.sel, 1)[0]) === null || _a === void 0 ? void 0 : _a[0];
|
|
649
687
|
if (descPath && descPath.length > 0) {
|
|
650
688
|
const modifiedPath = appendToLastPathSegment(descPath, ancestorSelectors);
|
|
651
|
-
element =
|
|
689
|
+
element = tryPathAndCache(modifiedPath);
|
|
652
690
|
if (element && !debug)
|
|
653
691
|
return { element };
|
|
654
692
|
}
|
|
@@ -657,7 +695,7 @@ const getElementUniversal = (document, selector, debug) => {
|
|
|
657
695
|
for (const textPath of textPaths) {
|
|
658
696
|
if (textPath && textPath.length > 0) {
|
|
659
697
|
const textBasedPath = appendToLastPathSegment(textPath, ancestorSelectors);
|
|
660
|
-
element =
|
|
698
|
+
element = tryPathAndCache(textBasedPath);
|
|
661
699
|
if (element && !debug)
|
|
662
700
|
return { element };
|
|
663
701
|
}
|
|
@@ -666,12 +704,12 @@ const getElementUniversal = (document, selector, debug) => {
|
|
|
666
704
|
}
|
|
667
705
|
}
|
|
668
706
|
for (const partialPath of naivePaths.slice(1)) {
|
|
669
|
-
element =
|
|
707
|
+
element = tryPathAndCache(partialPath);
|
|
670
708
|
if (element && !debug)
|
|
671
709
|
return { element };
|
|
672
710
|
}
|
|
673
711
|
for (const partialPath of partialRelativePaths) {
|
|
674
|
-
element =
|
|
712
|
+
element = tryPathAndCache(partialPath);
|
|
675
713
|
if (element && !debug)
|
|
676
714
|
return { element };
|
|
677
715
|
}
|
|
@@ -3133,6 +3171,43 @@ function cacheFrames(url, data) {
|
|
|
3133
3171
|
|
|
3134
3172
|
let conversionListenerStop = null;
|
|
3135
3173
|
const activeJSBinders = new Set();
|
|
3174
|
+
const missedUntil = new Map();
|
|
3175
|
+
const FIRST_RETRY_WAIT_MS = 2000;
|
|
3176
|
+
const RETRY_WAIT_FACTOR = 3;
|
|
3177
|
+
const MAX_RETRY_WAIT_MS = 60000;
|
|
3178
|
+
function hasUniversalSelector(selector) {
|
|
3179
|
+
var _a, _b;
|
|
3180
|
+
if (!selector)
|
|
3181
|
+
return false;
|
|
3182
|
+
if (selector.universal)
|
|
3183
|
+
return true;
|
|
3184
|
+
return (((_a = selector.and) !== null && _a !== void 0 ? _a : []).some(hasUniversalSelector) ||
|
|
3185
|
+
((_b = selector.or) !== null && _b !== void 0 ? _b : []).some(hasUniversalSelector));
|
|
3186
|
+
}
|
|
3187
|
+
function isWaitingAfterMiss(metricId, url, now) {
|
|
3188
|
+
const miss = missedUntil.get(metricId);
|
|
3189
|
+
return !!miss && miss.url === url && now < miss.nextAt;
|
|
3190
|
+
}
|
|
3191
|
+
let retryTimer = null;
|
|
3192
|
+
let retryAt = Infinity;
|
|
3193
|
+
function scheduleRetry(at, now, rebind) {
|
|
3194
|
+
if (retryTimer && at >= retryAt)
|
|
3195
|
+
return;
|
|
3196
|
+
if (retryTimer)
|
|
3197
|
+
clearTimeout(retryTimer);
|
|
3198
|
+
retryAt = at;
|
|
3199
|
+
retryTimer = setTimeout(() => {
|
|
3200
|
+
retryTimer = null;
|
|
3201
|
+
retryAt = Infinity;
|
|
3202
|
+
rebind();
|
|
3203
|
+
}, Math.max(0, at - now));
|
|
3204
|
+
}
|
|
3205
|
+
function recordMiss(metricId, url, now) {
|
|
3206
|
+
const prev = missedUntil.get(metricId);
|
|
3207
|
+
const misses = prev && prev.url === url ? prev.misses + 1 : 1;
|
|
3208
|
+
const wait = Math.min(FIRST_RETRY_WAIT_MS * RETRY_WAIT_FACTOR ** (misses - 1), MAX_RETRY_WAIT_MS);
|
|
3209
|
+
missedUntil.set(metricId, { url, misses, nextAt: now + wait });
|
|
3210
|
+
}
|
|
3136
3211
|
function rebindMetrics(coframe, logger, metrics, nonce) {
|
|
3137
3212
|
var _a, _b;
|
|
3138
3213
|
if (!metrics || metrics.length === 0) {
|
|
@@ -3176,6 +3251,9 @@ function rebindMetrics(coframe, logger, metrics, nonce) {
|
|
|
3176
3251
|
for (let i = 0; i < elementsToClean.length; i++) {
|
|
3177
3252
|
elementsToClean[i].removeAttribute('coframe-metric-ids');
|
|
3178
3253
|
}
|
|
3254
|
+
const currentUrl = getCurrentPageUrl();
|
|
3255
|
+
const now = Date.now();
|
|
3256
|
+
let earliestRetry = Infinity;
|
|
3179
3257
|
for (let i = 0; i < metrics.length; i++) {
|
|
3180
3258
|
const metric = metrics[i];
|
|
3181
3259
|
if (metric.js_binder) {
|
|
@@ -3192,11 +3270,23 @@ function rebindMetrics(coframe, logger, metrics, nonce) {
|
|
|
3192
3270
|
continue;
|
|
3193
3271
|
}
|
|
3194
3272
|
if (metric.selector) {
|
|
3273
|
+
const expensive = hasUniversalSelector(metric.selector);
|
|
3274
|
+
if (expensive && isWaitingAfterMiss(metric.id, currentUrl, now)) {
|
|
3275
|
+
const miss = missedUntil.get(metric.id);
|
|
3276
|
+
if (miss && miss.nextAt < earliestRetry)
|
|
3277
|
+
earliestRetry = miss.nextAt;
|
|
3278
|
+
continue;
|
|
3279
|
+
}
|
|
3195
3280
|
const elements = (_b = querySelector({
|
|
3196
3281
|
selector: metric.selector,
|
|
3197
|
-
currentUrl
|
|
3282
|
+
currentUrl,
|
|
3198
3283
|
isQueryingAll: true,
|
|
3199
3284
|
})) !== null && _b !== void 0 ? _b : [];
|
|
3285
|
+
if (!expensive) ;
|
|
3286
|
+
else if (elements.length === 0)
|
|
3287
|
+
recordMiss(metric.id, currentUrl, now);
|
|
3288
|
+
else
|
|
3289
|
+
missedUntil.delete(metric.id);
|
|
3200
3290
|
for (let j = 0; j < elements.length; j++) {
|
|
3201
3291
|
const e = elements[j];
|
|
3202
3292
|
const metricIdsStr = e.getAttribute('coframe-metric-ids');
|
|
@@ -3211,6 +3301,9 @@ function rebindMetrics(coframe, logger, metrics, nonce) {
|
|
|
3211
3301
|
}
|
|
3212
3302
|
}
|
|
3213
3303
|
}
|
|
3304
|
+
if (earliestRetry < Infinity) {
|
|
3305
|
+
scheduleRetry(earliestRetry, now, () => rebindMetrics(coframe, logger, metrics, nonce));
|
|
3306
|
+
}
|
|
3214
3307
|
}
|
|
3215
3308
|
|
|
3216
3309
|
let lastUrl = null;
|
|
@@ -3239,6 +3332,42 @@ function observeUrlChanges(baseUrlMatch, onUrlChange) {
|
|
|
3239
3332
|
patchHistoryMethod('replaceState');
|
|
3240
3333
|
}
|
|
3241
3334
|
|
|
3335
|
+
function mergeClientHeaders(client, server) {
|
|
3336
|
+
if (server)
|
|
3337
|
+
return { ...client, ...server };
|
|
3338
|
+
return client && Object.keys(client).length > 0 ? { ...client } : null;
|
|
3339
|
+
}
|
|
3340
|
+
function getQueuedPersonalizationHeaders() {
|
|
3341
|
+
var _a, _b, _c;
|
|
3342
|
+
const topLevel = (_a = findLastCmd((c) => !!c.personalizationHeaders)) === null || _a === void 0 ? void 0 : _a.personalizationHeaders;
|
|
3343
|
+
const nested = (_c = (_b = findLastCmd((c) => !!c.projectData)) === null || _b === void 0 ? void 0 : _b.projectData) === null || _c === void 0 ? void 0 : _c.personalizationHeaders;
|
|
3344
|
+
return mergeClientHeaders(topLevel, nested);
|
|
3345
|
+
}
|
|
3346
|
+
async function resolveProject(Coframe, previewVariantId, isSessionVariant, config) {
|
|
3347
|
+
var _a, _b;
|
|
3348
|
+
const logger = Coframe.logger;
|
|
3349
|
+
const projectData = (_a = findLastCmd((c) => !!c.projectData)) === null || _a === void 0 ? void 0 : _a.projectData;
|
|
3350
|
+
const queuedHeaders = getQueuedPersonalizationHeaders();
|
|
3351
|
+
let personalizationHeaders = queuedHeaders;
|
|
3352
|
+
let project = isSessionVariant ? undefined : projectData === null || projectData === void 0 ? void 0 : projectData.project;
|
|
3353
|
+
if (!project) {
|
|
3354
|
+
const edgeResult = await fetchProject(config.projectUrl, Coframe.projectId, config.currentUrl || getCurrentPageUrl(), undefined, config.userContext, previewVariantId || undefined, undefined, (_b = config.referrer) !== null && _b !== void 0 ? _b : getBrowserReferrer());
|
|
3355
|
+
personalizationHeaders = mergeClientHeaders(queuedHeaders, edgeResult === null || edgeResult === void 0 ? void 0 : edgeResult.personalizationHeaders);
|
|
3356
|
+
project = (edgeResult === null || edgeResult === void 0 ? void 0 : edgeResult.project) || undefined;
|
|
3357
|
+
}
|
|
3358
|
+
if (!project) {
|
|
3359
|
+
logger.error('No Coframe Project Config', 'no_project_config', {
|
|
3360
|
+
previewVariantId,
|
|
3361
|
+
});
|
|
3362
|
+
variantRendered();
|
|
3363
|
+
return null;
|
|
3364
|
+
}
|
|
3365
|
+
return {
|
|
3366
|
+
project,
|
|
3367
|
+
personalizationHeaders: personalizationHeaders,
|
|
3368
|
+
};
|
|
3369
|
+
}
|
|
3370
|
+
|
|
3242
3371
|
const callbacks = [];
|
|
3243
3372
|
function onEventsFlushed(callback) {
|
|
3244
3373
|
callbacks.push(callback);
|
|
@@ -3671,6 +3800,7 @@ function setupSPANavigation(Coframe, project, config, previewVariantId, isSessio
|
|
|
3671
3800
|
if (cached) {
|
|
3672
3801
|
pageProject = cached.project;
|
|
3673
3802
|
pagePersonalizationHeaders = {
|
|
3803
|
+
...getQueuedPersonalizationHeaders(),
|
|
3674
3804
|
...cached.personalizationHeaders,
|
|
3675
3805
|
'x-visit-url': newPageUrl,
|
|
3676
3806
|
};
|
|
@@ -3683,7 +3813,10 @@ function setupSPANavigation(Coframe, project, config, previewVariantId, isSessio
|
|
|
3683
3813
|
return;
|
|
3684
3814
|
if (result) {
|
|
3685
3815
|
pageProject = result.project;
|
|
3686
|
-
pagePersonalizationHeaders =
|
|
3816
|
+
pagePersonalizationHeaders = {
|
|
3817
|
+
...getQueuedPersonalizationHeaders(),
|
|
3818
|
+
...result.personalizationHeaders,
|
|
3819
|
+
};
|
|
3687
3820
|
cacheFrames(newPageUrl, result);
|
|
3688
3821
|
}
|
|
3689
3822
|
}
|
|
@@ -4117,30 +4250,6 @@ async function resolveIdentity(config, Coframe, timeoutMs, gracefulExit, preview
|
|
|
4117
4250
|
return { userToken, applyCookieConsent, onConsentChange };
|
|
4118
4251
|
}
|
|
4119
4252
|
|
|
4120
|
-
async function resolveProject(Coframe, previewVariantId, isSessionVariant, config) {
|
|
4121
|
-
var _a, _b;
|
|
4122
|
-
const logger = Coframe.logger;
|
|
4123
|
-
const projectData = (_a = findLastCmd((c) => !!c.projectData)) === null || _a === void 0 ? void 0 : _a.projectData;
|
|
4124
|
-
let personalizationHeaders = (projectData === null || projectData === void 0 ? void 0 : projectData.personalizationHeaders) || null;
|
|
4125
|
-
let project = isSessionVariant ? undefined : projectData === null || projectData === void 0 ? void 0 : projectData.project;
|
|
4126
|
-
if (!project) {
|
|
4127
|
-
const edgeResult = await fetchProject(config.projectUrl, Coframe.projectId, config.currentUrl || getCurrentPageUrl(), undefined, config.userContext, previewVariantId || undefined, undefined, (_b = config.referrer) !== null && _b !== void 0 ? _b : getBrowserReferrer());
|
|
4128
|
-
personalizationHeaders = (edgeResult === null || edgeResult === void 0 ? void 0 : edgeResult.personalizationHeaders) || null;
|
|
4129
|
-
project = (edgeResult === null || edgeResult === void 0 ? void 0 : edgeResult.project) || undefined;
|
|
4130
|
-
}
|
|
4131
|
-
if (!project) {
|
|
4132
|
-
logger.error('No Coframe Project Config', 'no_project_config', {
|
|
4133
|
-
previewVariantId,
|
|
4134
|
-
});
|
|
4135
|
-
variantRendered();
|
|
4136
|
-
return null;
|
|
4137
|
-
}
|
|
4138
|
-
return {
|
|
4139
|
-
project,
|
|
4140
|
-
personalizationHeaders: personalizationHeaders,
|
|
4141
|
-
};
|
|
4142
|
-
}
|
|
4143
|
-
|
|
4144
4253
|
const COFRAME_LAUNCHER_PROTOCOL_VERSION = 1;
|
|
4145
4254
|
|
|
4146
4255
|
const LAUNCHER_SCRIPT_ID = 'coframe-tools-launcher-script';
|
|
@@ -4205,6 +4314,10 @@ function injectOptions(options) {
|
|
|
4205
4314
|
window.CFQ = window.CFQ || [];
|
|
4206
4315
|
window.CFQ.push({ config: options.config });
|
|
4207
4316
|
}
|
|
4317
|
+
if (options.personalizationHeaders) {
|
|
4318
|
+
window.CFQ = window.CFQ || [];
|
|
4319
|
+
window.CFQ.push({ personalizationHeaders: options.personalizationHeaders });
|
|
4320
|
+
}
|
|
4208
4321
|
if (options.projectData) {
|
|
4209
4322
|
window.CFQ = window.CFQ || [];
|
|
4210
4323
|
window.CFQ.push({
|
package/dist/pkg/cf.esm.mjs
CHANGED
|
@@ -537,6 +537,30 @@ const getElement = (selector, options) => {
|
|
|
537
537
|
}
|
|
538
538
|
return null;
|
|
539
539
|
};
|
|
540
|
+
const resolvedPathCache = new Map();
|
|
541
|
+
const selectorKey = (selector) => selector.fingerprint || JSON.stringify(selector);
|
|
542
|
+
const keepsIdentity = (document, element, selector) => {
|
|
543
|
+
if (element.tagName.toLowerCase() !== selector.t.toLowerCase())
|
|
544
|
+
return false;
|
|
545
|
+
const attrs = [
|
|
546
|
+
['id', selector.id],
|
|
547
|
+
['data-test-id', selector.dataTestId],
|
|
548
|
+
['aria-label', selector.ariaLabel],
|
|
549
|
+
];
|
|
550
|
+
for (const [name, value] of attrs) {
|
|
551
|
+
if (!value || element.getAttribute(name) === value)
|
|
552
|
+
continue;
|
|
553
|
+
try {
|
|
554
|
+
const carriers = document.querySelectorAll(`[${name}="${value.replace(/["\\]/g, '\\$&')}"]`);
|
|
555
|
+
if (carriers.length === 1 && carriers[0] !== element)
|
|
556
|
+
return false;
|
|
557
|
+
}
|
|
558
|
+
catch (_a) {
|
|
559
|
+
return false;
|
|
560
|
+
}
|
|
561
|
+
}
|
|
562
|
+
return true;
|
|
563
|
+
};
|
|
540
564
|
const getElementUniversal = (document, selector, debug) => {
|
|
541
565
|
var _a, _b, _c;
|
|
542
566
|
const debugList = [];
|
|
@@ -619,20 +643,34 @@ const getElementUniversal = (document, selector, debug) => {
|
|
|
619
643
|
}
|
|
620
644
|
return element;
|
|
621
645
|
};
|
|
646
|
+
const key = selectorKey(selector);
|
|
647
|
+
const remembered = resolvedPathCache.get(key);
|
|
648
|
+
if (remembered && !debug) {
|
|
649
|
+
const element = tryPath(remembered);
|
|
650
|
+
if (element && keepsIdentity(document, element, selector))
|
|
651
|
+
return { element };
|
|
652
|
+
resolvedPathCache.delete(key);
|
|
653
|
+
}
|
|
654
|
+
const tryPathAndCache = (pathSegments) => {
|
|
655
|
+
const element = tryPath(pathSegments);
|
|
656
|
+
if (element && !debug)
|
|
657
|
+
resolvedPathCache.set(key, pathSegments);
|
|
658
|
+
return element;
|
|
659
|
+
};
|
|
622
660
|
const naivePaths = generateNaivePaths(selector);
|
|
623
|
-
let element =
|
|
661
|
+
let element = tryPathAndCache(naivePaths[0]);
|
|
624
662
|
if (element && !debug)
|
|
625
663
|
return { element };
|
|
626
664
|
const [relativePaths, partialRelativePaths] = generateRelativePaths(selector, 10);
|
|
627
665
|
for (const relativePath of relativePaths) {
|
|
628
|
-
element =
|
|
666
|
+
element = tryPathAndCache(relativePath);
|
|
629
667
|
if (element && !debug)
|
|
630
668
|
return { element };
|
|
631
669
|
}
|
|
632
670
|
if (selector.text) {
|
|
633
671
|
const textPaths = generatePathsByText(selector.text, selector.t);
|
|
634
672
|
for (const textPath of textPaths) {
|
|
635
|
-
element =
|
|
673
|
+
element = tryPathAndCache(textPath);
|
|
636
674
|
if (element && !debug)
|
|
637
675
|
return { element };
|
|
638
676
|
}
|
|
@@ -646,7 +684,7 @@ const getElementUniversal = (document, selector, debug) => {
|
|
|
646
684
|
const descPath = (_a = generateRelativePaths(descendant.sel, 1)[0]) === null || _a === void 0 ? void 0 : _a[0];
|
|
647
685
|
if (descPath && descPath.length > 0) {
|
|
648
686
|
const modifiedPath = appendToLastPathSegment(descPath, ancestorSelectors);
|
|
649
|
-
element =
|
|
687
|
+
element = tryPathAndCache(modifiedPath);
|
|
650
688
|
if (element && !debug)
|
|
651
689
|
return { element };
|
|
652
690
|
}
|
|
@@ -655,7 +693,7 @@ const getElementUniversal = (document, selector, debug) => {
|
|
|
655
693
|
for (const textPath of textPaths) {
|
|
656
694
|
if (textPath && textPath.length > 0) {
|
|
657
695
|
const textBasedPath = appendToLastPathSegment(textPath, ancestorSelectors);
|
|
658
|
-
element =
|
|
696
|
+
element = tryPathAndCache(textBasedPath);
|
|
659
697
|
if (element && !debug)
|
|
660
698
|
return { element };
|
|
661
699
|
}
|
|
@@ -664,12 +702,12 @@ const getElementUniversal = (document, selector, debug) => {
|
|
|
664
702
|
}
|
|
665
703
|
}
|
|
666
704
|
for (const partialPath of naivePaths.slice(1)) {
|
|
667
|
-
element =
|
|
705
|
+
element = tryPathAndCache(partialPath);
|
|
668
706
|
if (element && !debug)
|
|
669
707
|
return { element };
|
|
670
708
|
}
|
|
671
709
|
for (const partialPath of partialRelativePaths) {
|
|
672
|
-
element =
|
|
710
|
+
element = tryPathAndCache(partialPath);
|
|
673
711
|
if (element && !debug)
|
|
674
712
|
return { element };
|
|
675
713
|
}
|
|
@@ -3131,6 +3169,43 @@ function cacheFrames(url, data) {
|
|
|
3131
3169
|
|
|
3132
3170
|
let conversionListenerStop = null;
|
|
3133
3171
|
const activeJSBinders = new Set();
|
|
3172
|
+
const missedUntil = new Map();
|
|
3173
|
+
const FIRST_RETRY_WAIT_MS = 2000;
|
|
3174
|
+
const RETRY_WAIT_FACTOR = 3;
|
|
3175
|
+
const MAX_RETRY_WAIT_MS = 60000;
|
|
3176
|
+
function hasUniversalSelector(selector) {
|
|
3177
|
+
var _a, _b;
|
|
3178
|
+
if (!selector)
|
|
3179
|
+
return false;
|
|
3180
|
+
if (selector.universal)
|
|
3181
|
+
return true;
|
|
3182
|
+
return (((_a = selector.and) !== null && _a !== void 0 ? _a : []).some(hasUniversalSelector) ||
|
|
3183
|
+
((_b = selector.or) !== null && _b !== void 0 ? _b : []).some(hasUniversalSelector));
|
|
3184
|
+
}
|
|
3185
|
+
function isWaitingAfterMiss(metricId, url, now) {
|
|
3186
|
+
const miss = missedUntil.get(metricId);
|
|
3187
|
+
return !!miss && miss.url === url && now < miss.nextAt;
|
|
3188
|
+
}
|
|
3189
|
+
let retryTimer = null;
|
|
3190
|
+
let retryAt = Infinity;
|
|
3191
|
+
function scheduleRetry(at, now, rebind) {
|
|
3192
|
+
if (retryTimer && at >= retryAt)
|
|
3193
|
+
return;
|
|
3194
|
+
if (retryTimer)
|
|
3195
|
+
clearTimeout(retryTimer);
|
|
3196
|
+
retryAt = at;
|
|
3197
|
+
retryTimer = setTimeout(() => {
|
|
3198
|
+
retryTimer = null;
|
|
3199
|
+
retryAt = Infinity;
|
|
3200
|
+
rebind();
|
|
3201
|
+
}, Math.max(0, at - now));
|
|
3202
|
+
}
|
|
3203
|
+
function recordMiss(metricId, url, now) {
|
|
3204
|
+
const prev = missedUntil.get(metricId);
|
|
3205
|
+
const misses = prev && prev.url === url ? prev.misses + 1 : 1;
|
|
3206
|
+
const wait = Math.min(FIRST_RETRY_WAIT_MS * RETRY_WAIT_FACTOR ** (misses - 1), MAX_RETRY_WAIT_MS);
|
|
3207
|
+
missedUntil.set(metricId, { url, misses, nextAt: now + wait });
|
|
3208
|
+
}
|
|
3134
3209
|
function rebindMetrics(coframe, logger, metrics, nonce) {
|
|
3135
3210
|
var _a, _b;
|
|
3136
3211
|
if (!metrics || metrics.length === 0) {
|
|
@@ -3174,6 +3249,9 @@ function rebindMetrics(coframe, logger, metrics, nonce) {
|
|
|
3174
3249
|
for (let i = 0; i < elementsToClean.length; i++) {
|
|
3175
3250
|
elementsToClean[i].removeAttribute('coframe-metric-ids');
|
|
3176
3251
|
}
|
|
3252
|
+
const currentUrl = getCurrentPageUrl();
|
|
3253
|
+
const now = Date.now();
|
|
3254
|
+
let earliestRetry = Infinity;
|
|
3177
3255
|
for (let i = 0; i < metrics.length; i++) {
|
|
3178
3256
|
const metric = metrics[i];
|
|
3179
3257
|
if (metric.js_binder) {
|
|
@@ -3190,11 +3268,23 @@ function rebindMetrics(coframe, logger, metrics, nonce) {
|
|
|
3190
3268
|
continue;
|
|
3191
3269
|
}
|
|
3192
3270
|
if (metric.selector) {
|
|
3271
|
+
const expensive = hasUniversalSelector(metric.selector);
|
|
3272
|
+
if (expensive && isWaitingAfterMiss(metric.id, currentUrl, now)) {
|
|
3273
|
+
const miss = missedUntil.get(metric.id);
|
|
3274
|
+
if (miss && miss.nextAt < earliestRetry)
|
|
3275
|
+
earliestRetry = miss.nextAt;
|
|
3276
|
+
continue;
|
|
3277
|
+
}
|
|
3193
3278
|
const elements = (_b = querySelector({
|
|
3194
3279
|
selector: metric.selector,
|
|
3195
|
-
currentUrl
|
|
3280
|
+
currentUrl,
|
|
3196
3281
|
isQueryingAll: true,
|
|
3197
3282
|
})) !== null && _b !== void 0 ? _b : [];
|
|
3283
|
+
if (!expensive) ;
|
|
3284
|
+
else if (elements.length === 0)
|
|
3285
|
+
recordMiss(metric.id, currentUrl, now);
|
|
3286
|
+
else
|
|
3287
|
+
missedUntil.delete(metric.id);
|
|
3198
3288
|
for (let j = 0; j < elements.length; j++) {
|
|
3199
3289
|
const e = elements[j];
|
|
3200
3290
|
const metricIdsStr = e.getAttribute('coframe-metric-ids');
|
|
@@ -3209,6 +3299,9 @@ function rebindMetrics(coframe, logger, metrics, nonce) {
|
|
|
3209
3299
|
}
|
|
3210
3300
|
}
|
|
3211
3301
|
}
|
|
3302
|
+
if (earliestRetry < Infinity) {
|
|
3303
|
+
scheduleRetry(earliestRetry, now, () => rebindMetrics(coframe, logger, metrics, nonce));
|
|
3304
|
+
}
|
|
3212
3305
|
}
|
|
3213
3306
|
|
|
3214
3307
|
let lastUrl = null;
|
|
@@ -3237,6 +3330,42 @@ function observeUrlChanges(baseUrlMatch, onUrlChange) {
|
|
|
3237
3330
|
patchHistoryMethod('replaceState');
|
|
3238
3331
|
}
|
|
3239
3332
|
|
|
3333
|
+
function mergeClientHeaders(client, server) {
|
|
3334
|
+
if (server)
|
|
3335
|
+
return { ...client, ...server };
|
|
3336
|
+
return client && Object.keys(client).length > 0 ? { ...client } : null;
|
|
3337
|
+
}
|
|
3338
|
+
function getQueuedPersonalizationHeaders() {
|
|
3339
|
+
var _a, _b, _c;
|
|
3340
|
+
const topLevel = (_a = findLastCmd((c) => !!c.personalizationHeaders)) === null || _a === void 0 ? void 0 : _a.personalizationHeaders;
|
|
3341
|
+
const nested = (_c = (_b = findLastCmd((c) => !!c.projectData)) === null || _b === void 0 ? void 0 : _b.projectData) === null || _c === void 0 ? void 0 : _c.personalizationHeaders;
|
|
3342
|
+
return mergeClientHeaders(topLevel, nested);
|
|
3343
|
+
}
|
|
3344
|
+
async function resolveProject(Coframe, previewVariantId, isSessionVariant, config) {
|
|
3345
|
+
var _a, _b;
|
|
3346
|
+
const logger = Coframe.logger;
|
|
3347
|
+
const projectData = (_a = findLastCmd((c) => !!c.projectData)) === null || _a === void 0 ? void 0 : _a.projectData;
|
|
3348
|
+
const queuedHeaders = getQueuedPersonalizationHeaders();
|
|
3349
|
+
let personalizationHeaders = queuedHeaders;
|
|
3350
|
+
let project = isSessionVariant ? undefined : projectData === null || projectData === void 0 ? void 0 : projectData.project;
|
|
3351
|
+
if (!project) {
|
|
3352
|
+
const edgeResult = await fetchProject(config.projectUrl, Coframe.projectId, config.currentUrl || getCurrentPageUrl(), undefined, config.userContext, previewVariantId || undefined, undefined, (_b = config.referrer) !== null && _b !== void 0 ? _b : getBrowserReferrer());
|
|
3353
|
+
personalizationHeaders = mergeClientHeaders(queuedHeaders, edgeResult === null || edgeResult === void 0 ? void 0 : edgeResult.personalizationHeaders);
|
|
3354
|
+
project = (edgeResult === null || edgeResult === void 0 ? void 0 : edgeResult.project) || undefined;
|
|
3355
|
+
}
|
|
3356
|
+
if (!project) {
|
|
3357
|
+
logger.error('No Coframe Project Config', 'no_project_config', {
|
|
3358
|
+
previewVariantId,
|
|
3359
|
+
});
|
|
3360
|
+
variantRendered();
|
|
3361
|
+
return null;
|
|
3362
|
+
}
|
|
3363
|
+
return {
|
|
3364
|
+
project,
|
|
3365
|
+
personalizationHeaders: personalizationHeaders,
|
|
3366
|
+
};
|
|
3367
|
+
}
|
|
3368
|
+
|
|
3240
3369
|
const callbacks = [];
|
|
3241
3370
|
function onEventsFlushed(callback) {
|
|
3242
3371
|
callbacks.push(callback);
|
|
@@ -3669,6 +3798,7 @@ function setupSPANavigation(Coframe, project, config, previewVariantId, isSessio
|
|
|
3669
3798
|
if (cached) {
|
|
3670
3799
|
pageProject = cached.project;
|
|
3671
3800
|
pagePersonalizationHeaders = {
|
|
3801
|
+
...getQueuedPersonalizationHeaders(),
|
|
3672
3802
|
...cached.personalizationHeaders,
|
|
3673
3803
|
'x-visit-url': newPageUrl,
|
|
3674
3804
|
};
|
|
@@ -3681,7 +3811,10 @@ function setupSPANavigation(Coframe, project, config, previewVariantId, isSessio
|
|
|
3681
3811
|
return;
|
|
3682
3812
|
if (result) {
|
|
3683
3813
|
pageProject = result.project;
|
|
3684
|
-
pagePersonalizationHeaders =
|
|
3814
|
+
pagePersonalizationHeaders = {
|
|
3815
|
+
...getQueuedPersonalizationHeaders(),
|
|
3816
|
+
...result.personalizationHeaders,
|
|
3817
|
+
};
|
|
3685
3818
|
cacheFrames(newPageUrl, result);
|
|
3686
3819
|
}
|
|
3687
3820
|
}
|
|
@@ -4115,30 +4248,6 @@ async function resolveIdentity(config, Coframe, timeoutMs, gracefulExit, preview
|
|
|
4115
4248
|
return { userToken, applyCookieConsent, onConsentChange };
|
|
4116
4249
|
}
|
|
4117
4250
|
|
|
4118
|
-
async function resolveProject(Coframe, previewVariantId, isSessionVariant, config) {
|
|
4119
|
-
var _a, _b;
|
|
4120
|
-
const logger = Coframe.logger;
|
|
4121
|
-
const projectData = (_a = findLastCmd((c) => !!c.projectData)) === null || _a === void 0 ? void 0 : _a.projectData;
|
|
4122
|
-
let personalizationHeaders = (projectData === null || projectData === void 0 ? void 0 : projectData.personalizationHeaders) || null;
|
|
4123
|
-
let project = isSessionVariant ? undefined : projectData === null || projectData === void 0 ? void 0 : projectData.project;
|
|
4124
|
-
if (!project) {
|
|
4125
|
-
const edgeResult = await fetchProject(config.projectUrl, Coframe.projectId, config.currentUrl || getCurrentPageUrl(), undefined, config.userContext, previewVariantId || undefined, undefined, (_b = config.referrer) !== null && _b !== void 0 ? _b : getBrowserReferrer());
|
|
4126
|
-
personalizationHeaders = (edgeResult === null || edgeResult === void 0 ? void 0 : edgeResult.personalizationHeaders) || null;
|
|
4127
|
-
project = (edgeResult === null || edgeResult === void 0 ? void 0 : edgeResult.project) || undefined;
|
|
4128
|
-
}
|
|
4129
|
-
if (!project) {
|
|
4130
|
-
logger.error('No Coframe Project Config', 'no_project_config', {
|
|
4131
|
-
previewVariantId,
|
|
4132
|
-
});
|
|
4133
|
-
variantRendered();
|
|
4134
|
-
return null;
|
|
4135
|
-
}
|
|
4136
|
-
return {
|
|
4137
|
-
project,
|
|
4138
|
-
personalizationHeaders: personalizationHeaders,
|
|
4139
|
-
};
|
|
4140
|
-
}
|
|
4141
|
-
|
|
4142
4251
|
const COFRAME_LAUNCHER_PROTOCOL_VERSION = 1;
|
|
4143
4252
|
|
|
4144
4253
|
const LAUNCHER_SCRIPT_ID = 'coframe-tools-launcher-script';
|
|
@@ -4203,6 +4312,10 @@ function injectOptions(options) {
|
|
|
4203
4312
|
window.CFQ = window.CFQ || [];
|
|
4204
4313
|
window.CFQ.push({ config: options.config });
|
|
4205
4314
|
}
|
|
4315
|
+
if (options.personalizationHeaders) {
|
|
4316
|
+
window.CFQ = window.CFQ || [];
|
|
4317
|
+
window.CFQ.push({ personalizationHeaders: options.personalizationHeaders });
|
|
4318
|
+
}
|
|
4206
4319
|
if (options.projectData) {
|
|
4207
4320
|
window.CFQ = window.CFQ || [];
|
|
4208
4321
|
window.CFQ.push({
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@coframe/sdk",
|
|
3
|
-
"version": "1.1.
|
|
3
|
+
"version": "1.1.36",
|
|
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",
|