@mparticle/web-sdk 3.8.1 → 3.9.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/dist/mparticle.common.js +47 -44
- package/dist/mparticle.esm.js +47 -44
- package/dist/mparticle.js +185 -78
- package/dist/types/src/pageViewTracker.d.ts +0 -5
- package/dist/types/src/roktManager.d.ts +7 -0
- package/dist/types/src/routeChangeMonitor.d.ts +9 -0
- package/package.json +1 -1
- package/src/mp-instance.ts +1 -1
- package/src/pageViewTracker.ts +8 -102
- package/src/persistence.ts +13 -6
- package/src/roktManager.ts +54 -0
- package/src/routeChangeMonitor.ts +207 -0
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.9.0";
|
|
208
208
|
|
|
209
209
|
var Constants = {
|
|
210
210
|
sdkVersion: version,
|
|
@@ -5882,7 +5882,7 @@ var mParticle = (function () {
|
|
|
5882
5882
|
}
|
|
5883
5883
|
date.setTime(date.getTime() - 24 * 60 * 60 * 1000);
|
|
5884
5884
|
expires = '; expires=' + date.toUTCString();
|
|
5885
|
-
|
|
5885
|
+
writeCookie(cookieName + '=' + '' + expires + '; path=/' + domain);
|
|
5886
5886
|
};
|
|
5887
5887
|
this.getCookie = function () {
|
|
5888
5888
|
var cookies,
|
|
@@ -5964,7 +5964,7 @@ var mParticle = (function () {
|
|
|
5964
5964
|
}
|
|
5965
5965
|
encodedCookiesWithExpirationAndPath = self.reduceAndEncodePersistence(cookies, expires, domain, mpInstance._Store.SDKConfig.maxCookieSize);
|
|
5966
5966
|
mpInstance.Logger.verbose(Messages$4.InformationMessages.CookieSet);
|
|
5967
|
-
|
|
5967
|
+
writeCookie(encodeURIComponent(key) + '=' + encodedCookiesWithExpirationAndPath);
|
|
5968
5968
|
};
|
|
5969
5969
|
/* This function determines if a cookie is greater than the configured maxCookieSize.
|
|
5970
5970
|
- If it is, we remove an MPID and its associated UI/UA/CSD from the cookie.
|
|
@@ -6056,6 +6056,10 @@ var mParticle = (function () {
|
|
|
6056
6056
|
}
|
|
6057
6057
|
return removeCurrentSessionMpidsByAge(persistence, currentSessionMPIDs, expires, domain, maxCookieSize);
|
|
6058
6058
|
};
|
|
6059
|
+
function writeCookie(cookie) {
|
|
6060
|
+
var isHttpsPage = window.location.protocol === 'https:';
|
|
6061
|
+
window.document.cookie = isHttpsPage ? cookie + ';Secure' : cookie;
|
|
6062
|
+
}
|
|
6059
6063
|
function createFullEncodedCookie(persistence, expires, domain) {
|
|
6060
6064
|
return self.encodePersistence(JSON.stringify(persistence)) + ';expires=' + expires + ';path=/' + domain;
|
|
6061
6065
|
}
|
|
@@ -6319,7 +6323,7 @@ var mParticle = (function () {
|
|
|
6319
6323
|
}
|
|
6320
6324
|
if (mpInstance._Store.SDKConfig.useCookieStorage) {
|
|
6321
6325
|
var encodedCookiesWithExpirationAndPath = self.reduceAndEncodePersistence(persistence, expires, domain, mpInstance._Store.SDKConfig.maxCookieSize);
|
|
6322
|
-
|
|
6326
|
+
writeCookie(encodeURIComponent(key) + '=' + encodedCookiesWithExpirationAndPath);
|
|
6323
6327
|
} else {
|
|
6324
6328
|
if (mpInstance._Store.isLocalStorageAvailable) {
|
|
6325
6329
|
try {
|
|
@@ -6433,6 +6437,144 @@ var mParticle = (function () {
|
|
|
6433
6437
|
|
|
6434
6438
|
var HISTORY_METHODS = ['pushState', 'replaceState'];
|
|
6435
6439
|
var WRAPPED_MARKER = '__mpApvWrapped__';
|
|
6440
|
+
var supportsHistoryTracking = function supportsHistoryTracking(win) {
|
|
6441
|
+
return !!win && win.history !== undefined && typeof win.history.pushState === 'function' && typeof win.addEventListener === 'function';
|
|
6442
|
+
};
|
|
6443
|
+
// Wraps pushState/replaceState so `onNavigate` runs after the real method, and
|
|
6444
|
+
// returns the single function that undoes it — or null when nothing was
|
|
6445
|
+
// installed (history is already wrapped, or a frozen/sealed History rejected the
|
|
6446
|
+
// assignment). Handing back one undo closure keeps the wrapper and original
|
|
6447
|
+
// references out of the tracker entirely: there is no half-patched state for a
|
|
6448
|
+
// caller to inspect, and no way to restore the wrong pair.
|
|
6449
|
+
var patchHistory = function patchHistory(onNavigate, log) {
|
|
6450
|
+
if (window.history.pushState[WRAPPED_MARKER]) {
|
|
6451
|
+
log('[patch] history already wrapped, skipping to avoid double-wrap — STACKED WRAPPER DETECTED');
|
|
6452
|
+
return null;
|
|
6453
|
+
}
|
|
6454
|
+
var originals = {};
|
|
6455
|
+
var wrappers = {};
|
|
6456
|
+
HISTORY_METHODS.forEach(function (name) {
|
|
6457
|
+
var original = window.history[name];
|
|
6458
|
+
originals[name] = original;
|
|
6459
|
+
var wrapper = function wrapper() {
|
|
6460
|
+
var args = [];
|
|
6461
|
+
for (var _i = 0; _i < arguments.length; _i++) {
|
|
6462
|
+
args[_i] = arguments[_i];
|
|
6463
|
+
}
|
|
6464
|
+
var result = original.apply(this, args);
|
|
6465
|
+
onNavigate(name);
|
|
6466
|
+
return result;
|
|
6467
|
+
};
|
|
6468
|
+
Object.defineProperty(wrapper, WRAPPED_MARKER, {
|
|
6469
|
+
value: true,
|
|
6470
|
+
enumerable: false
|
|
6471
|
+
});
|
|
6472
|
+
wrappers[name] = wrapper;
|
|
6473
|
+
});
|
|
6474
|
+
// Restore per method: a third party may have patched one of the two on top of
|
|
6475
|
+
// ours after we installed. Clobbering theirs would break their tracking, so
|
|
6476
|
+
// leave anything that is no longer ours in place.
|
|
6477
|
+
var restore = function restore() {
|
|
6478
|
+
return HISTORY_METHODS.forEach(function (name) {
|
|
6479
|
+
if (window.history[name] === wrappers[name]) {
|
|
6480
|
+
window.history[name] = originals[name];
|
|
6481
|
+
log("[teardown] restored original ".concat(name));
|
|
6482
|
+
} else {
|
|
6483
|
+
log("[teardown] ".concat(name, " no longer ours; leaving in place, gating callback to no-op"));
|
|
6484
|
+
}
|
|
6485
|
+
});
|
|
6486
|
+
};
|
|
6487
|
+
try {
|
|
6488
|
+
HISTORY_METHODS.forEach(function (name) {
|
|
6489
|
+
window.history[name] = wrappers[name];
|
|
6490
|
+
});
|
|
6491
|
+
} catch (e) {
|
|
6492
|
+
log("[error] failed to patch history methods (frozen/sealed), rolling back: ".concat(e));
|
|
6493
|
+
try {
|
|
6494
|
+
restore();
|
|
6495
|
+
} catch (restoreError) {
|
|
6496
|
+
log("[error] failed to restore history methods after patch failure: ".concat(restoreError));
|
|
6497
|
+
}
|
|
6498
|
+
return null;
|
|
6499
|
+
}
|
|
6500
|
+
return restore;
|
|
6501
|
+
};
|
|
6502
|
+
// One History patch for the whole SDK, so page-view tracking and preselection do not
|
|
6503
|
+
// stack two wrappers.
|
|
6504
|
+
//
|
|
6505
|
+
// State lives on `window`, not module scope, because Next.js re-executes the bundle per
|
|
6506
|
+
// SPA navigation while the patch from the previous execution stays installed.
|
|
6507
|
+
var WIN_ROUTE_MONITOR_KEY = '__mpRouteMonitor__';
|
|
6508
|
+
var monitorState = function monitorState() {
|
|
6509
|
+
var win = window;
|
|
6510
|
+
if (!win[WIN_ROUTE_MONITOR_KEY]) {
|
|
6511
|
+
win[WIN_ROUTE_MONITOR_KEY] = {
|
|
6512
|
+
listeners: {},
|
|
6513
|
+
undoHistoryPatch: null,
|
|
6514
|
+
popStateListener: null
|
|
6515
|
+
};
|
|
6516
|
+
}
|
|
6517
|
+
return win[WIN_ROUTE_MONITOR_KEY];
|
|
6518
|
+
};
|
|
6519
|
+
// Reads the shared state at call time, so a wrapper installed by a previous bundle
|
|
6520
|
+
// execution still reaches the current listeners.
|
|
6521
|
+
var emit = function emit(source) {
|
|
6522
|
+
Object.values(monitorState().listeners).forEach(function (listener) {
|
|
6523
|
+
try {
|
|
6524
|
+
listener(source);
|
|
6525
|
+
} catch (e) {
|
|
6526
|
+
// One subscriber must not stop the others, and must never break navigation.
|
|
6527
|
+
}
|
|
6528
|
+
});
|
|
6529
|
+
};
|
|
6530
|
+
var install = function install(state, log) {
|
|
6531
|
+
if (state.undoHistoryPatch || state.popStateListener) {
|
|
6532
|
+
return;
|
|
6533
|
+
}
|
|
6534
|
+
state.undoHistoryPatch = patchHistory(emit, log);
|
|
6535
|
+
state.popStateListener = function () {
|
|
6536
|
+
return emit('popstate');
|
|
6537
|
+
};
|
|
6538
|
+
window.addEventListener('popstate', state.popStateListener);
|
|
6539
|
+
};
|
|
6540
|
+
var uninstall = function uninstall(state) {
|
|
6541
|
+
if (state.popStateListener) {
|
|
6542
|
+
window.removeEventListener('popstate', state.popStateListener);
|
|
6543
|
+
state.popStateListener = null;
|
|
6544
|
+
}
|
|
6545
|
+
if (state.undoHistoryPatch) {
|
|
6546
|
+
state.undoHistoryPatch();
|
|
6547
|
+
state.undoHistoryPatch = null;
|
|
6548
|
+
}
|
|
6549
|
+
};
|
|
6550
|
+
// Installs on the first subscriber and tears down after the last leaves, so a workspace
|
|
6551
|
+
// that needs neither is never patched. Unsubscribing only removes the listener while it
|
|
6552
|
+
// still owns its key, so an outgoing instance cannot remove its replacement.
|
|
6553
|
+
var subscribeToRouteChange = function subscribeToRouteChange(key, listener, log) {
|
|
6554
|
+
if (log === void 0) {
|
|
6555
|
+
log = function log() {
|
|
6556
|
+
return undefined;
|
|
6557
|
+
};
|
|
6558
|
+
}
|
|
6559
|
+
if (!supportsHistoryTracking(typeof window === 'undefined' ? null : window)) {
|
|
6560
|
+
return function () {
|
|
6561
|
+
return undefined;
|
|
6562
|
+
};
|
|
6563
|
+
}
|
|
6564
|
+
var state = monitorState();
|
|
6565
|
+
state.listeners[key] = listener;
|
|
6566
|
+
install(state, log);
|
|
6567
|
+
return function () {
|
|
6568
|
+
if (state.listeners[key] !== listener) {
|
|
6569
|
+
return;
|
|
6570
|
+
}
|
|
6571
|
+
delete state.listeners[key];
|
|
6572
|
+
if (Object.keys(state.listeners).length === 0) {
|
|
6573
|
+
uninstall(state);
|
|
6574
|
+
}
|
|
6575
|
+
};
|
|
6576
|
+
};
|
|
6577
|
+
|
|
6436
6578
|
// All APV state hangs off one window key, and it is the public debugging
|
|
6437
6579
|
// contract: `window.__mpApv__` is what you inspect in a console to see whether
|
|
6438
6580
|
// tracking is live.
|
|
@@ -6531,9 +6673,6 @@ var mParticle = (function () {
|
|
|
6531
6673
|
var isNewPage = function isNewPage(lastKey, candidateKey) {
|
|
6532
6674
|
return candidateKey !== lastKey;
|
|
6533
6675
|
};
|
|
6534
|
-
var supportsHistoryTracking = function supportsHistoryTracking(win) {
|
|
6535
|
-
return !!win && win.history !== undefined && typeof win.history.pushState === 'function' && typeof win.addEventListener === 'function';
|
|
6536
|
-
};
|
|
6537
6676
|
// Mirrors the event shape of the public mParticle.logPageView(), but carries the
|
|
6538
6677
|
// path and query params captured when the navigation was accepted rather than the
|
|
6539
6678
|
// live location.
|
|
@@ -6650,65 +6789,6 @@ var mParticle = (function () {
|
|
|
6650
6789
|
// ---------------------------------------------------------------------------
|
|
6651
6790
|
// History patching
|
|
6652
6791
|
// ---------------------------------------------------------------------------
|
|
6653
|
-
// Wraps pushState/replaceState so `onNavigate` runs after the real method, and
|
|
6654
|
-
// returns the single function that undoes it — or null when nothing was
|
|
6655
|
-
// installed (history is already wrapped, or a frozen/sealed History rejected the
|
|
6656
|
-
// assignment). Handing back one undo closure keeps the wrapper and original
|
|
6657
|
-
// references out of the tracker entirely: there is no half-patched state for a
|
|
6658
|
-
// caller to inspect, and no way to restore the wrong pair.
|
|
6659
|
-
var patchHistory = function patchHistory(onNavigate, log) {
|
|
6660
|
-
if (window.history.pushState[WRAPPED_MARKER]) {
|
|
6661
|
-
log('[patch] history already wrapped, skipping to avoid double-wrap — STACKED WRAPPER DETECTED');
|
|
6662
|
-
return null;
|
|
6663
|
-
}
|
|
6664
|
-
var originals = {};
|
|
6665
|
-
var wrappers = {};
|
|
6666
|
-
HISTORY_METHODS.forEach(function (name) {
|
|
6667
|
-
var original = window.history[name];
|
|
6668
|
-
originals[name] = original;
|
|
6669
|
-
var wrapper = function wrapper() {
|
|
6670
|
-
var args = [];
|
|
6671
|
-
for (var _i = 0; _i < arguments.length; _i++) {
|
|
6672
|
-
args[_i] = arguments[_i];
|
|
6673
|
-
}
|
|
6674
|
-
var result = original.apply(this, args);
|
|
6675
|
-
onNavigate(name);
|
|
6676
|
-
return result;
|
|
6677
|
-
};
|
|
6678
|
-
Object.defineProperty(wrapper, WRAPPED_MARKER, {
|
|
6679
|
-
value: true,
|
|
6680
|
-
enumerable: false
|
|
6681
|
-
});
|
|
6682
|
-
wrappers[name] = wrapper;
|
|
6683
|
-
});
|
|
6684
|
-
// Restore per method: a third party may have patched one of the two on top of
|
|
6685
|
-
// ours after we installed. Clobbering theirs would break their tracking, so
|
|
6686
|
-
// leave anything that is no longer ours in place.
|
|
6687
|
-
var restore = function restore() {
|
|
6688
|
-
return HISTORY_METHODS.forEach(function (name) {
|
|
6689
|
-
if (window.history[name] === wrappers[name]) {
|
|
6690
|
-
window.history[name] = originals[name];
|
|
6691
|
-
log("[teardown] restored original ".concat(name));
|
|
6692
|
-
} else {
|
|
6693
|
-
log("[teardown] ".concat(name, " no longer ours; leaving in place, gating callback to no-op"));
|
|
6694
|
-
}
|
|
6695
|
-
});
|
|
6696
|
-
};
|
|
6697
|
-
try {
|
|
6698
|
-
HISTORY_METHODS.forEach(function (name) {
|
|
6699
|
-
window.history[name] = wrappers[name];
|
|
6700
|
-
});
|
|
6701
|
-
} catch (e) {
|
|
6702
|
-
log("[error] failed to patch history methods (frozen/sealed), rolling back: ".concat(e));
|
|
6703
|
-
try {
|
|
6704
|
-
restore();
|
|
6705
|
-
} catch (restoreError) {
|
|
6706
|
-
log("[error] failed to restore history methods after patch failure: ".concat(restoreError));
|
|
6707
|
-
}
|
|
6708
|
-
return null;
|
|
6709
|
-
}
|
|
6710
|
-
return restore;
|
|
6711
|
-
};
|
|
6712
6792
|
// ---------------------------------------------------------------------------
|
|
6713
6793
|
// Tracker
|
|
6714
6794
|
// ---------------------------------------------------------------------------
|
|
@@ -6718,7 +6798,6 @@ var mParticle = (function () {
|
|
|
6718
6798
|
this.active = false;
|
|
6719
6799
|
this.pendingNavigations = [];
|
|
6720
6800
|
this.undoHistoryPatch = null;
|
|
6721
|
-
this.popStateListener = null;
|
|
6722
6801
|
this.mpInstance = mpInstance;
|
|
6723
6802
|
this.isAutoPageView = !!(options && options.isAutoPageView);
|
|
6724
6803
|
}
|
|
@@ -6753,15 +6832,11 @@ var mParticle = (function () {
|
|
|
6753
6832
|
this.active = true;
|
|
6754
6833
|
this.lastPage = currentPage();
|
|
6755
6834
|
this.log("[init] seeded lastPage: ".concat(describePage(this.lastPage)));
|
|
6756
|
-
this.undoHistoryPatch =
|
|
6835
|
+
this.undoHistoryPatch = subscribeToRouteChange('pageView', function (source) {
|
|
6757
6836
|
return _this.safeHandleNavigation(source);
|
|
6758
6837
|
}, function (message) {
|
|
6759
6838
|
return _this.log(message);
|
|
6760
6839
|
});
|
|
6761
|
-
this.popStateListener = function () {
|
|
6762
|
-
return _this.safeHandleNavigation('popstate');
|
|
6763
|
-
};
|
|
6764
|
-
window.addEventListener('popstate', this.popStateListener);
|
|
6765
6840
|
setActiveTracker(this);
|
|
6766
6841
|
this.log('[init] patched pushState/replaceState + listening for popstate');
|
|
6767
6842
|
inheritedPages.forEach(function (page) {
|
|
@@ -6773,10 +6848,6 @@ var mParticle = (function () {
|
|
|
6773
6848
|
// re-init). A handoff calls takePendingNavigations() first, so by this
|
|
6774
6849
|
// point those paths are already transferred rather than dropped.
|
|
6775
6850
|
this.takePendingNavigations();
|
|
6776
|
-
if (this.popStateListener) {
|
|
6777
|
-
window.removeEventListener('popstate', this.popStateListener);
|
|
6778
|
-
this.popStateListener = null;
|
|
6779
|
-
}
|
|
6780
6851
|
if (this.undoHistoryPatch) {
|
|
6781
6852
|
this.undoHistoryPatch();
|
|
6782
6853
|
this.undoHistoryPatch = null;
|
|
@@ -10608,7 +10679,10 @@ var mParticle = (function () {
|
|
|
10608
10679
|
//
|
|
10609
10680
|
// https://github.com/mparticle-integrations/mparticle-javascript-integration-rokt
|
|
10610
10681
|
var RoktManager = /** @class */function () {
|
|
10611
|
-
|
|
10682
|
+
// Keys this manager's route subscription, so a re-executed bundle's manager replaces
|
|
10683
|
+
// it while a second named instance keeps its own.
|
|
10684
|
+
function RoktManager(instanceName) {
|
|
10685
|
+
this.instanceName = instanceName;
|
|
10612
10686
|
this.kit = null;
|
|
10613
10687
|
this.filters = {};
|
|
10614
10688
|
this.currentUser = null;
|
|
@@ -10618,6 +10692,7 @@ var mParticle = (function () {
|
|
|
10618
10692
|
this.onReadyCallback = null;
|
|
10619
10693
|
this.initialized = false;
|
|
10620
10694
|
this.isShoppableAdsLoaded = false;
|
|
10695
|
+
this.stopRouteChangeWatch = null;
|
|
10621
10696
|
}
|
|
10622
10697
|
/**
|
|
10623
10698
|
* Sets a callback to be invoked when RoktManager becomes ready
|
|
@@ -10695,6 +10770,7 @@ var mParticle = (function () {
|
|
|
10695
10770
|
RoktManager.prototype.attachKit = function (kit) {
|
|
10696
10771
|
var _a, _b, _c, _d;
|
|
10697
10772
|
this.kit = kit;
|
|
10773
|
+
this.watchRouteChanges();
|
|
10698
10774
|
if ((_a = kit.settings) === null || _a === void 0 ? void 0 : _a.accountId) {
|
|
10699
10775
|
this.store.setRoktAccountId(kit.settings.accountId);
|
|
10700
10776
|
}
|
|
@@ -10708,6 +10784,37 @@ var mParticle = (function () {
|
|
|
10708
10784
|
(_d = this.logger) === null || _d === void 0 ? void 0 : _d.error('RoktManager: Error in onReadyCallback: ' + e);
|
|
10709
10785
|
}
|
|
10710
10786
|
};
|
|
10787
|
+
// Core already emits a page view per navigation when AutoLogPageView is on, so the kit
|
|
10788
|
+
// is only told about route changes when it is off.
|
|
10789
|
+
RoktManager.prototype.watchRouteChanges = function () {
|
|
10790
|
+
var _this = this;
|
|
10791
|
+
var _a, _b;
|
|
10792
|
+
if (!isFunction((_a = this.kit) === null || _a === void 0 ? void 0 : _a.onRouteChange) || this.isAutoLogPageViewEnabled()) {
|
|
10793
|
+
(_b = this.stopRouteChangeWatch) === null || _b === void 0 ? void 0 : _b.call(this);
|
|
10794
|
+
this.stopRouteChangeWatch = null;
|
|
10795
|
+
return;
|
|
10796
|
+
}
|
|
10797
|
+
if (!this.stopRouteChangeWatch) {
|
|
10798
|
+
this.stopRouteChangeWatch = subscribeToRouteChange("rokt:".concat(this.instanceName), function () {
|
|
10799
|
+
return _this.notifyRouteChange();
|
|
10800
|
+
});
|
|
10801
|
+
}
|
|
10802
|
+
// A full navigation lands on the trigger route without a route change of its own.
|
|
10803
|
+
this.notifyRouteChange();
|
|
10804
|
+
};
|
|
10805
|
+
// Reads `this.kit` at call time, so a kit attached by a later init() takes over.
|
|
10806
|
+
RoktManager.prototype.notifyRouteChange = function () {
|
|
10807
|
+
var _a, _b, _c;
|
|
10808
|
+
try {
|
|
10809
|
+
(_b = (_a = this.kit) === null || _a === void 0 ? void 0 : _a.onRouteChange) === null || _b === void 0 ? void 0 : _b.call(_a);
|
|
10810
|
+
} catch (e) {
|
|
10811
|
+
(_c = this.logger) === null || _c === void 0 ? void 0 : _c.error("RoktManager: Error in onRouteChange: ".concat(getErrorMessage(e)));
|
|
10812
|
+
}
|
|
10813
|
+
};
|
|
10814
|
+
RoktManager.prototype.isAutoLogPageViewEnabled = function () {
|
|
10815
|
+
var _a, _b, _c;
|
|
10816
|
+
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;
|
|
10817
|
+
};
|
|
10711
10818
|
/**
|
|
10712
10819
|
* Renders ads based on the options provided
|
|
10713
10820
|
*
|
|
@@ -11335,7 +11442,7 @@ var mParticle = (function () {
|
|
|
11335
11442
|
};
|
|
11336
11443
|
this._ErrorReportingDispatcher = new ErrorReportingDispatcher();
|
|
11337
11444
|
this._LoggingDispatcher = new LoggingDispatcher();
|
|
11338
|
-
this._RoktManager = new RoktManager();
|
|
11445
|
+
this._RoktManager = new RoktManager(instanceName);
|
|
11339
11446
|
this._RoktManager.setOnReadyCallback(function () {
|
|
11340
11447
|
self.processQueueOnIdentityFailure();
|
|
11341
11448
|
});
|
|
@@ -1,8 +1,6 @@
|
|
|
1
1
|
import { IMParticleWebSDKInstance } from './mp-instance';
|
|
2
2
|
import { BaseEvent } from './sdkRuntimeModels';
|
|
3
3
|
import { Dictionary } from './utils';
|
|
4
|
-
type HistoryMethodName = 'pushState' | 'replaceState';
|
|
5
|
-
type NavigationSource = HistoryMethodName | 'popstate';
|
|
6
4
|
export declare const WIN_APV_KEY = "__mpApv__";
|
|
7
5
|
export declare const ALLOWED_QUERY_PARAMS: string[];
|
|
8
6
|
interface IPageSnapshot {
|
|
@@ -22,20 +20,17 @@ export declare const AUTO_PAGE_VIEW_ATTRIBUTE = "is_auto_page_view";
|
|
|
22
20
|
export declare const autoPageViewAttribute: (isAutoPageView?: boolean) => Dictionary<boolean>;
|
|
23
21
|
export declare const pageKey: (page: IPageSnapshot) => string;
|
|
24
22
|
export declare const isNewPage: (lastKey: string | null, candidateKey: string) => boolean;
|
|
25
|
-
export declare const supportsHistoryTracking: (win: Window | null) => boolean;
|
|
26
23
|
export declare const buildPageViewEvent: ({ params, hostname, title, path, isAutoPageView, }: IPageViewData) => BaseEvent;
|
|
27
24
|
export declare const getActiveTracker: () => PageViewTracker | undefined;
|
|
28
25
|
export declare const hasInitialPageViewFired: () => boolean;
|
|
29
26
|
export declare const markInitialPageViewFired: () => void;
|
|
30
27
|
export declare const resetPageViewTracking: () => void;
|
|
31
|
-
export declare const patchHistory: (onNavigate: (source: NavigationSource) => void, log: (message: string) => void) => (() => void) | null;
|
|
32
28
|
export declare class PageViewTracker {
|
|
33
29
|
private readonly mpInstance;
|
|
34
30
|
private lastPage;
|
|
35
31
|
private active;
|
|
36
32
|
private pendingNavigations;
|
|
37
33
|
private undoHistoryPatch;
|
|
38
|
-
private popStateListener;
|
|
39
34
|
private readonly isAutoPageView;
|
|
40
35
|
constructor(mpInstance: IMParticleWebSDKInstance, options?: IPageViewOptions);
|
|
41
36
|
get isActive(): boolean;
|
|
@@ -58,6 +58,7 @@ export interface IRoktKit {
|
|
|
58
58
|
use: <T>(name: string) => Promise<T>;
|
|
59
59
|
onShoppableAdsReady(callback: () => void): void;
|
|
60
60
|
terminate?: () => Promise<void>;
|
|
61
|
+
onRouteChange?: () => void;
|
|
61
62
|
launcherOptions?: Dictionary<any>;
|
|
62
63
|
settings?: IRoktKitSettings;
|
|
63
64
|
integrationName?: string;
|
|
@@ -69,6 +70,7 @@ export interface IRoktOptions {
|
|
|
69
70
|
}
|
|
70
71
|
export type { IRoktLauncherOptions } from "./roktLauncherOptions";
|
|
71
72
|
export default class RoktManager {
|
|
73
|
+
private readonly instanceName?;
|
|
72
74
|
kit: IRoktKit;
|
|
73
75
|
filters: RoktKitFilterSettings;
|
|
74
76
|
private currentUser;
|
|
@@ -88,6 +90,8 @@ export default class RoktManager {
|
|
|
88
90
|
private onReadyCallback;
|
|
89
91
|
private initialized;
|
|
90
92
|
private isShoppableAdsLoaded;
|
|
93
|
+
private stopRouteChangeWatch;
|
|
94
|
+
constructor(instanceName?: string);
|
|
91
95
|
/**
|
|
92
96
|
* Sets a callback to be invoked when RoktManager becomes ready
|
|
93
97
|
*/
|
|
@@ -109,6 +113,9 @@ export default class RoktManager {
|
|
|
109
113
|
init(roktConfig: IKitConfigs, filteredUser: IMParticleUser, identityService: SDKIdentityApi, store: IStore, logger?: SDKLoggerApi, options?: IRoktOptions, captureTiming?: (metricsName: string) => void, errorReporter?: IErrorReportingService, loggingService?: ILoggingService, integrationCapture?: IntegrationCapture): void;
|
|
110
114
|
get isInitialized(): boolean;
|
|
111
115
|
attachKit(kit: IRoktKit): void;
|
|
116
|
+
private watchRouteChanges;
|
|
117
|
+
private notifyRouteChange;
|
|
118
|
+
private isAutoLogPageViewEnabled;
|
|
112
119
|
/**
|
|
113
120
|
* Renders ads based on the options provided
|
|
114
121
|
*
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
type HistoryMethodName = 'pushState' | 'replaceState';
|
|
2
|
+
export type RouteChangeSource = HistoryMethodName | 'popstate';
|
|
3
|
+
export type RouteChangeListener = (source: RouteChangeSource) => void;
|
|
4
|
+
export declare const supportsHistoryTracking: (win: Window | null) => boolean;
|
|
5
|
+
export declare const patchHistory: (onNavigate: RouteChangeListener, log: (message: string) => void) => (() => void) | null;
|
|
6
|
+
export declare const WIN_ROUTE_MONITOR_KEY = "__mpRouteMonitor__";
|
|
7
|
+
export declare const subscribeToRouteChange: (key: string, listener: RouteChangeListener, log?: (message: string) => void) => (() => void);
|
|
8
|
+
export declare const resetRouteChangeMonitor: () => void;
|
|
9
|
+
export {};
|
package/package.json
CHANGED
package/src/mp-instance.ts
CHANGED
|
@@ -159,7 +159,7 @@ export default function mParticleInstance(this: IMParticleWebSDKInstance, instan
|
|
|
159
159
|
this._ErrorReportingDispatcher = new ErrorReportingDispatcher();
|
|
160
160
|
this._LoggingDispatcher = new LoggingDispatcher();
|
|
161
161
|
|
|
162
|
-
this._RoktManager = new RoktManager();
|
|
162
|
+
this._RoktManager = new RoktManager(instanceName);
|
|
163
163
|
|
|
164
164
|
this._RoktManager.setOnReadyCallback(() => {
|
|
165
165
|
self.processQueueOnIdentityFailure();
|
package/src/pageViewTracker.ts
CHANGED
|
@@ -2,18 +2,13 @@ import { IMParticleWebSDKInstance } from './mp-instance';
|
|
|
2
2
|
import { BaseEvent } from './sdkRuntimeModels';
|
|
3
3
|
import { EventType, MessageType } from './types';
|
|
4
4
|
import { Dictionary, getHref, hasOwnProp, queryStringParser } from './utils';
|
|
5
|
+
import {
|
|
6
|
+
subscribeToRouteChange,
|
|
7
|
+
supportsHistoryTracking,
|
|
8
|
+
type RouteChangeSource,
|
|
9
|
+
} from './routeChangeMonitor';
|
|
5
10
|
|
|
6
|
-
type
|
|
7
|
-
type HistoryMethodName = 'pushState' | 'replaceState';
|
|
8
|
-
type NavigationSource = HistoryMethodName | 'popstate';
|
|
9
|
-
|
|
10
|
-
const HISTORY_METHODS: HistoryMethodName[] = ['pushState', 'replaceState'];
|
|
11
|
-
|
|
12
|
-
const WRAPPED_MARKER = '__mpApvWrapped__';
|
|
13
|
-
|
|
14
|
-
type MarkedHistoryMethod = HistoryStateMethod & {
|
|
15
|
-
[WRAPPED_MARKER]?: boolean;
|
|
16
|
-
};
|
|
11
|
+
type NavigationSource = RouteChangeSource;
|
|
17
12
|
|
|
18
13
|
// All APV state hangs off one window key, and it is the public debugging
|
|
19
14
|
// contract: `window.__mpApv__` is what you inspect in a console to see whether
|
|
@@ -203,12 +198,6 @@ export const isNewPage = (
|
|
|
203
198
|
candidateKey: string
|
|
204
199
|
): boolean => candidateKey !== lastKey;
|
|
205
200
|
|
|
206
|
-
export const supportsHistoryTracking = (win: Window | null): boolean =>
|
|
207
|
-
!!win &&
|
|
208
|
-
win.history !== undefined &&
|
|
209
|
-
typeof win.history.pushState === 'function' &&
|
|
210
|
-
typeof win.addEventListener === 'function';
|
|
211
|
-
|
|
212
201
|
// Mirrors the event shape of the public mParticle.logPageView(), but carries the
|
|
213
202
|
// path and query params captured when the navigation was accepted rather than the
|
|
214
203
|
// live location.
|
|
@@ -339,82 +328,6 @@ const describePage = (page: IPageSnapshot | null): string => {
|
|
|
339
328
|
// History patching
|
|
340
329
|
// ---------------------------------------------------------------------------
|
|
341
330
|
|
|
342
|
-
// Wraps pushState/replaceState so `onNavigate` runs after the real method, and
|
|
343
|
-
// returns the single function that undoes it — or null when nothing was
|
|
344
|
-
// installed (history is already wrapped, or a frozen/sealed History rejected the
|
|
345
|
-
// assignment). Handing back one undo closure keeps the wrapper and original
|
|
346
|
-
// references out of the tracker entirely: there is no half-patched state for a
|
|
347
|
-
// caller to inspect, and no way to restore the wrong pair.
|
|
348
|
-
export const patchHistory = (
|
|
349
|
-
onNavigate: (source: NavigationSource) => void,
|
|
350
|
-
log: (message: string) => void
|
|
351
|
-
): (() => void) | null => {
|
|
352
|
-
if ((window.history.pushState as MarkedHistoryMethod)[WRAPPED_MARKER]) {
|
|
353
|
-
log(
|
|
354
|
-
'[patch] history already wrapped, skipping to avoid double-wrap — STACKED WRAPPER DETECTED'
|
|
355
|
-
);
|
|
356
|
-
return null;
|
|
357
|
-
}
|
|
358
|
-
|
|
359
|
-
const originals = {} as Record<HistoryMethodName, HistoryStateMethod>;
|
|
360
|
-
const wrappers = {} as Record<HistoryMethodName, HistoryStateMethod>;
|
|
361
|
-
|
|
362
|
-
HISTORY_METHODS.forEach(name => {
|
|
363
|
-
const original = window.history[name];
|
|
364
|
-
originals[name] = original;
|
|
365
|
-
|
|
366
|
-
const wrapper = function(
|
|
367
|
-
this: History,
|
|
368
|
-
...args: Parameters<HistoryStateMethod>
|
|
369
|
-
): void {
|
|
370
|
-
const result = original.apply(this, args);
|
|
371
|
-
onNavigate(name);
|
|
372
|
-
return result;
|
|
373
|
-
};
|
|
374
|
-
|
|
375
|
-
Object.defineProperty(wrapper, WRAPPED_MARKER, {
|
|
376
|
-
value: true,
|
|
377
|
-
enumerable: false,
|
|
378
|
-
});
|
|
379
|
-
|
|
380
|
-
wrappers[name] = wrapper;
|
|
381
|
-
});
|
|
382
|
-
|
|
383
|
-
// Restore per method: a third party may have patched one of the two on top of
|
|
384
|
-
// ours after we installed. Clobbering theirs would break their tracking, so
|
|
385
|
-
// leave anything that is no longer ours in place.
|
|
386
|
-
const restore = (): void =>
|
|
387
|
-
HISTORY_METHODS.forEach(name => {
|
|
388
|
-
if (window.history[name] === wrappers[name]) {
|
|
389
|
-
window.history[name] = originals[name];
|
|
390
|
-
log(`[teardown] restored original ${name}`);
|
|
391
|
-
} else {
|
|
392
|
-
log(
|
|
393
|
-
`[teardown] ${name} no longer ours; leaving in place, gating callback to no-op`
|
|
394
|
-
);
|
|
395
|
-
}
|
|
396
|
-
});
|
|
397
|
-
|
|
398
|
-
try {
|
|
399
|
-
HISTORY_METHODS.forEach(name => {
|
|
400
|
-
window.history[name] = wrappers[name];
|
|
401
|
-
});
|
|
402
|
-
} catch (e) {
|
|
403
|
-
log(
|
|
404
|
-
`[error] failed to patch history methods (frozen/sealed), rolling back: ${e}`
|
|
405
|
-
);
|
|
406
|
-
try {
|
|
407
|
-
restore();
|
|
408
|
-
} catch (restoreError) {
|
|
409
|
-
log(
|
|
410
|
-
`[error] failed to restore history methods after patch failure: ${restoreError}`
|
|
411
|
-
);
|
|
412
|
-
}
|
|
413
|
-
return null;
|
|
414
|
-
}
|
|
415
|
-
|
|
416
|
-
return restore;
|
|
417
|
-
};
|
|
418
331
|
|
|
419
332
|
// ---------------------------------------------------------------------------
|
|
420
333
|
// Tracker
|
|
@@ -428,7 +341,6 @@ export class PageViewTracker {
|
|
|
428
341
|
private pendingNavigations: IPendingNavigation[] = [];
|
|
429
342
|
|
|
430
343
|
private undoHistoryPatch: (() => void) | null = null;
|
|
431
|
-
private popStateListener: (() => void) | null = null;
|
|
432
344
|
|
|
433
345
|
private readonly isAutoPageView: boolean;
|
|
434
346
|
|
|
@@ -473,12 +385,11 @@ export class PageViewTracker {
|
|
|
473
385
|
this.lastPage = currentPage();
|
|
474
386
|
this.log(`[init] seeded lastPage: ${describePage(this.lastPage)}`);
|
|
475
387
|
|
|
476
|
-
this.undoHistoryPatch =
|
|
388
|
+
this.undoHistoryPatch = subscribeToRouteChange(
|
|
389
|
+
'pageView',
|
|
477
390
|
source => this.safeHandleNavigation(source),
|
|
478
391
|
message => this.log(message)
|
|
479
392
|
);
|
|
480
|
-
this.popStateListener = () => this.safeHandleNavigation('popstate');
|
|
481
|
-
window.addEventListener('popstate', this.popStateListener);
|
|
482
393
|
|
|
483
394
|
setActiveTracker(this);
|
|
484
395
|
|
|
@@ -495,11 +406,6 @@ export class PageViewTracker {
|
|
|
495
406
|
// point those paths are already transferred rather than dropped.
|
|
496
407
|
this.takePendingNavigations();
|
|
497
408
|
|
|
498
|
-
if (this.popStateListener) {
|
|
499
|
-
window.removeEventListener('popstate', this.popStateListener);
|
|
500
|
-
this.popStateListener = null;
|
|
501
|
-
}
|
|
502
|
-
|
|
503
409
|
if (this.undoHistoryPatch) {
|
|
504
410
|
this.undoHistoryPatch();
|
|
505
411
|
this.undoHistoryPatch = null;
|
package/src/persistence.ts
CHANGED
|
@@ -407,7 +407,7 @@ export default function _Persistence(
|
|
|
407
407
|
|
|
408
408
|
date.setTime(date.getTime() - 24 * 60 * 60 * 1000);
|
|
409
409
|
expires = '; expires=' + date.toUTCString();
|
|
410
|
-
|
|
410
|
+
writeCookie(cookieName + '=' + '' + expires + '; path=/' + domain);
|
|
411
411
|
};
|
|
412
412
|
|
|
413
413
|
this.getCookie = function(): IPersistenceMinified | null {
|
|
@@ -532,8 +532,9 @@ export default function _Persistence(
|
|
|
532
532
|
|
|
533
533
|
mpInstance.Logger.verbose(Messages.InformationMessages.CookieSet);
|
|
534
534
|
|
|
535
|
-
|
|
536
|
-
encodeURIComponent(key) + '=' + encodedCookiesWithExpirationAndPath
|
|
535
|
+
writeCookie(
|
|
536
|
+
encodeURIComponent(key) + '=' + encodedCookiesWithExpirationAndPath
|
|
537
|
+
);
|
|
537
538
|
};
|
|
538
539
|
|
|
539
540
|
/* This function determines if a cookie is greater than the configured maxCookieSize.
|
|
@@ -730,6 +731,11 @@ export default function _Persistence(
|
|
|
730
731
|
);
|
|
731
732
|
};
|
|
732
733
|
|
|
734
|
+
function writeCookie(cookie: string): void {
|
|
735
|
+
const isHttpsPage = window.location.protocol === 'https:';
|
|
736
|
+
window.document.cookie = isHttpsPage ? cookie + ';Secure' : cookie;
|
|
737
|
+
}
|
|
738
|
+
|
|
733
739
|
function createFullEncodedCookie(persistence: IPersistenceMinified, expires: string, domain: string): string {
|
|
734
740
|
return (
|
|
735
741
|
self.encodePersistence(JSON.stringify(persistence)) +
|
|
@@ -1086,10 +1092,11 @@ export default function _Persistence(
|
|
|
1086
1092
|
domain,
|
|
1087
1093
|
mpInstance._Store.SDKConfig.maxCookieSize
|
|
1088
1094
|
);
|
|
1089
|
-
|
|
1095
|
+
writeCookie(
|
|
1090
1096
|
encodeURIComponent(key) +
|
|
1091
|
-
|
|
1092
|
-
|
|
1097
|
+
'=' +
|
|
1098
|
+
encodedCookiesWithExpirationAndPath
|
|
1099
|
+
);
|
|
1093
1100
|
} else {
|
|
1094
1101
|
if (mpInstance._Store.isLocalStorageAvailable) {
|
|
1095
1102
|
try {
|