@mparticle/web-sdk 2.32.5 → 2.33.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/dist/mparticle.common.js +30 -16
- package/dist/mparticle.esm.js +30 -16
- package/dist/mparticle.js +206 -12
- package/package.json +2 -2
- package/src/foregroundTimeTracker.ts +113 -0
- package/src/integrationCapture.ts +82 -2
- package/src/mockBatchCreator.ts +3 -0
- package/src/mp-instance.ts +2 -0
- package/src/sdkRuntimeModels.ts +2 -0
- package/src/sdkToEventsApiConverter.ts +1 -0
- package/src/serverModel.ts +7 -2
- package/src/sessionManager.ts +8 -1
- package/src/store.ts +2 -0
- package/src/utils.ts +9 -4
package/dist/mparticle.js
CHANGED
|
@@ -203,7 +203,7 @@ var mParticle = (function () {
|
|
|
203
203
|
Base64: Base64$1
|
|
204
204
|
};
|
|
205
205
|
|
|
206
|
-
var version = "2.
|
|
206
|
+
var version = "2.33.1";
|
|
207
207
|
|
|
208
208
|
var Constants = {
|
|
209
209
|
sdkVersion: version,
|
|
@@ -713,9 +713,14 @@ var mParticle = (function () {
|
|
|
713
713
|
pairs.forEach(function (pair) {
|
|
714
714
|
var _a = pair.split('='),
|
|
715
715
|
key = _a[0],
|
|
716
|
-
|
|
717
|
-
|
|
718
|
-
|
|
716
|
+
valueParts = _a.slice(1);
|
|
717
|
+
var value = valueParts.join('=');
|
|
718
|
+
if (key && value !== undefined) {
|
|
719
|
+
try {
|
|
720
|
+
params[key] = decodeURIComponent(value || '');
|
|
721
|
+
} catch (e) {
|
|
722
|
+
console.error("Failed to decode value for key ".concat(key, ": ").concat(e));
|
|
723
|
+
}
|
|
719
724
|
}
|
|
720
725
|
});
|
|
721
726
|
return {
|
|
@@ -1923,7 +1928,8 @@ var mParticle = (function () {
|
|
|
1923
1928
|
session_start_unixtime_ms: sdkEvent.SessionStartDate,
|
|
1924
1929
|
custom_attributes: sdkEvent.EventAttributes,
|
|
1925
1930
|
location: convertSDKLocation(sdkEvent.Location),
|
|
1926
|
-
source_message_id: sdkEvent.SourceMessageId
|
|
1931
|
+
source_message_id: sdkEvent.SourceMessageId,
|
|
1932
|
+
active_time_on_site_ms: sdkEvent.ActiveTimeOnSite
|
|
1927
1933
|
};
|
|
1928
1934
|
return commonEventData;
|
|
1929
1935
|
}
|
|
@@ -3380,21 +3386,23 @@ var mParticle = (function () {
|
|
|
3380
3386
|
}
|
|
3381
3387
|
};
|
|
3382
3388
|
this.endSession = function (override) {
|
|
3383
|
-
var _a;
|
|
3389
|
+
var _a, _b, _c, _d, _e;
|
|
3384
3390
|
mpInstance.Logger.verbose(Messages$6.InformationMessages.StartingEndSession);
|
|
3385
3391
|
if (override) {
|
|
3386
3392
|
mpInstance._Events.logEvent({
|
|
3387
3393
|
messageType: Types.MessageType.SessionEnd
|
|
3388
3394
|
});
|
|
3389
3395
|
mpInstance._Store.nullifySession();
|
|
3396
|
+
(_a = mpInstance._timeOnSiteTimer) === null || _a === void 0 ? void 0 : _a.resetTimer();
|
|
3390
3397
|
return;
|
|
3391
3398
|
}
|
|
3392
3399
|
if (!mpInstance._Helpers.canLog()) {
|
|
3393
|
-
// At this moment, an AbandonedEndSession is defined when
|
|
3400
|
+
// At this moment, an AbandonedEndSession is defined when one of three things occurs:
|
|
3394
3401
|
// - the SDK's store is not enabled because mParticle.setOptOut was called
|
|
3395
3402
|
// - the devToken is undefined
|
|
3396
3403
|
// - webviewBridgeEnabled is set to false
|
|
3397
3404
|
mpInstance.Logger.verbose(Messages$6.InformationMessages.AbandonEndSession);
|
|
3405
|
+
(_b = mpInstance._timeOnSiteTimer) === null || _b === void 0 ? void 0 : _b.resetTimer();
|
|
3398
3406
|
return;
|
|
3399
3407
|
}
|
|
3400
3408
|
var sessionTimeoutInMilliseconds;
|
|
@@ -3402,13 +3410,14 @@ var mParticle = (function () {
|
|
|
3402
3410
|
var cookies = mpInstance._Persistence.getPersistence();
|
|
3403
3411
|
if (!cookies || cookies.gs && !cookies.gs.sid) {
|
|
3404
3412
|
mpInstance.Logger.verbose(Messages$6.InformationMessages.NoSessionToEnd);
|
|
3413
|
+
(_c = mpInstance._timeOnSiteTimer) === null || _c === void 0 ? void 0 : _c.resetTimer();
|
|
3405
3414
|
return;
|
|
3406
3415
|
}
|
|
3407
3416
|
// sessionId is not equal to cookies.sid if cookies.sid is changed in another tab
|
|
3408
3417
|
if (cookies.gs.sid && mpInstance._Store.sessionId !== cookies.gs.sid) {
|
|
3409
3418
|
mpInstance._Store.sessionId = cookies.gs.sid;
|
|
3410
3419
|
}
|
|
3411
|
-
if ((
|
|
3420
|
+
if ((_d = cookies === null || cookies === void 0 ? void 0 : cookies.gs) === null || _d === void 0 ? void 0 : _d.les) {
|
|
3412
3421
|
sessionTimeoutInMilliseconds = mpInstance._Store.SDKConfig.sessionTimeout * 60000;
|
|
3413
3422
|
var newDate = new Date().getTime();
|
|
3414
3423
|
timeSinceLastEventSent = newDate - cookies.gs.les;
|
|
@@ -3422,6 +3431,7 @@ var mParticle = (function () {
|
|
|
3422
3431
|
mpInstance._Store.nullifySession();
|
|
3423
3432
|
}
|
|
3424
3433
|
}
|
|
3434
|
+
(_e = mpInstance._timeOnSiteTimer) === null || _e === void 0 ? void 0 : _e.resetTimer();
|
|
3425
3435
|
};
|
|
3426
3436
|
this.setSessionTimer = function () {
|
|
3427
3437
|
var sessionTimeoutInMilliseconds = mpInstance._Store.SDKConfig.sessionTimeout * 60000;
|
|
@@ -3872,6 +3882,109 @@ var mParticle = (function () {
|
|
|
3872
3882
|
};
|
|
3873
3883
|
}
|
|
3874
3884
|
|
|
3885
|
+
var ForegroundTimeTracker = /** @class */function () {
|
|
3886
|
+
function ForegroundTimeTracker(timerKey) {
|
|
3887
|
+
this.isTrackerActive = false;
|
|
3888
|
+
this.localStorageName = '';
|
|
3889
|
+
this.startTime = 0;
|
|
3890
|
+
this.totalTime = 0;
|
|
3891
|
+
this.localStorageName = "mprtcl-tos-".concat(timerKey);
|
|
3892
|
+
this.timerVault = new LocalStorageVault(this.localStorageName);
|
|
3893
|
+
this.loadTimeFromStorage();
|
|
3894
|
+
this.addHandlers();
|
|
3895
|
+
if (document.hidden === false) {
|
|
3896
|
+
this.startTracking();
|
|
3897
|
+
}
|
|
3898
|
+
}
|
|
3899
|
+
ForegroundTimeTracker.prototype.addHandlers = function () {
|
|
3900
|
+
var _this = this;
|
|
3901
|
+
// when user switches tabs or minimizes the window
|
|
3902
|
+
document.addEventListener('visibilitychange', function () {
|
|
3903
|
+
return _this.handleVisibilityChange();
|
|
3904
|
+
});
|
|
3905
|
+
// when user switches to another application
|
|
3906
|
+
window.addEventListener('blur', function () {
|
|
3907
|
+
return _this.handleWindowBlur();
|
|
3908
|
+
});
|
|
3909
|
+
// when window gains focus
|
|
3910
|
+
window.addEventListener('focus', function () {
|
|
3911
|
+
return _this.handleWindowFocus();
|
|
3912
|
+
});
|
|
3913
|
+
// this ensures that timers between tabs are in sync
|
|
3914
|
+
window.addEventListener('storage', function (event) {
|
|
3915
|
+
return _this.syncAcrossTabs(event);
|
|
3916
|
+
});
|
|
3917
|
+
// when user closes tab, refreshes, or navigates to another page via link
|
|
3918
|
+
window.addEventListener('beforeunload', function () {
|
|
3919
|
+
return _this.updateTimeInPersistence();
|
|
3920
|
+
});
|
|
3921
|
+
};
|
|
3922
|
+
ForegroundTimeTracker.prototype.handleVisibilityChange = function () {
|
|
3923
|
+
if (document.hidden) {
|
|
3924
|
+
this.stopTracking();
|
|
3925
|
+
} else {
|
|
3926
|
+
this.startTracking();
|
|
3927
|
+
}
|
|
3928
|
+
};
|
|
3929
|
+
ForegroundTimeTracker.prototype.handleWindowBlur = function () {
|
|
3930
|
+
if (this.isTrackerActive) {
|
|
3931
|
+
this.stopTracking();
|
|
3932
|
+
}
|
|
3933
|
+
};
|
|
3934
|
+
ForegroundTimeTracker.prototype.handleWindowFocus = function () {
|
|
3935
|
+
if (!this.isTrackerActive) {
|
|
3936
|
+
this.startTracking();
|
|
3937
|
+
}
|
|
3938
|
+
};
|
|
3939
|
+
ForegroundTimeTracker.prototype.syncAcrossTabs = function (event) {
|
|
3940
|
+
if (event.key === this.localStorageName && event.newValue !== null) {
|
|
3941
|
+
var newTime = parseFloat(event.newValue) || 0;
|
|
3942
|
+
this.totalTime = newTime;
|
|
3943
|
+
}
|
|
3944
|
+
};
|
|
3945
|
+
ForegroundTimeTracker.prototype.updateTimeInPersistence = function () {
|
|
3946
|
+
if (this.isTrackerActive) {
|
|
3947
|
+
this.timerVault.store(Math.round(this.totalTime));
|
|
3948
|
+
}
|
|
3949
|
+
};
|
|
3950
|
+
ForegroundTimeTracker.prototype.loadTimeFromStorage = function () {
|
|
3951
|
+
var storedTime = this.timerVault.retrieve();
|
|
3952
|
+
if (isNumber(storedTime) && storedTime !== null) {
|
|
3953
|
+
this.totalTime = storedTime;
|
|
3954
|
+
}
|
|
3955
|
+
};
|
|
3956
|
+
ForegroundTimeTracker.prototype.startTracking = function () {
|
|
3957
|
+
if (!document.hidden) {
|
|
3958
|
+
this.startTime = Math.floor(performance.now());
|
|
3959
|
+
this.isTrackerActive = true;
|
|
3960
|
+
}
|
|
3961
|
+
};
|
|
3962
|
+
ForegroundTimeTracker.prototype.stopTracking = function () {
|
|
3963
|
+
if (this.isTrackerActive) {
|
|
3964
|
+
this.setTotalTime();
|
|
3965
|
+
this.updateTimeInPersistence();
|
|
3966
|
+
this.isTrackerActive = false;
|
|
3967
|
+
}
|
|
3968
|
+
};
|
|
3969
|
+
ForegroundTimeTracker.prototype.setTotalTime = function () {
|
|
3970
|
+
if (this.isTrackerActive) {
|
|
3971
|
+
var now = Math.floor(performance.now());
|
|
3972
|
+
this.totalTime += now - this.startTime;
|
|
3973
|
+
this.startTime = now;
|
|
3974
|
+
}
|
|
3975
|
+
};
|
|
3976
|
+
ForegroundTimeTracker.prototype.getTimeInForeground = function () {
|
|
3977
|
+
this.setTotalTime();
|
|
3978
|
+
this.updateTimeInPersistence();
|
|
3979
|
+
return this.totalTime;
|
|
3980
|
+
};
|
|
3981
|
+
ForegroundTimeTracker.prototype.resetTimer = function () {
|
|
3982
|
+
this.totalTime = 0;
|
|
3983
|
+
this.updateTimeInPersistence();
|
|
3984
|
+
};
|
|
3985
|
+
return ForegroundTimeTracker;
|
|
3986
|
+
}();
|
|
3987
|
+
|
|
3875
3988
|
function createSDKConfig(config) {
|
|
3876
3989
|
// TODO: Refactor to create a default config object
|
|
3877
3990
|
var sdkConfig = {};
|
|
@@ -4220,6 +4333,7 @@ var mParticle = (function () {
|
|
|
4220
4333
|
}
|
|
4221
4334
|
if (workspaceToken) {
|
|
4222
4335
|
_this.SDKConfig.workspaceToken = workspaceToken;
|
|
4336
|
+
mpInstance._timeOnSiteTimer = new ForegroundTimeTracker(workspaceToken);
|
|
4223
4337
|
} else {
|
|
4224
4338
|
mpInstance.Logger.warning('You should have a workspaceToken on your config object for security purposes.');
|
|
4225
4339
|
}
|
|
@@ -6529,6 +6643,7 @@ var mParticle = (function () {
|
|
|
6529
6643
|
return jsonObject;
|
|
6530
6644
|
};
|
|
6531
6645
|
this.createEventObject = function (event, user) {
|
|
6646
|
+
var _a;
|
|
6532
6647
|
var uploadObject = {};
|
|
6533
6648
|
var eventObject = {};
|
|
6534
6649
|
// The `optOut` variable is passed later in this method to the `uploadObject`
|
|
@@ -6539,6 +6654,7 @@ var mParticle = (function () {
|
|
|
6539
6654
|
// TODO: Why is Webview Bridge Enabled or Opt Out necessary here?
|
|
6540
6655
|
if (mpInstance._Store.sessionId || event.messageType === Types.MessageType.OptOut || mpInstance._Store.webviewBridgeEnabled) {
|
|
6541
6656
|
var customFlags = __assign({}, event.customFlags);
|
|
6657
|
+
var integrationAttributes = mpInstance._Store.integrationAttributes;
|
|
6542
6658
|
// https://go.mparticle.com/work/SQDSDKS-5053
|
|
6543
6659
|
if (mpInstance._Helpers.getFeatureFlag && mpInstance._Helpers.getFeatureFlag(Constants.FeatureFlags.CaptureIntegrationSpecificIds)) {
|
|
6544
6660
|
// Attempt to recapture click IDs in case a third party integration
|
|
@@ -6546,6 +6662,8 @@ var mParticle = (function () {
|
|
|
6546
6662
|
mpInstance._IntegrationCapture.capture();
|
|
6547
6663
|
var transformedClickIDs = mpInstance._IntegrationCapture.getClickIdsAsCustomFlags();
|
|
6548
6664
|
customFlags = __assign(__assign({}, transformedClickIDs), customFlags);
|
|
6665
|
+
var transformedIntegrationAttributes = mpInstance._IntegrationCapture.getClickIdsAsIntegrationAttributes();
|
|
6666
|
+
integrationAttributes = __assign(__assign({}, transformedIntegrationAttributes), integrationAttributes);
|
|
6549
6667
|
}
|
|
6550
6668
|
if (event.hasOwnProperty('toEventAPIObject')) {
|
|
6551
6669
|
eventObject = event.toEventAPIObject();
|
|
@@ -6557,6 +6675,7 @@ var mParticle = (function () {
|
|
|
6557
6675
|
EventName: event.name || event.messageType,
|
|
6558
6676
|
EventCategory: event.eventType,
|
|
6559
6677
|
EventAttributes: mpInstance._Helpers.sanitizeAttributes(event.data, event.name),
|
|
6678
|
+
ActiveTimeOnSite: (_a = mpInstance._timeOnSiteTimer) === null || _a === void 0 ? void 0 : _a.getTimeInForeground(),
|
|
6560
6679
|
SourceMessageId: event.sourceMessageId || mpInstance._Helpers.generateUniqueId(),
|
|
6561
6680
|
EventDataType: event.messageType,
|
|
6562
6681
|
CustomFlags: customFlags,
|
|
@@ -6583,7 +6702,7 @@ var mParticle = (function () {
|
|
|
6583
6702
|
Package: mpInstance._Store.SDKConfig["package"],
|
|
6584
6703
|
ClientGeneratedId: mpInstance._Store.clientId,
|
|
6585
6704
|
DeviceId: mpInstance._Store.deviceId,
|
|
6586
|
-
IntegrationAttributes:
|
|
6705
|
+
IntegrationAttributes: integrationAttributes,
|
|
6587
6706
|
CurrencyCode: mpInstance._Store.currencyCode,
|
|
6588
6707
|
DataPlan: mpInstance._Store.SDKConfig.dataPlan ? mpInstance._Store.SDKConfig.dataPlan : {}
|
|
6589
6708
|
};
|
|
@@ -9201,9 +9320,11 @@ var mParticle = (function () {
|
|
|
9201
9320
|
// Integration outputs are used to determine how click ids are used within the SDK
|
|
9202
9321
|
// CUSTOM_FLAGS are sent out when an Event is created via ServerModel.createEventObject
|
|
9203
9322
|
// PARTNER_IDENTITIES are sent out in a Batch when a group of events are converted to a Batch
|
|
9323
|
+
// INTEGRATION_ATTRIBUTES are stored initially on the SDKEvent level but then is added to the Batch when the batch is created
|
|
9204
9324
|
var IntegrationOutputs = {
|
|
9205
9325
|
CUSTOM_FLAGS: 'custom_flags',
|
|
9206
|
-
PARTNER_IDENTITIES: 'partner_identities'
|
|
9326
|
+
PARTNER_IDENTITIES: 'partner_identities',
|
|
9327
|
+
INTEGRATION_ATTRIBUTES: 'integration_attributes'
|
|
9207
9328
|
};
|
|
9208
9329
|
var integrationMapping = {
|
|
9209
9330
|
// Facebook / Meta
|
|
@@ -9233,6 +9354,18 @@ var mParticle = (function () {
|
|
|
9233
9354
|
mappedKey: 'GoogleEnhancedConversions.Wbraid',
|
|
9234
9355
|
output: IntegrationOutputs.CUSTOM_FLAGS
|
|
9235
9356
|
},
|
|
9357
|
+
// Rokt
|
|
9358
|
+
// https://docs.rokt.com/developers/integration-guides/web/advanced/rokt-id-tag/
|
|
9359
|
+
rtid: {
|
|
9360
|
+
mappedKey: 'passbackconversiontrackingid',
|
|
9361
|
+
output: IntegrationOutputs.INTEGRATION_ATTRIBUTES,
|
|
9362
|
+
moduleId: 1277
|
|
9363
|
+
},
|
|
9364
|
+
RoktTransactionId: {
|
|
9365
|
+
mappedKey: 'passbackconversiontrackingid',
|
|
9366
|
+
output: IntegrationOutputs.INTEGRATION_ATTRIBUTES,
|
|
9367
|
+
moduleId: 1277
|
|
9368
|
+
},
|
|
9236
9369
|
// TIKTOK
|
|
9237
9370
|
ttclid: {
|
|
9238
9371
|
mappedKey: 'TikTok.Callback',
|
|
@@ -9249,6 +9382,7 @@ var mParticle = (function () {
|
|
|
9249
9382
|
// Cache filtered mappings for faster access
|
|
9250
9383
|
this.filteredPartnerIdentityMappings = this.filterMappings(IntegrationOutputs.PARTNER_IDENTITIES);
|
|
9251
9384
|
this.filteredCustomFlagMappings = this.filterMappings(IntegrationOutputs.CUSTOM_FLAGS);
|
|
9385
|
+
this.filteredIntegrationAttributeMappings = this.filterMappings(IntegrationOutputs.INTEGRATION_ATTRIBUTES);
|
|
9252
9386
|
}
|
|
9253
9387
|
/**
|
|
9254
9388
|
* Captures Integration Ids from cookies and query params and stores them in clickIds object
|
|
@@ -9256,19 +9390,33 @@ var mParticle = (function () {
|
|
|
9256
9390
|
IntegrationCapture.prototype.capture = function () {
|
|
9257
9391
|
var queryParams = this.captureQueryParams() || {};
|
|
9258
9392
|
var cookies = this.captureCookies() || {};
|
|
9393
|
+
var localStorage = this.captureLocalStorage() || {};
|
|
9259
9394
|
// Exclude _fbc if fbclid is present
|
|
9260
9395
|
// https://developers.facebook.com/docs/marketing-api/conversions-api/parameters/fbp-and-fbc#retrieve-from-fbclid-url-query-parameter
|
|
9261
9396
|
if (queryParams['fbclid'] && cookies['_fbc']) {
|
|
9262
9397
|
delete cookies['_fbc'];
|
|
9263
9398
|
}
|
|
9264
|
-
|
|
9399
|
+
// If both rtid and RoktTransactionId are present, prioritize rtid
|
|
9400
|
+
// If RoktTransactionId is present in both cookies and localStorage,
|
|
9401
|
+
// prioritize localStorage
|
|
9402
|
+
if (queryParams['rtid'] && localStorage['RoktTransactionId'] && cookies['RoktTransactionId']) {
|
|
9403
|
+
delete localStorage['RoktTransactionId'];
|
|
9404
|
+
delete cookies['RoktTransactionId'];
|
|
9405
|
+
} else if (queryParams['rtid'] && localStorage['RoktTransactionId']) {
|
|
9406
|
+
delete localStorage['RoktTransactionId'];
|
|
9407
|
+
} else if (queryParams['rtid'] && cookies['RoktTransactionId']) {
|
|
9408
|
+
delete cookies['RoktTransactionId'];
|
|
9409
|
+
} else if (localStorage['RoktTransactionId'] && cookies['RoktTransactionId']) {
|
|
9410
|
+
delete cookies['RoktTransactionId'];
|
|
9411
|
+
}
|
|
9412
|
+
this.clickIds = __assign(__assign(__assign(__assign({}, this.clickIds), queryParams), localStorage), cookies);
|
|
9265
9413
|
};
|
|
9266
9414
|
/**
|
|
9267
9415
|
* Captures cookies based on the integration ID mapping.
|
|
9268
9416
|
*/
|
|
9269
9417
|
IntegrationCapture.prototype.captureCookies = function () {
|
|
9270
9418
|
var cookies = getCookies(Object.keys(integrationMapping));
|
|
9271
|
-
return this.applyProcessors(cookies);
|
|
9419
|
+
return this.applyProcessors(cookies, getHref(), this.initialTimestamp);
|
|
9272
9420
|
};
|
|
9273
9421
|
/**
|
|
9274
9422
|
* Captures query parameters based on the integration ID mapping.
|
|
@@ -9277,6 +9425,19 @@ var mParticle = (function () {
|
|
|
9277
9425
|
var queryParams = this.getQueryParams();
|
|
9278
9426
|
return this.applyProcessors(queryParams, getHref(), this.initialTimestamp);
|
|
9279
9427
|
};
|
|
9428
|
+
/**
|
|
9429
|
+
* Captures local storage based on the integration ID mapping.
|
|
9430
|
+
*/
|
|
9431
|
+
IntegrationCapture.prototype.captureLocalStorage = function () {
|
|
9432
|
+
var localStorageItems = {};
|
|
9433
|
+
for (var key in integrationMapping) {
|
|
9434
|
+
var localStorageItem = localStorage.getItem(key);
|
|
9435
|
+
if (localStorageItem) {
|
|
9436
|
+
localStorageItems[key] = localStorageItem;
|
|
9437
|
+
}
|
|
9438
|
+
}
|
|
9439
|
+
return this.applyProcessors(localStorageItems, getHref(), this.initialTimestamp);
|
|
9440
|
+
};
|
|
9280
9441
|
/**
|
|
9281
9442
|
* Gets the query parameters based on the integration ID mapping.
|
|
9282
9443
|
* @returns {Dictionary<string>} The query parameters.
|
|
@@ -9298,6 +9459,36 @@ var mParticle = (function () {
|
|
|
9298
9459
|
IntegrationCapture.prototype.getClickIdsAsPartnerIdentities = function () {
|
|
9299
9460
|
return this.getClickIds(this.clickIds, this.filteredPartnerIdentityMappings);
|
|
9300
9461
|
};
|
|
9462
|
+
/**
|
|
9463
|
+
* Returns only the `integration_attributes` mapped integration output.
|
|
9464
|
+
* @returns {IntegrationAttributes} The integration attributes.
|
|
9465
|
+
*/
|
|
9466
|
+
IntegrationCapture.prototype.getClickIdsAsIntegrationAttributes = function () {
|
|
9467
|
+
var _a;
|
|
9468
|
+
var _b, _c;
|
|
9469
|
+
// Integration IDs are stored in the following format:
|
|
9470
|
+
// {
|
|
9471
|
+
// "integration_attributes": {
|
|
9472
|
+
// "<moduleId>": {
|
|
9473
|
+
// "mappedKey": "clickIdValue"
|
|
9474
|
+
// }
|
|
9475
|
+
// }
|
|
9476
|
+
// }
|
|
9477
|
+
var mappedClickIds = {};
|
|
9478
|
+
for (var key in this.clickIds) {
|
|
9479
|
+
if (this.clickIds.hasOwnProperty(key)) {
|
|
9480
|
+
var value = this.clickIds[key];
|
|
9481
|
+
var mappingKey = (_b = this.filteredIntegrationAttributeMappings[key]) === null || _b === void 0 ? void 0 : _b.mappedKey;
|
|
9482
|
+
if (!isEmpty(mappingKey)) {
|
|
9483
|
+
var moduleId = (_c = this.filteredIntegrationAttributeMappings[key]) === null || _c === void 0 ? void 0 : _c.moduleId;
|
|
9484
|
+
if (moduleId && !mappedClickIds[moduleId]) {
|
|
9485
|
+
mappedClickIds[moduleId] = (_a = {}, _a[mappingKey] = value, _a);
|
|
9486
|
+
}
|
|
9487
|
+
}
|
|
9488
|
+
}
|
|
9489
|
+
}
|
|
9490
|
+
return mappedClickIds;
|
|
9491
|
+
};
|
|
9301
9492
|
IntegrationCapture.prototype.getClickIds = function (clickIds, mappingList) {
|
|
9302
9493
|
var _a;
|
|
9303
9494
|
var mappedClickIds = {};
|
|
@@ -10472,6 +10663,9 @@ var mParticle = (function () {
|
|
|
10472
10663
|
},
|
|
10473
10664
|
_resetForTests: mockFunction,
|
|
10474
10665
|
_APIClient: null,
|
|
10666
|
+
_timeOnSiteTimer: {
|
|
10667
|
+
getTimeInForeground: mockFunction
|
|
10668
|
+
},
|
|
10475
10669
|
MPSideloadedKit: null,
|
|
10476
10670
|
_Consent: null,
|
|
10477
10671
|
_Events: null,
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@mparticle/web-sdk",
|
|
3
|
-
"version": "2.
|
|
3
|
+
"version": "2.33.1",
|
|
4
4
|
"description": "mParticle core SDK for web applications",
|
|
5
5
|
"license": "Apache-2.0",
|
|
6
6
|
"keywords": [
|
|
@@ -87,7 +87,7 @@
|
|
|
87
87
|
"@babel/preset-env": "^7.6.0",
|
|
88
88
|
"@babel/preset-typescript": "^7.6.0",
|
|
89
89
|
"@mparticle/data-planning-models": "^0.1.0",
|
|
90
|
-
"@mparticle/event-models": "^1.1.
|
|
90
|
+
"@mparticle/event-models": "^1.1.9",
|
|
91
91
|
"@rollup/plugin-babel": "6.0.3",
|
|
92
92
|
"@rollup/plugin-commonjs": "25.0.4",
|
|
93
93
|
"@rollup/plugin-json": "^5.0.2",
|
|
@@ -0,0 +1,113 @@
|
|
|
1
|
+
import { isNumber } from './utils';
|
|
2
|
+
import { LocalStorageVault } from './vault';
|
|
3
|
+
|
|
4
|
+
export default class ForegroundTimeTracker {
|
|
5
|
+
private isTrackerActive: boolean = false;
|
|
6
|
+
private localStorageName: string = '';
|
|
7
|
+
private timerVault: LocalStorageVault<number>;
|
|
8
|
+
public startTime: number = 0;
|
|
9
|
+
public totalTime: number = 0;
|
|
10
|
+
|
|
11
|
+
constructor(timerKey: string) {
|
|
12
|
+
this.localStorageName = `mprtcl-tos-${timerKey}`;
|
|
13
|
+
this.timerVault = new LocalStorageVault<number>(this.localStorageName);
|
|
14
|
+
this.loadTimeFromStorage();
|
|
15
|
+
this.addHandlers();
|
|
16
|
+
if (document.hidden === false) {
|
|
17
|
+
this.startTracking();
|
|
18
|
+
}
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
private addHandlers(): void {
|
|
22
|
+
// when user switches tabs or minimizes the window
|
|
23
|
+
document.addEventListener('visibilitychange', () =>
|
|
24
|
+
this.handleVisibilityChange()
|
|
25
|
+
);
|
|
26
|
+
// when user switches to another application
|
|
27
|
+
window.addEventListener('blur', () => this.handleWindowBlur());
|
|
28
|
+
// when window gains focus
|
|
29
|
+
window.addEventListener('focus', () => this.handleWindowFocus());
|
|
30
|
+
// this ensures that timers between tabs are in sync
|
|
31
|
+
window.addEventListener('storage', event => this.syncAcrossTabs(event));
|
|
32
|
+
// when user closes tab, refreshes, or navigates to another page via link
|
|
33
|
+
window.addEventListener('beforeunload', () =>
|
|
34
|
+
this.updateTimeInPersistence()
|
|
35
|
+
);
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
private handleVisibilityChange(): void {
|
|
39
|
+
if (document.hidden) {
|
|
40
|
+
this.stopTracking();
|
|
41
|
+
} else {
|
|
42
|
+
this.startTracking();
|
|
43
|
+
}
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
private handleWindowBlur(): void {
|
|
47
|
+
if (this.isTrackerActive) {
|
|
48
|
+
this.stopTracking();
|
|
49
|
+
}
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
private handleWindowFocus(): void {
|
|
53
|
+
if (!this.isTrackerActive) {
|
|
54
|
+
this.startTracking();
|
|
55
|
+
}
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
private syncAcrossTabs(event: StorageEvent): void {
|
|
59
|
+
if (event.key === this.localStorageName && event.newValue !== null) {
|
|
60
|
+
const newTime = parseFloat(event.newValue) || 0;
|
|
61
|
+
this.totalTime = newTime;
|
|
62
|
+
}
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
public updateTimeInPersistence(): void {
|
|
66
|
+
if (this.isTrackerActive) {
|
|
67
|
+
this.timerVault.store(Math.round(this.totalTime));
|
|
68
|
+
}
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
private loadTimeFromStorage(): void {
|
|
72
|
+
const storedTime = this.timerVault.retrieve();
|
|
73
|
+
if (isNumber(storedTime) && storedTime !== null) {
|
|
74
|
+
this.totalTime = storedTime;
|
|
75
|
+
}
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
|
|
79
|
+
private startTracking(): void {
|
|
80
|
+
if (!document.hidden) {
|
|
81
|
+
this.startTime = Math.floor(performance.now());
|
|
82
|
+
this.isTrackerActive = true;
|
|
83
|
+
}
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
private stopTracking(): void {
|
|
87
|
+
if (this.isTrackerActive) {
|
|
88
|
+
this.setTotalTime();
|
|
89
|
+
this.updateTimeInPersistence();
|
|
90
|
+
this.isTrackerActive = false;
|
|
91
|
+
}
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
private setTotalTime(): void {
|
|
95
|
+
if (this.isTrackerActive) {
|
|
96
|
+
const now = Math.floor(performance.now());
|
|
97
|
+
this.totalTime += now - this.startTime;
|
|
98
|
+
this.startTime = now;
|
|
99
|
+
|
|
100
|
+
}
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
public getTimeInForeground(): number {
|
|
104
|
+
this.setTotalTime();
|
|
105
|
+
this.updateTimeInPersistence();
|
|
106
|
+
return this.totalTime;
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
public resetTimer(): void {
|
|
110
|
+
this.totalTime = 0;
|
|
111
|
+
this.updateTimeInPersistence();
|
|
112
|
+
}
|
|
113
|
+
}
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { SDKEventCustomFlags } from './sdkRuntimeModels';
|
|
2
|
+
import { IntegrationAttributes } from './store';
|
|
2
3
|
import {
|
|
3
4
|
Dictionary,
|
|
4
5
|
queryStringParser,
|
|
@@ -53,16 +54,19 @@ export const facebookClickIdProcessor: IntegrationCaptureProcessorFunction = (
|
|
|
53
54
|
// Integration outputs are used to determine how click ids are used within the SDK
|
|
54
55
|
// CUSTOM_FLAGS are sent out when an Event is created via ServerModel.createEventObject
|
|
55
56
|
// PARTNER_IDENTITIES are sent out in a Batch when a group of events are converted to a Batch
|
|
57
|
+
// INTEGRATION_ATTRIBUTES are stored initially on the SDKEvent level but then is added to the Batch when the batch is created
|
|
56
58
|
|
|
57
59
|
const IntegrationOutputs = {
|
|
58
60
|
CUSTOM_FLAGS: 'custom_flags',
|
|
59
61
|
PARTNER_IDENTITIES: 'partner_identities',
|
|
62
|
+
INTEGRATION_ATTRIBUTES: 'integration_attributes',
|
|
60
63
|
} as const;
|
|
61
64
|
|
|
62
65
|
interface IntegrationMappingItem {
|
|
63
66
|
mappedKey: string;
|
|
64
67
|
output: valueof<typeof IntegrationOutputs>;
|
|
65
68
|
processor?: IntegrationCaptureProcessorFunction;
|
|
69
|
+
moduleId?: number;
|
|
66
70
|
}
|
|
67
71
|
|
|
68
72
|
interface IntegrationIdMapping {
|
|
@@ -99,6 +103,19 @@ const integrationMapping: IntegrationIdMapping = {
|
|
|
99
103
|
output: IntegrationOutputs.CUSTOM_FLAGS,
|
|
100
104
|
},
|
|
101
105
|
|
|
106
|
+
// Rokt
|
|
107
|
+
// https://docs.rokt.com/developers/integration-guides/web/advanced/rokt-id-tag/
|
|
108
|
+
rtid: {
|
|
109
|
+
mappedKey: 'passbackconversiontrackingid',
|
|
110
|
+
output: IntegrationOutputs.INTEGRATION_ATTRIBUTES,
|
|
111
|
+
moduleId: 1277,
|
|
112
|
+
},
|
|
113
|
+
RoktTransactionId: {
|
|
114
|
+
mappedKey: 'passbackconversiontrackingid',
|
|
115
|
+
output: IntegrationOutputs.INTEGRATION_ATTRIBUTES,
|
|
116
|
+
moduleId: 1277,
|
|
117
|
+
},
|
|
118
|
+
|
|
102
119
|
// TIKTOK
|
|
103
120
|
ttclid: {
|
|
104
121
|
mappedKey: 'TikTok.Callback',
|
|
@@ -115,6 +132,7 @@ export default class IntegrationCapture {
|
|
|
115
132
|
public readonly initialTimestamp: number;
|
|
116
133
|
public readonly filteredPartnerIdentityMappings: IntegrationIdMapping;
|
|
117
134
|
public readonly filteredCustomFlagMappings: IntegrationIdMapping;
|
|
135
|
+
public readonly filteredIntegrationAttributeMappings: IntegrationIdMapping;
|
|
118
136
|
|
|
119
137
|
constructor() {
|
|
120
138
|
this.initialTimestamp = Date.now();
|
|
@@ -122,6 +140,7 @@ export default class IntegrationCapture {
|
|
|
122
140
|
// Cache filtered mappings for faster access
|
|
123
141
|
this.filteredPartnerIdentityMappings = this.filterMappings(IntegrationOutputs.PARTNER_IDENTITIES);
|
|
124
142
|
this.filteredCustomFlagMappings = this.filterMappings(IntegrationOutputs.CUSTOM_FLAGS);
|
|
143
|
+
this.filteredIntegrationAttributeMappings = this.filterMappings(IntegrationOutputs.INTEGRATION_ATTRIBUTES);
|
|
125
144
|
}
|
|
126
145
|
|
|
127
146
|
/**
|
|
@@ -130,6 +149,7 @@ export default class IntegrationCapture {
|
|
|
130
149
|
public capture(): void {
|
|
131
150
|
const queryParams = this.captureQueryParams() || {};
|
|
132
151
|
const cookies = this.captureCookies() || {};
|
|
152
|
+
const localStorage = this.captureLocalStorage() || {};
|
|
133
153
|
|
|
134
154
|
// Exclude _fbc if fbclid is present
|
|
135
155
|
// https://developers.facebook.com/docs/marketing-api/conversions-api/parameters/fbp-and-fbc#retrieve-from-fbclid-url-query-parameter
|
|
@@ -137,7 +157,21 @@ export default class IntegrationCapture {
|
|
|
137
157
|
delete cookies['_fbc'];
|
|
138
158
|
}
|
|
139
159
|
|
|
140
|
-
|
|
160
|
+
// If both rtid and RoktTransactionId are present, prioritize rtid
|
|
161
|
+
// If RoktTransactionId is present in both cookies and localStorage,
|
|
162
|
+
// prioritize localStorage
|
|
163
|
+
if (queryParams['rtid'] && localStorage['RoktTransactionId'] && cookies['RoktTransactionId']) {
|
|
164
|
+
delete localStorage['RoktTransactionId'];
|
|
165
|
+
delete cookies['RoktTransactionId'];
|
|
166
|
+
} else if (queryParams['rtid'] && localStorage['RoktTransactionId']) {
|
|
167
|
+
delete localStorage['RoktTransactionId'];
|
|
168
|
+
} else if (queryParams['rtid'] && cookies['RoktTransactionId']) {
|
|
169
|
+
delete cookies['RoktTransactionId'];
|
|
170
|
+
} else if (localStorage['RoktTransactionId'] && cookies['RoktTransactionId']) {
|
|
171
|
+
delete cookies['RoktTransactionId'];
|
|
172
|
+
}
|
|
173
|
+
|
|
174
|
+
this.clickIds = { ...this.clickIds, ...queryParams, ...localStorage, ...cookies };
|
|
141
175
|
}
|
|
142
176
|
|
|
143
177
|
/**
|
|
@@ -145,7 +179,7 @@ export default class IntegrationCapture {
|
|
|
145
179
|
*/
|
|
146
180
|
public captureCookies(): Dictionary<string> {
|
|
147
181
|
const cookies = getCookies(Object.keys(integrationMapping));
|
|
148
|
-
return this.applyProcessors(cookies);
|
|
182
|
+
return this.applyProcessors(cookies, getHref(), this.initialTimestamp);
|
|
149
183
|
}
|
|
150
184
|
|
|
151
185
|
/**
|
|
@@ -156,6 +190,21 @@ export default class IntegrationCapture {
|
|
|
156
190
|
return this.applyProcessors(queryParams, getHref(), this.initialTimestamp);
|
|
157
191
|
}
|
|
158
192
|
|
|
193
|
+
/**
|
|
194
|
+
* Captures local storage based on the integration ID mapping.
|
|
195
|
+
*/
|
|
196
|
+
public captureLocalStorage(): Dictionary<string> {
|
|
197
|
+
let localStorageItems: Dictionary<string> = {};
|
|
198
|
+
for (const key in integrationMapping) {
|
|
199
|
+
const localStorageItem = localStorage.getItem(key);
|
|
200
|
+
if (localStorageItem) {
|
|
201
|
+
localStorageItems[key] = localStorageItem;
|
|
202
|
+
}
|
|
203
|
+
}
|
|
204
|
+
|
|
205
|
+
return this.applyProcessors(localStorageItems, getHref(), this.initialTimestamp);
|
|
206
|
+
}
|
|
207
|
+
|
|
159
208
|
/**
|
|
160
209
|
* Gets the query parameters based on the integration ID mapping.
|
|
161
210
|
* @returns {Dictionary<string>} The query parameters.
|
|
@@ -180,6 +229,37 @@ export default class IntegrationCapture {
|
|
|
180
229
|
return this.getClickIds(this.clickIds, this.filteredPartnerIdentityMappings);
|
|
181
230
|
}
|
|
182
231
|
|
|
232
|
+
/**
|
|
233
|
+
* Returns only the `integration_attributes` mapped integration output.
|
|
234
|
+
* @returns {IntegrationAttributes} The integration attributes.
|
|
235
|
+
*/
|
|
236
|
+
public getClickIdsAsIntegrationAttributes(): IntegrationAttributes {
|
|
237
|
+
// Integration IDs are stored in the following format:
|
|
238
|
+
// {
|
|
239
|
+
// "integration_attributes": {
|
|
240
|
+
// "<moduleId>": {
|
|
241
|
+
// "mappedKey": "clickIdValue"
|
|
242
|
+
// }
|
|
243
|
+
// }
|
|
244
|
+
// }
|
|
245
|
+
const mappedClickIds: IntegrationAttributes = {};
|
|
246
|
+
|
|
247
|
+
for (const key in this.clickIds) {
|
|
248
|
+
if (this.clickIds.hasOwnProperty(key)) {
|
|
249
|
+
const value = this.clickIds[key];
|
|
250
|
+
const mappingKey = this.filteredIntegrationAttributeMappings[key]?.mappedKey;
|
|
251
|
+
if (!isEmpty(mappingKey)) {
|
|
252
|
+
const moduleId = this.filteredIntegrationAttributeMappings[key]?.moduleId;
|
|
253
|
+
if (moduleId && !mappedClickIds[moduleId]) {
|
|
254
|
+
mappedClickIds[moduleId] = { [mappingKey]: value };
|
|
255
|
+
}
|
|
256
|
+
}
|
|
257
|
+
}
|
|
258
|
+
}
|
|
259
|
+
return mappedClickIds;
|
|
260
|
+
}
|
|
261
|
+
|
|
262
|
+
|
|
183
263
|
private getClickIds(
|
|
184
264
|
clickIds: Dictionary<string>,
|
|
185
265
|
mappingList: IntegrationIdMapping
|
package/src/mockBatchCreator.ts
CHANGED