@coframe/sdk 1.1.16 → 1.1.21
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 +28 -1
- package/dist/pkg/cf.cjs.js +237 -102
- package/dist/pkg/cf.esm.mjs +237 -102
- package/dist/pkg/types/index.d.ts +4 -0
- package/dist/pkg/types/react.d.ts +4 -0
- package/dist/pkg/types/server.d.ts +2 -0
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -40,13 +40,40 @@ await init({
|
|
|
40
40
|
|
|
41
41
|
`init()` accepts `config` and optional `projectData`, so npm consumers do not need to manually populate `window.CFQ` first.
|
|
42
42
|
|
|
43
|
+
### Runtime endpoint overrides
|
|
44
|
+
|
|
45
|
+
Private-CDN integrations can override the browser SDK's project and ingest
|
|
46
|
+
endpoints:
|
|
47
|
+
|
|
48
|
+
```ts
|
|
49
|
+
await init({
|
|
50
|
+
config: {
|
|
51
|
+
projectId: 'your-project-id',
|
|
52
|
+
projectUrl: 'https://cdn.example.com/coframe/project.json',
|
|
53
|
+
ingestUrl: 'https://www.example.com/ingest/v2',
|
|
54
|
+
enableDebug: false,
|
|
55
|
+
},
|
|
56
|
+
})
|
|
57
|
+
```
|
|
58
|
+
|
|
59
|
+
`projectUrl` must return a raw, complete `Project` JSON object. `ingestUrl`
|
|
60
|
+
replaces the ingest base URL (`https://ingest.app.coframe.com/ingest/v2`); the
|
|
61
|
+
SDK still appends the category and project path, so beacons go to
|
|
62
|
+
`<ingestUrl>/batched_events/<projectId>/`, `<ingestUrl>/batched_monitoring/<projectId>/`,
|
|
63
|
+
`<ingestUrl>/session_result/`, and `<ingestUrl>/identify/<projectId>/`. A proxy
|
|
64
|
+
only has to forward `<ingestUrl>/*` to `https://ingest.app.coframe.com/ingest/v2/*`
|
|
65
|
+
with the path unchanged. Both overrides are optional and retain the compiled
|
|
66
|
+
Coframe endpoints when omitted.
|
|
67
|
+
|
|
43
68
|
### URL controls
|
|
44
69
|
|
|
45
70
|
The npm entry uses the same browser URL controls as the script-tag and Edge
|
|
46
71
|
installations:
|
|
47
72
|
|
|
48
73
|
- `cf_disable` skips initialization and reveals any antiflicker state.
|
|
49
|
-
- `coframe_variant_id` previews one or more comma-separated variant IDs.
|
|
74
|
+
- `coframe_variant_id` previews one or more comma-separated variant IDs. Add
|
|
75
|
+
`rollouts` to the list to apply them on top of the rolled-out winners a
|
|
76
|
+
production visitor would get.
|
|
50
77
|
- `coframe_should_send_events=true` allows events during preview for testing.
|
|
51
78
|
|
|
52
79
|
Debug tools are allowed by default. Open the Launcher with `cf_preview=true` and
|
package/dist/pkg/cf.cjs.js
CHANGED
|
@@ -24,6 +24,19 @@ if (!Array.prototype.find) {
|
|
|
24
24
|
enumerable: false,
|
|
25
25
|
});
|
|
26
26
|
}
|
|
27
|
+
if (!Array.prototype.includes) {
|
|
28
|
+
Object.defineProperty(Array.prototype, 'includes', {
|
|
29
|
+
value: function (searchElement) {
|
|
30
|
+
if (this == null) {
|
|
31
|
+
throw new TypeError('Array.prototype.includes called on null or undefined');
|
|
32
|
+
}
|
|
33
|
+
return Array.prototype.indexOf.call(this, searchElement) !== -1;
|
|
34
|
+
},
|
|
35
|
+
writable: true,
|
|
36
|
+
configurable: true,
|
|
37
|
+
enumerable: false,
|
|
38
|
+
});
|
|
39
|
+
}
|
|
27
40
|
if (!Array.prototype.flatMap) {
|
|
28
41
|
Object.defineProperty(Array.prototype, 'flatMap', {
|
|
29
42
|
value: function (callback, thisArg) {
|
|
@@ -1070,6 +1083,17 @@ const SDK_VERSION = '2.7.0';
|
|
|
1070
1083
|
const queuedEvents = [];
|
|
1071
1084
|
const queuedMonitoringEvents = [];
|
|
1072
1085
|
const queuedSessions = [];
|
|
1086
|
+
let ingestUrl;
|
|
1087
|
+
const COMPILED_INGEST_BASE = "https://ingest.app.coframe.com/ingest/v2";
|
|
1088
|
+
function configureIngestUrl(url) {
|
|
1089
|
+
const trimmed = url === null || url === void 0 ? void 0 : url.trim().replace(/\/+$/, '');
|
|
1090
|
+
ingestUrl = trimmed || undefined;
|
|
1091
|
+
}
|
|
1092
|
+
function resolveIngestUrl(defaultUrl) {
|
|
1093
|
+
if (!ingestUrl || !defaultUrl.startsWith(COMPILED_INGEST_BASE))
|
|
1094
|
+
return defaultUrl;
|
|
1095
|
+
return ingestUrl + defaultUrl.slice(COMPILED_INGEST_BASE.length);
|
|
1096
|
+
}
|
|
1073
1097
|
const MAX_BEACON_BATCH_BYTES = 48 * 1024;
|
|
1074
1098
|
function getBeaconPayloadBytes(data) {
|
|
1075
1099
|
return new Blob([JSON.stringify(data)]).size;
|
|
@@ -1252,7 +1276,7 @@ function sendPageEngagementEvent(coframe, eventType, event, { projectId, session
|
|
|
1252
1276
|
}
|
|
1253
1277
|
}
|
|
1254
1278
|
function sendEventToBackend(projectId, data, eventCategory = 'events') {
|
|
1255
|
-
const eventsEndpoint = `${"https://ingest.app.coframe.com/ingest/v2"}/${eventCategory}/${projectId}
|
|
1279
|
+
const eventsEndpoint = resolveIngestUrl(`${"https://ingest.app.coframe.com/ingest/v2"}/${eventCategory}/${projectId}/`);
|
|
1256
1280
|
if (navigator.sendBeacon) {
|
|
1257
1281
|
const textData = JSON.stringify(data);
|
|
1258
1282
|
const blob = new Blob([textData], { type: 'text/plain' });
|
|
@@ -1265,7 +1289,7 @@ function sendEventToBackend(projectId, data, eventCategory = 'events') {
|
|
|
1265
1289
|
}
|
|
1266
1290
|
}
|
|
1267
1291
|
function createSession(data) {
|
|
1268
|
-
const sessionApiUrl = `${"https://ingest.app.coframe.com/ingest/v2"}/session_result
|
|
1292
|
+
const sessionApiUrl = resolveIngestUrl(`${"https://ingest.app.coframe.com/ingest/v2"}/session_result/`);
|
|
1269
1293
|
if (navigator.sendBeacon) {
|
|
1270
1294
|
const textData = JSON.stringify(data);
|
|
1271
1295
|
const blob = new Blob([textData], { type: 'text/plain' });
|
|
@@ -1305,6 +1329,26 @@ async function fetchProjectFromEdge(projectId, currentUrl, signal, userContext,
|
|
|
1305
1329
|
return null;
|
|
1306
1330
|
}
|
|
1307
1331
|
}
|
|
1332
|
+
async function fetchProject(projectUrl, projectId, currentUrl, signal, userContext, previewVariantId, headers, referrer) {
|
|
1333
|
+
if (!projectUrl) {
|
|
1334
|
+
return fetchProjectFromEdge(projectId, currentUrl, signal, userContext, previewVariantId, headers, referrer);
|
|
1335
|
+
}
|
|
1336
|
+
try {
|
|
1337
|
+
const response = await fetch(projectUrl, { headers, signal });
|
|
1338
|
+
if (!response.ok)
|
|
1339
|
+
return null;
|
|
1340
|
+
return {
|
|
1341
|
+
project: (await response.json()),
|
|
1342
|
+
personalizationHeaders: {},
|
|
1343
|
+
};
|
|
1344
|
+
}
|
|
1345
|
+
catch (error) {
|
|
1346
|
+
if (error instanceof DOMException && error.name === 'AbortError') {
|
|
1347
|
+
return null;
|
|
1348
|
+
}
|
|
1349
|
+
return null;
|
|
1350
|
+
}
|
|
1351
|
+
}
|
|
1308
1352
|
|
|
1309
1353
|
const isPageElement = (element) => {
|
|
1310
1354
|
return (element === document.body ||
|
|
@@ -2156,6 +2200,78 @@ function resolveLaneWinners(claims, reachableByLane, lanes, userToken) {
|
|
|
2156
2200
|
return excluded;
|
|
2157
2201
|
}
|
|
2158
2202
|
|
|
2203
|
+
var CoInspectorMessageType;
|
|
2204
|
+
(function (CoInspectorMessageType) {
|
|
2205
|
+
CoInspectorMessageType["onReady"] = "onReady";
|
|
2206
|
+
CoInspectorMessageType["onHoverElement"] = "onHoverElement";
|
|
2207
|
+
CoInspectorMessageType["onClickElement"] = "onClickElement";
|
|
2208
|
+
CoInspectorMessageType["onPageUrlChange"] = "onPageUrlChange";
|
|
2209
|
+
CoInspectorMessageType["onCreateNewElement"] = "onCreateNewElement";
|
|
2210
|
+
CoInspectorMessageType["onCancelNewElement"] = "onCancelNewElement";
|
|
2211
|
+
CoInspectorMessageType["onCopy"] = "onCopy";
|
|
2212
|
+
CoInspectorMessageType["onCloseDomInspectorPanel"] = "onCloseDomInspectorPanel";
|
|
2213
|
+
CoInspectorMessageType["onEditElement"] = "onEditElement";
|
|
2214
|
+
CoInspectorMessageType["onDeleteElement"] = "onDeleteElement";
|
|
2215
|
+
CoInspectorMessageType["onScroll"] = "onScroll";
|
|
2216
|
+
CoInspectorMessageType["setAllRects"] = "setAllRects";
|
|
2217
|
+
CoInspectorMessageType["onUpdateRects"] = "onUpdateRects";
|
|
2218
|
+
CoInspectorMessageType["DisableMouseTracking"] = "DisableMouseTracking";
|
|
2219
|
+
CoInspectorMessageType["EnableMouseTracking"] = "EnableMouseTracking";
|
|
2220
|
+
CoInspectorMessageType["onLeaveElement"] = "onLeaveElement";
|
|
2221
|
+
})(CoInspectorMessageType || (CoInspectorMessageType = {}));
|
|
2222
|
+
var CoMainSiteMessageType;
|
|
2223
|
+
(function (CoMainSiteMessageType) {
|
|
2224
|
+
CoMainSiteMessageType["ActiveInspect"] = "ActiveInspect";
|
|
2225
|
+
CoMainSiteMessageType["FreezeInspect"] = "FreezeInspect";
|
|
2226
|
+
CoMainSiteMessageType["SetElementChanges"] = "SetElementChanges";
|
|
2227
|
+
CoMainSiteMessageType["ShowDomInspector"] = "ShowDomInspector";
|
|
2228
|
+
CoMainSiteMessageType["RestoreOriginal"] = "RestoreOriginal";
|
|
2229
|
+
CoMainSiteMessageType["CreateNewElement"] = "CreateNewElement";
|
|
2230
|
+
CoMainSiteMessageType["ClickHoverElement"] = "ClickHoverElement";
|
|
2231
|
+
CoMainSiteMessageType["ReloadIframe"] = "ReloadIframe";
|
|
2232
|
+
})(CoMainSiteMessageType || (CoMainSiteMessageType = {}));
|
|
2233
|
+
|
|
2234
|
+
const COFRAME_PREVIEW_SESSION_STORAGE_KEY = 'coframe.preview_variant';
|
|
2235
|
+
const COFRAME_PREVIEW_VARIANT_QUERY_PARAM = 'coframe_variant_id';
|
|
2236
|
+
const ROLLOUTS_PREVIEW_ID = 'rollouts';
|
|
2237
|
+
function splitPreviewVariantIds(raw) {
|
|
2238
|
+
var _a;
|
|
2239
|
+
return ((_a = raw === null || raw === void 0 ? void 0 : raw.split(',').map((id) => id.trim()).filter(Boolean)) !== null && _a !== void 0 ? _a : []);
|
|
2240
|
+
}
|
|
2241
|
+
function isPreviewSentinel(id) {
|
|
2242
|
+
return id === GLOBAL_HOLDOUT || id === ROLLOUTS_PREVIEW_ID;
|
|
2243
|
+
}
|
|
2244
|
+
function normalizePreviewVariantId(raw) {
|
|
2245
|
+
const ids = splitPreviewVariantIds(raw);
|
|
2246
|
+
return ids.length > 0 ? ids.join(',') : null;
|
|
2247
|
+
}
|
|
2248
|
+
function readPreviewVariantIdFromUrl(url = window.location.href) {
|
|
2249
|
+
try {
|
|
2250
|
+
return normalizePreviewVariantId(getUrlSearchParams(url).get(COFRAME_PREVIEW_VARIANT_QUERY_PARAM));
|
|
2251
|
+
}
|
|
2252
|
+
catch (_a) {
|
|
2253
|
+
return null;
|
|
2254
|
+
}
|
|
2255
|
+
}
|
|
2256
|
+
function readStoredPreviewVariantId() {
|
|
2257
|
+
try {
|
|
2258
|
+
return normalizePreviewVariantId(window.sessionStorage.getItem(COFRAME_PREVIEW_SESSION_STORAGE_KEY));
|
|
2259
|
+
}
|
|
2260
|
+
catch (_a) {
|
|
2261
|
+
return null;
|
|
2262
|
+
}
|
|
2263
|
+
}
|
|
2264
|
+
function resolvePreviewSource(url = window.location.href) {
|
|
2265
|
+
const urlVariantId = readPreviewVariantIdFromUrl(url);
|
|
2266
|
+
const storedVariantId = readStoredPreviewVariantId();
|
|
2267
|
+
return {
|
|
2268
|
+
effectiveVariantId: urlVariantId || storedVariantId,
|
|
2269
|
+
isKeptForSession: Boolean(storedVariantId && storedVariantId === (urlVariantId || storedVariantId)),
|
|
2270
|
+
storedVariantId,
|
|
2271
|
+
urlVariantId,
|
|
2272
|
+
};
|
|
2273
|
+
}
|
|
2274
|
+
|
|
2159
2275
|
function isElementVisible(el) {
|
|
2160
2276
|
const rect = el.getBoundingClientRect();
|
|
2161
2277
|
return rect.top >= 0 && rect.bottom <= window.innerHeight;
|
|
@@ -2195,11 +2311,11 @@ function checkActivationCondition(condition, personalizationHeaders, currentUrl,
|
|
|
2195
2311
|
}
|
|
2196
2312
|
if (condition.url &&
|
|
2197
2313
|
condition.url !== '*' &&
|
|
2198
|
-
!
|
|
2314
|
+
!urlConditionMatches(condition.url, currentUrl, false, logger)) {
|
|
2199
2315
|
return false;
|
|
2200
2316
|
}
|
|
2201
2317
|
if (condition.base_url_matches &&
|
|
2202
|
-
!
|
|
2318
|
+
!urlConditionMatches(condition.base_url_matches, currentUrl, true, logger)) {
|
|
2203
2319
|
return false;
|
|
2204
2320
|
}
|
|
2205
2321
|
if (condition.url_regex) {
|
|
@@ -2313,6 +2429,18 @@ const normalizeUrl = (url, baseUrlMatch) => {
|
|
|
2313
2429
|
}
|
|
2314
2430
|
return `${hostname}${pathname}${parsedUrl.search}${parsedUrl.hash}`;
|
|
2315
2431
|
};
|
|
2432
|
+
function urlConditionMatches(conditionUrl, currentUrl, baseUrlMatch, logger) {
|
|
2433
|
+
try {
|
|
2434
|
+
return urlsMatch(conditionUrl, currentUrl, baseUrlMatch);
|
|
2435
|
+
}
|
|
2436
|
+
catch (_a) {
|
|
2437
|
+
logger.error('Error parsing URL condition', 'url_condition_error', {
|
|
2438
|
+
conditionUrl,
|
|
2439
|
+
currentUrl,
|
|
2440
|
+
});
|
|
2441
|
+
return false;
|
|
2442
|
+
}
|
|
2443
|
+
}
|
|
2316
2444
|
function urlsMatch(conditionUrl, currentUrl, baseUrlMatch) {
|
|
2317
2445
|
if (currentUrl.includes('localhost') || currentUrl.includes('0.0.0.0')) {
|
|
2318
2446
|
const conditionUrlObj = new URL(conditionUrl);
|
|
@@ -2423,15 +2551,15 @@ const inRange = (bins, scale, seed, uid) => {
|
|
|
2423
2551
|
}
|
|
2424
2552
|
return false;
|
|
2425
2553
|
};
|
|
2426
|
-
function checkAllAudiences(metadata,
|
|
2554
|
+
function checkAllAudiences(metadata, ctx) {
|
|
2427
2555
|
var _a;
|
|
2428
2556
|
const audienceIds = (_a = metadata.activation_condition.audience_ids) !== null && _a !== void 0 ? _a : [];
|
|
2429
2557
|
let result = true;
|
|
2430
2558
|
for (const audienceId of audienceIds) {
|
|
2431
|
-
const audience = project.audiences[audienceId];
|
|
2559
|
+
const audience = ctx.project.audiences[audienceId];
|
|
2432
2560
|
if (!audience)
|
|
2433
2561
|
continue;
|
|
2434
|
-
const activated = checkActivationCondition(audience.selector, personalizationHeaders, currentPageUrl, languages, browserPlatform, userToken, userVisitCount, (js, args) => executeJs(js, args, { isExpression: true, nonce }), logger);
|
|
2562
|
+
const activated = checkActivationCondition(audience.selector, ctx.personalizationHeaders, ctx.currentPageUrl, ctx.languages, ctx.browserPlatform, ctx.userToken, ctx.userVisitCount, (js, args) => executeJs(js, args, { isExpression: true, nonce: ctx.nonce }), ctx.logger);
|
|
2435
2563
|
if (activated === false)
|
|
2436
2564
|
return false;
|
|
2437
2565
|
if (activated !== true)
|
|
@@ -2440,9 +2568,8 @@ function checkAllAudiences(metadata, project, personalizationHeaders, currentPag
|
|
|
2440
2568
|
return result;
|
|
2441
2569
|
}
|
|
2442
2570
|
async function getVariantsAndElements(personalizationHeaders, project, previewVariantId, userToken, currentPageUrl, languages, browserPlatform, logger, nonce, laneClaims = {}, silentFallback = false) {
|
|
2443
|
-
var _a
|
|
2571
|
+
var _a;
|
|
2444
2572
|
const experimentsInfo = [];
|
|
2445
|
-
const variantsAndElements = [];
|
|
2446
2573
|
const cloakBot = !!((_a = project.settings) === null || _a === void 0 ? void 0 : _a.bot_cloaking_enabled) &&
|
|
2447
2574
|
personalizationHeaders['x-is-bot'] === 'true';
|
|
2448
2575
|
const buildResponse = ({ variantsAndElements, experimentsInfo, hasActivatedFrames: frameActivated = false, laneClaims: meClaims = laneClaims, }) => {
|
|
@@ -2453,39 +2580,30 @@ async function getVariantsAndElements(personalizationHeaders, project, previewVa
|
|
|
2453
2580
|
laneClaims: meClaims,
|
|
2454
2581
|
};
|
|
2455
2582
|
};
|
|
2456
|
-
const
|
|
2583
|
+
const userVisitCount = Number.parseInt(getCookie(VISIT_COUNT_COOKIE_KEY) || '0', 10);
|
|
2584
|
+
const ctx = {
|
|
2585
|
+
project,
|
|
2586
|
+
personalizationHeaders,
|
|
2587
|
+
userToken,
|
|
2588
|
+
currentPageUrl,
|
|
2589
|
+
languages,
|
|
2590
|
+
browserPlatform,
|
|
2591
|
+
userVisitCount,
|
|
2592
|
+
nonce,
|
|
2593
|
+
logger,
|
|
2594
|
+
};
|
|
2595
|
+
const validatedClaims = validateClaims(laneClaims, project.lanes);
|
|
2596
|
+
const previewVariantIds = splitPreviewVariantIds(previewVariantId);
|
|
2457
2597
|
if (previewVariantIds.length > 0) {
|
|
2458
|
-
const
|
|
2459
|
-
|
|
2460
|
-
variant,
|
|
2461
|
-
elements: frame.elements,
|
|
2462
|
-
}))))
|
|
2463
|
-
.filter((item) => previewVariantIds.includes(item.variant.id));
|
|
2464
|
-
const skipAlert = previewVariantIds.some((id) => id === project.holdout_info.holdout_variant_id || id === GLOBAL_HOLDOUT);
|
|
2465
|
-
if (filteredVariantsAndElements.length > 0) {
|
|
2598
|
+
const variantsAndElements = previewVariants(previewVariantIds, validatedClaims, ctx, silentFallback);
|
|
2599
|
+
if (variantsAndElements) {
|
|
2466
2600
|
return buildResponse({
|
|
2467
|
-
variantsAndElements
|
|
2468
|
-
hasActivatedFrames:
|
|
2601
|
+
variantsAndElements,
|
|
2602
|
+
hasActivatedFrames: variantsAndElements.length > 0,
|
|
2469
2603
|
});
|
|
2470
2604
|
}
|
|
2471
|
-
if (!skipAlert && !silentFallback) {
|
|
2472
|
-
window.alert(`[Coframe] Variant preview unavailable: ${previewVariantId}.`);
|
|
2473
|
-
}
|
|
2474
|
-
if (silentFallback) ;
|
|
2475
|
-
else {
|
|
2476
|
-
return buildResponse({});
|
|
2477
|
-
}
|
|
2478
2605
|
}
|
|
2479
|
-
const
|
|
2480
|
-
const validatedClaims = validateClaims(laneClaims, project.lanes);
|
|
2481
|
-
const activeFrames = project.frames.filter((frame) => {
|
|
2482
|
-
if (!frame.experiments)
|
|
2483
|
-
return false;
|
|
2484
|
-
const frameActivated = checkActivationCondition(frame.activation_condition, personalizationHeaders, currentPageUrl, languages, browserPlatform, userToken, userVisitCount, (js, args) => executeJs(js, args, { isExpression: true, nonce }), logger);
|
|
2485
|
-
if (!frameActivated)
|
|
2486
|
-
return false;
|
|
2487
|
-
return true;
|
|
2488
|
-
});
|
|
2606
|
+
const activeFrames = activateFrames(ctx);
|
|
2489
2607
|
if (activeFrames.length === 0) {
|
|
2490
2608
|
return buildResponse({ laneClaims: validatedClaims });
|
|
2491
2609
|
}
|
|
@@ -2503,7 +2621,6 @@ async function getVariantsAndElements(personalizationHeaders, project, previewVa
|
|
|
2503
2621
|
level: GLOBAL_HOLDOUT,
|
|
2504
2622
|
});
|
|
2505
2623
|
return buildResponse({
|
|
2506
|
-
variantsAndElements,
|
|
2507
2624
|
experimentsInfo,
|
|
2508
2625
|
hasActivatedFrames: true,
|
|
2509
2626
|
laneClaims: validatedClaims,
|
|
@@ -2518,7 +2635,27 @@ async function getVariantsAndElements(personalizationHeaders, project, previewVa
|
|
|
2518
2635
|
final_state: false,
|
|
2519
2636
|
level: GLOBAL_HOLDOUT,
|
|
2520
2637
|
});
|
|
2521
|
-
const
|
|
2638
|
+
const assignment = assignFrames(activeFrames, validatedClaims, ctx);
|
|
2639
|
+
return buildResponse({
|
|
2640
|
+
...assignment,
|
|
2641
|
+
experimentsInfo: [...experimentsInfo, ...assignment.experimentsInfo],
|
|
2642
|
+
});
|
|
2643
|
+
}
|
|
2644
|
+
function activateFrames(ctx) {
|
|
2645
|
+
return ctx.project.frames.filter((frame) => {
|
|
2646
|
+
if (!frame.experiments)
|
|
2647
|
+
return false;
|
|
2648
|
+
const frameActivated = checkActivationCondition(frame.activation_condition, ctx.personalizationHeaders, ctx.currentPageUrl, ctx.languages, ctx.browserPlatform, ctx.userToken, ctx.userVisitCount, (js, args) => executeJs(js, args, { isExpression: true, nonce: ctx.nonce }), ctx.logger);
|
|
2649
|
+
if (!frameActivated)
|
|
2650
|
+
return false;
|
|
2651
|
+
return true;
|
|
2652
|
+
});
|
|
2653
|
+
}
|
|
2654
|
+
function assignFrames(activeFrames, validatedClaims, ctx) {
|
|
2655
|
+
const { project, userToken, logger } = ctx;
|
|
2656
|
+
const experimentsInfo = [];
|
|
2657
|
+
const variantsAndElements = [];
|
|
2658
|
+
const evalAudiences = (metadata) => checkAllAudiences(metadata, ctx) !== false;
|
|
2522
2659
|
const audiencePass = new Map();
|
|
2523
2660
|
const reachableByLane = {};
|
|
2524
2661
|
for (const frame of activeFrames) {
|
|
@@ -2611,50 +2748,49 @@ async function getVariantsAndElements(personalizationHeaders, project, previewVa
|
|
|
2611
2748
|
variantsAndElements.push({ variant, elements });
|
|
2612
2749
|
}
|
|
2613
2750
|
}
|
|
2614
|
-
return
|
|
2751
|
+
return {
|
|
2615
2752
|
variantsAndElements,
|
|
2616
2753
|
experimentsInfo,
|
|
2617
2754
|
hasActivatedFrames,
|
|
2618
2755
|
laneClaims: updatedClaims,
|
|
2619
|
-
}
|
|
2756
|
+
};
|
|
2620
2757
|
}
|
|
2621
|
-
|
|
2622
|
-
const
|
|
2623
|
-
const
|
|
2624
|
-
|
|
2625
|
-
|
|
2758
|
+
function previewVariants(previewVariantIds, validatedClaims, ctx, silentFallback) {
|
|
2759
|
+
const previewRollouts = previewVariantIds.includes(ROLLOUTS_PREVIEW_ID);
|
|
2760
|
+
const requestedVariantIds = previewVariantIds.filter((id) => !isPreviewSentinel(id));
|
|
2761
|
+
const requestedVariants = findVariants(ctx.project.frames, requestedVariantIds);
|
|
2762
|
+
const requestedVariantsMissing = requestedVariantIds.length > 0 && requestedVariants.length === 0;
|
|
2763
|
+
if (requestedVariantsMissing && !previewRollouts && silentFallback) {
|
|
2626
2764
|
return null;
|
|
2627
|
-
const ids = raw
|
|
2628
|
-
.split(',')
|
|
2629
|
-
.map((id) => id.trim())
|
|
2630
|
-
.filter(Boolean);
|
|
2631
|
-
return ids.length > 0 ? ids.join(',') : null;
|
|
2632
|
-
}
|
|
2633
|
-
function readPreviewVariantIdFromUrl(url = window.location.href) {
|
|
2634
|
-
try {
|
|
2635
|
-
return normalizePreviewVariantId(getUrlSearchParams(url).get(COFRAME_PREVIEW_VARIANT_QUERY_PARAM));
|
|
2636
2765
|
}
|
|
2637
|
-
|
|
2638
|
-
|
|
2766
|
+
const requestedHoldout = requestedVariantIds.includes(ctx.project.holdout_info.holdout_variant_id);
|
|
2767
|
+
if (requestedVariantsMissing && !requestedHoldout && !silentFallback) {
|
|
2768
|
+
window.alert(`[Coframe] Variant preview unavailable: ${previewVariantIds.join(',')}.`);
|
|
2639
2769
|
}
|
|
2770
|
+
const rolledOutVariants = previewRollouts && !previewVariantIds.includes(GLOBAL_HOLDOUT)
|
|
2771
|
+
? assignFrames(keepRolledOutExperiments(activateFrames(ctx)), validatedClaims, ctx).variantsAndElements
|
|
2772
|
+
: [];
|
|
2773
|
+
return uniqueByVariantId([...rolledOutVariants, ...requestedVariants]);
|
|
2640
2774
|
}
|
|
2641
|
-
function
|
|
2642
|
-
|
|
2643
|
-
|
|
2644
|
-
|
|
2645
|
-
catch (_a) {
|
|
2646
|
-
return null;
|
|
2647
|
-
}
|
|
2775
|
+
function findVariants(frames, variantIds) {
|
|
2776
|
+
return frames.flatMap((frame) => frame.experiments.flatMap((experiment) => experiment.variants
|
|
2777
|
+
.filter((variant) => variantIds.includes(variant.id))
|
|
2778
|
+
.map((variant) => ({ variant, elements: frame.elements }))));
|
|
2648
2779
|
}
|
|
2649
|
-
function
|
|
2650
|
-
const
|
|
2651
|
-
|
|
2652
|
-
|
|
2653
|
-
|
|
2654
|
-
|
|
2655
|
-
|
|
2656
|
-
|
|
2657
|
-
|
|
2780
|
+
function uniqueByVariantId(items) {
|
|
2781
|
+
const seen = {};
|
|
2782
|
+
return items.filter(({ variant }) => {
|
|
2783
|
+
if (seen[variant.id])
|
|
2784
|
+
return false;
|
|
2785
|
+
seen[variant.id] = true;
|
|
2786
|
+
return true;
|
|
2787
|
+
});
|
|
2788
|
+
}
|
|
2789
|
+
function keepRolledOutExperiments(frames) {
|
|
2790
|
+
return frames.map((frame) => ({
|
|
2791
|
+
...frame,
|
|
2792
|
+
experiments: frame.experiments.filter((experiment) => experiment.metadata.serving_mode === 'winner'),
|
|
2793
|
+
}));
|
|
2658
2794
|
}
|
|
2659
2795
|
|
|
2660
2796
|
function buildSessionContext(isInitialApply) {
|
|
@@ -2940,29 +3076,27 @@ function createTreatmentAnalytics(Coframe, previewVariantId) {
|
|
|
2940
3076
|
});
|
|
2941
3077
|
}
|
|
2942
3078
|
}
|
|
2943
|
-
|
|
2944
|
-
|
|
2945
|
-
|
|
2946
|
-
|
|
2947
|
-
|
|
2948
|
-
|
|
2949
|
-
|
|
2950
|
-
|
|
2951
|
-
|
|
2952
|
-
|
|
2953
|
-
|
|
2954
|
-
|
|
2955
|
-
|
|
2956
|
-
|
|
2957
|
-
|
|
2958
|
-
|
|
2959
|
-
|
|
2960
|
-
|
|
2961
|
-
|
|
2962
|
-
|
|
2963
|
-
|
|
2964
|
-
});
|
|
2965
|
-
}
|
|
3079
|
+
const previewIds = splitPreviewVariantIds(previewVariantId).filter((id) => !isPreviewSentinel(id));
|
|
3080
|
+
for (const id of previewIds) {
|
|
3081
|
+
treatmentsData.push({
|
|
3082
|
+
impressionId: sessionId,
|
|
3083
|
+
userToken,
|
|
3084
|
+
experimentId: `preview_id_${id}`,
|
|
3085
|
+
holdoutExperimentId: `preview_holdout_id_${id}`,
|
|
3086
|
+
variantId: id,
|
|
3087
|
+
inGlobalHoldout: false,
|
|
3088
|
+
isBaseline: false,
|
|
3089
|
+
});
|
|
3090
|
+
treatmentsDataV2.push({
|
|
3091
|
+
coframe_experiment_id: `preview_id_${id}`,
|
|
3092
|
+
coframe_experiment_slug: `preview_id_${id}`,
|
|
3093
|
+
coframe_variant_id: id,
|
|
3094
|
+
coframe_variant_slug: id,
|
|
3095
|
+
coframe_user_token: userToken,
|
|
3096
|
+
coframe_impression_id: sessionId,
|
|
3097
|
+
coframe_in_global_holdout: false,
|
|
3098
|
+
coframe_in_exp_baseline: false,
|
|
3099
|
+
});
|
|
2966
3100
|
}
|
|
2967
3101
|
Coframe.treatmentsData = treatmentsData;
|
|
2968
3102
|
Coframe.treatmentsDataV2 = treatmentsDataV2;
|
|
@@ -3207,12 +3341,12 @@ async function ensureBody(Coframe, cdnProject, timeoutMs, nonce) {
|
|
|
3207
3341
|
}
|
|
3208
3342
|
const FLUSH_EVENTS_TIME = 1000 * 3;
|
|
3209
3343
|
let flushInterval = null;
|
|
3210
|
-
function setupFlushInterval(
|
|
3211
|
-
flushQueuedEvents(projectId);
|
|
3344
|
+
function setupFlushInterval(Coframe) {
|
|
3345
|
+
flushQueuedEvents(Coframe.projectId);
|
|
3212
3346
|
if (flushInterval !== null) {
|
|
3213
3347
|
clearInterval(flushInterval);
|
|
3214
3348
|
}
|
|
3215
|
-
flushInterval = setInterval(() => flushQueuedEvents(projectId), FLUSH_EVENTS_TIME);
|
|
3349
|
+
flushInterval = setInterval(() => flushQueuedEvents(Coframe.projectId), FLUSH_EVENTS_TIME);
|
|
3216
3350
|
}
|
|
3217
3351
|
function setupSPANavigation(Coframe, project, config, previewVariantId, isSessionVariant, applyVariants) {
|
|
3218
3352
|
var _a;
|
|
@@ -3260,7 +3394,7 @@ function setupSPANavigation(Coframe, project, config, previewVariantId, isSessio
|
|
|
3260
3394
|
else {
|
|
3261
3395
|
try {
|
|
3262
3396
|
const preview = resolvePreview(newPageUrl, previewVariantId, isSessionVariant);
|
|
3263
|
-
const result = await
|
|
3397
|
+
const result = await fetchProject(config.projectUrl, Coframe.projectId, newPageUrl, signal, config.userContext, preview.previewVariantId || undefined, undefined, (_a = config.referrer) !== null && _a !== void 0 ? _a : getBrowserReferrer());
|
|
3264
3398
|
if (signal.aborted)
|
|
3265
3399
|
return;
|
|
3266
3400
|
if (result) {
|
|
@@ -3358,7 +3492,7 @@ async function modifyPage(Coframe, configResult, projectResult, analytics) {
|
|
|
3358
3492
|
}
|
|
3359
3493
|
reportInitTiming(Coframe, cdnProject, integrationStartTime, executionStartTime);
|
|
3360
3494
|
setupSPANavigation(Coframe, cdnProject, config, previewVariantId, isSessionVariant, applyVariants);
|
|
3361
|
-
setupFlushInterval(Coframe
|
|
3495
|
+
setupFlushInterval(Coframe);
|
|
3362
3496
|
}
|
|
3363
3497
|
|
|
3364
3498
|
const TIMEOUT_MAX_MS = 5000;
|
|
@@ -3394,6 +3528,7 @@ async function resolveConfig(Coframe, revealPage) {
|
|
|
3394
3528
|
: null;
|
|
3395
3529
|
const executionStartTime = new Date();
|
|
3396
3530
|
Coframe.batchSize = config.batchSize || 32;
|
|
3531
|
+
configureIngestUrl(config.ingestUrl);
|
|
3397
3532
|
const gracefulExit = (msg) => {
|
|
3398
3533
|
console.warn(`[Coframe] ${msg}`);
|
|
3399
3534
|
revealPage();
|
|
@@ -3521,7 +3656,7 @@ async function resolveProject(Coframe, previewVariantId, isSessionVariant, confi
|
|
|
3521
3656
|
let personalizationHeaders = (projectData === null || projectData === void 0 ? void 0 : projectData.personalizationHeaders) || null;
|
|
3522
3657
|
let project = isSessionVariant ? undefined : projectData === null || projectData === void 0 ? void 0 : projectData.project;
|
|
3523
3658
|
if (!project) {
|
|
3524
|
-
const edgeResult = await
|
|
3659
|
+
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());
|
|
3525
3660
|
personalizationHeaders = (edgeResult === null || edgeResult === void 0 ? void 0 : edgeResult.personalizationHeaders) || null;
|
|
3526
3661
|
project = (edgeResult === null || edgeResult === void 0 ? void 0 : edgeResult.project) || undefined;
|
|
3527
3662
|
}
|
package/dist/pkg/cf.esm.mjs
CHANGED
|
@@ -22,6 +22,19 @@ if (!Array.prototype.find) {
|
|
|
22
22
|
enumerable: false,
|
|
23
23
|
});
|
|
24
24
|
}
|
|
25
|
+
if (!Array.prototype.includes) {
|
|
26
|
+
Object.defineProperty(Array.prototype, 'includes', {
|
|
27
|
+
value: function (searchElement) {
|
|
28
|
+
if (this == null) {
|
|
29
|
+
throw new TypeError('Array.prototype.includes called on null or undefined');
|
|
30
|
+
}
|
|
31
|
+
return Array.prototype.indexOf.call(this, searchElement) !== -1;
|
|
32
|
+
},
|
|
33
|
+
writable: true,
|
|
34
|
+
configurable: true,
|
|
35
|
+
enumerable: false,
|
|
36
|
+
});
|
|
37
|
+
}
|
|
25
38
|
if (!Array.prototype.flatMap) {
|
|
26
39
|
Object.defineProperty(Array.prototype, 'flatMap', {
|
|
27
40
|
value: function (callback, thisArg) {
|
|
@@ -1068,6 +1081,17 @@ const SDK_VERSION = '2.7.0';
|
|
|
1068
1081
|
const queuedEvents = [];
|
|
1069
1082
|
const queuedMonitoringEvents = [];
|
|
1070
1083
|
const queuedSessions = [];
|
|
1084
|
+
let ingestUrl;
|
|
1085
|
+
const COMPILED_INGEST_BASE = "https://ingest.app.coframe.com/ingest/v2";
|
|
1086
|
+
function configureIngestUrl(url) {
|
|
1087
|
+
const trimmed = url === null || url === void 0 ? void 0 : url.trim().replace(/\/+$/, '');
|
|
1088
|
+
ingestUrl = trimmed || undefined;
|
|
1089
|
+
}
|
|
1090
|
+
function resolveIngestUrl(defaultUrl) {
|
|
1091
|
+
if (!ingestUrl || !defaultUrl.startsWith(COMPILED_INGEST_BASE))
|
|
1092
|
+
return defaultUrl;
|
|
1093
|
+
return ingestUrl + defaultUrl.slice(COMPILED_INGEST_BASE.length);
|
|
1094
|
+
}
|
|
1071
1095
|
const MAX_BEACON_BATCH_BYTES = 48 * 1024;
|
|
1072
1096
|
function getBeaconPayloadBytes(data) {
|
|
1073
1097
|
return new Blob([JSON.stringify(data)]).size;
|
|
@@ -1250,7 +1274,7 @@ function sendPageEngagementEvent(coframe, eventType, event, { projectId, session
|
|
|
1250
1274
|
}
|
|
1251
1275
|
}
|
|
1252
1276
|
function sendEventToBackend(projectId, data, eventCategory = 'events') {
|
|
1253
|
-
const eventsEndpoint = `${"https://ingest.app.coframe.com/ingest/v2"}/${eventCategory}/${projectId}
|
|
1277
|
+
const eventsEndpoint = resolveIngestUrl(`${"https://ingest.app.coframe.com/ingest/v2"}/${eventCategory}/${projectId}/`);
|
|
1254
1278
|
if (navigator.sendBeacon) {
|
|
1255
1279
|
const textData = JSON.stringify(data);
|
|
1256
1280
|
const blob = new Blob([textData], { type: 'text/plain' });
|
|
@@ -1263,7 +1287,7 @@ function sendEventToBackend(projectId, data, eventCategory = 'events') {
|
|
|
1263
1287
|
}
|
|
1264
1288
|
}
|
|
1265
1289
|
function createSession(data) {
|
|
1266
|
-
const sessionApiUrl = `${"https://ingest.app.coframe.com/ingest/v2"}/session_result
|
|
1290
|
+
const sessionApiUrl = resolveIngestUrl(`${"https://ingest.app.coframe.com/ingest/v2"}/session_result/`);
|
|
1267
1291
|
if (navigator.sendBeacon) {
|
|
1268
1292
|
const textData = JSON.stringify(data);
|
|
1269
1293
|
const blob = new Blob([textData], { type: 'text/plain' });
|
|
@@ -1303,6 +1327,26 @@ async function fetchProjectFromEdge(projectId, currentUrl, signal, userContext,
|
|
|
1303
1327
|
return null;
|
|
1304
1328
|
}
|
|
1305
1329
|
}
|
|
1330
|
+
async function fetchProject(projectUrl, projectId, currentUrl, signal, userContext, previewVariantId, headers, referrer) {
|
|
1331
|
+
if (!projectUrl) {
|
|
1332
|
+
return fetchProjectFromEdge(projectId, currentUrl, signal, userContext, previewVariantId, headers, referrer);
|
|
1333
|
+
}
|
|
1334
|
+
try {
|
|
1335
|
+
const response = await fetch(projectUrl, { headers, signal });
|
|
1336
|
+
if (!response.ok)
|
|
1337
|
+
return null;
|
|
1338
|
+
return {
|
|
1339
|
+
project: (await response.json()),
|
|
1340
|
+
personalizationHeaders: {},
|
|
1341
|
+
};
|
|
1342
|
+
}
|
|
1343
|
+
catch (error) {
|
|
1344
|
+
if (error instanceof DOMException && error.name === 'AbortError') {
|
|
1345
|
+
return null;
|
|
1346
|
+
}
|
|
1347
|
+
return null;
|
|
1348
|
+
}
|
|
1349
|
+
}
|
|
1306
1350
|
|
|
1307
1351
|
const isPageElement = (element) => {
|
|
1308
1352
|
return (element === document.body ||
|
|
@@ -2154,6 +2198,78 @@ function resolveLaneWinners(claims, reachableByLane, lanes, userToken) {
|
|
|
2154
2198
|
return excluded;
|
|
2155
2199
|
}
|
|
2156
2200
|
|
|
2201
|
+
var CoInspectorMessageType;
|
|
2202
|
+
(function (CoInspectorMessageType) {
|
|
2203
|
+
CoInspectorMessageType["onReady"] = "onReady";
|
|
2204
|
+
CoInspectorMessageType["onHoverElement"] = "onHoverElement";
|
|
2205
|
+
CoInspectorMessageType["onClickElement"] = "onClickElement";
|
|
2206
|
+
CoInspectorMessageType["onPageUrlChange"] = "onPageUrlChange";
|
|
2207
|
+
CoInspectorMessageType["onCreateNewElement"] = "onCreateNewElement";
|
|
2208
|
+
CoInspectorMessageType["onCancelNewElement"] = "onCancelNewElement";
|
|
2209
|
+
CoInspectorMessageType["onCopy"] = "onCopy";
|
|
2210
|
+
CoInspectorMessageType["onCloseDomInspectorPanel"] = "onCloseDomInspectorPanel";
|
|
2211
|
+
CoInspectorMessageType["onEditElement"] = "onEditElement";
|
|
2212
|
+
CoInspectorMessageType["onDeleteElement"] = "onDeleteElement";
|
|
2213
|
+
CoInspectorMessageType["onScroll"] = "onScroll";
|
|
2214
|
+
CoInspectorMessageType["setAllRects"] = "setAllRects";
|
|
2215
|
+
CoInspectorMessageType["onUpdateRects"] = "onUpdateRects";
|
|
2216
|
+
CoInspectorMessageType["DisableMouseTracking"] = "DisableMouseTracking";
|
|
2217
|
+
CoInspectorMessageType["EnableMouseTracking"] = "EnableMouseTracking";
|
|
2218
|
+
CoInspectorMessageType["onLeaveElement"] = "onLeaveElement";
|
|
2219
|
+
})(CoInspectorMessageType || (CoInspectorMessageType = {}));
|
|
2220
|
+
var CoMainSiteMessageType;
|
|
2221
|
+
(function (CoMainSiteMessageType) {
|
|
2222
|
+
CoMainSiteMessageType["ActiveInspect"] = "ActiveInspect";
|
|
2223
|
+
CoMainSiteMessageType["FreezeInspect"] = "FreezeInspect";
|
|
2224
|
+
CoMainSiteMessageType["SetElementChanges"] = "SetElementChanges";
|
|
2225
|
+
CoMainSiteMessageType["ShowDomInspector"] = "ShowDomInspector";
|
|
2226
|
+
CoMainSiteMessageType["RestoreOriginal"] = "RestoreOriginal";
|
|
2227
|
+
CoMainSiteMessageType["CreateNewElement"] = "CreateNewElement";
|
|
2228
|
+
CoMainSiteMessageType["ClickHoverElement"] = "ClickHoverElement";
|
|
2229
|
+
CoMainSiteMessageType["ReloadIframe"] = "ReloadIframe";
|
|
2230
|
+
})(CoMainSiteMessageType || (CoMainSiteMessageType = {}));
|
|
2231
|
+
|
|
2232
|
+
const COFRAME_PREVIEW_SESSION_STORAGE_KEY = 'coframe.preview_variant';
|
|
2233
|
+
const COFRAME_PREVIEW_VARIANT_QUERY_PARAM = 'coframe_variant_id';
|
|
2234
|
+
const ROLLOUTS_PREVIEW_ID = 'rollouts';
|
|
2235
|
+
function splitPreviewVariantIds(raw) {
|
|
2236
|
+
var _a;
|
|
2237
|
+
return ((_a = raw === null || raw === void 0 ? void 0 : raw.split(',').map((id) => id.trim()).filter(Boolean)) !== null && _a !== void 0 ? _a : []);
|
|
2238
|
+
}
|
|
2239
|
+
function isPreviewSentinel(id) {
|
|
2240
|
+
return id === GLOBAL_HOLDOUT || id === ROLLOUTS_PREVIEW_ID;
|
|
2241
|
+
}
|
|
2242
|
+
function normalizePreviewVariantId(raw) {
|
|
2243
|
+
const ids = splitPreviewVariantIds(raw);
|
|
2244
|
+
return ids.length > 0 ? ids.join(',') : null;
|
|
2245
|
+
}
|
|
2246
|
+
function readPreviewVariantIdFromUrl(url = window.location.href) {
|
|
2247
|
+
try {
|
|
2248
|
+
return normalizePreviewVariantId(getUrlSearchParams(url).get(COFRAME_PREVIEW_VARIANT_QUERY_PARAM));
|
|
2249
|
+
}
|
|
2250
|
+
catch (_a) {
|
|
2251
|
+
return null;
|
|
2252
|
+
}
|
|
2253
|
+
}
|
|
2254
|
+
function readStoredPreviewVariantId() {
|
|
2255
|
+
try {
|
|
2256
|
+
return normalizePreviewVariantId(window.sessionStorage.getItem(COFRAME_PREVIEW_SESSION_STORAGE_KEY));
|
|
2257
|
+
}
|
|
2258
|
+
catch (_a) {
|
|
2259
|
+
return null;
|
|
2260
|
+
}
|
|
2261
|
+
}
|
|
2262
|
+
function resolvePreviewSource(url = window.location.href) {
|
|
2263
|
+
const urlVariantId = readPreviewVariantIdFromUrl(url);
|
|
2264
|
+
const storedVariantId = readStoredPreviewVariantId();
|
|
2265
|
+
return {
|
|
2266
|
+
effectiveVariantId: urlVariantId || storedVariantId,
|
|
2267
|
+
isKeptForSession: Boolean(storedVariantId && storedVariantId === (urlVariantId || storedVariantId)),
|
|
2268
|
+
storedVariantId,
|
|
2269
|
+
urlVariantId,
|
|
2270
|
+
};
|
|
2271
|
+
}
|
|
2272
|
+
|
|
2157
2273
|
function isElementVisible(el) {
|
|
2158
2274
|
const rect = el.getBoundingClientRect();
|
|
2159
2275
|
return rect.top >= 0 && rect.bottom <= window.innerHeight;
|
|
@@ -2193,11 +2309,11 @@ function checkActivationCondition(condition, personalizationHeaders, currentUrl,
|
|
|
2193
2309
|
}
|
|
2194
2310
|
if (condition.url &&
|
|
2195
2311
|
condition.url !== '*' &&
|
|
2196
|
-
!
|
|
2312
|
+
!urlConditionMatches(condition.url, currentUrl, false, logger)) {
|
|
2197
2313
|
return false;
|
|
2198
2314
|
}
|
|
2199
2315
|
if (condition.base_url_matches &&
|
|
2200
|
-
!
|
|
2316
|
+
!urlConditionMatches(condition.base_url_matches, currentUrl, true, logger)) {
|
|
2201
2317
|
return false;
|
|
2202
2318
|
}
|
|
2203
2319
|
if (condition.url_regex) {
|
|
@@ -2311,6 +2427,18 @@ const normalizeUrl = (url, baseUrlMatch) => {
|
|
|
2311
2427
|
}
|
|
2312
2428
|
return `${hostname}${pathname}${parsedUrl.search}${parsedUrl.hash}`;
|
|
2313
2429
|
};
|
|
2430
|
+
function urlConditionMatches(conditionUrl, currentUrl, baseUrlMatch, logger) {
|
|
2431
|
+
try {
|
|
2432
|
+
return urlsMatch(conditionUrl, currentUrl, baseUrlMatch);
|
|
2433
|
+
}
|
|
2434
|
+
catch (_a) {
|
|
2435
|
+
logger.error('Error parsing URL condition', 'url_condition_error', {
|
|
2436
|
+
conditionUrl,
|
|
2437
|
+
currentUrl,
|
|
2438
|
+
});
|
|
2439
|
+
return false;
|
|
2440
|
+
}
|
|
2441
|
+
}
|
|
2314
2442
|
function urlsMatch(conditionUrl, currentUrl, baseUrlMatch) {
|
|
2315
2443
|
if (currentUrl.includes('localhost') || currentUrl.includes('0.0.0.0')) {
|
|
2316
2444
|
const conditionUrlObj = new URL(conditionUrl);
|
|
@@ -2421,15 +2549,15 @@ const inRange = (bins, scale, seed, uid) => {
|
|
|
2421
2549
|
}
|
|
2422
2550
|
return false;
|
|
2423
2551
|
};
|
|
2424
|
-
function checkAllAudiences(metadata,
|
|
2552
|
+
function checkAllAudiences(metadata, ctx) {
|
|
2425
2553
|
var _a;
|
|
2426
2554
|
const audienceIds = (_a = metadata.activation_condition.audience_ids) !== null && _a !== void 0 ? _a : [];
|
|
2427
2555
|
let result = true;
|
|
2428
2556
|
for (const audienceId of audienceIds) {
|
|
2429
|
-
const audience = project.audiences[audienceId];
|
|
2557
|
+
const audience = ctx.project.audiences[audienceId];
|
|
2430
2558
|
if (!audience)
|
|
2431
2559
|
continue;
|
|
2432
|
-
const activated = checkActivationCondition(audience.selector, personalizationHeaders, currentPageUrl, languages, browserPlatform, userToken, userVisitCount, (js, args) => executeJs(js, args, { isExpression: true, nonce }), logger);
|
|
2560
|
+
const activated = checkActivationCondition(audience.selector, ctx.personalizationHeaders, ctx.currentPageUrl, ctx.languages, ctx.browserPlatform, ctx.userToken, ctx.userVisitCount, (js, args) => executeJs(js, args, { isExpression: true, nonce: ctx.nonce }), ctx.logger);
|
|
2433
2561
|
if (activated === false)
|
|
2434
2562
|
return false;
|
|
2435
2563
|
if (activated !== true)
|
|
@@ -2438,9 +2566,8 @@ function checkAllAudiences(metadata, project, personalizationHeaders, currentPag
|
|
|
2438
2566
|
return result;
|
|
2439
2567
|
}
|
|
2440
2568
|
async function getVariantsAndElements(personalizationHeaders, project, previewVariantId, userToken, currentPageUrl, languages, browserPlatform, logger, nonce, laneClaims = {}, silentFallback = false) {
|
|
2441
|
-
var _a
|
|
2569
|
+
var _a;
|
|
2442
2570
|
const experimentsInfo = [];
|
|
2443
|
-
const variantsAndElements = [];
|
|
2444
2571
|
const cloakBot = !!((_a = project.settings) === null || _a === void 0 ? void 0 : _a.bot_cloaking_enabled) &&
|
|
2445
2572
|
personalizationHeaders['x-is-bot'] === 'true';
|
|
2446
2573
|
const buildResponse = ({ variantsAndElements, experimentsInfo, hasActivatedFrames: frameActivated = false, laneClaims: meClaims = laneClaims, }) => {
|
|
@@ -2451,39 +2578,30 @@ async function getVariantsAndElements(personalizationHeaders, project, previewVa
|
|
|
2451
2578
|
laneClaims: meClaims,
|
|
2452
2579
|
};
|
|
2453
2580
|
};
|
|
2454
|
-
const
|
|
2581
|
+
const userVisitCount = Number.parseInt(getCookie(VISIT_COUNT_COOKIE_KEY) || '0', 10);
|
|
2582
|
+
const ctx = {
|
|
2583
|
+
project,
|
|
2584
|
+
personalizationHeaders,
|
|
2585
|
+
userToken,
|
|
2586
|
+
currentPageUrl,
|
|
2587
|
+
languages,
|
|
2588
|
+
browserPlatform,
|
|
2589
|
+
userVisitCount,
|
|
2590
|
+
nonce,
|
|
2591
|
+
logger,
|
|
2592
|
+
};
|
|
2593
|
+
const validatedClaims = validateClaims(laneClaims, project.lanes);
|
|
2594
|
+
const previewVariantIds = splitPreviewVariantIds(previewVariantId);
|
|
2455
2595
|
if (previewVariantIds.length > 0) {
|
|
2456
|
-
const
|
|
2457
|
-
|
|
2458
|
-
variant,
|
|
2459
|
-
elements: frame.elements,
|
|
2460
|
-
}))))
|
|
2461
|
-
.filter((item) => previewVariantIds.includes(item.variant.id));
|
|
2462
|
-
const skipAlert = previewVariantIds.some((id) => id === project.holdout_info.holdout_variant_id || id === GLOBAL_HOLDOUT);
|
|
2463
|
-
if (filteredVariantsAndElements.length > 0) {
|
|
2596
|
+
const variantsAndElements = previewVariants(previewVariantIds, validatedClaims, ctx, silentFallback);
|
|
2597
|
+
if (variantsAndElements) {
|
|
2464
2598
|
return buildResponse({
|
|
2465
|
-
variantsAndElements
|
|
2466
|
-
hasActivatedFrames:
|
|
2599
|
+
variantsAndElements,
|
|
2600
|
+
hasActivatedFrames: variantsAndElements.length > 0,
|
|
2467
2601
|
});
|
|
2468
2602
|
}
|
|
2469
|
-
if (!skipAlert && !silentFallback) {
|
|
2470
|
-
window.alert(`[Coframe] Variant preview unavailable: ${previewVariantId}.`);
|
|
2471
|
-
}
|
|
2472
|
-
if (silentFallback) ;
|
|
2473
|
-
else {
|
|
2474
|
-
return buildResponse({});
|
|
2475
|
-
}
|
|
2476
2603
|
}
|
|
2477
|
-
const
|
|
2478
|
-
const validatedClaims = validateClaims(laneClaims, project.lanes);
|
|
2479
|
-
const activeFrames = project.frames.filter((frame) => {
|
|
2480
|
-
if (!frame.experiments)
|
|
2481
|
-
return false;
|
|
2482
|
-
const frameActivated = checkActivationCondition(frame.activation_condition, personalizationHeaders, currentPageUrl, languages, browserPlatform, userToken, userVisitCount, (js, args) => executeJs(js, args, { isExpression: true, nonce }), logger);
|
|
2483
|
-
if (!frameActivated)
|
|
2484
|
-
return false;
|
|
2485
|
-
return true;
|
|
2486
|
-
});
|
|
2604
|
+
const activeFrames = activateFrames(ctx);
|
|
2487
2605
|
if (activeFrames.length === 0) {
|
|
2488
2606
|
return buildResponse({ laneClaims: validatedClaims });
|
|
2489
2607
|
}
|
|
@@ -2501,7 +2619,6 @@ async function getVariantsAndElements(personalizationHeaders, project, previewVa
|
|
|
2501
2619
|
level: GLOBAL_HOLDOUT,
|
|
2502
2620
|
});
|
|
2503
2621
|
return buildResponse({
|
|
2504
|
-
variantsAndElements,
|
|
2505
2622
|
experimentsInfo,
|
|
2506
2623
|
hasActivatedFrames: true,
|
|
2507
2624
|
laneClaims: validatedClaims,
|
|
@@ -2516,7 +2633,27 @@ async function getVariantsAndElements(personalizationHeaders, project, previewVa
|
|
|
2516
2633
|
final_state: false,
|
|
2517
2634
|
level: GLOBAL_HOLDOUT,
|
|
2518
2635
|
});
|
|
2519
|
-
const
|
|
2636
|
+
const assignment = assignFrames(activeFrames, validatedClaims, ctx);
|
|
2637
|
+
return buildResponse({
|
|
2638
|
+
...assignment,
|
|
2639
|
+
experimentsInfo: [...experimentsInfo, ...assignment.experimentsInfo],
|
|
2640
|
+
});
|
|
2641
|
+
}
|
|
2642
|
+
function activateFrames(ctx) {
|
|
2643
|
+
return ctx.project.frames.filter((frame) => {
|
|
2644
|
+
if (!frame.experiments)
|
|
2645
|
+
return false;
|
|
2646
|
+
const frameActivated = checkActivationCondition(frame.activation_condition, ctx.personalizationHeaders, ctx.currentPageUrl, ctx.languages, ctx.browserPlatform, ctx.userToken, ctx.userVisitCount, (js, args) => executeJs(js, args, { isExpression: true, nonce: ctx.nonce }), ctx.logger);
|
|
2647
|
+
if (!frameActivated)
|
|
2648
|
+
return false;
|
|
2649
|
+
return true;
|
|
2650
|
+
});
|
|
2651
|
+
}
|
|
2652
|
+
function assignFrames(activeFrames, validatedClaims, ctx) {
|
|
2653
|
+
const { project, userToken, logger } = ctx;
|
|
2654
|
+
const experimentsInfo = [];
|
|
2655
|
+
const variantsAndElements = [];
|
|
2656
|
+
const evalAudiences = (metadata) => checkAllAudiences(metadata, ctx) !== false;
|
|
2520
2657
|
const audiencePass = new Map();
|
|
2521
2658
|
const reachableByLane = {};
|
|
2522
2659
|
for (const frame of activeFrames) {
|
|
@@ -2609,50 +2746,49 @@ async function getVariantsAndElements(personalizationHeaders, project, previewVa
|
|
|
2609
2746
|
variantsAndElements.push({ variant, elements });
|
|
2610
2747
|
}
|
|
2611
2748
|
}
|
|
2612
|
-
return
|
|
2749
|
+
return {
|
|
2613
2750
|
variantsAndElements,
|
|
2614
2751
|
experimentsInfo,
|
|
2615
2752
|
hasActivatedFrames,
|
|
2616
2753
|
laneClaims: updatedClaims,
|
|
2617
|
-
}
|
|
2754
|
+
};
|
|
2618
2755
|
}
|
|
2619
|
-
|
|
2620
|
-
const
|
|
2621
|
-
const
|
|
2622
|
-
|
|
2623
|
-
|
|
2756
|
+
function previewVariants(previewVariantIds, validatedClaims, ctx, silentFallback) {
|
|
2757
|
+
const previewRollouts = previewVariantIds.includes(ROLLOUTS_PREVIEW_ID);
|
|
2758
|
+
const requestedVariantIds = previewVariantIds.filter((id) => !isPreviewSentinel(id));
|
|
2759
|
+
const requestedVariants = findVariants(ctx.project.frames, requestedVariantIds);
|
|
2760
|
+
const requestedVariantsMissing = requestedVariantIds.length > 0 && requestedVariants.length === 0;
|
|
2761
|
+
if (requestedVariantsMissing && !previewRollouts && silentFallback) {
|
|
2624
2762
|
return null;
|
|
2625
|
-
const ids = raw
|
|
2626
|
-
.split(',')
|
|
2627
|
-
.map((id) => id.trim())
|
|
2628
|
-
.filter(Boolean);
|
|
2629
|
-
return ids.length > 0 ? ids.join(',') : null;
|
|
2630
|
-
}
|
|
2631
|
-
function readPreviewVariantIdFromUrl(url = window.location.href) {
|
|
2632
|
-
try {
|
|
2633
|
-
return normalizePreviewVariantId(getUrlSearchParams(url).get(COFRAME_PREVIEW_VARIANT_QUERY_PARAM));
|
|
2634
2763
|
}
|
|
2635
|
-
|
|
2636
|
-
|
|
2764
|
+
const requestedHoldout = requestedVariantIds.includes(ctx.project.holdout_info.holdout_variant_id);
|
|
2765
|
+
if (requestedVariantsMissing && !requestedHoldout && !silentFallback) {
|
|
2766
|
+
window.alert(`[Coframe] Variant preview unavailable: ${previewVariantIds.join(',')}.`);
|
|
2637
2767
|
}
|
|
2768
|
+
const rolledOutVariants = previewRollouts && !previewVariantIds.includes(GLOBAL_HOLDOUT)
|
|
2769
|
+
? assignFrames(keepRolledOutExperiments(activateFrames(ctx)), validatedClaims, ctx).variantsAndElements
|
|
2770
|
+
: [];
|
|
2771
|
+
return uniqueByVariantId([...rolledOutVariants, ...requestedVariants]);
|
|
2638
2772
|
}
|
|
2639
|
-
function
|
|
2640
|
-
|
|
2641
|
-
|
|
2642
|
-
|
|
2643
|
-
catch (_a) {
|
|
2644
|
-
return null;
|
|
2645
|
-
}
|
|
2773
|
+
function findVariants(frames, variantIds) {
|
|
2774
|
+
return frames.flatMap((frame) => frame.experiments.flatMap((experiment) => experiment.variants
|
|
2775
|
+
.filter((variant) => variantIds.includes(variant.id))
|
|
2776
|
+
.map((variant) => ({ variant, elements: frame.elements }))));
|
|
2646
2777
|
}
|
|
2647
|
-
function
|
|
2648
|
-
const
|
|
2649
|
-
|
|
2650
|
-
|
|
2651
|
-
|
|
2652
|
-
|
|
2653
|
-
|
|
2654
|
-
|
|
2655
|
-
|
|
2778
|
+
function uniqueByVariantId(items) {
|
|
2779
|
+
const seen = {};
|
|
2780
|
+
return items.filter(({ variant }) => {
|
|
2781
|
+
if (seen[variant.id])
|
|
2782
|
+
return false;
|
|
2783
|
+
seen[variant.id] = true;
|
|
2784
|
+
return true;
|
|
2785
|
+
});
|
|
2786
|
+
}
|
|
2787
|
+
function keepRolledOutExperiments(frames) {
|
|
2788
|
+
return frames.map((frame) => ({
|
|
2789
|
+
...frame,
|
|
2790
|
+
experiments: frame.experiments.filter((experiment) => experiment.metadata.serving_mode === 'winner'),
|
|
2791
|
+
}));
|
|
2656
2792
|
}
|
|
2657
2793
|
|
|
2658
2794
|
function buildSessionContext(isInitialApply) {
|
|
@@ -2938,29 +3074,27 @@ function createTreatmentAnalytics(Coframe, previewVariantId) {
|
|
|
2938
3074
|
});
|
|
2939
3075
|
}
|
|
2940
3076
|
}
|
|
2941
|
-
|
|
2942
|
-
|
|
2943
|
-
|
|
2944
|
-
|
|
2945
|
-
|
|
2946
|
-
|
|
2947
|
-
|
|
2948
|
-
|
|
2949
|
-
|
|
2950
|
-
|
|
2951
|
-
|
|
2952
|
-
|
|
2953
|
-
|
|
2954
|
-
|
|
2955
|
-
|
|
2956
|
-
|
|
2957
|
-
|
|
2958
|
-
|
|
2959
|
-
|
|
2960
|
-
|
|
2961
|
-
|
|
2962
|
-
});
|
|
2963
|
-
}
|
|
3077
|
+
const previewIds = splitPreviewVariantIds(previewVariantId).filter((id) => !isPreviewSentinel(id));
|
|
3078
|
+
for (const id of previewIds) {
|
|
3079
|
+
treatmentsData.push({
|
|
3080
|
+
impressionId: sessionId,
|
|
3081
|
+
userToken,
|
|
3082
|
+
experimentId: `preview_id_${id}`,
|
|
3083
|
+
holdoutExperimentId: `preview_holdout_id_${id}`,
|
|
3084
|
+
variantId: id,
|
|
3085
|
+
inGlobalHoldout: false,
|
|
3086
|
+
isBaseline: false,
|
|
3087
|
+
});
|
|
3088
|
+
treatmentsDataV2.push({
|
|
3089
|
+
coframe_experiment_id: `preview_id_${id}`,
|
|
3090
|
+
coframe_experiment_slug: `preview_id_${id}`,
|
|
3091
|
+
coframe_variant_id: id,
|
|
3092
|
+
coframe_variant_slug: id,
|
|
3093
|
+
coframe_user_token: userToken,
|
|
3094
|
+
coframe_impression_id: sessionId,
|
|
3095
|
+
coframe_in_global_holdout: false,
|
|
3096
|
+
coframe_in_exp_baseline: false,
|
|
3097
|
+
});
|
|
2964
3098
|
}
|
|
2965
3099
|
Coframe.treatmentsData = treatmentsData;
|
|
2966
3100
|
Coframe.treatmentsDataV2 = treatmentsDataV2;
|
|
@@ -3205,12 +3339,12 @@ async function ensureBody(Coframe, cdnProject, timeoutMs, nonce) {
|
|
|
3205
3339
|
}
|
|
3206
3340
|
const FLUSH_EVENTS_TIME = 1000 * 3;
|
|
3207
3341
|
let flushInterval = null;
|
|
3208
|
-
function setupFlushInterval(
|
|
3209
|
-
flushQueuedEvents(projectId);
|
|
3342
|
+
function setupFlushInterval(Coframe) {
|
|
3343
|
+
flushQueuedEvents(Coframe.projectId);
|
|
3210
3344
|
if (flushInterval !== null) {
|
|
3211
3345
|
clearInterval(flushInterval);
|
|
3212
3346
|
}
|
|
3213
|
-
flushInterval = setInterval(() => flushQueuedEvents(projectId), FLUSH_EVENTS_TIME);
|
|
3347
|
+
flushInterval = setInterval(() => flushQueuedEvents(Coframe.projectId), FLUSH_EVENTS_TIME);
|
|
3214
3348
|
}
|
|
3215
3349
|
function setupSPANavigation(Coframe, project, config, previewVariantId, isSessionVariant, applyVariants) {
|
|
3216
3350
|
var _a;
|
|
@@ -3258,7 +3392,7 @@ function setupSPANavigation(Coframe, project, config, previewVariantId, isSessio
|
|
|
3258
3392
|
else {
|
|
3259
3393
|
try {
|
|
3260
3394
|
const preview = resolvePreview(newPageUrl, previewVariantId, isSessionVariant);
|
|
3261
|
-
const result = await
|
|
3395
|
+
const result = await fetchProject(config.projectUrl, Coframe.projectId, newPageUrl, signal, config.userContext, preview.previewVariantId || undefined, undefined, (_a = config.referrer) !== null && _a !== void 0 ? _a : getBrowserReferrer());
|
|
3262
3396
|
if (signal.aborted)
|
|
3263
3397
|
return;
|
|
3264
3398
|
if (result) {
|
|
@@ -3356,7 +3490,7 @@ async function modifyPage(Coframe, configResult, projectResult, analytics) {
|
|
|
3356
3490
|
}
|
|
3357
3491
|
reportInitTiming(Coframe, cdnProject, integrationStartTime, executionStartTime);
|
|
3358
3492
|
setupSPANavigation(Coframe, cdnProject, config, previewVariantId, isSessionVariant, applyVariants);
|
|
3359
|
-
setupFlushInterval(Coframe
|
|
3493
|
+
setupFlushInterval(Coframe);
|
|
3360
3494
|
}
|
|
3361
3495
|
|
|
3362
3496
|
const TIMEOUT_MAX_MS = 5000;
|
|
@@ -3392,6 +3526,7 @@ async function resolveConfig(Coframe, revealPage) {
|
|
|
3392
3526
|
: null;
|
|
3393
3527
|
const executionStartTime = new Date();
|
|
3394
3528
|
Coframe.batchSize = config.batchSize || 32;
|
|
3529
|
+
configureIngestUrl(config.ingestUrl);
|
|
3395
3530
|
const gracefulExit = (msg) => {
|
|
3396
3531
|
console.warn(`[Coframe] ${msg}`);
|
|
3397
3532
|
revealPage();
|
|
@@ -3519,7 +3654,7 @@ async function resolveProject(Coframe, previewVariantId, isSessionVariant, confi
|
|
|
3519
3654
|
let personalizationHeaders = (projectData === null || projectData === void 0 ? void 0 : projectData.personalizationHeaders) || null;
|
|
3520
3655
|
let project = isSessionVariant ? undefined : projectData === null || projectData === void 0 ? void 0 : projectData.project;
|
|
3521
3656
|
if (!project) {
|
|
3522
|
-
const edgeResult = await
|
|
3657
|
+
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());
|
|
3523
3658
|
personalizationHeaders = (edgeResult === null || edgeResult === void 0 ? void 0 : edgeResult.personalizationHeaders) || null;
|
|
3524
3659
|
project = (edgeResult === null || edgeResult === void 0 ? void 0 : edgeResult.project) || undefined;
|
|
3525
3660
|
}
|
|
@@ -172,7 +172,9 @@ interface ExperimentMetadata {
|
|
|
172
172
|
audience_ids?: string[];
|
|
173
173
|
};
|
|
174
174
|
lane_ids?: string[];
|
|
175
|
+
serving_mode?: ServingMode;
|
|
175
176
|
}
|
|
177
|
+
type ServingMode = 'off' | 'split' | 'winner';
|
|
176
178
|
interface Allocation {
|
|
177
179
|
[variantId: string]: number[][];
|
|
178
180
|
}
|
|
@@ -246,6 +248,8 @@ type CoframeConfig = {
|
|
|
246
248
|
timeoutMs?: number;
|
|
247
249
|
timeoutBehavior?: 'exclude';
|
|
248
250
|
currentUrl?: string;
|
|
251
|
+
projectUrl?: string;
|
|
252
|
+
ingestUrl?: string;
|
|
249
253
|
referrer?: string;
|
|
250
254
|
userContext?: Record<string, unknown>;
|
|
251
255
|
nonce?: string;
|
|
@@ -175,7 +175,9 @@ interface ExperimentMetadata {
|
|
|
175
175
|
audience_ids?: string[];
|
|
176
176
|
};
|
|
177
177
|
lane_ids?: string[];
|
|
178
|
+
serving_mode?: ServingMode;
|
|
178
179
|
}
|
|
180
|
+
type ServingMode = 'off' | 'split' | 'winner';
|
|
179
181
|
interface Allocation {
|
|
180
182
|
[variantId: string]: number[][];
|
|
181
183
|
}
|
|
@@ -249,6 +251,8 @@ type CoframeConfig = {
|
|
|
249
251
|
timeoutMs?: number;
|
|
250
252
|
timeoutBehavior?: 'exclude';
|
|
251
253
|
currentUrl?: string;
|
|
254
|
+
projectUrl?: string;
|
|
255
|
+
ingestUrl?: string;
|
|
252
256
|
referrer?: string;
|
|
253
257
|
userContext?: Record<string, unknown>;
|
|
254
258
|
nonce?: string;
|
|
@@ -138,7 +138,9 @@ interface ExperimentMetadata {
|
|
|
138
138
|
audience_ids?: string[];
|
|
139
139
|
};
|
|
140
140
|
lane_ids?: string[];
|
|
141
|
+
serving_mode?: ServingMode;
|
|
141
142
|
}
|
|
143
|
+
type ServingMode = 'off' | 'split' | 'winner';
|
|
142
144
|
interface Allocation {
|
|
143
145
|
[variantId: string]: number[][];
|
|
144
146
|
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@coframe/sdk",
|
|
3
|
-
"version": "1.1.
|
|
3
|
+
"version": "1.1.21",
|
|
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",
|