@coframe/sdk 1.1.56 → 1.1.60
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/README.md +34 -6
- package/dist/pkg/cf.cjs.js +290 -39
- package/dist/pkg/cf.esm.mjs +290 -39
- package/dist/pkg/server.cjs.js +52 -13
- package/dist/pkg/server.esm.mjs +52 -14
- package/dist/pkg/types/index.d.ts +1 -0
- package/dist/pkg/types/react.d.ts +1 -0
- package/dist/pkg/types/server.d.ts +8 -3
- package/package.json +12 -14
package/dist/pkg/cf.esm.mjs
CHANGED
|
@@ -478,6 +478,10 @@ const getSelectorWithoutCache = (element, options) => {
|
|
|
478
478
|
}
|
|
479
479
|
return null;
|
|
480
480
|
}
|
|
481
|
+
const ownId = (el) => {
|
|
482
|
+
const id = el.getAttribute('id');
|
|
483
|
+
return id && !isGeneratedIdentifier(id) ? id : undefined;
|
|
484
|
+
};
|
|
481
485
|
const getParentNode = (element) => {
|
|
482
486
|
return element.parentElement || getShadowHost(element);
|
|
483
487
|
};
|
|
@@ -485,7 +489,7 @@ const getSelectorWithoutCache = (element, options) => {
|
|
|
485
489
|
var _a;
|
|
486
490
|
const selector = {
|
|
487
491
|
t: el.tagName.toLowerCase(),
|
|
488
|
-
id: el
|
|
492
|
+
id: ownId(el),
|
|
489
493
|
text: getInnerText(el) || undefined,
|
|
490
494
|
href: el.getAttribute('href') || undefined,
|
|
491
495
|
dataTestId: el.getAttribute('data-test-id') || undefined,
|
|
@@ -570,12 +574,33 @@ const getElement = (selector, options) => {
|
|
|
570
574
|
return null;
|
|
571
575
|
};
|
|
572
576
|
const resolvedPathCache = new Map();
|
|
577
|
+
const isGeneratedIdentifier = (value) => {
|
|
578
|
+
const token = value.trim();
|
|
579
|
+
if (!token)
|
|
580
|
+
return false;
|
|
581
|
+
const frameworkId = /^(?::r[0-9a-z]+:|«r[0-9a-z]+»|radix-:?r?[0-9a-z]+:?.*|headlessui-[a-z-]+-:?r?[0-9a-z]+:?|react-aria\d+.*|mui-\d+|ember\d+)$/;
|
|
582
|
+
const cssInJsClass = /^(?:css-[0-9a-z]{5,}(?:-[A-Za-z0-9]+)?|sc-[A-Za-z]{5,}|jsx-\d{6,}|[A-Za-z][A-Za-z0-9]*_[A-Za-z0-9]+__[A-Za-z0-9_-]{5})$/;
|
|
583
|
+
if (frameworkId.test(token) || cssInJsClass.test(token))
|
|
584
|
+
return true;
|
|
585
|
+
return token.split(/[-_:.]+/).some((segment) => {
|
|
586
|
+
var _a, _b;
|
|
587
|
+
if (/^\d{8,}$/.test(segment))
|
|
588
|
+
return true;
|
|
589
|
+
if (/^[0-9a-f]{6,}$/.test(segment) &&
|
|
590
|
+
/\d/.test(segment) &&
|
|
591
|
+
/[a-f]/.test(segment))
|
|
592
|
+
return true;
|
|
593
|
+
return (/^[0-9a-zA-Z]{8,}$/.test(segment) &&
|
|
594
|
+
((_b = (_a = segment.match(/\d+|[a-zA-Z]+/g)) === null || _a === void 0 ? void 0 : _a.length) !== null && _b !== void 0 ? _b : 0) >= 5);
|
|
595
|
+
});
|
|
596
|
+
};
|
|
597
|
+
const stableId = (id) => id && !isGeneratedIdentifier(id) ? id : undefined;
|
|
573
598
|
const selectorKey = (selector) => selector.fingerprint || JSON.stringify(selector);
|
|
574
599
|
const keepsIdentity = (document, element, selector) => {
|
|
575
600
|
if (element.tagName.toLowerCase() !== selector.t.toLowerCase())
|
|
576
601
|
return false;
|
|
577
602
|
const attrs = [
|
|
578
|
-
['id', selector.id],
|
|
603
|
+
['id', stableId(selector.id)],
|
|
579
604
|
['data-test-id', selector.dataTestId],
|
|
580
605
|
['aria-label', selector.ariaLabel],
|
|
581
606
|
];
|
|
@@ -841,7 +866,7 @@ const generateRelativePaths = (sel, max) => {
|
|
|
841
866
|
const uniqueQueries = [];
|
|
842
867
|
const nonUniqQueries = [];
|
|
843
868
|
const newWipPaths = [];
|
|
844
|
-
if (currentSel.id) {
|
|
869
|
+
if (currentSel.id && !isGeneratedIdentifier(currentSel.id)) {
|
|
845
870
|
uniqueQueries.push({
|
|
846
871
|
xpath: `[@id="${currentSel.id}"]`,
|
|
847
872
|
css: `#${currentSel.id}`,
|
|
@@ -1636,6 +1661,60 @@ const executeTags = (tags, logger, nonce) => {
|
|
|
1636
1661
|
}
|
|
1637
1662
|
};
|
|
1638
1663
|
|
|
1664
|
+
function isRecord(value) {
|
|
1665
|
+
return !!value && typeof value === 'object' && !Array.isArray(value);
|
|
1666
|
+
}
|
|
1667
|
+
|
|
1668
|
+
const SCOPED = new Set(['update', 'delete', 'insert_into', 'insert_by']);
|
|
1669
|
+
const ADDED = new Set(['add_modal', 'add_banner']);
|
|
1670
|
+
function safeSelector(css) {
|
|
1671
|
+
return css.trim() !== '' && !/[<{}]/.test(css) && !css.includes('/*');
|
|
1672
|
+
}
|
|
1673
|
+
function modificationScope(modifications, elements) {
|
|
1674
|
+
const selectors = [];
|
|
1675
|
+
if (!isRecord(modifications) || !isRecord(elements))
|
|
1676
|
+
return { kind: 'page', reason: 'invalid_variant' };
|
|
1677
|
+
for (const [id, changes] of Object.entries(modifications)) {
|
|
1678
|
+
if (!Array.isArray(changes))
|
|
1679
|
+
return { kind: 'page', reason: 'invalid_variant' };
|
|
1680
|
+
let scoped = false;
|
|
1681
|
+
for (const change of changes) {
|
|
1682
|
+
const type = isRecord(change) ? change.type : undefined;
|
|
1683
|
+
if (typeof type === 'string' && SCOPED.has(type))
|
|
1684
|
+
scoped = true;
|
|
1685
|
+
else if (type === 'execute_js' &&
|
|
1686
|
+
isRecord(change) &&
|
|
1687
|
+
change.css !== undefined) {
|
|
1688
|
+
const { css: list } = change;
|
|
1689
|
+
const declared = Array.isArray(list) ? list : [list];
|
|
1690
|
+
if (declared.length === 0)
|
|
1691
|
+
return { kind: 'page', reason: `unscoped_change:${type}` };
|
|
1692
|
+
for (const css of declared) {
|
|
1693
|
+
if (typeof css !== 'string' || !safeSelector(css))
|
|
1694
|
+
return { kind: 'page', reason: `unscoped_selector:${id}` };
|
|
1695
|
+
selectors.push(css.trim());
|
|
1696
|
+
}
|
|
1697
|
+
}
|
|
1698
|
+
else if (typeof type !== 'string' || !ADDED.has(type))
|
|
1699
|
+
return { kind: 'page', reason: `unscoped_change:${String(type)}` };
|
|
1700
|
+
}
|
|
1701
|
+
if (!scoped)
|
|
1702
|
+
continue;
|
|
1703
|
+
const conditions = elements[id];
|
|
1704
|
+
if (!Array.isArray(conditions) || conditions.length === 0)
|
|
1705
|
+
return { kind: 'page', reason: 'invalid_variant' };
|
|
1706
|
+
const css = [];
|
|
1707
|
+
for (const condition of conditions) {
|
|
1708
|
+
const value = isRecord(condition) ? condition.css : undefined;
|
|
1709
|
+
if (typeof value !== 'string' || !safeSelector(value))
|
|
1710
|
+
return { kind: 'page', reason: `unscoped_selector:${id}` };
|
|
1711
|
+
css.push(value.trim());
|
|
1712
|
+
}
|
|
1713
|
+
selectors.push(css.join(', '));
|
|
1714
|
+
}
|
|
1715
|
+
return selectors.length ? { kind: 'elements', selectors } : { kind: 'none' };
|
|
1716
|
+
}
|
|
1717
|
+
|
|
1639
1718
|
function getLogCallback() {
|
|
1640
1719
|
const queue = window.CFQ;
|
|
1641
1720
|
if (!queue) {
|
|
@@ -1947,6 +2026,75 @@ function subscribeToCmd(predicate, callback, queueName = QueueName.CFQ) {
|
|
|
1947
2026
|
return __addListener(predicate, callback, queueName);
|
|
1948
2027
|
}
|
|
1949
2028
|
|
|
2029
|
+
function scopeOwners(variants, selectors) {
|
|
2030
|
+
const matches = new Map();
|
|
2031
|
+
const select = (css) => {
|
|
2032
|
+
if (!matches.has(css)) {
|
|
2033
|
+
try {
|
|
2034
|
+
matches.set(css, document.querySelectorAll(css));
|
|
2035
|
+
}
|
|
2036
|
+
catch (_a) {
|
|
2037
|
+
matches.set(css, null);
|
|
2038
|
+
}
|
|
2039
|
+
}
|
|
2040
|
+
return matches.get(css);
|
|
2041
|
+
};
|
|
2042
|
+
const overlaps = (hidden, changed) => {
|
|
2043
|
+
if (hidden === changed)
|
|
2044
|
+
return true;
|
|
2045
|
+
const left = select(hidden);
|
|
2046
|
+
const right = select(changed);
|
|
2047
|
+
if (!(left === null || left === void 0 ? void 0 : left.length) || !(right === null || right === void 0 ? void 0 : right.length))
|
|
2048
|
+
return true;
|
|
2049
|
+
for (let i = 0; i < left.length; i++) {
|
|
2050
|
+
for (let j = 0; j < right.length; j++) {
|
|
2051
|
+
if (left[i].contains(right[j]) || right[j].contains(left[i]))
|
|
2052
|
+
return true;
|
|
2053
|
+
}
|
|
2054
|
+
}
|
|
2055
|
+
return false;
|
|
2056
|
+
};
|
|
2057
|
+
const scopes = variants.map(({ variant, elements }) => modificationScope(variant.modifications, elements));
|
|
2058
|
+
return selectors.map((selector) => {
|
|
2059
|
+
const owners = [];
|
|
2060
|
+
scopes.forEach((scope, index) => {
|
|
2061
|
+
if (scope.kind === 'page' ||
|
|
2062
|
+
(scope.kind === 'elements' &&
|
|
2063
|
+
scope.selectors.some((changed) => overlaps(selector, changed)))) {
|
|
2064
|
+
owners.push(index);
|
|
2065
|
+
}
|
|
2066
|
+
});
|
|
2067
|
+
return owners;
|
|
2068
|
+
});
|
|
2069
|
+
}
|
|
2070
|
+
function beginProxyBatch(variants) {
|
|
2071
|
+
const request = findLastCmd((cmd) => cmd.proxyReveal === true);
|
|
2072
|
+
if (!request)
|
|
2073
|
+
return undefined;
|
|
2074
|
+
const queue = ensureQueueExists();
|
|
2075
|
+
const batchId = queue.length + 1;
|
|
2076
|
+
const keys = variants.map(({ variant }, index) => JSON.stringify([variant.experiment_id, variant.id, index]));
|
|
2077
|
+
const owners = request.proxySelectors
|
|
2078
|
+
? scopeOwners(variants, request.proxySelectors)
|
|
2079
|
+
: undefined;
|
|
2080
|
+
queue.push({ proxyBatch: { batchId, keys, ...(owners ? { owners } : {}) } });
|
|
2081
|
+
return (index) => {
|
|
2082
|
+
let completed = false;
|
|
2083
|
+
const complete = (() => {
|
|
2084
|
+
if (completed)
|
|
2085
|
+
return;
|
|
2086
|
+
completed = true;
|
|
2087
|
+
queue.push({ proxyVariantRendered: { batchId, key: keys[index] } });
|
|
2088
|
+
});
|
|
2089
|
+
complete.silent = () => {
|
|
2090
|
+
if (completed)
|
|
2091
|
+
return;
|
|
2092
|
+
queue.push({ proxyVariantSilent: { batchId, key: keys[index] } });
|
|
2093
|
+
};
|
|
2094
|
+
return complete;
|
|
2095
|
+
};
|
|
2096
|
+
}
|
|
2097
|
+
|
|
1950
2098
|
function describeError(error) {
|
|
1951
2099
|
if (error && (typeof error === 'object' || typeof error === 'function')) {
|
|
1952
2100
|
const stack = readString(() => error.stack);
|
|
@@ -2085,13 +2233,15 @@ function variantRendered() {
|
|
|
2085
2233
|
const queue = ensureQueueExists();
|
|
2086
2234
|
queue.push({
|
|
2087
2235
|
emit: 'variantRendered',
|
|
2236
|
+
sdkVariantRendered: true,
|
|
2088
2237
|
});
|
|
2089
2238
|
}
|
|
2239
|
+
const SIGNALS_COMPLETION = /variantRendered|variantSession/;
|
|
2090
2240
|
function hasJavascriptModification(variantElements) {
|
|
2091
2241
|
const modifications = variantElements.variant.modifications || {};
|
|
2092
2242
|
return Object.keys(modifications).some((elementId) => (modifications[elementId] || []).some((modification) => modification.type === 'execute_js'));
|
|
2093
2243
|
}
|
|
2094
|
-
const applyVariantChanges = (variantElements, currentUrl, logger, nonce, lifecycleContext) => {
|
|
2244
|
+
const applyVariantChanges = (variantElements, currentUrl, logger, nonce, lifecycleContext, proxyComplete) => {
|
|
2095
2245
|
var _a;
|
|
2096
2246
|
const { variant, elements } = variantElements;
|
|
2097
2247
|
const variantMetadata = {
|
|
@@ -2099,6 +2249,35 @@ const applyVariantChanges = (variantElements, currentUrl, logger, nonce, lifecyc
|
|
|
2099
2249
|
experiment_id: variant.experiment_id,
|
|
2100
2250
|
};
|
|
2101
2251
|
setApplyVariantChangesStarted(true);
|
|
2252
|
+
const javascriptPending = [];
|
|
2253
|
+
const javascriptSilent = [];
|
|
2254
|
+
let applying = true;
|
|
2255
|
+
const maybeComplete = () => {
|
|
2256
|
+
if (applying)
|
|
2257
|
+
return;
|
|
2258
|
+
if (javascriptPending.every((pending) => !pending))
|
|
2259
|
+
proxyComplete === null || proxyComplete === void 0 ? void 0 : proxyComplete();
|
|
2260
|
+
else if (javascriptPending.every((pending, i) => !pending || javascriptSilent[i]))
|
|
2261
|
+
proxyComplete === null || proxyComplete === void 0 ? void 0 : proxyComplete.silent();
|
|
2262
|
+
};
|
|
2263
|
+
const scriptCompletion = () => {
|
|
2264
|
+
const index = javascriptPending.push(true) - 1;
|
|
2265
|
+
javascriptSilent.push(false);
|
|
2266
|
+
const complete = (() => {
|
|
2267
|
+
var _a;
|
|
2268
|
+
if (!javascriptPending[index])
|
|
2269
|
+
return;
|
|
2270
|
+
javascriptPending[index] = false;
|
|
2271
|
+
(_a = complete.settled) === null || _a === void 0 ? void 0 : _a.call(complete);
|
|
2272
|
+
complete.settled = undefined;
|
|
2273
|
+
maybeComplete();
|
|
2274
|
+
});
|
|
2275
|
+
complete.silent = () => {
|
|
2276
|
+
if (javascriptPending[index])
|
|
2277
|
+
javascriptSilent[index] = true;
|
|
2278
|
+
};
|
|
2279
|
+
return complete;
|
|
2280
|
+
};
|
|
2102
2281
|
const session = lifecycleContext && hasJavascriptModification(variantElements)
|
|
2103
2282
|
? lifecycleContext.runtime.createVariantSession({
|
|
2104
2283
|
batchId: lifecycleContext.batchId,
|
|
@@ -2109,6 +2288,7 @@ const applyVariantChanges = (variantElements, currentUrl, logger, nonce, lifecyc
|
|
|
2109
2288
|
if (!variant.modifications ||
|
|
2110
2289
|
Object.keys(variant.modifications).length === 0) {
|
|
2111
2290
|
variantRendered();
|
|
2291
|
+
proxyComplete === null || proxyComplete === void 0 ? void 0 : proxyComplete();
|
|
2112
2292
|
return true;
|
|
2113
2293
|
}
|
|
2114
2294
|
for (const elementId of Object.keys(variant.modifications)) {
|
|
@@ -2132,7 +2312,7 @@ const applyVariantChanges = (variantElements, currentUrl, logger, nonce, lifecyc
|
|
|
2132
2312
|
}
|
|
2133
2313
|
continue;
|
|
2134
2314
|
}
|
|
2135
|
-
const edited = editElement(selectedElement, variant.modifications, elementId, logger, nonce, variantMetadata, session === null || session === void 0 ? void 0 : session.facade);
|
|
2315
|
+
const edited = editElement(selectedElement, variant.modifications, elementId, logger, nonce, variantMetadata, session === null || session === void 0 ? void 0 : session.facade, proxyComplete ? scriptCompletion : undefined);
|
|
2136
2316
|
if (!edited) {
|
|
2137
2317
|
logger.error('element not edited', 'element_not_edited', {
|
|
2138
2318
|
...variantMetadata,
|
|
@@ -2150,6 +2330,8 @@ const applyVariantChanges = (variantElements, currentUrl, logger, nonce, lifecyc
|
|
|
2150
2330
|
}
|
|
2151
2331
|
}
|
|
2152
2332
|
}
|
|
2333
|
+
applying = false;
|
|
2334
|
+
maybeComplete();
|
|
2153
2335
|
return true;
|
|
2154
2336
|
};
|
|
2155
2337
|
function describeElement(element) {
|
|
@@ -2161,7 +2343,7 @@ function describeElement(element) {
|
|
|
2161
2343
|
const className = target.getAttribute('class');
|
|
2162
2344
|
return `<${String(target.tagName).toLowerCase()}${id ? ` id=${JSON.stringify(id)}` : ''}${className ? ` class=${JSON.stringify(className)}` : ''}>`.slice(0, 200);
|
|
2163
2345
|
}
|
|
2164
|
-
const editElement = (element, modifications, elementId, logger, nonce, logMetadata = {}, variantSession) => {
|
|
2346
|
+
const editElement = (element, modifications, elementId, logger, nonce, logMetadata = {}, variantSession, scriptCompletion) => {
|
|
2165
2347
|
if (!modifications[elementId]) {
|
|
2166
2348
|
logger.warn('no modifications for element', 'no_modifications_for_element', {
|
|
2167
2349
|
...logMetadata,
|
|
@@ -2172,13 +2354,37 @@ const editElement = (element, modifications, elementId, logger, nonce, logMetada
|
|
|
2172
2354
|
}
|
|
2173
2355
|
for (const content of modifications[elementId]) {
|
|
2174
2356
|
switch (content.type) {
|
|
2175
|
-
case 'execute_js':
|
|
2176
|
-
|
|
2177
|
-
|
|
2357
|
+
case 'execute_js': {
|
|
2358
|
+
const complete = scriptCompletion === null || scriptCompletion === void 0 ? void 0 : scriptCompletion();
|
|
2359
|
+
const session = variantSession && complete
|
|
2360
|
+
? {
|
|
2361
|
+
...variantSession,
|
|
2362
|
+
complete() {
|
|
2363
|
+
variantSession.complete();
|
|
2364
|
+
complete();
|
|
2365
|
+
},
|
|
2366
|
+
error(error) {
|
|
2367
|
+
variantSession.error(error);
|
|
2368
|
+
complete();
|
|
2369
|
+
},
|
|
2370
|
+
}
|
|
2371
|
+
: variantSession;
|
|
2372
|
+
const stop = complete &&
|
|
2373
|
+
subscribeToCmd((cmd) => !cmd.sdkVariantRendered &&
|
|
2374
|
+
(cmd.variantRendered === true || cmd.emit === 'variantRendered'), () => complete());
|
|
2375
|
+
if (complete && stop)
|
|
2376
|
+
complete.settled = stop;
|
|
2377
|
+
const applied = applyJavascriptModification(element, content, logger, nonce, logMetadata, session ? { variantSession: session } : undefined);
|
|
2378
|
+
if (!applied)
|
|
2379
|
+
complete === null || complete === void 0 ? void 0 : complete();
|
|
2380
|
+
if (applied && complete && !SIGNALS_COMPLETION.test(content.js))
|
|
2381
|
+
complete.silent();
|
|
2382
|
+
if (!applied && variantSession) {
|
|
2178
2383
|
variantSession.error(new Error('JavaScript variant modification did not run'));
|
|
2179
2384
|
return false;
|
|
2180
2385
|
}
|
|
2181
2386
|
break;
|
|
2387
|
+
}
|
|
2182
2388
|
case 'update':
|
|
2183
2389
|
applyUpdateModification(element, content, logger, logMetadata);
|
|
2184
2390
|
variantRendered();
|
|
@@ -2237,13 +2443,14 @@ function revealPage() {
|
|
|
2237
2443
|
async function replaceVariants(variants, orgId, logger, nonce, runtime) {
|
|
2238
2444
|
const failedReplacements = [];
|
|
2239
2445
|
let currentVariant;
|
|
2446
|
+
const proxyCompletion = beginProxyBatch(variants);
|
|
2240
2447
|
const batch = runtime === null || runtime === void 0 ? void 0 : runtime.beginBatch({
|
|
2241
2448
|
expectedSessionCount: variants.filter(hasJavascriptModification).length,
|
|
2242
2449
|
});
|
|
2243
2450
|
try {
|
|
2244
|
-
for (const v of variants) {
|
|
2451
|
+
for (const [index, v] of variants.entries()) {
|
|
2245
2452
|
currentVariant = v.variant;
|
|
2246
|
-
if (!applyVariantChanges(v, getCurrentPageUrl(), logger, nonce, batch && runtime ? { runtime, batchId: batch.batchId } : undefined)) {
|
|
2453
|
+
if (!applyVariantChanges(v, getCurrentPageUrl(), logger, nonce, batch && runtime ? { runtime, batchId: batch.batchId } : undefined, proxyCompletion === null || proxyCompletion === void 0 ? void 0 : proxyCompletion(index))) {
|
|
2247
2454
|
failedReplacements.push({
|
|
2248
2455
|
message: 'Original element not found',
|
|
2249
2456
|
metadata: {
|
|
@@ -2504,6 +2711,7 @@ function isElementVisible(el) {
|
|
|
2504
2711
|
}
|
|
2505
2712
|
const VALUE_UNKNOWN_YET = 'n/a';
|
|
2506
2713
|
function checkActivationCondition(condition, personalizationHeaders, currentUrl, languages, browserPlatform, userToken, userVisitCount, runJsFunction, logger, options) {
|
|
2714
|
+
var _a;
|
|
2507
2715
|
if (condition.and) {
|
|
2508
2716
|
const results = condition.and.map((c) => checkActivationCondition(c, personalizationHeaders, currentUrl, languages, browserPlatform, userToken, userVisitCount, runJsFunction, logger));
|
|
2509
2717
|
const hasUnknown = results.some((r) => r === VALUE_UNKNOWN_YET);
|
|
@@ -2610,12 +2818,13 @@ function checkActivationCondition(condition, personalizationHeaders, currentUrl,
|
|
|
2610
2818
|
}
|
|
2611
2819
|
}
|
|
2612
2820
|
}
|
|
2613
|
-
if (condition.device) {
|
|
2614
|
-
|
|
2615
|
-
if (
|
|
2616
|
-
|
|
2821
|
+
if ((_a = condition.device) === null || _a === void 0 ? void 0 : _a.length) {
|
|
2822
|
+
let device = personalizationHeaders['x-device-type'];
|
|
2823
|
+
if (!['desktop', 'mobile', 'tablet'].includes(device)) {
|
|
2824
|
+
device =
|
|
2825
|
+
personalizationHeaders['x-is-mobile-viewer'] === 'true' ? 'mobile' : '';
|
|
2617
2826
|
}
|
|
2618
|
-
if (condition.device.includes(
|
|
2827
|
+
if (!condition.device.includes(device)) {
|
|
2619
2828
|
return false;
|
|
2620
2829
|
}
|
|
2621
2830
|
}
|
|
@@ -2794,8 +3003,7 @@ function checkAllAudiences(metadata, ctx) {
|
|
|
2794
3003
|
}
|
|
2795
3004
|
return result;
|
|
2796
3005
|
}
|
|
2797
|
-
function audiencesPass(
|
|
2798
|
-
const result = checkAllAudiences(metadata, ctx);
|
|
3006
|
+
function audiencesPass(result, ctx) {
|
|
2799
3007
|
return ctx.unknownIsInactive ? result === true : result !== false;
|
|
2800
3008
|
}
|
|
2801
3009
|
async function getVariantsAndElements(personalizationHeaders, project, previewVariantId, userToken, currentPageUrl, languages, browserPlatform, logger, nonce, laneClaims = {}, silentFallback = false, chooseCmabVariants, userVisitCountOverride, runtime = {}) {
|
|
@@ -2877,57 +3085,89 @@ async function getVariantsAndElements(personalizationHeaders, project, previewVa
|
|
|
2877
3085
|
experimentsInfo: [...experimentsInfo, ...assignment.experimentsInfo],
|
|
2878
3086
|
});
|
|
2879
3087
|
}
|
|
3088
|
+
function frameActivation(frame, ctx) {
|
|
3089
|
+
return checkActivationCondition(frame.activation_condition, ctx.personalizationHeaders, ctx.currentPageUrl, ctx.languages, ctx.browserPlatform, ctx.userToken, ctx.userVisitCount, ctx.runJsFunction, ctx.logger);
|
|
3090
|
+
}
|
|
2880
3091
|
function activateFrames(ctx) {
|
|
2881
3092
|
return ctx.project.frames.filter((frame) => {
|
|
2882
3093
|
if (!frame.experiments)
|
|
2883
3094
|
return false;
|
|
2884
|
-
const frameActivated =
|
|
3095
|
+
const frameActivated = frameActivation(frame, ctx);
|
|
2885
3096
|
return ctx.unknownIsInactive ? frameActivated === true : !!frameActivated;
|
|
2886
3097
|
});
|
|
2887
3098
|
}
|
|
3099
|
+
function undecidedFrames(ctx) {
|
|
3100
|
+
if (!ctx.unknownIsInactive)
|
|
3101
|
+
return [];
|
|
3102
|
+
return ctx.project.frames.filter((frame) => {
|
|
3103
|
+
if (!frame.experiments)
|
|
3104
|
+
return false;
|
|
3105
|
+
const activated = frameActivation(frame, ctx);
|
|
3106
|
+
return activated !== true && activated !== false;
|
|
3107
|
+
});
|
|
3108
|
+
}
|
|
2888
3109
|
async function assignFrames(activeFrames, validatedClaims, ctx, chooseCmabVariants) {
|
|
2889
|
-
var _a, _b, _c;
|
|
3110
|
+
var _a, _b, _c, _d;
|
|
2890
3111
|
const { project, userToken, logger } = ctx;
|
|
2891
3112
|
const experimentsInfo = [];
|
|
2892
3113
|
const variantsAndElements = [];
|
|
2893
|
-
const
|
|
3114
|
+
const audienceResult = new Map();
|
|
2894
3115
|
const reachableByLane = {};
|
|
3116
|
+
const undecidableLanes = new Set();
|
|
2895
3117
|
for (const frame of activeFrames) {
|
|
2896
3118
|
for (const experiment of (_a = frame.experiments) !== null && _a !== void 0 ? _a : []) {
|
|
2897
3119
|
const metadata = experiment.metadata;
|
|
2898
3120
|
const laneIds = experimentLaneIds(metadata);
|
|
2899
3121
|
if (laneIds.length === 0)
|
|
2900
3122
|
continue;
|
|
2901
|
-
const
|
|
2902
|
-
|
|
2903
|
-
if (
|
|
3123
|
+
const result = checkAllAudiences(metadata, ctx);
|
|
3124
|
+
audienceResult.set(metadata.experiment_id, result);
|
|
3125
|
+
if (audiencesPass(result, ctx)) {
|
|
2904
3126
|
for (const laneId of laneIds) {
|
|
2905
3127
|
if (!reachableByLane[laneId])
|
|
2906
3128
|
reachableByLane[laneId] = [];
|
|
2907
3129
|
reachableByLane[laneId].push(metadata.experiment_id);
|
|
2908
3130
|
}
|
|
2909
3131
|
}
|
|
3132
|
+
else if (ctx.unknownIsInactive && result !== false) {
|
|
3133
|
+
for (const laneId of laneIds)
|
|
3134
|
+
if (!validatedClaims[laneId])
|
|
3135
|
+
undecidableLanes.add(laneId);
|
|
3136
|
+
}
|
|
2910
3137
|
}
|
|
2911
3138
|
}
|
|
3139
|
+
for (const frame of undecidedFrames(ctx))
|
|
3140
|
+
for (const experiment of (_b = frame.experiments) !== null && _b !== void 0 ? _b : [])
|
|
3141
|
+
for (const laneId of experimentLaneIds(experiment.metadata))
|
|
3142
|
+
if (!validatedClaims[laneId])
|
|
3143
|
+
undecidableLanes.add(laneId);
|
|
2912
3144
|
const excludedExperimentIds = resolveLaneWinners(validatedClaims, reachableByLane, project.lanes, userToken);
|
|
2913
3145
|
const updatedClaims = { ...validatedClaims };
|
|
2914
3146
|
const assignmentEntries = [];
|
|
2915
3147
|
let hasActivatedFrames = false;
|
|
2916
3148
|
for (const frame of activeFrames) {
|
|
2917
3149
|
let atLeastOneExperimentWasActivated = false;
|
|
2918
|
-
for (const experiment of (
|
|
3150
|
+
for (const experiment of (_c = frame.experiments) !== null && _c !== void 0 ? _c : []) {
|
|
2919
3151
|
if (atLeastOneExperimentWasActivated)
|
|
2920
3152
|
break;
|
|
2921
3153
|
const metadata = experiment.metadata;
|
|
2922
3154
|
const variants = experiment.variants;
|
|
2923
3155
|
const elements = frame.elements;
|
|
3156
|
+
if (ctx.unknownIsInactive &&
|
|
3157
|
+
experimentLaneIds(metadata).some((id) => undecidableLanes.has(id))) {
|
|
3158
|
+
logger.warn('Leaving the frame to the browser: a lane member needs the page', 'undecidable_lane', { experiment_id: metadata.experiment_id });
|
|
3159
|
+
break;
|
|
3160
|
+
}
|
|
2924
3161
|
if (excludedExperimentIds.has(metadata.experiment_id))
|
|
2925
3162
|
continue;
|
|
2926
|
-
let
|
|
2927
|
-
if (
|
|
2928
|
-
|
|
3163
|
+
let result = audienceResult.get(metadata.experiment_id);
|
|
3164
|
+
if (result === undefined)
|
|
3165
|
+
result = checkAllAudiences(metadata, ctx);
|
|
3166
|
+
if (result !== true && result !== false && ctx.unknownIsInactive) {
|
|
3167
|
+
logger.warn('Leaving the frame to the browser: an audience needs the page', 'undecidable_audience', { experiment_id: metadata.experiment_id });
|
|
3168
|
+
break;
|
|
2929
3169
|
}
|
|
2930
|
-
if (!
|
|
3170
|
+
if (!audiencesPass(result, ctx))
|
|
2931
3171
|
continue;
|
|
2932
3172
|
atLeastOneExperimentWasActivated = true;
|
|
2933
3173
|
hasActivatedFrames = true;
|
|
@@ -2981,7 +3221,7 @@ async function assignFrames(activeFrames, validatedClaims, ctx, chooseCmabVarian
|
|
|
2981
3221
|
try {
|
|
2982
3222
|
mlVariantIds = await chooseCmabVariants(Array.from(cmabMetadataById.values()), userToken);
|
|
2983
3223
|
}
|
|
2984
|
-
catch (
|
|
3224
|
+
catch (_e) {
|
|
2985
3225
|
mlVariantIds = new Map();
|
|
2986
3226
|
}
|
|
2987
3227
|
}
|
|
@@ -2992,7 +3232,7 @@ async function assignFrames(activeFrames, validatedClaims, ctx, chooseCmabVarian
|
|
|
2992
3232
|
}
|
|
2993
3233
|
const { metadata, variants, elements } = entry;
|
|
2994
3234
|
let mlVariantId = metadata.type === 'CMAB'
|
|
2995
|
-
? ((
|
|
3235
|
+
? ((_d = mlVariantIds.get(metadata.experiment_id)) !== null && _d !== void 0 ? _d : null)
|
|
2996
3236
|
: null;
|
|
2997
3237
|
if (mlVariantId && !variants.some((v) => v.id === mlVariantId)) {
|
|
2998
3238
|
logger.warn(`CMAB variant ${mlVariantId} not in experiment ${metadata.experiment_id}`, 'cmab_variant_not_found', { experiment_id: metadata.experiment_id });
|
|
@@ -3535,7 +3775,7 @@ function shouldSdkWaitForHydration(config) {
|
|
|
3535
3775
|
!isVariantRuntimeLifecycleEnabled(config));
|
|
3536
3776
|
}
|
|
3537
3777
|
|
|
3538
|
-
function createRevealCoordinator(revealPage, reportError = () => { }) {
|
|
3778
|
+
function createRevealCoordinator(revealPage, reportError = () => { }, onForced = () => { }) {
|
|
3539
3779
|
const notify = (listener, reason) => {
|
|
3540
3780
|
try {
|
|
3541
3781
|
listener(reason);
|
|
@@ -3587,6 +3827,18 @@ function createRevealCoordinator(revealPage, reportError = () => { }) {
|
|
|
3587
3827
|
reveal(reason);
|
|
3588
3828
|
},
|
|
3589
3829
|
forceReveal(reason) {
|
|
3830
|
+
if (pageRevealed)
|
|
3831
|
+
return;
|
|
3832
|
+
try {
|
|
3833
|
+
onForced(reason);
|
|
3834
|
+
}
|
|
3835
|
+
catch (error) {
|
|
3836
|
+
try {
|
|
3837
|
+
reportError(error);
|
|
3838
|
+
}
|
|
3839
|
+
catch (_a) {
|
|
3840
|
+
}
|
|
3841
|
+
}
|
|
3590
3842
|
reveal(reason);
|
|
3591
3843
|
},
|
|
3592
3844
|
block(batchId) {
|
|
@@ -3774,10 +4026,6 @@ function notifyEventsFlushed() {
|
|
|
3774
4026
|
}
|
|
3775
4027
|
}
|
|
3776
4028
|
|
|
3777
|
-
function isRecord(value) {
|
|
3778
|
-
return !!value && typeof value === 'object' && !Array.isArray(value);
|
|
3779
|
-
}
|
|
3780
|
-
|
|
3781
4029
|
const OPT_IN_COUNTRIES = new Set(('AT BE BG HR CY CZ DK EE FI FR DE GR HU IE IT LV LT LU MT NL PL PT RO SK SI ES SE ' +
|
|
3782
4030
|
'AX GF GP MF MQ RE YT ' +
|
|
3783
4031
|
'IS LI NO ' +
|
|
@@ -4981,6 +5229,7 @@ function createApplyVariants(Coframe, config, previewVariantId, isSessionVariant
|
|
|
4981
5229
|
Coframe.debug.laneClaims = laneClaims;
|
|
4982
5230
|
}
|
|
4983
5231
|
if (config.trackingOnly) {
|
|
5232
|
+
beginProxyBatch([]);
|
|
4984
5233
|
variantRendered();
|
|
4985
5234
|
}
|
|
4986
5235
|
else {
|
|
@@ -5003,7 +5252,7 @@ async function modifyPage(Coframe, configResult, projectResult, analytics, lifec
|
|
|
5003
5252
|
var _a;
|
|
5004
5253
|
const { config, timeoutMs, previewVariantId, isSessionVariant, integrationStartTime, executionStartTime, } = configResult;
|
|
5005
5254
|
const { project: cdnProject, personalizationHeaders, assignmentContext, } = projectResult;
|
|
5006
|
-
const revealCoordinator = (_a = lifecycle === null || lifecycle === void 0 ? void 0 : lifecycle.revealCoordinator) !== null && _a !== void 0 ? _a : createRevealCoordinator(revealPage, logRevealListenerError(() => Coframe.logger));
|
|
5255
|
+
const revealCoordinator = (_a = lifecycle === null || lifecycle === void 0 ? void 0 : lifecycle.revealCoordinator) !== null && _a !== void 0 ? _a : createRevealCoordinator(revealPage, logRevealListenerError(() => Coframe.logger), () => beginProxyBatch([]));
|
|
5007
5256
|
const runtime = lifecycle === null || lifecycle === void 0 ? void 0 : lifecycle.runtime;
|
|
5008
5257
|
if (runtime && config.waitForHydration) {
|
|
5009
5258
|
if (findLastCmd(isPageHydratedCmd)) {
|
|
@@ -5370,6 +5619,7 @@ async function resolveConfig(Coframe, revealActions) {
|
|
|
5370
5619
|
}
|
|
5371
5620
|
|
|
5372
5621
|
async function resolveIdentity(config, Coframe, timeoutMs, gracefulExit, previewVariantId) {
|
|
5622
|
+
var _a;
|
|
5373
5623
|
const logger = Coframe.logger;
|
|
5374
5624
|
let userToken;
|
|
5375
5625
|
if (config.waitForUserToken) {
|
|
@@ -5387,7 +5637,8 @@ async function resolveIdentity(config, Coframe, timeoutMs, gracefulExit, preview
|
|
|
5387
5637
|
}
|
|
5388
5638
|
}
|
|
5389
5639
|
else {
|
|
5390
|
-
|
|
5640
|
+
const proxied = (_a = findLastCmd((cmd) => typeof cmd.proxyUserToken === 'string' && !!cmd.proxyUserToken)) === null || _a === void 0 ? void 0 : _a.proxyUserToken;
|
|
5641
|
+
userToken = proxied || getOrGenerateUserToken();
|
|
5391
5642
|
}
|
|
5392
5643
|
Coframe.userToken = userToken;
|
|
5393
5644
|
const persistCookies = () => {
|
|
@@ -6380,7 +6631,7 @@ const Coframe = {
|
|
|
6380
6631
|
},
|
|
6381
6632
|
};
|
|
6382
6633
|
Coframe.logger = createLogger(() => Coframe);
|
|
6383
|
-
const revealCoordinator = createRevealCoordinator(revealPage, logRevealListenerError(() => Coframe.logger));
|
|
6634
|
+
const revealCoordinator = createRevealCoordinator(revealPage, logRevealListenerError(() => Coframe.logger), () => beginProxyBatch([]));
|
|
6384
6635
|
let activeRuntime = null;
|
|
6385
6636
|
function clearActiveRuntime() {
|
|
6386
6637
|
activeRuntime === null || activeRuntime === void 0 ? void 0 : activeRuntime.destroy();
|