@mparticle/web-sdk 2.32.0 → 2.32.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 +18 -36
- package/dist/mparticle.esm.js +18 -36
- package/dist/mparticle.js +86 -117
- package/package.json +1 -1
- package/src/aliasRequestApiClient.ts +2 -1
- package/src/configAPIClient.ts +2 -12
- package/src/consent.ts +4 -0
- package/src/cookieSyncManager.ts +162 -0
- package/src/identity.js +1 -5
- package/src/identityApiClient.interfaces.ts +44 -0
- package/src/nativeSdkHelpers.interfaces.ts +13 -0
- package/src/persistence.interfaces.ts +3 -4
- package/src/sdkRuntimeModels.ts +5 -1
- package/src/store.ts +3 -3
- package/src/utils.ts +25 -0
- package/src/cookieSyncManager.js +0 -197
package/dist/mparticle.js
CHANGED
|
@@ -393,7 +393,7 @@ var mParticle = (function () {
|
|
|
393
393
|
return e.name = "SuppressedError", e.error = error, e.suppressed = suppressed, e;
|
|
394
394
|
};
|
|
395
395
|
|
|
396
|
-
var version = "2.32.
|
|
396
|
+
var version = "2.32.1";
|
|
397
397
|
|
|
398
398
|
var Constants = {
|
|
399
399
|
sdkVersion: version,
|
|
@@ -705,6 +705,19 @@ var mParticle = (function () {
|
|
|
705
705
|
var replaceQuotesWithApostrophes = function replaceQuotesWithApostrophes(value) {
|
|
706
706
|
return value.replace(/\"/g, "'");
|
|
707
707
|
};
|
|
708
|
+
var replaceMPID = function replaceMPID(value, mpid) {
|
|
709
|
+
return value.replace('%%mpid%%', mpid);
|
|
710
|
+
};
|
|
711
|
+
var replaceAmpWithAmpersand = function replaceAmpWithAmpersand(value) {
|
|
712
|
+
return value.replace(/&/g, '&');
|
|
713
|
+
};
|
|
714
|
+
var createCookieSyncUrl = function createCookieSyncUrl(mpid, pixelUrl, redirectUrl) {
|
|
715
|
+
var modifiedPixelUrl = replaceAmpWithAmpersand(pixelUrl);
|
|
716
|
+
var modifiedDirectUrl = redirectUrl ? replaceAmpWithAmpersand(redirectUrl) : null;
|
|
717
|
+
var url = replaceMPID(modifiedPixelUrl, mpid);
|
|
718
|
+
var redirect = modifiedDirectUrl ? replaceMPID(modifiedDirectUrl, mpid) : '';
|
|
719
|
+
return url + encodeURIComponent(redirect);
|
|
720
|
+
};
|
|
708
721
|
// FIXME: REFACTOR for V3
|
|
709
722
|
// only used in store.js to sanitize server-side formatting of
|
|
710
723
|
// booleans when checking for `isDevelopmentMode`
|
|
@@ -3300,124 +3313,80 @@ var mParticle = (function () {
|
|
|
3300
3313
|
}
|
|
3301
3314
|
|
|
3302
3315
|
var Messages$8 = Constants.Messages;
|
|
3303
|
-
|
|
3316
|
+
var InformationMessages = Messages$8.InformationMessages;
|
|
3317
|
+
var DAYS_IN_MILLISECONDS = 1000 * 60 * 60 * 24;
|
|
3318
|
+
function CookieSyncManager(mpInstance) {
|
|
3304
3319
|
var self = this;
|
|
3305
|
-
|
|
3306
3320
|
// Public
|
|
3307
|
-
this.attemptCookieSync = function (
|
|
3308
|
-
|
|
3309
|
-
|
|
3310
|
-
|
|
3311
|
-
|
|
3312
|
-
if (mpid && !mpInstance._Store.webviewBridgeEnabled) {
|
|
3313
|
-
mpInstance._Store.pixelConfigurations.forEach(function (pixelSettings) {
|
|
3314
|
-
// set requiresConsent to false to start each additional pixel configuration
|
|
3315
|
-
// set to true only if filteringConsenRuleValues.values.length exists
|
|
3316
|
-
requiresConsent = false;
|
|
3317
|
-
|
|
3318
|
-
// TODO: Replace with isEmpty
|
|
3319
|
-
if (pixelSettings.filteringConsentRuleValues && pixelSettings.filteringConsentRuleValues.values && pixelSettings.filteringConsentRuleValues.values.length) {
|
|
3320
|
-
requiresConsent = true;
|
|
3321
|
-
}
|
|
3322
|
-
pixelConfig = {
|
|
3323
|
-
// Kit Module ID
|
|
3324
|
-
moduleId: pixelSettings.moduleId,
|
|
3325
|
-
// Tells you how often we should do a cookie sync (in days)
|
|
3326
|
-
frequencyCap: pixelSettings.frequencyCap,
|
|
3327
|
-
// Url for cookie sync pixel
|
|
3328
|
-
pixelUrl: self.replaceAmp(pixelSettings.pixelUrl),
|
|
3329
|
-
// TODO: Document requirements for redirectUrl
|
|
3330
|
-
redirectUrl: pixelSettings.redirectUrl ? self.replaceAmp(pixelSettings.redirectUrl) : null,
|
|
3331
|
-
// Filtering rules as defined in UI
|
|
3332
|
-
filteringConsentRuleValues: pixelSettings.filteringConsentRuleValues
|
|
3333
|
-
};
|
|
3334
|
-
|
|
3335
|
-
// TODO: combine replaceMPID and replaceAmp into sanitizeUrl function
|
|
3336
|
-
url = self.replaceMPID(pixelConfig.pixelUrl, mpid);
|
|
3337
|
-
redirect = pixelConfig.redirectUrl ? self.replaceMPID(pixelConfig.redirectUrl, mpid) : '';
|
|
3338
|
-
urlWithRedirect = url + encodeURIComponent(redirect);
|
|
3339
|
-
|
|
3340
|
-
// TODO: Refactor so that Persistence is only called once
|
|
3341
|
-
// outside of the loop
|
|
3342
|
-
var persistence = mpInstance._Persistence.getPersistence();
|
|
3343
|
-
|
|
3344
|
-
// TODO: Is there a historic reason for checking for previousMPID?
|
|
3345
|
-
// it does not appear to be passed in anywhere
|
|
3346
|
-
if (previousMPID && previousMPID !== mpid) {
|
|
3347
|
-
if (persistence && persistence[mpid]) {
|
|
3348
|
-
if (!persistence[mpid].csd) {
|
|
3349
|
-
persistence[mpid].csd = {};
|
|
3350
|
-
}
|
|
3351
|
-
self.performCookieSync(urlWithRedirect, pixelConfig.moduleId, mpid, persistence[mpid].csd, pixelConfig.filteringConsentRuleValues, mpidIsNotInCookies, requiresConsent);
|
|
3352
|
-
}
|
|
3353
|
-
return;
|
|
3354
|
-
} else {
|
|
3355
|
-
// TODO: Refactor to check for the inverse and exit early
|
|
3356
|
-
// rather than nesting
|
|
3357
|
-
if (persistence[mpid]) {
|
|
3358
|
-
if (!persistence[mpid].csd) {
|
|
3359
|
-
persistence[mpid].csd = {};
|
|
3360
|
-
}
|
|
3361
|
-
lastSyncDateForModule = persistence[mpid].csd[pixelConfig.moduleId.toString()] ? persistence[mpid].csd[pixelConfig.moduleId.toString()] : null;
|
|
3362
|
-
if (lastSyncDateForModule) {
|
|
3363
|
-
// Check to see if we need to refresh cookieSync
|
|
3364
|
-
if (
|
|
3365
|
-
// TODO: Turn this into a convenience method for readability?
|
|
3366
|
-
// We use similar comparisons elsewhere in the SDK,
|
|
3367
|
-
// so perhaps we can make a time comparison convenience method
|
|
3368
|
-
new Date().getTime() > new Date(lastSyncDateForModule).getTime() + pixelConfig.frequencyCap *
|
|
3369
|
-
// TODO: Turn these numbers into a constant so
|
|
3370
|
-
// we can remember what this number is for
|
|
3371
|
-
60 * 1000 * 60 * 24) {
|
|
3372
|
-
self.performCookieSync(urlWithRedirect, pixelConfig.moduleId, mpid, persistence[mpid].csd, pixelConfig.filteringConsentRuleValues, mpidIsNotInCookies, requiresConsent);
|
|
3373
|
-
}
|
|
3374
|
-
} else {
|
|
3375
|
-
self.performCookieSync(urlWithRedirect, pixelConfig.moduleId, mpid, persistence[mpid].csd, pixelConfig.filteringConsentRuleValues, mpidIsNotInCookies, requiresConsent);
|
|
3376
|
-
}
|
|
3377
|
-
}
|
|
3378
|
-
}
|
|
3379
|
-
});
|
|
3380
|
-
}
|
|
3381
|
-
};
|
|
3382
|
-
|
|
3383
|
-
// Private
|
|
3384
|
-
this.replaceMPID = function (string, mpid) {
|
|
3385
|
-
return string.replace('%%mpid%%', mpid);
|
|
3386
|
-
};
|
|
3387
|
-
|
|
3388
|
-
// Private
|
|
3389
|
-
// TODO: Rename function to replaceAmpWithAmpersand
|
|
3390
|
-
this.replaceAmp = function (string) {
|
|
3391
|
-
return string.replace(/&/g, '&');
|
|
3392
|
-
};
|
|
3393
|
-
|
|
3394
|
-
// Private
|
|
3395
|
-
this.performCookieSync = function (url, moduleId, mpid, cookieSyncDates, filteringConsentRuleValues, mpidIsNotInCookies, requiresConsent) {
|
|
3396
|
-
// if MPID is new to cookies, we should not try to perform the cookie sync
|
|
3397
|
-
// because a cookie sync can only occur once a user either consents or doesn't
|
|
3398
|
-
// we should not check if its enabled if the user has a blank consent
|
|
3399
|
-
// TODO: We should do this check outside of this function
|
|
3400
|
-
if (requiresConsent && mpidIsNotInCookies) {
|
|
3321
|
+
this.attemptCookieSync = function (mpid, mpidIsNotInCookies) {
|
|
3322
|
+
var _a = mpInstance._Store,
|
|
3323
|
+
pixelConfigurations = _a.pixelConfigurations,
|
|
3324
|
+
webviewBridgeEnabled = _a.webviewBridgeEnabled;
|
|
3325
|
+
if (!mpid || webviewBridgeEnabled) {
|
|
3401
3326
|
return;
|
|
3402
3327
|
}
|
|
3403
|
-
|
|
3404
|
-
|
|
3405
|
-
|
|
3406
|
-
// cookie sync attempt per module.
|
|
3407
|
-
// Currently, attemptCookieSync is called as a loop and therefore this
|
|
3408
|
-
// function polls the user object and consent multiple times.
|
|
3409
|
-
if (mpInstance._Consent.isEnabledForUserConsent(filteringConsentRuleValues, mpInstance.Identity.getCurrentUser())) {
|
|
3410
|
-
var img = document.createElement('img');
|
|
3411
|
-
mpInstance.Logger.verbose(Messages$8.InformationMessages.CookieSync);
|
|
3412
|
-
img.onload = function () {
|
|
3413
|
-
// TODO: Break this out into a convenience method so we can unit test
|
|
3414
|
-
cookieSyncDates[moduleId.toString()] = new Date().getTime();
|
|
3415
|
-
mpInstance._Persistence.saveUserCookieSyncDatesToPersistence(mpid, cookieSyncDates);
|
|
3416
|
-
};
|
|
3417
|
-
img.src = url;
|
|
3328
|
+
var persistence = mpInstance._Persistence.getPersistence();
|
|
3329
|
+
if (isEmpty(persistence)) {
|
|
3330
|
+
return;
|
|
3418
3331
|
}
|
|
3332
|
+
pixelConfigurations.forEach(function (pixelSettings) {
|
|
3333
|
+
var _a, _b;
|
|
3334
|
+
// set requiresConsent to false to start each additional pixel configuration
|
|
3335
|
+
// set to true only if filteringConsenRuleValues.values.length exists
|
|
3336
|
+
var requiresConsent = false;
|
|
3337
|
+
// Filtering rules as defined in UI
|
|
3338
|
+
var filteringConsentRuleValues = pixelSettings.filteringConsentRuleValues,
|
|
3339
|
+
pixelUrl = pixelSettings.pixelUrl,
|
|
3340
|
+
redirectUrl = pixelSettings.redirectUrl,
|
|
3341
|
+
moduleId = pixelSettings.moduleId,
|
|
3342
|
+
// Tells you how often we should do a cookie sync (in days)
|
|
3343
|
+
frequencyCap = pixelSettings.frequencyCap;
|
|
3344
|
+
var values = (filteringConsentRuleValues || {}).values;
|
|
3345
|
+
if (isEmpty(pixelUrl)) {
|
|
3346
|
+
return;
|
|
3347
|
+
}
|
|
3348
|
+
if (!isEmpty(values)) {
|
|
3349
|
+
requiresConsent = true;
|
|
3350
|
+
}
|
|
3351
|
+
// If MPID is new to cookies, we should not try to perform the cookie sync
|
|
3352
|
+
// because a cookie sync can only occur once a user either consents or doesn't.
|
|
3353
|
+
// we should not check if it's enabled if the user has a blank consent
|
|
3354
|
+
if (requiresConsent && mpidIsNotInCookies) {
|
|
3355
|
+
return;
|
|
3356
|
+
}
|
|
3357
|
+
var isEnabledForUserConsent = mpInstance._Consent.isEnabledForUserConsent;
|
|
3358
|
+
if (!isEnabledForUserConsent(filteringConsentRuleValues, mpInstance.Identity.getCurrentUser())) {
|
|
3359
|
+
return;
|
|
3360
|
+
}
|
|
3361
|
+
var cookieSyncDates = (_b = (_a = persistence[mpid]) === null || _a === void 0 ? void 0 : _a.csd) !== null && _b !== void 0 ? _b : {};
|
|
3362
|
+
var lastSyncDateForModule = cookieSyncDates[moduleId] || null;
|
|
3363
|
+
if (!isLastSyncDateExpired(frequencyCap, lastSyncDateForModule)) {
|
|
3364
|
+
return;
|
|
3365
|
+
}
|
|
3366
|
+
// Url for cookie sync pixel
|
|
3367
|
+
var fullUrl = createCookieSyncUrl(mpid, pixelUrl, redirectUrl);
|
|
3368
|
+
self.performCookieSync(fullUrl, moduleId.toString(), mpid, cookieSyncDates);
|
|
3369
|
+
});
|
|
3370
|
+
};
|
|
3371
|
+
// Private
|
|
3372
|
+
this.performCookieSync = function (url, moduleId, mpid, cookieSyncDates) {
|
|
3373
|
+
var img = document.createElement('img');
|
|
3374
|
+
mpInstance.Logger.verbose(InformationMessages.CookieSync);
|
|
3375
|
+
img.onload = function () {
|
|
3376
|
+
cookieSyncDates[moduleId] = new Date().getTime();
|
|
3377
|
+
mpInstance._Persistence.saveUserCookieSyncDatesToPersistence(mpid, cookieSyncDates);
|
|
3378
|
+
};
|
|
3379
|
+
img.src = url;
|
|
3419
3380
|
};
|
|
3420
3381
|
}
|
|
3382
|
+
var isLastSyncDateExpired = function isLastSyncDateExpired(frequencyCap, lastSyncDate) {
|
|
3383
|
+
// If there is no lastSyncDate, then there is no previous cookie sync, so we should sync the cookie
|
|
3384
|
+
if (!lastSyncDate) {
|
|
3385
|
+
return true;
|
|
3386
|
+
}
|
|
3387
|
+
// Otherwise, compare the last sync date to determine if it should do a cookie sync again
|
|
3388
|
+
return new Date().getTime() > new Date(lastSyncDate).getTime() + frequencyCap * DAYS_IN_MILLISECONDS;
|
|
3389
|
+
};
|
|
3421
3390
|
|
|
3422
3391
|
var Messages$7 = Constants.Messages;
|
|
3423
3392
|
function SessionManager(mpInstance) {
|
|
@@ -7853,7 +7822,7 @@ var mParticle = (function () {
|
|
|
7853
7822
|
setConsentState: function setConsentState(state) {
|
|
7854
7823
|
mpInstance._Store.setConsentState(mpid, state);
|
|
7855
7824
|
mpInstance._Forwarders.initForwarders(this.getUserIdentities().userIdentities, mpInstance._APIClient.prepareForwardingStats);
|
|
7856
|
-
mpInstance._CookieSyncManager.attemptCookieSync(
|
|
7825
|
+
mpInstance._CookieSyncManager.attemptCookieSync(this.getMPID());
|
|
7857
7826
|
},
|
|
7858
7827
|
isLoggedIn: function isLoggedIn() {
|
|
7859
7828
|
return _isLoggedIn;
|
|
@@ -8050,7 +8019,7 @@ var mParticle = (function () {
|
|
|
8050
8019
|
mpInstance._Persistence.setFirstSeenTime(identityApiResult.mpid);
|
|
8051
8020
|
}
|
|
8052
8021
|
mpInstance._Store.addMpidToSessionHistory(identityApiResult.mpid, previousMPID);
|
|
8053
|
-
mpInstance._CookieSyncManager.attemptCookieSync(
|
|
8022
|
+
mpInstance._CookieSyncManager.attemptCookieSync(identityApiResult.mpid, mpidIsNotInCookies);
|
|
8054
8023
|
mpInstance._Persistence.swapCurrentUser(previousMPID, identityApiResult.mpid, mpInstance._Store.currentSessionMPIDs);
|
|
8055
8024
|
if (identityApiData && !isEmpty(identityApiData.userIdentities)) {
|
|
8056
8025
|
newIdentitiesByType = self.IdentityRequest.combineUserIdentities(incomingUIByName, identityApiData.userIdentities);
|
|
@@ -9033,7 +9002,7 @@ var mParticle = (function () {
|
|
|
9033
9002
|
|
|
9034
9003
|
var HTTPCodes$2 = Constants.HTTPCodes,
|
|
9035
9004
|
Messages$2 = Constants.Messages;
|
|
9036
|
-
function sendAliasRequest(mpInstance, aliasRequest, aliasCallback) {
|
|
9005
|
+
var sendAliasRequest = function sendAliasRequest(mpInstance, aliasRequest, aliasCallback) {
|
|
9037
9006
|
return __awaiter(this, void 0, void 0, function () {
|
|
9038
9007
|
var _a, verbose, error, invokeAliasCallback, aliasUrl, apiKey, uploadUrl, uploader, uploadPayload, response, message, aliasResponseBody, xhrResponse, errorMessage, e_2, err;
|
|
9039
9008
|
return __generator(this, function (_b) {
|
|
@@ -9109,7 +9078,7 @@ var mParticle = (function () {
|
|
|
9109
9078
|
}
|
|
9110
9079
|
});
|
|
9111
9080
|
});
|
|
9112
|
-
}
|
|
9081
|
+
};
|
|
9113
9082
|
|
|
9114
9083
|
var HTTPCodes$1 = Constants.HTTPCodes,
|
|
9115
9084
|
Messages$1 = Constants.Messages;
|
|
@@ -9430,7 +9399,7 @@ var mParticle = (function () {
|
|
|
9430
9399
|
this._Persistence = new _Persistence(this);
|
|
9431
9400
|
this._Helpers = new Helpers(this);
|
|
9432
9401
|
this._Events = new Events(this);
|
|
9433
|
-
this._CookieSyncManager = new
|
|
9402
|
+
this._CookieSyncManager = new CookieSyncManager(this);
|
|
9434
9403
|
this._ServerModel = new ServerModel(this);
|
|
9435
9404
|
this._Ecommerce = new Ecommerce(this);
|
|
9436
9405
|
this._ForwardingStatsUploader = new forwardingStatsUploader(this);
|
package/package.json
CHANGED
|
@@ -3,6 +3,7 @@ import { MParticleWebSDK } from "./sdkRuntimeModels";
|
|
|
3
3
|
import Constants from './constants';
|
|
4
4
|
import { FetchUploader, XHRUploader } from './uploaders';
|
|
5
5
|
import { HTTP_ACCEPTED, HTTP_OK } from "./constants";
|
|
6
|
+
import { IIdentityApiClientSendAliasRequest } from "./identityApiClient.interfaces";
|
|
6
7
|
|
|
7
8
|
|
|
8
9
|
const { HTTPCodes, Messages } = Constants;
|
|
@@ -11,7 +12,7 @@ interface IAliasResponseBody {
|
|
|
11
12
|
message?: string
|
|
12
13
|
}
|
|
13
14
|
|
|
14
|
-
export async function
|
|
15
|
+
export const sendAliasRequest: IIdentityApiClientSendAliasRequest = async function (mpInstance: MParticleWebSDK, aliasRequest: IAliasRequest, aliasCallback: IAliasCallback): Promise<void> {
|
|
15
16
|
const { verbose, error } = mpInstance.Logger;
|
|
16
17
|
const { invokeAliasCallback } = mpInstance._Helpers;
|
|
17
18
|
const { aliasUrl } = mpInstance._Store.SDKConfig;
|
package/src/configAPIClient.ts
CHANGED
|
@@ -13,6 +13,7 @@ import {
|
|
|
13
13
|
FetchUploader,
|
|
14
14
|
XHRUploader,
|
|
15
15
|
} from './uploaders';
|
|
16
|
+
import { IPixelConfiguration } from './cookieSyncManager';
|
|
16
17
|
|
|
17
18
|
export interface IKitConfigs extends IKitFilterSettings {
|
|
18
19
|
name: string;
|
|
@@ -65,17 +66,6 @@ export interface IConsentRuleValue {
|
|
|
65
66
|
hasConsented: boolean;
|
|
66
67
|
}
|
|
67
68
|
|
|
68
|
-
export interface IPixelConfig {
|
|
69
|
-
name: string;
|
|
70
|
-
moduleId: number;
|
|
71
|
-
esId: number;
|
|
72
|
-
isDebug: boolean;
|
|
73
|
-
isProduction: boolean;
|
|
74
|
-
settings: Dictionary;
|
|
75
|
-
frequencyCap: number;
|
|
76
|
-
pixelUrl: string;
|
|
77
|
-
redirectUrl: string;
|
|
78
|
-
}
|
|
79
69
|
|
|
80
70
|
export interface IConfigResponse {
|
|
81
71
|
appName: string;
|
|
@@ -85,7 +75,7 @@ export interface IConfigResponse {
|
|
|
85
75
|
secureServiceUrl: string;
|
|
86
76
|
minWebviewBridgeVersion: number;
|
|
87
77
|
workspaceToken: string;
|
|
88
|
-
pixelConfigs:
|
|
78
|
+
pixelConfigs: IPixelConfiguration[];
|
|
89
79
|
flags: SDKEventCustomFlags;
|
|
90
80
|
}
|
|
91
81
|
|
package/src/consent.ts
CHANGED
|
@@ -38,6 +38,10 @@ export interface SDKConsentApi {
|
|
|
38
38
|
createConsentState: (consentState?: ConsentState) => ConsentState;
|
|
39
39
|
ConsentSerialization: IConsentSerialization;
|
|
40
40
|
createPrivacyConsent: ICreatePrivacyConsentFunction;
|
|
41
|
+
isEnabledForUserConsent: (
|
|
42
|
+
consentRules: IConsentRules,
|
|
43
|
+
user: IMParticleUser
|
|
44
|
+
) => boolean;
|
|
41
45
|
}
|
|
42
46
|
|
|
43
47
|
export interface IConsentSerialization {
|
|
@@ -0,0 +1,162 @@
|
|
|
1
|
+
import {
|
|
2
|
+
Dictionary,
|
|
3
|
+
isEmpty,
|
|
4
|
+
createCookieSyncUrl,
|
|
5
|
+
} from './utils';
|
|
6
|
+
import Constants from './constants';
|
|
7
|
+
import { MParticleWebSDK } from './sdkRuntimeModels';
|
|
8
|
+
import { MPID } from '@mparticle/web-sdk';
|
|
9
|
+
import { IConsentRules } from './consent';
|
|
10
|
+
|
|
11
|
+
const { Messages } = Constants;
|
|
12
|
+
const { InformationMessages } = Messages;
|
|
13
|
+
|
|
14
|
+
export const DAYS_IN_MILLISECONDS = 1000 * 60 * 60 * 24;
|
|
15
|
+
|
|
16
|
+
export type CookieSyncDates = Dictionary<number>;
|
|
17
|
+
|
|
18
|
+
export interface IPixelConfiguration {
|
|
19
|
+
name?: string;
|
|
20
|
+
moduleId: number;
|
|
21
|
+
esId?: number;
|
|
22
|
+
isDebug?: boolean;
|
|
23
|
+
isProduction?: boolean;
|
|
24
|
+
settings: Dictionary<string>;
|
|
25
|
+
frequencyCap: number;
|
|
26
|
+
pixelUrl: string;
|
|
27
|
+
redirectUrl: string;
|
|
28
|
+
filteringConsentRuleValues?: IConsentRules;
|
|
29
|
+
}
|
|
30
|
+
export interface ICookieSyncManager {
|
|
31
|
+
attemptCookieSync: (
|
|
32
|
+
mpid: MPID,
|
|
33
|
+
mpidIsNotInCookies?: boolean
|
|
34
|
+
) => void;
|
|
35
|
+
performCookieSync: (
|
|
36
|
+
url: string,
|
|
37
|
+
moduleId: string,
|
|
38
|
+
mpid: MPID,
|
|
39
|
+
cookieSyncDates: CookieSyncDates,
|
|
40
|
+
) => void;
|
|
41
|
+
combineUrlWithRedirect: (
|
|
42
|
+
mpid: MPID,
|
|
43
|
+
pixelUrl: string,
|
|
44
|
+
redirectUrl: string
|
|
45
|
+
) => string;
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
export default function CookieSyncManager(
|
|
49
|
+
this: ICookieSyncManager,
|
|
50
|
+
mpInstance: MParticleWebSDK
|
|
51
|
+
) {
|
|
52
|
+
const self = this;
|
|
53
|
+
|
|
54
|
+
// Public
|
|
55
|
+
this.attemptCookieSync = (
|
|
56
|
+
mpid: MPID,
|
|
57
|
+
mpidIsNotInCookies?: boolean
|
|
58
|
+
): void => {
|
|
59
|
+
const { pixelConfigurations, webviewBridgeEnabled } = mpInstance._Store;
|
|
60
|
+
|
|
61
|
+
if (!mpid || webviewBridgeEnabled) {
|
|
62
|
+
return;
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
const persistence = mpInstance._Persistence.getPersistence();
|
|
66
|
+
|
|
67
|
+
if (isEmpty(persistence)) {
|
|
68
|
+
return;
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
pixelConfigurations.forEach((pixelSettings: IPixelConfiguration) => {
|
|
72
|
+
// set requiresConsent to false to start each additional pixel configuration
|
|
73
|
+
// set to true only if filteringConsenRuleValues.values.length exists
|
|
74
|
+
let requiresConsent = false;
|
|
75
|
+
// Filtering rules as defined in UI
|
|
76
|
+
const {
|
|
77
|
+
filteringConsentRuleValues,
|
|
78
|
+
pixelUrl,
|
|
79
|
+
redirectUrl,
|
|
80
|
+
moduleId,
|
|
81
|
+
// Tells you how often we should do a cookie sync (in days)
|
|
82
|
+
frequencyCap,
|
|
83
|
+
} = pixelSettings;
|
|
84
|
+
const { values } = filteringConsentRuleValues || {};
|
|
85
|
+
|
|
86
|
+
if (isEmpty(pixelUrl)) {
|
|
87
|
+
return;
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
if (!isEmpty(values)) {
|
|
91
|
+
requiresConsent = true;
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
// If MPID is new to cookies, we should not try to perform the cookie sync
|
|
95
|
+
// because a cookie sync can only occur once a user either consents or doesn't.
|
|
96
|
+
// we should not check if it's enabled if the user has a blank consent
|
|
97
|
+
if (requiresConsent && mpidIsNotInCookies) {
|
|
98
|
+
return;
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
const { isEnabledForUserConsent } = mpInstance._Consent;
|
|
102
|
+
|
|
103
|
+
if (!isEnabledForUserConsent(filteringConsentRuleValues, mpInstance.Identity.getCurrentUser())) {
|
|
104
|
+
return;
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
const cookieSyncDates: CookieSyncDates = persistence[mpid]?.csd ?? {};
|
|
108
|
+
const lastSyncDateForModule: number = cookieSyncDates[moduleId] || null;
|
|
109
|
+
|
|
110
|
+
if (!isLastSyncDateExpired(frequencyCap, lastSyncDateForModule)) {
|
|
111
|
+
return;
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
// Url for cookie sync pixel
|
|
115
|
+
const fullUrl = createCookieSyncUrl(mpid, pixelUrl, redirectUrl)
|
|
116
|
+
|
|
117
|
+
self.performCookieSync(
|
|
118
|
+
fullUrl,
|
|
119
|
+
moduleId.toString(),
|
|
120
|
+
mpid,
|
|
121
|
+
cookieSyncDates
|
|
122
|
+
);
|
|
123
|
+
});
|
|
124
|
+
};
|
|
125
|
+
|
|
126
|
+
// Private
|
|
127
|
+
this.performCookieSync = (
|
|
128
|
+
url: string,
|
|
129
|
+
moduleId: string,
|
|
130
|
+
mpid: MPID,
|
|
131
|
+
cookieSyncDates: CookieSyncDates,
|
|
132
|
+
): void => {
|
|
133
|
+
const img = document.createElement('img');
|
|
134
|
+
|
|
135
|
+
mpInstance.Logger.verbose(InformationMessages.CookieSync);
|
|
136
|
+
img.onload = function() {
|
|
137
|
+
cookieSyncDates[moduleId] = new Date().getTime();
|
|
138
|
+
|
|
139
|
+
mpInstance._Persistence.saveUserCookieSyncDatesToPersistence(
|
|
140
|
+
mpid,
|
|
141
|
+
cookieSyncDates
|
|
142
|
+
);
|
|
143
|
+
};
|
|
144
|
+
img.src = url;
|
|
145
|
+
};
|
|
146
|
+
}
|
|
147
|
+
|
|
148
|
+
export const isLastSyncDateExpired = (
|
|
149
|
+
frequencyCap: number,
|
|
150
|
+
lastSyncDate?: number
|
|
151
|
+
): boolean => {
|
|
152
|
+
// If there is no lastSyncDate, then there is no previous cookie sync, so we should sync the cookie
|
|
153
|
+
if (!lastSyncDate) {
|
|
154
|
+
return true;
|
|
155
|
+
}
|
|
156
|
+
|
|
157
|
+
// Otherwise, compare the last sync date to determine if it should do a cookie sync again
|
|
158
|
+
return (
|
|
159
|
+
new Date().getTime() >
|
|
160
|
+
new Date(lastSyncDate).getTime() + frequencyCap * DAYS_IN_MILLISECONDS
|
|
161
|
+
);
|
|
162
|
+
};
|
package/src/identity.js
CHANGED
|
@@ -1231,10 +1231,7 @@ export default function Identity(mpInstance) {
|
|
|
1231
1231
|
this.getUserIdentities().userIdentities,
|
|
1232
1232
|
mpInstance._APIClient.prepareForwardingStats
|
|
1233
1233
|
);
|
|
1234
|
-
mpInstance._CookieSyncManager.attemptCookieSync(
|
|
1235
|
-
null,
|
|
1236
|
-
this.getMPID()
|
|
1237
|
-
);
|
|
1234
|
+
mpInstance._CookieSyncManager.attemptCookieSync(this.getMPID());
|
|
1238
1235
|
},
|
|
1239
1236
|
isLoggedIn: function() {
|
|
1240
1237
|
return isLoggedIn;
|
|
@@ -1563,7 +1560,6 @@ export default function Identity(mpInstance) {
|
|
|
1563
1560
|
);
|
|
1564
1561
|
|
|
1565
1562
|
mpInstance._CookieSyncManager.attemptCookieSync(
|
|
1566
|
-
previousMPID,
|
|
1567
1563
|
identityApiResult.mpid,
|
|
1568
1564
|
mpidIsNotInCookies
|
|
1569
1565
|
);
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
import { IdentityApiData, MPID, UserIdentities } from '@mparticle/web-sdk';
|
|
2
|
+
import {
|
|
3
|
+
IdentityCallback,
|
|
4
|
+
IIdentityResponse,
|
|
5
|
+
} from './identity-user-interfaces';
|
|
6
|
+
import {
|
|
7
|
+
IAliasRequest,
|
|
8
|
+
IAliasCallback,
|
|
9
|
+
IIdentityRequest,
|
|
10
|
+
IdentityAPIMethod,
|
|
11
|
+
IIdentity,
|
|
12
|
+
} from './identity.interfaces';
|
|
13
|
+
import { MParticleWebSDK } from './sdkRuntimeModels';
|
|
14
|
+
|
|
15
|
+
export interface IIdentityApiClient {
|
|
16
|
+
sendAliasRequest: (
|
|
17
|
+
aliasRequest: IAliasRequest,
|
|
18
|
+
aliasCallback: IAliasCallback
|
|
19
|
+
) => Promise<void>;
|
|
20
|
+
sendIdentityRequest: (
|
|
21
|
+
identityApiRequest: IIdentityRequest,
|
|
22
|
+
method: IdentityAPIMethod,
|
|
23
|
+
callback: IdentityCallback,
|
|
24
|
+
originalIdentityApiData: IdentityApiData,
|
|
25
|
+
parseIdentityResponse: IIdentity['parseIdentityResponse'],
|
|
26
|
+
mpid: MPID,
|
|
27
|
+
knownIdentities: UserIdentities
|
|
28
|
+
) => Promise<void>;
|
|
29
|
+
getUploadUrl: (method: IdentityAPIMethod, mpid: MPID) => string;
|
|
30
|
+
getIdentityResponseFromFetch: (
|
|
31
|
+
response: Response,
|
|
32
|
+
responseBody: string
|
|
33
|
+
) => IIdentityResponse;
|
|
34
|
+
getIdentityResponseFromXHR: (response: Response) => IIdentityResponse;
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
// https://go.mparticle.com/work/SQDSDKS-6568
|
|
38
|
+
// https://go.mparticle.com/work/SQDSDKS-6679
|
|
39
|
+
// Combine with `sendIdentityRequest` above once module is fully migrated
|
|
40
|
+
export type IIdentityApiClientSendAliasRequest = (
|
|
41
|
+
mpInstance: MParticleWebSDK,
|
|
42
|
+
aliasRequest: IAliasRequest,
|
|
43
|
+
aliasCallback: IAliasCallback
|
|
44
|
+
) => Promise<void>;
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
export interface INativeSdkHelpers {
|
|
2
|
+
initializeSessionAttributes: (apiKey: string) => void;
|
|
3
|
+
isBridgeV2Available: (bridgeName: string) => boolean;
|
|
4
|
+
isWebviewEnabled: (
|
|
5
|
+
requiredWebviewBridgeName: string,
|
|
6
|
+
minWebviewBridgeVersion: number
|
|
7
|
+
) => boolean;
|
|
8
|
+
isBridgeV1Available: () => boolean;
|
|
9
|
+
sendToNative: (path: string, value: string) => void;
|
|
10
|
+
sendViaBridgeV1: (path: string, value: string) => void;
|
|
11
|
+
sendViaIframeToIOS: (path: string, value: string) => void;
|
|
12
|
+
sendViaBridgeV2: (path: string, value: string, requiredWebviewBridgeName: boolean) => void;
|
|
13
|
+
}
|
|
@@ -14,6 +14,7 @@ import {
|
|
|
14
14
|
import { Dictionary } from './utils';
|
|
15
15
|
import { IMinifiedConsentJSONObject } from './consent';
|
|
16
16
|
import { UserAttributes } from './identity-user-interfaces';
|
|
17
|
+
import { CookieSyncDates } from './cookieSyncManager';
|
|
17
18
|
|
|
18
19
|
export type UploadsTable = Dictionary<any>;
|
|
19
20
|
export interface iForwardingStatsBatches {
|
|
@@ -79,10 +80,8 @@ export interface IPersistenceMinified extends Dictionary {
|
|
|
79
80
|
// };
|
|
80
81
|
}
|
|
81
82
|
|
|
82
|
-
export type CookieSyncDate = Dictionary<number>;
|
|
83
|
-
|
|
84
83
|
export interface IUserPersistenceMinified extends Dictionary {
|
|
85
|
-
csd:
|
|
84
|
+
csd: CookieSyncDates; // list of timestamps for last cookie sync per module
|
|
86
85
|
con: IMinifiedConsentJSONObject; // Consent State
|
|
87
86
|
ui: UserIdentities; // User Identities
|
|
88
87
|
ua: UserAttributes; // User Attributes
|
|
@@ -121,7 +120,7 @@ export interface IPersistence {
|
|
|
121
120
|
getDomain(doc: string, locationHostname: string): string;
|
|
122
121
|
getCartProducts(mpid: MPID): Product[];
|
|
123
122
|
setCartProducts(allProducts: Product[]): void;
|
|
124
|
-
saveUserCookieSyncDatesToPersistence(mpid: MPID, csd:
|
|
123
|
+
saveUserCookieSyncDatesToPersistence(mpid: MPID, csd: CookieSyncDates): void;
|
|
125
124
|
savePersistence(persistance: IPersistenceMinified): void;
|
|
126
125
|
getPersistence(): IPersistenceMinified;
|
|
127
126
|
getFirstSeenTime(mpid: MPID): string | null;
|
package/src/sdkRuntimeModels.ts
CHANGED
|
@@ -31,6 +31,8 @@ import {
|
|
|
31
31
|
} from './identity-user-interfaces';
|
|
32
32
|
import { IIdentityType } from './types.interfaces';
|
|
33
33
|
import IntegrationCapture from './integrationCapture';
|
|
34
|
+
import { INativeSdkHelpers } from './nativeSdkHelpers.interfaces';
|
|
35
|
+
import { ICookieSyncManager, IPixelConfiguration } from './cookieSyncManager';
|
|
34
36
|
|
|
35
37
|
// TODO: Resolve this with version in @mparticle/web-sdk
|
|
36
38
|
export type SDKEventCustomFlags = Dictionary<any>;
|
|
@@ -158,6 +160,7 @@ export interface MParticleWebSDK {
|
|
|
158
160
|
Logger: SDKLoggerApi;
|
|
159
161
|
MPSideloadedKit: IMPSideloadedKit;
|
|
160
162
|
_APIClient: any; // TODO: Set up API Client
|
|
163
|
+
_CookieSyncManager: ICookieSyncManager;
|
|
161
164
|
_Store: IStore;
|
|
162
165
|
_Forwarders: any;
|
|
163
166
|
_Helpers: SDKHelpersApi;
|
|
@@ -167,7 +170,7 @@ export interface MParticleWebSDK {
|
|
|
167
170
|
_SessionManager: ISessionManager;
|
|
168
171
|
_Consent: SDKConsentApi;
|
|
169
172
|
Consent: SDKConsentApi;
|
|
170
|
-
_NativeSdkHelpers:
|
|
173
|
+
_NativeSdkHelpers: INativeSdkHelpers;
|
|
171
174
|
_Persistence: IPersistence;
|
|
172
175
|
_preInit: any; // TODO: Set up API
|
|
173
176
|
_instances?: Dictionary<MParticleWebSDK>;
|
|
@@ -228,6 +231,7 @@ export interface SDKInitConfig
|
|
|
228
231
|
sideloadedKits?: MPForwarder[];
|
|
229
232
|
dataPlanOptions?: KitBlockerOptions;
|
|
230
233
|
flags?: Dictionary;
|
|
234
|
+
pixelConfigs?: IPixelConfiguration[];
|
|
231
235
|
|
|
232
236
|
aliasMaxWindow?: number;
|
|
233
237
|
deviceId?: string;
|
package/src/store.ts
CHANGED
|
@@ -37,6 +37,7 @@ import {
|
|
|
37
37
|
IGlobalStoreV2MinifiedKeys,
|
|
38
38
|
IPersistenceMinified,
|
|
39
39
|
} from './persistence.interfaces';
|
|
40
|
+
import { CookieSyncDates, IPixelConfiguration } from './cookieSyncManager';
|
|
40
41
|
|
|
41
42
|
// This represents the runtime configuration of the SDK AFTER
|
|
42
43
|
// initialization has been complete and all settings and
|
|
@@ -118,7 +119,6 @@ function createSDKConfig(config: SDKInitConfig): SDKConfig {
|
|
|
118
119
|
|
|
119
120
|
// TODO: Placeholder Types to be filled in as we migrate more modules
|
|
120
121
|
// to TypeScript
|
|
121
|
-
export type PixelConfiguration = Dictionary;
|
|
122
122
|
export type ServerSettings = Dictionary;
|
|
123
123
|
export type SessionAttributes = Dictionary;
|
|
124
124
|
export type IntegrationAttributes = Dictionary<Dictionary<string>>;
|
|
@@ -168,7 +168,7 @@ export interface IStore {
|
|
|
168
168
|
identifyCalled: boolean;
|
|
169
169
|
isLoggedIn: boolean;
|
|
170
170
|
sideloadedKitsCount?: number;
|
|
171
|
-
cookieSyncDates:
|
|
171
|
+
cookieSyncDates: CookieSyncDates;
|
|
172
172
|
integrationAttributes: IntegrationAttributes;
|
|
173
173
|
requireDelay: boolean;
|
|
174
174
|
isLocalStorageAvailable: boolean | null;
|
|
@@ -178,7 +178,7 @@ export interface IStore {
|
|
|
178
178
|
kits: Dictionary<MPForwarder>;
|
|
179
179
|
sideloadedKits: MPForwarder[];
|
|
180
180
|
configuredForwarders: MPForwarder[];
|
|
181
|
-
pixelConfigurations:
|
|
181
|
+
pixelConfigurations: IPixelConfiguration[];
|
|
182
182
|
integrationDelayTimeoutStart: number; // UNIX Timestamp
|
|
183
183
|
webviewBridgeEnabled?: boolean;
|
|
184
184
|
wrapperSDKInfo: WrapperSDKInfo;
|