@runbandit/sdk 3.4.0 → 3.5.1
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 +1 -1
- package/dist/{decision-cookie-CNIp56yQ.d.ts → decision-cookie-g9aDdSx9.d.ts} +11 -4
- package/dist/index.d.ts +60 -4
- package/dist/index.js +302 -9
- package/dist/index.js.map +1 -1
- package/dist/server.d.ts +2 -2
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -614,7 +614,7 @@ function matchesConversionPath(pattern, pathname) {
|
|
|
614
614
|
}
|
|
615
615
|
|
|
616
616
|
// ../shared/dist/site.js
|
|
617
|
-
var SITE_TARGET_KINDS = ["text", "image"];
|
|
617
|
+
var SITE_TARGET_KINDS = ["text", "image", "order"];
|
|
618
618
|
var TAG_NAME = /^[a-z][a-z0-9-]*$/;
|
|
619
619
|
function collapseWhitespace(raw) {
|
|
620
620
|
return raw.replace(/\s+/g, " ").trim();
|
|
@@ -649,13 +649,13 @@ function parseSiteContent(config) {
|
|
|
649
649
|
}
|
|
650
650
|
function normalizeSiteTarget(target) {
|
|
651
651
|
if (!SITE_TARGET_KINDS.includes(target.kind))
|
|
652
|
-
throw new Error("A target is text or
|
|
652
|
+
throw new Error("A target is text, an image, or a list");
|
|
653
653
|
return {
|
|
654
654
|
page: requirePage(target.page),
|
|
655
655
|
selector: requireText(target.selector, "The picked element has no selector"),
|
|
656
656
|
tag: requireTag(target.tag),
|
|
657
657
|
kind: target.kind,
|
|
658
|
-
original: requireText(target.original, "The picked element has no content to replace")
|
|
658
|
+
original: target.kind === "order" ? formatOrder(parseOrder(target.original)) : requireText(target.original, "The picked element has no content to replace")
|
|
659
659
|
};
|
|
660
660
|
}
|
|
661
661
|
function normalizeFunnelGoal(goal) {
|
|
@@ -679,6 +679,39 @@ function goalMatchesPage(goal, pathname) {
|
|
|
679
679
|
var MAX_ALTERNATIVES = 5;
|
|
680
680
|
var MAX_TEXT_ALTERNATIVE_LENGTH = 300;
|
|
681
681
|
var MAX_IMAGE_URL_LENGTH = 2048;
|
|
682
|
+
var MIN_ORDER_ITEMS = 2;
|
|
683
|
+
var MAX_ORDER_ITEMS = 24;
|
|
684
|
+
var MAX_ORDER_KEY_LENGTH = 160;
|
|
685
|
+
function formatOrder(keys) {
|
|
686
|
+
return JSON.stringify(keys);
|
|
687
|
+
}
|
|
688
|
+
function parseOrder(raw) {
|
|
689
|
+
let value;
|
|
690
|
+
try {
|
|
691
|
+
value = JSON.parse(raw);
|
|
692
|
+
} catch {
|
|
693
|
+
throw new Error("An order is a list of the items in the order to show them");
|
|
694
|
+
}
|
|
695
|
+
if (!Array.isArray(value) || !value.every((key) => typeof key === "string" && key.length > 0)) {
|
|
696
|
+
throw new Error("An order is a list of the items in the order to show them");
|
|
697
|
+
}
|
|
698
|
+
const keys = value;
|
|
699
|
+
if (keys.length < MIN_ORDER_ITEMS)
|
|
700
|
+
throw new Error(`A list needs at least ${MIN_ORDER_ITEMS} items`);
|
|
701
|
+
if (keys.length > MAX_ORDER_ITEMS)
|
|
702
|
+
throw new Error(`Reorder lists of at most ${MAX_ORDER_ITEMS} items`);
|
|
703
|
+
if (keys.some((key) => key.length > MAX_ORDER_KEY_LENGTH))
|
|
704
|
+
throw new Error("An item in that list is too long");
|
|
705
|
+
if (new Set(keys).size !== keys.length)
|
|
706
|
+
throw new Error("Every item in the list must be different");
|
|
707
|
+
return keys;
|
|
708
|
+
}
|
|
709
|
+
function isReorderOf(original, order) {
|
|
710
|
+
if (original.length !== order.length)
|
|
711
|
+
return false;
|
|
712
|
+
const remaining = new Set(original);
|
|
713
|
+
return order.every((key) => remaining.delete(key));
|
|
714
|
+
}
|
|
682
715
|
var SUGGESTED_SITE_EXPERIMENTS = 3;
|
|
683
716
|
function moreExperimentsSentence(running, suggested) {
|
|
684
717
|
const noun = (count) => count === 1 ? "experiment" : "experiments";
|
|
@@ -707,6 +740,8 @@ function parseAlternative(kind, raw) {
|
|
|
707
740
|
}
|
|
708
741
|
return text;
|
|
709
742
|
}
|
|
743
|
+
if (kind === "order")
|
|
744
|
+
return formatOrder(parseOrder(raw));
|
|
710
745
|
const trimmed = raw.trim();
|
|
711
746
|
if (trimmed.length > MAX_IMAGE_URL_LENGTH)
|
|
712
747
|
throw new Error("That image address is too long");
|
|
@@ -722,8 +757,8 @@ function parseAlternative(kind, raw) {
|
|
|
722
757
|
}
|
|
723
758
|
var PICK_CHANNEL = "bandit-pick";
|
|
724
759
|
var PICK_PROTOCOL_VERSION = 1;
|
|
725
|
-
var PICK_MODES = ["idle", "target", "goal-click"];
|
|
726
|
-
var PICK_REJECTIONS = ["not-text-or-image", "has-markup", "not-clickable", "no-selector"];
|
|
760
|
+
var PICK_MODES = ["idle", "target", "order", "goal-click"];
|
|
761
|
+
var PICK_REJECTIONS = ["not-text-or-image", "has-markup", "not-a-list", "not-clickable", "no-selector"];
|
|
727
762
|
var PICK_TOKEN_PREFIX = "bpick_";
|
|
728
763
|
function pickEnvelope(msg) {
|
|
729
764
|
return { channel: PICK_CHANNEL, v: PICK_PROTOCOL_VERSION, msg };
|
|
@@ -806,6 +841,20 @@ function parsePanelMessage(data) {
|
|
|
806
841
|
// ../shared/dist/site-platforms.js
|
|
807
842
|
var SITE_PLATFORMS = [
|
|
808
843
|
{ id: "shopify", label: "Shopify", path: "shopify", codeBox: "", steps: [] },
|
|
844
|
+
{
|
|
845
|
+
id: "shopify_theme",
|
|
846
|
+
label: "Shopify",
|
|
847
|
+
path: "script",
|
|
848
|
+
codeBox: "Online Store, Themes, Edit code, layout/theme.liquid, just before </head>.",
|
|
849
|
+
steps: [
|
|
850
|
+
"In your Shopify admin open Online Store, then Themes.",
|
|
851
|
+
"On your live theme click the three dots, then Edit code.",
|
|
852
|
+
"Open layout/theme.liquid.",
|
|
853
|
+
"Paste the script on the line just before </head>.",
|
|
854
|
+
"Click Save.",
|
|
855
|
+
"Then add the purchase pixel below, so Bandit learns from orders."
|
|
856
|
+
]
|
|
857
|
+
},
|
|
809
858
|
{
|
|
810
859
|
id: "webflow",
|
|
811
860
|
label: "Webflow",
|
|
@@ -1148,6 +1197,9 @@ function touchFromPage(page) {
|
|
|
1148
1197
|
const trackingParam = Object.keys(TRACKING_PARAM_SOURCES).find((name) => params.has(name));
|
|
1149
1198
|
if (trackingParam)
|
|
1150
1199
|
touch.trackingParam = trackingParam;
|
|
1200
|
+
const klaviyoExchangeId = params.get("_kx");
|
|
1201
|
+
if (klaviyoExchangeId)
|
|
1202
|
+
touch.klaviyoExchangeId = klaviyoExchangeId;
|
|
1151
1203
|
const referrerHost = normalizeHost(safeUrl(page.referrer)?.hostname);
|
|
1152
1204
|
if (referrerHost && referrerHost !== normalizeHost(url.hostname))
|
|
1153
1205
|
touch.referrerHost = referrerHost;
|
|
@@ -1160,7 +1212,8 @@ function touchSignature(touch) {
|
|
|
1160
1212
|
touch.utmCampaign ?? "",
|
|
1161
1213
|
touch.utmContent ?? "",
|
|
1162
1214
|
touch.trackingParam ?? "",
|
|
1163
|
-
touch.referrerHost ?? ""
|
|
1215
|
+
touch.referrerHost ?? "",
|
|
1216
|
+
touch.klaviyoExchangeId ?? ""
|
|
1164
1217
|
]);
|
|
1165
1218
|
}
|
|
1166
1219
|
function shouldReportTouch(touch, stored, sessionId, now) {
|
|
@@ -1201,6 +1254,100 @@ function sourceOf(arrival) {
|
|
|
1201
1254
|
return { key: "ch:tagged", label: "Tagged" };
|
|
1202
1255
|
}
|
|
1203
1256
|
|
|
1257
|
+
// ../shared/dist/cdp-aliases.js
|
|
1258
|
+
var CDP_SOURCES = ["segment", "rudderstack", "posthog"];
|
|
1259
|
+
var MAX_CDP_EXTERNAL_ID_LENGTH = 256;
|
|
1260
|
+
var RUDDERSTACK_ENCRYPTED_PREFIX = "RS_ENC_v3_";
|
|
1261
|
+
var RUDDERSTACK_LEGACY_ENCRYPTED_PREFIX = "RudderEncrypt:";
|
|
1262
|
+
function decoded(raw) {
|
|
1263
|
+
try {
|
|
1264
|
+
return decodeURIComponent(raw);
|
|
1265
|
+
} catch {
|
|
1266
|
+
return raw;
|
|
1267
|
+
}
|
|
1268
|
+
}
|
|
1269
|
+
function jsonValue(text) {
|
|
1270
|
+
try {
|
|
1271
|
+
return JSON.parse(text);
|
|
1272
|
+
} catch {
|
|
1273
|
+
return void 0;
|
|
1274
|
+
}
|
|
1275
|
+
}
|
|
1276
|
+
function nonEmpty(value) {
|
|
1277
|
+
return typeof value === "string" && value.length > 0 ? value : null;
|
|
1278
|
+
}
|
|
1279
|
+
function plainOrQuoted(raw) {
|
|
1280
|
+
const text = decoded(raw);
|
|
1281
|
+
return nonEmpty(text.startsWith('"') ? jsonValue(text) : text);
|
|
1282
|
+
}
|
|
1283
|
+
function rudderstackValue(raw) {
|
|
1284
|
+
const text = plainOrQuoted(raw);
|
|
1285
|
+
if (text === null || text.startsWith(RUDDERSTACK_LEGACY_ENCRYPTED_PREFIX))
|
|
1286
|
+
return null;
|
|
1287
|
+
if (!text.startsWith(RUDDERSTACK_ENCRYPTED_PREFIX))
|
|
1288
|
+
return text;
|
|
1289
|
+
try {
|
|
1290
|
+
return nonEmpty(jsonValue(atob(text.slice(RUDDERSTACK_ENCRYPTED_PREFIX.length))));
|
|
1291
|
+
} catch {
|
|
1292
|
+
return null;
|
|
1293
|
+
}
|
|
1294
|
+
}
|
|
1295
|
+
function posthogDistinctId(raw) {
|
|
1296
|
+
const parsed = jsonValue(decoded(raw));
|
|
1297
|
+
if (typeof parsed !== "object" || parsed === null)
|
|
1298
|
+
return null;
|
|
1299
|
+
const state = parsed;
|
|
1300
|
+
const deviceId = nonEmpty(state.$device_id);
|
|
1301
|
+
if (deviceId !== null)
|
|
1302
|
+
return deviceId;
|
|
1303
|
+
return state.$user_state === "identified" ? null : nonEmpty(state.distinct_id);
|
|
1304
|
+
}
|
|
1305
|
+
var CDP_SOURCE_REGISTRY = [
|
|
1306
|
+
{ source: "segment", key: /^ajs_anonymous_id$/, parse: plainOrQuoted },
|
|
1307
|
+
{ source: "rudderstack", key: /^rl_anonymous_id$/, parse: rudderstackValue },
|
|
1308
|
+
{ source: "posthog", key: /^ph_.+_posthog$/, parse: posthogDistinctId }
|
|
1309
|
+
];
|
|
1310
|
+
function cookiePairs(header) {
|
|
1311
|
+
const pairs = [];
|
|
1312
|
+
for (const part of header.split(";")) {
|
|
1313
|
+
const index = part.indexOf("=");
|
|
1314
|
+
if (index === -1)
|
|
1315
|
+
continue;
|
|
1316
|
+
pairs.push([part.slice(0, index).trim(), part.slice(index + 1).trim()]);
|
|
1317
|
+
}
|
|
1318
|
+
return pairs;
|
|
1319
|
+
}
|
|
1320
|
+
function storagePairs(storage) {
|
|
1321
|
+
const pairs = [];
|
|
1322
|
+
try {
|
|
1323
|
+
for (let i = 0; i < (storage?.length ?? 0); i++) {
|
|
1324
|
+
const key = storage.key(i);
|
|
1325
|
+
const value = key === null ? null : storage.getItem(key);
|
|
1326
|
+
if (key !== null && value !== null)
|
|
1327
|
+
pairs.push([key, value]);
|
|
1328
|
+
}
|
|
1329
|
+
} catch {
|
|
1330
|
+
return pairs;
|
|
1331
|
+
}
|
|
1332
|
+
return pairs;
|
|
1333
|
+
}
|
|
1334
|
+
function readCdpAliases(cookieHeader, storage) {
|
|
1335
|
+
const candidates = [...cookiePairs(cookieHeader), ...storagePairs(storage)];
|
|
1336
|
+
const aliases = [];
|
|
1337
|
+
for (const { source, key, parse } of CDP_SOURCE_REGISTRY) {
|
|
1338
|
+
for (const [name, raw] of candidates) {
|
|
1339
|
+
if (!key.test(name))
|
|
1340
|
+
continue;
|
|
1341
|
+
const externalId = parse(raw);
|
|
1342
|
+
if (externalId === null || externalId.length > MAX_CDP_EXTERNAL_ID_LENGTH)
|
|
1343
|
+
continue;
|
|
1344
|
+
aliases.push({ source, externalId });
|
|
1345
|
+
break;
|
|
1346
|
+
}
|
|
1347
|
+
}
|
|
1348
|
+
return aliases;
|
|
1349
|
+
}
|
|
1350
|
+
|
|
1204
1351
|
// ../shared/dist/payout-unit.js
|
|
1205
1352
|
var PAYOUT_UNITS = ["count", "revenue", "margin"];
|
|
1206
1353
|
var NEW_PAYOUT_UNIT = "count";
|
|
@@ -1246,6 +1393,24 @@ function formatPayout(unit, value) {
|
|
|
1246
1393
|
return isCurrencyUnit(unit) ? USD.format(value) : value.toLocaleString("en-US", { maximumFractionDigits: 2 });
|
|
1247
1394
|
}
|
|
1248
1395
|
|
|
1396
|
+
// ../shared/dist/trial-rule.js
|
|
1397
|
+
var TRIAL_RULES = ["served", "exposure"];
|
|
1398
|
+
function isTrialRule(value) {
|
|
1399
|
+
return value === "served" || value === "exposure";
|
|
1400
|
+
}
|
|
1401
|
+
function trialRuleFor({ target, requested }) {
|
|
1402
|
+
if (requested)
|
|
1403
|
+
return requested;
|
|
1404
|
+
return target ? "exposure" : "served";
|
|
1405
|
+
}
|
|
1406
|
+
function trialRuleOf(experiment) {
|
|
1407
|
+
return experiment.trialOn ?? "served";
|
|
1408
|
+
}
|
|
1409
|
+
var TRIAL_RULE_COPY = {
|
|
1410
|
+
served: "Counts a trial when served",
|
|
1411
|
+
exposure: "Counts a trial when seen"
|
|
1412
|
+
};
|
|
1413
|
+
|
|
1249
1414
|
// src/client.ts
|
|
1250
1415
|
var ARRIVAL_KEY = "bandits_arrival";
|
|
1251
1416
|
function readStoredArrival(storage) {
|
|
@@ -1257,6 +1422,22 @@ function readStoredArrival(storage) {
|
|
|
1257
1422
|
return null;
|
|
1258
1423
|
}
|
|
1259
1424
|
}
|
|
1425
|
+
var CDP_ALIASES_KEY = "bandits_cdp_aliases";
|
|
1426
|
+
function readSentAliases(storage, visitorId) {
|
|
1427
|
+
try {
|
|
1428
|
+
const parsed = JSON.parse(storage?.getItem(CDP_ALIASES_KEY) ?? "null");
|
|
1429
|
+
return parsed?.visitorId === visitorId && typeof parsed.sent === "object" && parsed.sent !== null ? parsed.sent : {};
|
|
1430
|
+
} catch {
|
|
1431
|
+
return {};
|
|
1432
|
+
}
|
|
1433
|
+
}
|
|
1434
|
+
function readCookieHeader() {
|
|
1435
|
+
try {
|
|
1436
|
+
return document.cookie ?? "";
|
|
1437
|
+
} catch {
|
|
1438
|
+
return "";
|
|
1439
|
+
}
|
|
1440
|
+
}
|
|
1260
1441
|
var BanditsRequestError = class extends Error {
|
|
1261
1442
|
status;
|
|
1262
1443
|
constructor(message, status) {
|
|
@@ -1279,6 +1460,8 @@ var BanditsClient = class {
|
|
|
1279
1460
|
namedEventQueue = [];
|
|
1280
1461
|
sessionId;
|
|
1281
1462
|
visitorId;
|
|
1463
|
+
exposureQueue = [];
|
|
1464
|
+
exposedIds = /* @__PURE__ */ new Set();
|
|
1282
1465
|
flushTimer;
|
|
1283
1466
|
constructor(config) {
|
|
1284
1467
|
this.config = {
|
|
@@ -1292,6 +1475,32 @@ var BanditsClient = class {
|
|
|
1292
1475
|
this.visitorId = config.visitorId ?? getOrCreateVisitorId(defaultSessionStorage());
|
|
1293
1476
|
this.startBatchFlush();
|
|
1294
1477
|
if (config.captureArrival !== false) void this.reportArrival();
|
|
1478
|
+
if (config.captureCdpAliases !== false) void this.reportCdpAliases();
|
|
1479
|
+
}
|
|
1480
|
+
async reportCdpAliases() {
|
|
1481
|
+
if (typeof document === "undefined") return false;
|
|
1482
|
+
const storage = defaultSessionStorage();
|
|
1483
|
+
const sent = readSentAliases(storage, this.visitorId);
|
|
1484
|
+
const fresh = readCdpAliases(readCookieHeader(), storage).filter(({ source, externalId }) => sent[source] !== externalId);
|
|
1485
|
+
if (fresh.length === 0) return false;
|
|
1486
|
+
try {
|
|
1487
|
+
await this.aliasVisitor(fresh);
|
|
1488
|
+
} catch {
|
|
1489
|
+
return false;
|
|
1490
|
+
}
|
|
1491
|
+
const record = { visitorId: this.visitorId, sent: { ...sent, ...Object.fromEntries(fresh.map((a) => [a.source, a.externalId])) } };
|
|
1492
|
+
try {
|
|
1493
|
+
storage?.setItem(CDP_ALIASES_KEY, JSON.stringify(record));
|
|
1494
|
+
} catch {
|
|
1495
|
+
return true;
|
|
1496
|
+
}
|
|
1497
|
+
return true;
|
|
1498
|
+
}
|
|
1499
|
+
async aliasVisitor(aliases) {
|
|
1500
|
+
const response = await this.makeRequest("/aliases", "POST", { visitorId: this.visitorId, aliases });
|
|
1501
|
+
if (!response.success) {
|
|
1502
|
+
throw requestError(response, "Failed to alias visitor");
|
|
1503
|
+
}
|
|
1295
1504
|
}
|
|
1296
1505
|
async reportArrival() {
|
|
1297
1506
|
if (typeof location === "undefined" || typeof document === "undefined") return false;
|
|
@@ -1336,7 +1545,8 @@ var BanditsClient = class {
|
|
|
1336
1545
|
experimentId,
|
|
1337
1546
|
userId,
|
|
1338
1547
|
config: assignment.treatment?.config || {},
|
|
1339
|
-
funnelId: assignment.funnelId
|
|
1548
|
+
funnelId: assignment.funnelId,
|
|
1549
|
+
trialOn: assignment.trialOn
|
|
1340
1550
|
};
|
|
1341
1551
|
}
|
|
1342
1552
|
trackNamedEvent(event, opts) {
|
|
@@ -1373,6 +1583,12 @@ var BanditsClient = class {
|
|
|
1373
1583
|
}
|
|
1374
1584
|
}
|
|
1375
1585
|
async flush() {
|
|
1586
|
+
const results = await Promise.allSettled([this.flushNamedEvents(), this.flushExposures()]);
|
|
1587
|
+
for (const result of results) {
|
|
1588
|
+
if (result.status === "rejected") throw result.reason;
|
|
1589
|
+
}
|
|
1590
|
+
}
|
|
1591
|
+
async flushNamedEvents() {
|
|
1376
1592
|
const namedEvents = [...this.namedEventQueue];
|
|
1377
1593
|
this.namedEventQueue = [];
|
|
1378
1594
|
if (namedEvents.length === 0) return;
|
|
@@ -1391,14 +1607,75 @@ var BanditsClient = class {
|
|
|
1391
1607
|
throw error;
|
|
1392
1608
|
}
|
|
1393
1609
|
}
|
|
1394
|
-
async
|
|
1610
|
+
async flushExposures() {
|
|
1611
|
+
const exposures = [...this.exposureQueue];
|
|
1612
|
+
this.exposureQueue = [];
|
|
1613
|
+
if (exposures.length === 0) return;
|
|
1614
|
+
try {
|
|
1615
|
+
await fetch(`${this.normalizeApiUrl()}/exposures`, {
|
|
1616
|
+
method: "POST",
|
|
1617
|
+
headers: {
|
|
1618
|
+
"Authorization": `Bearer ${this.config.apiKey}`,
|
|
1619
|
+
"Content-Type": "application/json"
|
|
1620
|
+
},
|
|
1621
|
+
body: JSON.stringify({ exposures }),
|
|
1622
|
+
keepalive: true
|
|
1623
|
+
});
|
|
1624
|
+
} catch (error) {
|
|
1625
|
+
this.exposureQueue.unshift(...exposures);
|
|
1626
|
+
throw error;
|
|
1627
|
+
}
|
|
1628
|
+
}
|
|
1629
|
+
exposed(assignmentId, opts) {
|
|
1630
|
+
if (this.exposedIds.has(assignmentId)) return;
|
|
1631
|
+
this.exposedIds.add(assignmentId);
|
|
1632
|
+
this.exposureQueue.push({ assignmentId, exposedAt: Date.now() });
|
|
1633
|
+
if (opts?.immediate || this.exposureQueue.length >= this.config.batchSize) {
|
|
1634
|
+
this.flushExposures().catch(console.error);
|
|
1635
|
+
}
|
|
1636
|
+
}
|
|
1637
|
+
observeExposure(assignmentId, element, opts) {
|
|
1638
|
+
if (typeof IntersectionObserver === "undefined") return () => {
|
|
1639
|
+
};
|
|
1640
|
+
const threshold = opts?.threshold ?? 0.5;
|
|
1641
|
+
const dwellMs = opts?.dwellMs ?? 1e3;
|
|
1642
|
+
let dwell;
|
|
1643
|
+
const stop = () => {
|
|
1644
|
+
clearTimeout(dwell);
|
|
1645
|
+
dwell = void 0;
|
|
1646
|
+
};
|
|
1647
|
+
const observer = new IntersectionObserver(
|
|
1648
|
+
(entries) => {
|
|
1649
|
+
const entry = entries[entries.length - 1];
|
|
1650
|
+
if (!entry) return;
|
|
1651
|
+
const coversViewport = entry.rootBounds != null && entry.intersectionRect.height >= threshold * entry.rootBounds.height;
|
|
1652
|
+
if (entry.isIntersecting && (entry.intersectionRatio >= threshold || coversViewport)) {
|
|
1653
|
+
dwell ??= setTimeout(() => {
|
|
1654
|
+
this.exposed(assignmentId);
|
|
1655
|
+
disconnect();
|
|
1656
|
+
}, dwellMs);
|
|
1657
|
+
} else {
|
|
1658
|
+
stop();
|
|
1659
|
+
}
|
|
1660
|
+
},
|
|
1661
|
+
{ threshold: Array.from({ length: 21 }, (_, i) => i / 20) }
|
|
1662
|
+
);
|
|
1663
|
+
const disconnect = () => {
|
|
1664
|
+
stop();
|
|
1665
|
+
observer.disconnect();
|
|
1666
|
+
};
|
|
1667
|
+
observer.observe(element);
|
|
1668
|
+
return disconnect;
|
|
1669
|
+
}
|
|
1670
|
+
async identify(anonymousId, identifiedUserId, mergeReason, options) {
|
|
1395
1671
|
const response = await this.makeRequest(
|
|
1396
1672
|
"/identify",
|
|
1397
1673
|
"POST",
|
|
1398
1674
|
{
|
|
1399
1675
|
anonymousId,
|
|
1400
1676
|
identifiedUserId,
|
|
1401
|
-
mergeReason: mergeReason || "manual"
|
|
1677
|
+
mergeReason: mergeReason || "manual",
|
|
1678
|
+
...options?.email ? { email: options.email } : {}
|
|
1402
1679
|
}
|
|
1403
1680
|
);
|
|
1404
1681
|
if (!response.success) {
|
|
@@ -1412,6 +1689,7 @@ var BanditsClient = class {
|
|
|
1412
1689
|
}
|
|
1413
1690
|
}
|
|
1414
1691
|
async trackFunnelReward(funnelId, userId, value) {
|
|
1692
|
+
await this.flushExposures().catch(() => void 0);
|
|
1415
1693
|
const response = await this.makeRequest(
|
|
1416
1694
|
`/funnels/${funnelId}/reward`,
|
|
1417
1695
|
"POST",
|
|
@@ -1725,6 +2003,8 @@ export {
|
|
|
1725
2003
|
BanditsClient as BanditClient,
|
|
1726
2004
|
BanditsClient,
|
|
1727
2005
|
BanditsRequestError,
|
|
2006
|
+
CDP_SOURCES,
|
|
2007
|
+
CDP_SOURCE_REGISTRY,
|
|
1728
2008
|
CHANNEL_LABELS,
|
|
1729
2009
|
CHANNEL_RULES,
|
|
1730
2010
|
CONTENT_TYPE_BY_KIND,
|
|
@@ -1739,12 +2019,16 @@ export {
|
|
|
1739
2019
|
FunnelStatus,
|
|
1740
2020
|
MAX_ALTERNATIVES,
|
|
1741
2021
|
MAX_ARRIVAL_VALUE_LENGTH,
|
|
2022
|
+
MAX_CDP_EXTERNAL_ID_LENGTH,
|
|
1742
2023
|
MAX_IMAGE_URL_LENGTH,
|
|
1743
2024
|
MAX_ORDERING_ITEMS,
|
|
2025
|
+
MAX_ORDER_ITEMS,
|
|
2026
|
+
MAX_ORDER_KEY_LENGTH,
|
|
1744
2027
|
MAX_RAW_TOUCH_VALUE_LENGTH,
|
|
1745
2028
|
MAX_REFERRER_HOST_LENGTH,
|
|
1746
2029
|
MAX_TEXT_ALTERNATIVE_LENGTH,
|
|
1747
2030
|
MIN_ORDERING_ITEMS,
|
|
2031
|
+
MIN_ORDER_ITEMS,
|
|
1748
2032
|
NEW_PAYOUT_UNIT,
|
|
1749
2033
|
PASS_THROUGH_HOSTS,
|
|
1750
2034
|
PAYOUT_UNITS,
|
|
@@ -1768,6 +2052,8 @@ export {
|
|
|
1768
2052
|
SUGGESTED_SITE_EXPERIMENTS,
|
|
1769
2053
|
SnapshotClient,
|
|
1770
2054
|
TRACKING_PARAM_SOURCES,
|
|
2055
|
+
TRIAL_RULES,
|
|
2056
|
+
TRIAL_RULE_COPY,
|
|
1771
2057
|
UNKNOWN_SOURCE_KEY,
|
|
1772
2058
|
UTM_PARAMS,
|
|
1773
2059
|
VISITOR_COOKIE,
|
|
@@ -1781,6 +2067,7 @@ export {
|
|
|
1781
2067
|
extractEmailLinks,
|
|
1782
2068
|
extractSlotNames,
|
|
1783
2069
|
extractSubdomain,
|
|
2070
|
+
formatOrder,
|
|
1784
2071
|
formatPayout,
|
|
1785
2072
|
generateId,
|
|
1786
2073
|
generateSubdomain,
|
|
@@ -1796,8 +2083,10 @@ export {
|
|
|
1796
2083
|
isPassThroughHost,
|
|
1797
2084
|
isPayoutUnit,
|
|
1798
2085
|
isPlacement,
|
|
2086
|
+
isReorderOf,
|
|
1799
2087
|
isShopifyCdnUrl,
|
|
1800
2088
|
isSlotBinding,
|
|
2089
|
+
isTrialRule,
|
|
1801
2090
|
isValidEmail,
|
|
1802
2091
|
isValidSubdomain,
|
|
1803
2092
|
kindOfPlacement,
|
|
@@ -1814,6 +2103,7 @@ export {
|
|
|
1814
2103
|
normalizeTreatmentWeights,
|
|
1815
2104
|
parseAlternative,
|
|
1816
2105
|
parseDecisions,
|
|
2106
|
+
parseOrder,
|
|
1817
2107
|
parsePanelMessage,
|
|
1818
2108
|
parsePickerMessage,
|
|
1819
2109
|
parseSiteContent,
|
|
@@ -1824,6 +2114,7 @@ export {
|
|
|
1824
2114
|
pickStep,
|
|
1825
2115
|
pickTreatment,
|
|
1826
2116
|
platformById,
|
|
2117
|
+
readCdpAliases,
|
|
1827
2118
|
readCookie,
|
|
1828
2119
|
renderEmail,
|
|
1829
2120
|
renderEmailDocument,
|
|
@@ -1842,6 +2133,8 @@ export {
|
|
|
1842
2133
|
targetMatchesPage,
|
|
1843
2134
|
touchFromPage,
|
|
1844
2135
|
touchSignature,
|
|
2136
|
+
trialRuleFor,
|
|
2137
|
+
trialRuleOf,
|
|
1845
2138
|
uniformFor,
|
|
1846
2139
|
validateTreatmentWeights,
|
|
1847
2140
|
verifyEmailToken
|