@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.
@@ -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.getAttribute('id') || undefined,
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
- if (!applyJavascriptModification(element, content, logger, nonce, logMetadata, variantSession ? { variantSession } : undefined) &&
2177
- variantSession) {
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
- const isMobileDevice = personalizationHeaders['x-is-mobile-viewer'] === 'true';
2615
- if (condition.device.includes('mobile') && !isMobileDevice) {
2616
- return false;
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('desktop') && isMobileDevice) {
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(metadata, ctx) {
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 = checkActivationCondition(frame.activation_condition, ctx.personalizationHeaders, ctx.currentPageUrl, ctx.languages, ctx.browserPlatform, ctx.userToken, ctx.userVisitCount, ctx.runJsFunction, ctx.logger);
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 audiencePass = new Map();
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 passes = audiencesPass(metadata, ctx);
2902
- audiencePass.set(metadata.experiment_id, passes);
2903
- if (passes) {
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 (_b = frame.experiments) !== null && _b !== void 0 ? _b : []) {
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 activated = audiencePass.get(metadata.experiment_id);
2927
- if (activated === undefined) {
2928
- activated = audiencesPass(metadata, ctx);
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 (!activated)
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 (_d) {
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
- ? ((_c = mlVariantIds.get(metadata.experiment_id)) !== null && _c !== void 0 ? _c : null)
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
- userToken = getOrGenerateUserToken();
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();