@mparticle/web-sdk 3.16.1 → 3.17.0
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 +4 -3
- package/dist/mparticle.common.js +32 -15
- package/dist/mparticle.esm.js +32 -15
- package/dist/mparticle.js +435 -4
- package/dist/types/src/checkoutIntentClassifier.d.ts +4 -0
- package/dist/types/src/checkoutIntentTracker.d.ts +23 -0
- package/dist/types/src/constants.d.ts +1 -0
- package/dist/types/src/internal-types.d.ts +1 -1
- package/dist/types/src/mp-instance.d.ts +2 -0
- package/dist/types/src/roktManager.d.ts +11 -0
- package/dist/types/src/store.d.ts +1 -0
- package/package.json +1 -1
- package/src/checkoutIntentClassifier.ts +231 -0
- package/src/checkoutIntentTracker.ts +244 -0
- package/src/constants.ts +1 -0
- package/src/internal-types.ts +1 -0
- package/src/mp-instance.ts +38 -1
- package/src/roktManager.ts +76 -0
- package/src/store.ts +4 -1
package/dist/mparticle.js
CHANGED
|
@@ -204,7 +204,7 @@ var mParticle = (function () {
|
|
|
204
204
|
Base64: Base64$1
|
|
205
205
|
};
|
|
206
206
|
|
|
207
|
-
var version = "3.
|
|
207
|
+
var version = "3.17.0";
|
|
208
208
|
|
|
209
209
|
var Constants = {
|
|
210
210
|
sdkVersion: version,
|
|
@@ -379,7 +379,8 @@ var mParticle = (function () {
|
|
|
379
379
|
// - 'roktonly' → capture only Rokt-related IDs
|
|
380
380
|
CaptureIntegrationSpecificIdsV2: 'captureIntegrationSpecificIds.V2',
|
|
381
381
|
AstBackgroundEvents: 'astBackgroundEvents',
|
|
382
|
-
AutoLogPageView: 'autoLogPageView'
|
|
382
|
+
AutoLogPageView: 'autoLogPageView',
|
|
383
|
+
CheckoutIntent: 'checkoutIntent'
|
|
383
384
|
},
|
|
384
385
|
DefaultInstance: 'default_instance',
|
|
385
386
|
CCPAPurpose: 'data_sale_opt_out',
|
|
@@ -5788,7 +5789,8 @@ var mParticle = (function () {
|
|
|
5788
5789
|
CaptureIntegrationSpecificIds = _a.CaptureIntegrationSpecificIds,
|
|
5789
5790
|
CaptureIntegrationSpecificIdsV2 = _a.CaptureIntegrationSpecificIdsV2,
|
|
5790
5791
|
AstBackgroundEvents = _a.AstBackgroundEvents,
|
|
5791
|
-
AutoLogPageView = _a.AutoLogPageView
|
|
5792
|
+
AutoLogPageView = _a.AutoLogPageView,
|
|
5793
|
+
CheckoutIntent = _a.CheckoutIntent;
|
|
5792
5794
|
if (!config.flags) {
|
|
5793
5795
|
return {};
|
|
5794
5796
|
}
|
|
@@ -5805,6 +5807,7 @@ var mParticle = (function () {
|
|
|
5805
5807
|
flags[CaptureIntegrationSpecificIdsV2] = config.flags[CaptureIntegrationSpecificIdsV2] || 'none';
|
|
5806
5808
|
flags[AstBackgroundEvents] = config.flags[AstBackgroundEvents] === 'True';
|
|
5807
5809
|
flags[AutoLogPageView] = config.flags[AutoLogPageView] === 'True';
|
|
5810
|
+
flags[CheckoutIntent] = config.flags[CheckoutIntent] === 'True';
|
|
5808
5811
|
return flags;
|
|
5809
5812
|
}
|
|
5810
5813
|
function processBaseUrls(config, flags, apiKey) {
|
|
@@ -10624,6 +10627,8 @@ var mParticle = (function () {
|
|
|
10624
10627
|
}
|
|
10625
10628
|
|
|
10626
10629
|
var PASSBACK_CONVERSION_TRACKING_ID = 'passbackconversiontrackingid';
|
|
10630
|
+
var CHECKOUT_INTENT_BUFFER_LIMIT = 4;
|
|
10631
|
+
var CHECKOUT_INTENT_MAX_AGE_MS = 30000;
|
|
10627
10632
|
var ON_SHOPPABLE_ADS_READY_METHOD = 'onShoppableAdsReady';
|
|
10628
10633
|
// The purpose of this class is to create a link between the Core mParticle SDK and the
|
|
10629
10634
|
// Rokt Web SDK via a Web Kit.
|
|
@@ -10649,6 +10654,8 @@ var mParticle = (function () {
|
|
|
10649
10654
|
this.initialized = false;
|
|
10650
10655
|
this.isShoppableAdsLoaded = false;
|
|
10651
10656
|
this.stopRouteChangeWatch = null;
|
|
10657
|
+
// Checkout intent raised before the kit attached: latest per kind.
|
|
10658
|
+
this.pendingCheckoutIntents = [];
|
|
10652
10659
|
}
|
|
10653
10660
|
/**
|
|
10654
10661
|
* Sets a callback to be invoked when RoktManager becomes ready
|
|
@@ -10727,6 +10734,7 @@ var mParticle = (function () {
|
|
|
10727
10734
|
var _a, _b, _c, _d;
|
|
10728
10735
|
this.kit = kit;
|
|
10729
10736
|
this.watchRouteChanges();
|
|
10737
|
+
this.flushCheckoutIntents();
|
|
10730
10738
|
if ((_a = kit.settings) === null || _a === void 0 ? void 0 : _a.accountId) {
|
|
10731
10739
|
this.store.setRoktAccountId(kit.settings.accountId);
|
|
10732
10740
|
}
|
|
@@ -10772,6 +10780,70 @@ var mParticle = (function () {
|
|
|
10772
10780
|
(_c = this.logger) === null || _c === void 0 ? void 0 : _c.error("RoktManager: Error in onRouteChange: ".concat(getErrorMessage(e)));
|
|
10773
10781
|
}
|
|
10774
10782
|
};
|
|
10783
|
+
// Checkout intent is off unless the flag is on, and under opt-out, any Rokt
|
|
10784
|
+
// privacy launcher option, or Global Privacy Control.
|
|
10785
|
+
RoktManager.prototype.isCheckoutIntentSuppressed = function () {
|
|
10786
|
+
var _a, _b;
|
|
10787
|
+
var flags = (_b = (_a = this.store) === null || _a === void 0 ? void 0 : _a.SDKConfig) === null || _b === void 0 ? void 0 : _b.flags;
|
|
10788
|
+
if (!flags || flags[Constants.FeatureFlags.CheckoutIntent] !== true || !this.store.isEnabled) {
|
|
10789
|
+
return true;
|
|
10790
|
+
}
|
|
10791
|
+
var options = this.launcherOptions || {};
|
|
10792
|
+
if (options.noFunctional || options.noTargeting || options.doNotShareOrSell) {
|
|
10793
|
+
return true;
|
|
10794
|
+
}
|
|
10795
|
+
var nav = typeof navigator === 'undefined' ? undefined : navigator;
|
|
10796
|
+
return !!nav && nav.globalPrivacyControl === true;
|
|
10797
|
+
};
|
|
10798
|
+
// Reads `this.kit` at call time; before a kit attaches the signal is buffered
|
|
10799
|
+
// with the path it was raised on.
|
|
10800
|
+
RoktManager.prototype.notifyCheckoutIntent = function (signal, pathname) {
|
|
10801
|
+
var _a;
|
|
10802
|
+
if (pathname === void 0) {
|
|
10803
|
+
pathname = window.location.pathname;
|
|
10804
|
+
}
|
|
10805
|
+
if (this.isCheckoutIntentSuppressed()) {
|
|
10806
|
+
return;
|
|
10807
|
+
}
|
|
10808
|
+
var kit = this.kit;
|
|
10809
|
+
if (!kit) {
|
|
10810
|
+
this.pendingCheckoutIntents = this.pendingCheckoutIntents.filter(function (pending) {
|
|
10811
|
+
return pending.signal.kind !== signal.kind;
|
|
10812
|
+
}).concat({
|
|
10813
|
+
signal: signal,
|
|
10814
|
+
pathname: pathname
|
|
10815
|
+
}).slice(-CHECKOUT_INTENT_BUFFER_LIMIT);
|
|
10816
|
+
return;
|
|
10817
|
+
}
|
|
10818
|
+
try {
|
|
10819
|
+
if (isFunction(kit.onCheckoutIntent)) {
|
|
10820
|
+
kit.onCheckoutIntent(signal);
|
|
10821
|
+
}
|
|
10822
|
+
} catch (e) {
|
|
10823
|
+
(_a = this.logger) === null || _a === void 0 ? void 0 : _a.error("RoktManager: Error in onCheckoutIntent: ".concat(getErrorMessage(e)));
|
|
10824
|
+
}
|
|
10825
|
+
};
|
|
10826
|
+
RoktManager.prototype.discardCheckoutIntents = function () {
|
|
10827
|
+
this.pendingCheckoutIntents = [];
|
|
10828
|
+
};
|
|
10829
|
+
// Replays recent buffered signals raised on the current page, oldest first.
|
|
10830
|
+
RoktManager.prototype.flushCheckoutIntents = function () {
|
|
10831
|
+
var _this = this;
|
|
10832
|
+
var pending = this.pendingCheckoutIntents;
|
|
10833
|
+
this.pendingCheckoutIntents = [];
|
|
10834
|
+
var now = Date.now();
|
|
10835
|
+
var pathname = window.location.pathname;
|
|
10836
|
+
pending.filter(function (_a) {
|
|
10837
|
+
var signal = _a.signal,
|
|
10838
|
+
signalPathname = _a.pathname;
|
|
10839
|
+
return now - signal.t < CHECKOUT_INTENT_MAX_AGE_MS && signalPathname === pathname;
|
|
10840
|
+
}).sort(function (a, b) {
|
|
10841
|
+
return a.signal.t - b.signal.t;
|
|
10842
|
+
}).forEach(function (_a) {
|
|
10843
|
+
var signal = _a.signal;
|
|
10844
|
+
return _this.notifyCheckoutIntent(signal);
|
|
10845
|
+
});
|
|
10846
|
+
};
|
|
10775
10847
|
RoktManager.prototype.isAutoLogPageViewEnabled = function () {
|
|
10776
10848
|
var _a, _b, _c;
|
|
10777
10849
|
return ((_c = (_b = (_a = this.store) === null || _a === void 0 ? void 0 : _a.SDKConfig) === null || _b === void 0 ? void 0 : _b.flags) === null || _c === void 0 ? void 0 : _c[Constants.FeatureFlags.AutoLogPageView]) === true;
|
|
@@ -11387,6 +11459,335 @@ var mParticle = (function () {
|
|
|
11387
11459
|
return LoggingDispatcher;
|
|
11388
11460
|
}();
|
|
11389
11461
|
|
|
11462
|
+
var checkoutPath = /(?:^|\/)(?:checkouts?|payment|order|kasse|paiement|commander?|pago)(?:\/|$)/i;
|
|
11463
|
+
var exclusions = new RegExp(['coupon|promo|newsletter|sign in|add to cart|gift card|pay later|pay in|payment plan|learn more', 'gutschein|anmelden|warenkorb|bon cadeau|connexion|panier|cupón|iniciar sesión|carrito', 'carrello|codice sconto|accedi|buono regalo|winkelwagen|kortingscode|inloggen|cadeaubon|achteraf betalen', 'カート|クーポン|ログイン|会員登録|ギフト|後払い|メルマガ'].join('|'));
|
|
11464
|
+
var commits = new RegExp('^(?:' + ['(?:place|submit|complete|confirm|finali[sz]e)(?!(?: [^ ]+){0,2} (?:another|new|next)(?: |$))(?: [^ ]+){0,2} (?:order|purchase|booking|reservation|payment|checkout)', 'pay(?: securely)?(?: now)?|confirm and pay|order and pay|order with obligation to pay', '(?:jetzt )?(?:zahlungs|kosten)pflichtig (?:bestellen|buchen)|(?:jetzt )?bezahlen|kauf abschließen|bestellung abschließen', 'commander et payer|payer(?: maintenant)?|(?:confirmer|finaliser) (?:ma |la )?commande', "valider et payer|confirmer et payer|commande avec obligation de paiement|finaliser l'achat", '(?:realizar|confirmar|completar) (?:el |mi |la )?(?:pedido|compra|reserva)|finalizar (?:el |mi )?pedido|pagar(?: ahora)?', 'pedido con obligación de pago', "(?:effettua|conferma|concludi|completa) (?:l'|il )?(?:ordine|acquisto)|ordine con obbligo di pagamento", 'paga(?: ora| adesso)?|ordina e paga', '(?:nu )?betalen|bestellen en betalen|bestelling plaatsen|plaats bestelling|bestelling afronden', 'bestelling met betalingsverplichting', '(?:この内容で|上記の?内容で)?ご?(?:注文|購入|予約|決済|お?支払い?)を?(?:確定|完了)(?:する)?', '(?:この内容で|上記の?内容で)ご?(?:注文|購入|予約)する|ご?注文する|決済する|(?:今すぐ|を)?支払う'].join('|') + ')$');
|
|
11465
|
+
var routeGatedCommits = new RegExp('^(?:buy now|purchase|jetzt kaufen|kaufen|commander|(?:passer|valider) (?:la |ma )?commande|finalizar (?:la |mi )?compra|' + 'comprar ahora|acquista ora|nu kopen|今すぐ購入|購入する|この内容で申し込む)$');
|
|
11466
|
+
var steps = new RegExp('^(?:' + ['checkout|check out|check-out|continue to payment|proceed to checkout', 'zur kasse|zur kasse gehen|auschecken|weiter zur zahlung', 'passer à la caisse|continuer vers le paiement|procéder au paiement', 'ir a caja|continuar al pago|tramitar pedido', "procedi al checkout|procedi all'acquisto|procedi al pagamento|vai alla cassa", 'afrekenen|verder naar betalen|doorgaan naar betalen', 'レジに進む|ご?(?:購入|注文)手続き(?:へ|に)(?:進む)?|お?支払い(?:へ|に)進む|(?:ご注文内容の)?確認画面へ(?:進む)?'].join('|') + ')$');
|
|
11467
|
+
var wallets = /^(?:apple pay|google pay|paypal|venmo|amazon pay|shop pay|klarna|afterpay|affirm)$/;
|
|
11468
|
+
// Exact HTTPS hosts of hosted wallet and payment frames.
|
|
11469
|
+
var frameHosts = new Set(['www.paypal.com', 'www.sandbox.paypal.com', 'pay.google.com', 'applepay.cdn-apple.com', 'js.stripe.com', 'checkoutshopper-live.adyen.com', 'payments.amazon.com', 'pay.shopify.com']);
|
|
11470
|
+
var CONTROL_SELECTOR = 'button, input[type="submit"], input[type="button"], input[type="image"], [role="button"]';
|
|
11471
|
+
function getIntentRouteClass(pathname) {
|
|
11472
|
+
return checkoutPath.test(pathname) ? 'checkout_path' : 'other';
|
|
11473
|
+
}
|
|
11474
|
+
// Rokt's own placements and frames never count as partner checkout controls.
|
|
11475
|
+
function isRoktElement(element) {
|
|
11476
|
+
if (element.closest('[data-core-type], #rokt-controller-frame')) {
|
|
11477
|
+
return true;
|
|
11478
|
+
}
|
|
11479
|
+
var src = element.getAttribute('src');
|
|
11480
|
+
if (src) {
|
|
11481
|
+
try {
|
|
11482
|
+
if (new URL(src, 'https://example.test').pathname.indexOf('/wsdk/') !== -1) {
|
|
11483
|
+
return true;
|
|
11484
|
+
}
|
|
11485
|
+
} catch (e) {
|
|
11486
|
+
// An unparseable src is not a Rokt element.
|
|
11487
|
+
}
|
|
11488
|
+
}
|
|
11489
|
+
return false;
|
|
11490
|
+
}
|
|
11491
|
+
function isWalletElement(element) {
|
|
11492
|
+
return element.matches('apple-pay-button, shop-pay-button, .gpay-button, #AmazonPayButton, [data-amazon-pay-button]');
|
|
11493
|
+
}
|
|
11494
|
+
function normalize(text) {
|
|
11495
|
+
if (!text || text.length > 128) {
|
|
11496
|
+
return undefined;
|
|
11497
|
+
}
|
|
11498
|
+
return text.toLowerCase().replace(/[’‘]/g, "'").replace(/[0-90-9$€£¥¥₹円.,,]/g, '').replace(/\s+/g, ' ').trim();
|
|
11499
|
+
}
|
|
11500
|
+
// Labels come from aria-label then visible text. Only submit and button inputs
|
|
11501
|
+
// have their value read, so a typed field value is never touched.
|
|
11502
|
+
function labels(element) {
|
|
11503
|
+
if (element.children.length > 4 || element.querySelector('input, select, textarea')) {
|
|
11504
|
+
return [];
|
|
11505
|
+
}
|
|
11506
|
+
var text = null;
|
|
11507
|
+
if (element.tagName.toLowerCase() === 'input') {
|
|
11508
|
+
var typeAttr = element.getAttribute('type');
|
|
11509
|
+
var type = typeAttr ? typeAttr.toLowerCase() : typeAttr;
|
|
11510
|
+
if (type === 'submit' || type === 'button') {
|
|
11511
|
+
text = element.value;
|
|
11512
|
+
} else if (type === 'image') {
|
|
11513
|
+
text = element.getAttribute('alt');
|
|
11514
|
+
}
|
|
11515
|
+
} else {
|
|
11516
|
+
text = element.textContent;
|
|
11517
|
+
}
|
|
11518
|
+
return [normalize(element.getAttribute('aria-label')), normalize(text)].filter(function (label) {
|
|
11519
|
+
return !!label;
|
|
11520
|
+
});
|
|
11521
|
+
}
|
|
11522
|
+
function classifyLabel(text, button, pathname) {
|
|
11523
|
+
if (commits.test(text) || routeGatedCommits.test(text) && getIntentRouteClass(pathname) === 'checkout_path') {
|
|
11524
|
+
return 'commit';
|
|
11525
|
+
}
|
|
11526
|
+
if (button && wallets.test(text)) {
|
|
11527
|
+
return 'wallet';
|
|
11528
|
+
}
|
|
11529
|
+
if (steps.test(text)) {
|
|
11530
|
+
return 'checkout_step';
|
|
11531
|
+
}
|
|
11532
|
+
return undefined;
|
|
11533
|
+
}
|
|
11534
|
+
// Walks at most 12 entries of an event's composed path for the nearest control.
|
|
11535
|
+
function classifyIntentControl(path, pathname) {
|
|
11536
|
+
var control;
|
|
11537
|
+
for (var _i = 0, _a = path.slice(0, 12); _i < _a.length; _i++) {
|
|
11538
|
+
var target = _a[_i];
|
|
11539
|
+
if (!(target instanceof Element)) {
|
|
11540
|
+
continue;
|
|
11541
|
+
}
|
|
11542
|
+
if (isRoktElement(target)) {
|
|
11543
|
+
return undefined;
|
|
11544
|
+
}
|
|
11545
|
+
if (!control && (target.matches(CONTROL_SELECTOR + ', a[href]') || isWalletElement(target))) {
|
|
11546
|
+
control = target;
|
|
11547
|
+
}
|
|
11548
|
+
}
|
|
11549
|
+
if (!control || isRoktElement(control)) {
|
|
11550
|
+
return undefined;
|
|
11551
|
+
}
|
|
11552
|
+
var texts = labels(control);
|
|
11553
|
+
if (texts.some(function (text) {
|
|
11554
|
+
return exclusions.test(text);
|
|
11555
|
+
})) {
|
|
11556
|
+
return undefined;
|
|
11557
|
+
}
|
|
11558
|
+
var button = false;
|
|
11559
|
+
if (!control.matches('a[href]')) {
|
|
11560
|
+
button = control.matches(CONTROL_SELECTOR) || isWalletElement(control);
|
|
11561
|
+
}
|
|
11562
|
+
if (button && isWalletElement(control)) {
|
|
11563
|
+
return 'wallet';
|
|
11564
|
+
}
|
|
11565
|
+
for (var _b = 0, texts_1 = texts; _b < texts_1.length; _b++) {
|
|
11566
|
+
var text = texts_1[_b];
|
|
11567
|
+
var kind = classifyLabel(text, button, pathname);
|
|
11568
|
+
if (kind) {
|
|
11569
|
+
return kind;
|
|
11570
|
+
}
|
|
11571
|
+
}
|
|
11572
|
+
return undefined;
|
|
11573
|
+
}
|
|
11574
|
+
// Focus moving into a visible hosted wallet or payment frame.
|
|
11575
|
+
function classifyIntentFrame(target, win) {
|
|
11576
|
+
if (win.document.visibilityState !== 'visible' || !(target instanceof HTMLIFrameElement)) {
|
|
11577
|
+
return undefined;
|
|
11578
|
+
}
|
|
11579
|
+
if (isRoktElement(target)) {
|
|
11580
|
+
return undefined;
|
|
11581
|
+
}
|
|
11582
|
+
try {
|
|
11583
|
+
var url = new URL(target.src);
|
|
11584
|
+
if (url.protocol === 'https:' && frameHosts.has(url.hostname)) {
|
|
11585
|
+
return 'frame';
|
|
11586
|
+
}
|
|
11587
|
+
} catch (e) {
|
|
11588
|
+
// An unparseable frame src is not a wallet frame.
|
|
11589
|
+
}
|
|
11590
|
+
return undefined;
|
|
11591
|
+
}
|
|
11592
|
+
|
|
11593
|
+
// State lives on `window`, like APV, so a re-executed bundle never doubles the
|
|
11594
|
+
// listeners. Inspect `window.__mpCit__` in a console to see if one is live.
|
|
11595
|
+
var WIN_CIT_KEY = '__mpCit__';
|
|
11596
|
+
var THROTTLE_MS = 2000;
|
|
11597
|
+
var SUBMIT_AFTER_COMMIT_CLICK_MS = 1000;
|
|
11598
|
+
var PATH_LIMIT = 12;
|
|
11599
|
+
var citWindow = function citWindow() {
|
|
11600
|
+
return typeof window === 'undefined' ? null : window;
|
|
11601
|
+
};
|
|
11602
|
+
var getActiveCheckoutIntentTracker = function getActiveCheckoutIntentTracker() {
|
|
11603
|
+
var win = citWindow();
|
|
11604
|
+
var state = win ? win[WIN_CIT_KEY] : undefined;
|
|
11605
|
+
return state ? state.tracker : undefined;
|
|
11606
|
+
};
|
|
11607
|
+
// Stops whichever tracker is active, including one from an earlier bundle load.
|
|
11608
|
+
var resetCheckoutIntentTracking = function resetCheckoutIntentTracking() {
|
|
11609
|
+
var win = citWindow();
|
|
11610
|
+
if (!win) {
|
|
11611
|
+
return;
|
|
11612
|
+
}
|
|
11613
|
+
var active = getActiveCheckoutIntentTracker();
|
|
11614
|
+
if (active) {
|
|
11615
|
+
active.teardown();
|
|
11616
|
+
}
|
|
11617
|
+
win[WIN_CIT_KEY] = {};
|
|
11618
|
+
};
|
|
11619
|
+
var CAPTURE_PASSIVE = {
|
|
11620
|
+
capture: true,
|
|
11621
|
+
passive: true
|
|
11622
|
+
};
|
|
11623
|
+
var PASSIVE = {
|
|
11624
|
+
passive: true
|
|
11625
|
+
};
|
|
11626
|
+
// Listens for checkout clicks, submits and wallet frame focus, and hands a
|
|
11627
|
+
// frozen {kind, t} to the Rokt kit. No storage, no network, no event logging.
|
|
11628
|
+
var CheckoutIntentTracker = /** @class */function () {
|
|
11629
|
+
function CheckoutIntentTracker(mpInstance) {
|
|
11630
|
+
var _this = this;
|
|
11631
|
+
this.active = false;
|
|
11632
|
+
// Bumped on reset so classification queued before it is dropped.
|
|
11633
|
+
this.generation = 0;
|
|
11634
|
+
this.lastCommitClick = -Infinity;
|
|
11635
|
+
this.lastSent = {};
|
|
11636
|
+
this.onPageShow = function (event) {
|
|
11637
|
+
// A page restored from the back-forward cache starts fresh.
|
|
11638
|
+
if (event.persisted) {
|
|
11639
|
+
_this.reset();
|
|
11640
|
+
}
|
|
11641
|
+
};
|
|
11642
|
+
this.onEvent = function (event) {
|
|
11643
|
+
try {
|
|
11644
|
+
_this.observe(event);
|
|
11645
|
+
} catch (e) {
|
|
11646
|
+
_this.log('[error] event handler threw: ' + e);
|
|
11647
|
+
}
|
|
11648
|
+
};
|
|
11649
|
+
this.mpInstance = mpInstance;
|
|
11650
|
+
}
|
|
11651
|
+
Object.defineProperty(CheckoutIntentTracker.prototype, "isActive", {
|
|
11652
|
+
get: function get() {
|
|
11653
|
+
return this.active;
|
|
11654
|
+
},
|
|
11655
|
+
enumerable: false,
|
|
11656
|
+
configurable: true
|
|
11657
|
+
});
|
|
11658
|
+
CheckoutIntentTracker.prototype.init = function () {
|
|
11659
|
+
var win = citWindow();
|
|
11660
|
+
if (!win) {
|
|
11661
|
+
return;
|
|
11662
|
+
}
|
|
11663
|
+
var previous = getActiveCheckoutIntentTracker();
|
|
11664
|
+
if (previous) {
|
|
11665
|
+
previous.teardown();
|
|
11666
|
+
}
|
|
11667
|
+
if (this.active) {
|
|
11668
|
+
this.teardown();
|
|
11669
|
+
}
|
|
11670
|
+
if (this.isSuppressed()) {
|
|
11671
|
+
this.log('privacy settings suppress checkout intent, not starting');
|
|
11672
|
+
return;
|
|
11673
|
+
}
|
|
11674
|
+
win.document.addEventListener('click', this.onEvent, CAPTURE_PASSIVE);
|
|
11675
|
+
win.document.addEventListener('submit', this.onEvent, CAPTURE_PASSIVE);
|
|
11676
|
+
win.addEventListener('blur', this.onEvent, PASSIVE);
|
|
11677
|
+
win.addEventListener('pageshow', this.onPageShow, PASSIVE);
|
|
11678
|
+
this.active = true;
|
|
11679
|
+
if (!win[WIN_CIT_KEY]) {
|
|
11680
|
+
win[WIN_CIT_KEY] = {};
|
|
11681
|
+
}
|
|
11682
|
+
win[WIN_CIT_KEY].tracker = this;
|
|
11683
|
+
this.log('listening');
|
|
11684
|
+
};
|
|
11685
|
+
CheckoutIntentTracker.prototype.teardown = function () {
|
|
11686
|
+
var win = citWindow();
|
|
11687
|
+
if (win) {
|
|
11688
|
+
win.document.removeEventListener('click', this.onEvent, true);
|
|
11689
|
+
win.document.removeEventListener('submit', this.onEvent, true);
|
|
11690
|
+
win.removeEventListener('blur', this.onEvent);
|
|
11691
|
+
win.removeEventListener('pageshow', this.onPageShow);
|
|
11692
|
+
var state = win[WIN_CIT_KEY];
|
|
11693
|
+
if (state && state.tracker === this) {
|
|
11694
|
+
state.tracker = undefined;
|
|
11695
|
+
}
|
|
11696
|
+
}
|
|
11697
|
+
this.active = false;
|
|
11698
|
+
// Signals not yet handed to a kit go with the tracker.
|
|
11699
|
+
this.clearPending();
|
|
11700
|
+
};
|
|
11701
|
+
// Drops queued classification, commit timing and buffered signals, so
|
|
11702
|
+
// nothing captured before an opt-out is delivered after an opt-in.
|
|
11703
|
+
CheckoutIntentTracker.prototype.clearPending = function () {
|
|
11704
|
+
this.reset();
|
|
11705
|
+
var roktManager = this.mpInstance._RoktManager;
|
|
11706
|
+
if (roktManager) {
|
|
11707
|
+
roktManager.discardCheckoutIntents();
|
|
11708
|
+
}
|
|
11709
|
+
};
|
|
11710
|
+
CheckoutIntentTracker.prototype.reset = function () {
|
|
11711
|
+
this.generation++;
|
|
11712
|
+
this.lastCommitClick = -Infinity;
|
|
11713
|
+
this.lastSent = {};
|
|
11714
|
+
};
|
|
11715
|
+
CheckoutIntentTracker.prototype.observe = function (event) {
|
|
11716
|
+
var _this = this;
|
|
11717
|
+
if (!this.active || !event.isTrusted || this.isSuppressed()) {
|
|
11718
|
+
return;
|
|
11719
|
+
}
|
|
11720
|
+
var t = Date.now();
|
|
11721
|
+
var pathname = window.location.pathname;
|
|
11722
|
+
var layer = event.type;
|
|
11723
|
+
// The composed path is only populated during dispatch, so copy it now.
|
|
11724
|
+
var path = layer === 'click' && typeof event.composedPath === 'function' ? event.composedPath().slice(0, PATH_LIMIT) : [];
|
|
11725
|
+
var target;
|
|
11726
|
+
if (layer === 'submit') {
|
|
11727
|
+
target = event.submitter;
|
|
11728
|
+
} else if (layer === 'blur') {
|
|
11729
|
+
// Read after the blur settles: some browsers have not moved focus
|
|
11730
|
+
// into the frame yet when the window blurs.
|
|
11731
|
+
target = null;
|
|
11732
|
+
} else {
|
|
11733
|
+
target = event.target;
|
|
11734
|
+
}
|
|
11735
|
+
var generation = this.generation;
|
|
11736
|
+
setTimeout(function () {
|
|
11737
|
+
if (generation !== _this.generation) {
|
|
11738
|
+
return;
|
|
11739
|
+
}
|
|
11740
|
+
try {
|
|
11741
|
+
var kind = void 0;
|
|
11742
|
+
if (layer === 'blur') {
|
|
11743
|
+
kind = classifyIntentFrame(document.activeElement, window);
|
|
11744
|
+
} else if (layer === 'submit' && target === null) {
|
|
11745
|
+
// A form submitted without a submitter only counts right
|
|
11746
|
+
// after a commit click.
|
|
11747
|
+
kind = t - _this.lastCommitClick <= SUBMIT_AFTER_COMMIT_CLICK_MS ? 'commit' : undefined;
|
|
11748
|
+
} else {
|
|
11749
|
+
kind = classifyIntentControl(layer === 'submit' ? [target] : path, pathname);
|
|
11750
|
+
}
|
|
11751
|
+
if (kind) {
|
|
11752
|
+
_this.emit(kind, layer, t, pathname);
|
|
11753
|
+
}
|
|
11754
|
+
} catch (e) {
|
|
11755
|
+
_this.log('[error] classification threw: ' + e);
|
|
11756
|
+
}
|
|
11757
|
+
}, 0);
|
|
11758
|
+
};
|
|
11759
|
+
CheckoutIntentTracker.prototype.emit = function (kind, layer, t, pathname) {
|
|
11760
|
+
if (this.isSuppressed()) {
|
|
11761
|
+
return;
|
|
11762
|
+
}
|
|
11763
|
+
if (kind === 'commit' && layer === 'click') {
|
|
11764
|
+
this.lastCommitClick = t;
|
|
11765
|
+
}
|
|
11766
|
+
var last = this.lastSent[kind];
|
|
11767
|
+
if (last && last.pathname === pathname && t - last.t < THROTTLE_MS) {
|
|
11768
|
+
return;
|
|
11769
|
+
}
|
|
11770
|
+
this.lastSent[kind] = {
|
|
11771
|
+
t: t,
|
|
11772
|
+
pathname: pathname
|
|
11773
|
+
};
|
|
11774
|
+
this.mpInstance._RoktManager.notifyCheckoutIntent(Object.freeze({
|
|
11775
|
+
kind: kind,
|
|
11776
|
+
t: t
|
|
11777
|
+
}), pathname);
|
|
11778
|
+
};
|
|
11779
|
+
// The Rokt manager owns the privacy gates: flag, opt-out, launcher options
|
|
11780
|
+
// and Global Privacy Control.
|
|
11781
|
+
CheckoutIntentTracker.prototype.isSuppressed = function () {
|
|
11782
|
+
var roktManager = this.mpInstance._RoktManager;
|
|
11783
|
+
return !roktManager || roktManager.isCheckoutIntentSuppressed();
|
|
11784
|
+
};
|
|
11785
|
+
CheckoutIntentTracker.prototype.log = function (message) {
|
|
11786
|
+
this.mpInstance.Logger.verbose('mParticle checkout intent: ' + message);
|
|
11787
|
+
};
|
|
11788
|
+
return CheckoutIntentTracker;
|
|
11789
|
+
}();
|
|
11790
|
+
|
|
11390
11791
|
var Messages = Constants.Messages,
|
|
11391
11792
|
HTTPCodes = Constants.HTTPCodes,
|
|
11392
11793
|
FeatureFlags = Constants.FeatureFlags,
|
|
@@ -11520,6 +11921,10 @@ var mParticle = (function () {
|
|
|
11520
11921
|
this.reset = function (instance) {
|
|
11521
11922
|
try {
|
|
11522
11923
|
instance._Persistence.resetPersistence();
|
|
11924
|
+
// The Rokt manager keeps its own store reference, so stop checkout
|
|
11925
|
+
// intent here rather than relying on the deleted store.
|
|
11926
|
+
resetCheckoutIntentTracking();
|
|
11927
|
+
instance._CheckoutIntentTracker = undefined;
|
|
11523
11928
|
if (instance._Store) {
|
|
11524
11929
|
delete instance._Store;
|
|
11525
11930
|
}
|
|
@@ -11541,6 +11946,8 @@ var mParticle = (function () {
|
|
|
11541
11946
|
instance._Events.stopTracking();
|
|
11542
11947
|
resetPageViewTracking();
|
|
11543
11948
|
instance._PageViewTracker = undefined;
|
|
11949
|
+
resetCheckoutIntentTracking();
|
|
11950
|
+
instance._CheckoutIntentTracker = undefined;
|
|
11544
11951
|
if (!keepPersistence) {
|
|
11545
11952
|
instance._Persistence.resetPersistence();
|
|
11546
11953
|
}
|
|
@@ -12139,6 +12546,12 @@ var mParticle = (function () {
|
|
|
12139
12546
|
if (queued) return;
|
|
12140
12547
|
self._SessionManager.resetSessionTimer();
|
|
12141
12548
|
self._Store.isEnabled = !isOptingOut;
|
|
12549
|
+
if (isOptingOut) {
|
|
12550
|
+
if (self._CheckoutIntentTracker) {
|
|
12551
|
+
self._CheckoutIntentTracker.clearPending();
|
|
12552
|
+
}
|
|
12553
|
+
self._RoktManager.discardCheckoutIntents();
|
|
12554
|
+
}
|
|
12142
12555
|
self._Events.logOptOut();
|
|
12143
12556
|
self._Persistence.update();
|
|
12144
12557
|
if (self._Store.activeForwarders.length) {
|
|
@@ -12305,7 +12718,9 @@ var mParticle = (function () {
|
|
|
12305
12718
|
var _a, _b, _c, _d;
|
|
12306
12719
|
var kitBlocker = createKitBlocker(config, mpInstance);
|
|
12307
12720
|
var getFeatureFlag = mpInstance._Helpers.getFeatureFlag;
|
|
12308
|
-
var
|
|
12721
|
+
var _e = Constants.FeatureFlags,
|
|
12722
|
+
AutoLogPageView = _e.AutoLogPageView,
|
|
12723
|
+
CheckoutIntent = _e.CheckoutIntent;
|
|
12309
12724
|
// Destroy previous batch uploader to prevent leaked timers and event listeners
|
|
12310
12725
|
if ((_a = mpInstance._APIClient) === null || _a === void 0 ? void 0 : _a.uploader) {
|
|
12311
12726
|
mpInstance._APIClient.uploader.destroy();
|
|
@@ -12321,6 +12736,8 @@ var mParticle = (function () {
|
|
|
12321
12736
|
// persistence or Identity directly.
|
|
12322
12737
|
if (mpInstance._Store.webviewBridgeEnabled) {
|
|
12323
12738
|
mpInstance._NativeSdkHelpers.initializeSessionAttributes(apiKey);
|
|
12739
|
+
// Checkout intent never runs as a native passthrough.
|
|
12740
|
+
resetCheckoutIntentTracking();
|
|
12324
12741
|
} else {
|
|
12325
12742
|
// Main SDK initialization flow
|
|
12326
12743
|
// Load any settings/identities/attributes from cookie or localStorage
|
|
@@ -12400,6 +12817,18 @@ var mParticle = (function () {
|
|
|
12400
12817
|
// so it stops listening. Re-created if the flag is re-enabled later.
|
|
12401
12818
|
mpInstance._PageViewTracker.teardown();
|
|
12402
12819
|
}
|
|
12820
|
+
// Checkout intent only feeds the Rokt kit, so it listens only when the
|
|
12821
|
+
// workspace opts in and this init configures a Rokt kit.
|
|
12822
|
+
if (getFeatureFlag(CheckoutIntent) && roktConfig) {
|
|
12823
|
+
if (!mpInstance._CheckoutIntentTracker) {
|
|
12824
|
+
mpInstance._CheckoutIntentTracker = new CheckoutIntentTracker(mpInstance);
|
|
12825
|
+
}
|
|
12826
|
+
mpInstance._CheckoutIntentTracker.init();
|
|
12827
|
+
} else {
|
|
12828
|
+
// Also retires a tracker left by an earlier bundle load. Like APV,
|
|
12829
|
+
// this assumes a single active SDK instance.
|
|
12830
|
+
resetCheckoutIntentTracking();
|
|
12831
|
+
}
|
|
12403
12832
|
processIdentityCallback(mpInstance, currentUser, currentUserMPID, currentUserIdentities);
|
|
12404
12833
|
}
|
|
12405
12834
|
// We will continue to clear out the ready queue as part of the initial init flow
|
|
@@ -12493,6 +12922,8 @@ var mParticle = (function () {
|
|
|
12493
12922
|
mpInstance._LoggingDispatcher.logger = mpInstance.Logger;
|
|
12494
12923
|
mpInstance._Store = new Store(config, mpInstance, apiKey);
|
|
12495
12924
|
window.mParticle.Store = mpInstance._Store;
|
|
12925
|
+
// Checkout intent stops until this init's config decides whether it runs.
|
|
12926
|
+
resetCheckoutIntentTracking();
|
|
12496
12927
|
mpInstance.Logger.verbose(StartingInitialization);
|
|
12497
12928
|
// Initialize CookieConsentManager with privacy flags from launcherOptions
|
|
12498
12929
|
var _a = normalizeRoktLauncherOptions(config === null || config === void 0 ? void 0 : config.launcherOptions),
|
|
@@ -0,0 +1,4 @@
|
|
|
1
|
+
export type CheckoutIntentKind = 'commit' | 'wallet' | 'checkout_step' | 'frame';
|
|
2
|
+
export declare function getIntentRouteClass(pathname: string): 'checkout_path' | 'other';
|
|
3
|
+
export declare function classifyIntentControl(path: Array<EventTarget | null>, pathname: string): CheckoutIntentKind | undefined;
|
|
4
|
+
export declare function classifyIntentFrame(target: EventTarget | null, win: Window): 'frame' | undefined;
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
import { IMParticleWebSDKInstance } from './mp-instance';
|
|
2
|
+
export declare const WIN_CIT_KEY = "__mpCit__";
|
|
3
|
+
export declare const getActiveCheckoutIntentTracker: () => CheckoutIntentTracker | undefined;
|
|
4
|
+
export declare const resetCheckoutIntentTracking: () => void;
|
|
5
|
+
export declare class CheckoutIntentTracker {
|
|
6
|
+
private readonly mpInstance;
|
|
7
|
+
private active;
|
|
8
|
+
private generation;
|
|
9
|
+
private lastCommitClick;
|
|
10
|
+
private lastSent;
|
|
11
|
+
constructor(mpInstance: IMParticleWebSDKInstance);
|
|
12
|
+
get isActive(): boolean;
|
|
13
|
+
init(): void;
|
|
14
|
+
teardown(): void;
|
|
15
|
+
clearPending(): void;
|
|
16
|
+
private reset;
|
|
17
|
+
private readonly onPageShow;
|
|
18
|
+
private readonly onEvent;
|
|
19
|
+
private observe;
|
|
20
|
+
private emit;
|
|
21
|
+
private isSuppressed;
|
|
22
|
+
private log;
|
|
23
|
+
}
|
|
@@ -162,6 +162,7 @@ declare const Constants: {
|
|
|
162
162
|
readonly CaptureIntegrationSpecificIdsV2: "captureIntegrationSpecificIds.V2";
|
|
163
163
|
readonly AstBackgroundEvents: "astBackgroundEvents";
|
|
164
164
|
readonly AutoLogPageView: "autoLogPageView";
|
|
165
|
+
readonly CheckoutIntent: "checkoutIntent";
|
|
165
166
|
};
|
|
166
167
|
readonly DefaultInstance: "default_instance";
|
|
167
168
|
readonly CCPAPurpose: "data_sale_opt_out";
|
|
@@ -14,7 +14,7 @@
|
|
|
14
14
|
*/
|
|
15
15
|
export * from './public-types';
|
|
16
16
|
export type { KitInterface, } from './forwarders.interfaces';
|
|
17
|
-
export type { RoktAttributeValue, RoktAttributeValueType, RoktAttributeValueArray, RoktAttributes, IRoktPartnerExtensionData, IRoktSelectPlacementsOptions, IRoktSelection, IRoktLauncher, IRoktMessage, RoktKitFilterSettings, IRoktKitSettings, IRoktKit, IRoktOptions, IRoktLauncherOptions, } from './roktManager';
|
|
17
|
+
export type { RoktAttributeValue, RoktAttributeValueType, RoktAttributeValueArray, RoktAttributes, IRoktPartnerExtensionData, IRoktSelectPlacementsOptions, IRoktSelection, IRoktLauncher, IRoktMessage, RoktKitFilterSettings, IRoktKitSettings, IRoktKit, ICheckoutIntentSignal, IRoktOptions, IRoktLauncherOptions, } from './roktManager';
|
|
18
18
|
export type { ErrorCodes, WSDKErrorSeverity, } from './reporting/types';
|
|
19
19
|
export type { ISDKError, ISDKLogEntry, IErrorReportingService, ILoggingService, } from './reporting/types';
|
|
20
20
|
export type { SDKEvent, SDKProductAction, SDKProductActionType, SDKPromotionAction, SDKGeoLocation, SDKDataPlan, SDKLoggerApi, SDKConfigApi, IMParticleInstanceManager, } from './sdkRuntimeModels';
|
|
@@ -22,6 +22,7 @@ import { ICookieConsentManager } from './cookieConsentManager';
|
|
|
22
22
|
import { ErrorReportingDispatcher } from './reporting/errorReportingDispatcher';
|
|
23
23
|
import { LoggingDispatcher } from './reporting/loggingDispatcher';
|
|
24
24
|
import { PageViewTracker } from './pageViewTracker';
|
|
25
|
+
import { CheckoutIntentTracker } from './checkoutIntentTracker';
|
|
25
26
|
export interface IErrorLogMessage {
|
|
26
27
|
message?: string;
|
|
27
28
|
name?: string;
|
|
@@ -47,6 +48,7 @@ export interface IMParticleWebSDKInstance extends MParticleWebSDK {
|
|
|
47
48
|
_IntegrationCapture: IntegrationCapture;
|
|
48
49
|
_NativeSdkHelpers: INativeSdkHelpers;
|
|
49
50
|
_PageViewTracker?: PageViewTracker;
|
|
51
|
+
_CheckoutIntentTracker?: CheckoutIntentTracker;
|
|
50
52
|
_Persistence: IPersistence;
|
|
51
53
|
_CookieConsentManager: ICookieConsentManager;
|
|
52
54
|
_ErrorReportingDispatcher: ErrorReportingDispatcher;
|
|
@@ -8,6 +8,7 @@ import { IStore, LocalSessionAttributes } from "./store";
|
|
|
8
8
|
import { IErrorReportingService, ILoggingService } from "./reporting/types";
|
|
9
9
|
import { IRoktLauncherOptions } from "./roktLauncherOptions";
|
|
10
10
|
import IntegrationCapture from "./integrationCapture";
|
|
11
|
+
import type { CheckoutIntentKind } from "./checkoutIntentClassifier";
|
|
11
12
|
export type RoktAttributeValueArray = Array<string | number | boolean>;
|
|
12
13
|
export type RoktAttributeValueType = string | number | boolean | undefined | null;
|
|
13
14
|
export type RoktAttributeValue = RoktAttributeValueType | RoktAttributeValueArray;
|
|
@@ -42,6 +43,10 @@ export interface RoktKitFilterSettings {
|
|
|
42
43
|
filterUserAttributes?: (userAttributes: Dictionary<string>, filterList: number[]) => Dictionary<string>;
|
|
43
44
|
filteredUser?: IMParticleUser | null;
|
|
44
45
|
}
|
|
46
|
+
export interface ICheckoutIntentSignal {
|
|
47
|
+
kind: CheckoutIntentKind;
|
|
48
|
+
t: number;
|
|
49
|
+
}
|
|
45
50
|
export interface IRoktKitSettings {
|
|
46
51
|
accountId?: string;
|
|
47
52
|
placementAttributesMapping?: string;
|
|
@@ -59,6 +64,7 @@ export interface IRoktKit {
|
|
|
59
64
|
onShoppableAdsReady(callback: () => void): void;
|
|
60
65
|
terminate?: () => Promise<void>;
|
|
61
66
|
onRouteChange?: () => void;
|
|
67
|
+
onCheckoutIntent?: (signal: ICheckoutIntentSignal) => void;
|
|
62
68
|
launcherOptions?: Dictionary<any>;
|
|
63
69
|
settings?: IRoktKitSettings;
|
|
64
70
|
integrationName?: string;
|
|
@@ -91,6 +97,7 @@ export default class RoktManager {
|
|
|
91
97
|
private initialized;
|
|
92
98
|
private isShoppableAdsLoaded;
|
|
93
99
|
private stopRouteChangeWatch;
|
|
100
|
+
private pendingCheckoutIntents;
|
|
94
101
|
constructor(instanceName?: string);
|
|
95
102
|
/**
|
|
96
103
|
* Sets a callback to be invoked when RoktManager becomes ready
|
|
@@ -115,6 +122,10 @@ export default class RoktManager {
|
|
|
115
122
|
attachKit(kit: IRoktKit): void;
|
|
116
123
|
private watchRouteChanges;
|
|
117
124
|
private notifyRouteChange;
|
|
125
|
+
isCheckoutIntentSuppressed(): boolean;
|
|
126
|
+
notifyCheckoutIntent(signal: ICheckoutIntentSignal, pathname?: string): void;
|
|
127
|
+
discardCheckoutIntents(): void;
|
|
128
|
+
private flushCheckoutIntents;
|
|
118
129
|
private isAutoLogPageViewEnabled;
|
|
119
130
|
/**
|
|
120
131
|
* Renders ads based on the options provided
|