@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.
@@ -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 = tryPath(naivePaths[0]);
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 = tryPath(relativePath);
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 = tryPath(textPath);
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 = tryPath(modifiedPath);
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 = tryPath(textBasedPath);
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 = tryPath(partialPath);
707
+ element = tryPathAndCache(partialPath);
670
708
  if (element && !debug)
671
709
  return { element };
672
710
  }
673
711
  for (const partialPath of partialRelativePaths) {
674
- element = tryPath(partialPath);
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: getCurrentPageUrl(),
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 = result.personalizationHeaders;
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({
@@ -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 = tryPath(naivePaths[0]);
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 = tryPath(relativePath);
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 = tryPath(textPath);
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 = tryPath(modifiedPath);
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 = tryPath(textBasedPath);
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 = tryPath(partialPath);
705
+ element = tryPathAndCache(partialPath);
668
706
  if (element && !debug)
669
707
  return { element };
670
708
  }
671
709
  for (const partialPath of partialRelativePaths) {
672
- element = tryPath(partialPath);
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: getCurrentPageUrl(),
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 = result.personalizationHeaders;
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({
@@ -297,6 +297,7 @@ interface ProjectData {
297
297
  interface CoframeInitOptions {
298
298
  config?: CoframeConfig;
299
299
  projectData?: ProjectData;
300
+ personalizationHeaders?: Partial<PersonalizationHeaders>;
300
301
  }
301
302
  type LogPayload = {
302
303
  kind: 'warn' | 'error' | 'exception';
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@coframe/sdk",
3
- "version": "1.1.34",
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",