@mparticle/web-sdk 2.31.1 → 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.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.31.1";
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`
@@ -1495,6 +1508,8 @@ var mParticle = (function () {
1495
1508
  SDKIdentityTypeEnum["phoneNumber3"] = "phone_number_3";
1496
1509
  })(SDKIdentityTypeEnum || (SDKIdentityTypeEnum = {}));
1497
1510
 
1511
+ var FeatureFlags$2 = Constants.FeatureFlags;
1512
+ var CaptureIntegrationSpecificIds$1 = FeatureFlags$2.CaptureIntegrationSpecificIds;
1498
1513
  function convertEvents(mpid, sdkEvents, mpInstance) {
1499
1514
  if (!mpid) {
1500
1515
  return null;
@@ -1502,6 +1517,9 @@ var mParticle = (function () {
1502
1517
  if (!sdkEvents || sdkEvents.length < 1) {
1503
1518
  return null;
1504
1519
  }
1520
+ var _IntegrationCapture = mpInstance._IntegrationCapture,
1521
+ _Helpers = mpInstance._Helpers;
1522
+ var getFeatureFlag = _Helpers.getFeatureFlag;
1505
1523
  var user = mpInstance.Identity.getCurrentUser();
1506
1524
  var uploadEvents = [];
1507
1525
  var lastEvent = null;
@@ -1558,6 +1576,13 @@ var mParticle = (function () {
1558
1576
  }
1559
1577
  };
1560
1578
  }
1579
+ var isIntegrationCaptureEnabled = getFeatureFlag && Boolean(getFeatureFlag(CaptureIntegrationSpecificIds$1));
1580
+ if (isIntegrationCaptureEnabled) {
1581
+ var capturedPartnerIdentities = _IntegrationCapture === null || _IntegrationCapture === void 0 ? void 0 : _IntegrationCapture.getClickIdsAsPartnerIdentities();
1582
+ if (!isEmpty(capturedPartnerIdentities)) {
1583
+ upload.partner_identities = capturedPartnerIdentities;
1584
+ }
1585
+ }
1561
1586
  return upload;
1562
1587
  }
1563
1588
  function convertConsentState(sdkConsentState) {
@@ -3288,124 +3313,80 @@ var mParticle = (function () {
3288
3313
  }
3289
3314
 
3290
3315
  var Messages$8 = Constants.Messages;
3291
- function cookieSyncManager(mpInstance) {
3316
+ var InformationMessages = Messages$8.InformationMessages;
3317
+ var DAYS_IN_MILLISECONDS = 1000 * 60 * 60 * 24;
3318
+ function CookieSyncManager(mpInstance) {
3292
3319
  var self = this;
3293
-
3294
3320
  // Public
3295
- this.attemptCookieSync = function (previousMPID, mpid, mpidIsNotInCookies) {
3296
- // TODO: These should move inside the for loop
3297
- var pixelConfig, lastSyncDateForModule, url, redirect, urlWithRedirect, requiresConsent;
3298
-
3299
- // TODO: Make this exit quicker instead of nested
3300
- if (mpid && !mpInstance._Store.webviewBridgeEnabled) {
3301
- mpInstance._Store.pixelConfigurations.forEach(function (pixelSettings) {
3302
- // set requiresConsent to false to start each additional pixel configuration
3303
- // set to true only if filteringConsenRuleValues.values.length exists
3304
- requiresConsent = false;
3305
-
3306
- // TODO: Replace with isEmpty
3307
- if (pixelSettings.filteringConsentRuleValues && pixelSettings.filteringConsentRuleValues.values && pixelSettings.filteringConsentRuleValues.values.length) {
3308
- requiresConsent = true;
3309
- }
3310
- pixelConfig = {
3311
- // Kit Module ID
3312
- moduleId: pixelSettings.moduleId,
3313
- // Tells you how often we should do a cookie sync (in days)
3314
- frequencyCap: pixelSettings.frequencyCap,
3315
- // Url for cookie sync pixel
3316
- pixelUrl: self.replaceAmp(pixelSettings.pixelUrl),
3317
- // TODO: Document requirements for redirectUrl
3318
- redirectUrl: pixelSettings.redirectUrl ? self.replaceAmp(pixelSettings.redirectUrl) : null,
3319
- // Filtering rules as defined in UI
3320
- filteringConsentRuleValues: pixelSettings.filteringConsentRuleValues
3321
- };
3322
-
3323
- // TODO: combine replaceMPID and replaceAmp into sanitizeUrl function
3324
- url = self.replaceMPID(pixelConfig.pixelUrl, mpid);
3325
- redirect = pixelConfig.redirectUrl ? self.replaceMPID(pixelConfig.redirectUrl, mpid) : '';
3326
- urlWithRedirect = url + encodeURIComponent(redirect);
3327
-
3328
- // TODO: Refactor so that Persistence is only called once
3329
- // outside of the loop
3330
- var persistence = mpInstance._Persistence.getPersistence();
3331
-
3332
- // TODO: Is there a historic reason for checking for previousMPID?
3333
- // it does not appear to be passed in anywhere
3334
- if (previousMPID && previousMPID !== mpid) {
3335
- if (persistence && persistence[mpid]) {
3336
- if (!persistence[mpid].csd) {
3337
- persistence[mpid].csd = {};
3338
- }
3339
- self.performCookieSync(urlWithRedirect, pixelConfig.moduleId, mpid, persistence[mpid].csd, pixelConfig.filteringConsentRuleValues, mpidIsNotInCookies, requiresConsent);
3340
- }
3341
- return;
3342
- } else {
3343
- // TODO: Refactor to check for the inverse and exit early
3344
- // rather than nesting
3345
- if (persistence[mpid]) {
3346
- if (!persistence[mpid].csd) {
3347
- persistence[mpid].csd = {};
3348
- }
3349
- lastSyncDateForModule = persistence[mpid].csd[pixelConfig.moduleId.toString()] ? persistence[mpid].csd[pixelConfig.moduleId.toString()] : null;
3350
- if (lastSyncDateForModule) {
3351
- // Check to see if we need to refresh cookieSync
3352
- if (
3353
- // TODO: Turn this into a convenience method for readability?
3354
- // We use similar comparisons elsewhere in the SDK,
3355
- // so perhaps we can make a time comparison convenience method
3356
- new Date().getTime() > new Date(lastSyncDateForModule).getTime() + pixelConfig.frequencyCap *
3357
- // TODO: Turn these numbers into a constant so
3358
- // we can remember what this number is for
3359
- 60 * 1000 * 60 * 24) {
3360
- self.performCookieSync(urlWithRedirect, pixelConfig.moduleId, mpid, persistence[mpid].csd, pixelConfig.filteringConsentRuleValues, mpidIsNotInCookies, requiresConsent);
3361
- }
3362
- } else {
3363
- self.performCookieSync(urlWithRedirect, pixelConfig.moduleId, mpid, persistence[mpid].csd, pixelConfig.filteringConsentRuleValues, mpidIsNotInCookies, requiresConsent);
3364
- }
3365
- }
3366
- }
3367
- });
3368
- }
3369
- };
3370
-
3371
- // Private
3372
- this.replaceMPID = function (string, mpid) {
3373
- return string.replace('%%mpid%%', mpid);
3374
- };
3375
-
3376
- // Private
3377
- // TODO: Rename function to replaceAmpWithAmpersand
3378
- this.replaceAmp = function (string) {
3379
- return string.replace(/&amp;/g, '&');
3380
- };
3381
-
3382
- // Private
3383
- this.performCookieSync = function (url, moduleId, mpid, cookieSyncDates, filteringConsentRuleValues, mpidIsNotInCookies, requiresConsent) {
3384
- // if MPID is new to cookies, we should not try to perform the cookie sync
3385
- // because a cookie sync can only occur once a user either consents or doesn't
3386
- // we should not check if its enabled if the user has a blank consent
3387
- // TODO: We should do this check outside of this function
3388
- 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) {
3389
3326
  return;
3390
3327
  }
3391
-
3392
- // TODO: Refactor so that check is made outside of the function.
3393
- // Cache or store the boolean so that it only gets called once per
3394
- // cookie sync attempt per module.
3395
- // Currently, attemptCookieSync is called as a loop and therefore this
3396
- // function polls the user object and consent multiple times.
3397
- if (mpInstance._Consent.isEnabledForUserConsent(filteringConsentRuleValues, mpInstance.Identity.getCurrentUser())) {
3398
- var img = document.createElement('img');
3399
- mpInstance.Logger.verbose(Messages$8.InformationMessages.CookieSync);
3400
- img.onload = function () {
3401
- // TODO: Break this out into a convenience method so we can unit test
3402
- cookieSyncDates[moduleId.toString()] = new Date().getTime();
3403
- mpInstance._Persistence.saveUserCookieSyncDatesToPersistence(mpid, cookieSyncDates);
3404
- };
3405
- img.src = url;
3328
+ var persistence = mpInstance._Persistence.getPersistence();
3329
+ if (isEmpty(persistence)) {
3330
+ return;
3406
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;
3407
3380
  };
3408
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
+ };
3409
3390
 
3410
3391
  var Messages$7 = Constants.Messages;
3411
3392
  function SessionManager(mpInstance) {
@@ -7841,7 +7822,7 @@ var mParticle = (function () {
7841
7822
  setConsentState: function setConsentState(state) {
7842
7823
  mpInstance._Store.setConsentState(mpid, state);
7843
7824
  mpInstance._Forwarders.initForwarders(this.getUserIdentities().userIdentities, mpInstance._APIClient.prepareForwardingStats);
7844
- mpInstance._CookieSyncManager.attemptCookieSync(null, this.getMPID());
7825
+ mpInstance._CookieSyncManager.attemptCookieSync(this.getMPID());
7845
7826
  },
7846
7827
  isLoggedIn: function isLoggedIn() {
7847
7828
  return _isLoggedIn;
@@ -8038,7 +8019,7 @@ var mParticle = (function () {
8038
8019
  mpInstance._Persistence.setFirstSeenTime(identityApiResult.mpid);
8039
8020
  }
8040
8021
  mpInstance._Store.addMpidToSessionHistory(identityApiResult.mpid, previousMPID);
8041
- mpInstance._CookieSyncManager.attemptCookieSync(previousMPID, identityApiResult.mpid, mpidIsNotInCookies);
8022
+ mpInstance._CookieSyncManager.attemptCookieSync(identityApiResult.mpid, mpidIsNotInCookies);
8042
8023
  mpInstance._Persistence.swapCurrentUser(previousMPID, identityApiResult.mpid, mpInstance._Store.currentSessionMPIDs);
8043
8024
  if (identityApiData && !isEmpty(identityApiData.userIdentities)) {
8044
8025
  newIdentitiesByType = self.IdentityRequest.combineUserIdentities(incomingUIByName, identityApiData.userIdentities);
@@ -9021,7 +9002,7 @@ var mParticle = (function () {
9021
9002
 
9022
9003
  var HTTPCodes$2 = Constants.HTTPCodes,
9023
9004
  Messages$2 = Constants.Messages;
9024
- function sendAliasRequest(mpInstance, aliasRequest, aliasCallback) {
9005
+ var sendAliasRequest = function sendAliasRequest(mpInstance, aliasRequest, aliasCallback) {
9025
9006
  return __awaiter(this, void 0, void 0, function () {
9026
9007
  var _a, verbose, error, invokeAliasCallback, aliasUrl, apiKey, uploadUrl, uploader, uploadPayload, response, message, aliasResponseBody, xhrResponse, errorMessage, e_2, err;
9027
9008
  return __generator(this, function (_b) {
@@ -9097,7 +9078,7 @@ var mParticle = (function () {
9097
9078
  }
9098
9079
  });
9099
9080
  });
9100
- }
9081
+ };
9101
9082
 
9102
9083
  var HTTPCodes$1 = Constants.HTTPCodes,
9103
9084
  Messages$1 = Constants.Messages;
@@ -9247,32 +9228,57 @@ var mParticle = (function () {
9247
9228
  var _timestamp = timestamp || Date.now();
9248
9229
  return "fb.".concat(subdomainIndex, ".").concat(_timestamp, ".").concat(clickId);
9249
9230
  };
9231
+ // Integration outputs are used to determine how click ids are used within the SDK
9232
+ // CUSTOM_FLAGS are sent out when an Event is created via ServerModel.createEventObject
9233
+ // PARTNER_IDENTITIES are sent out in a Batch when a group of events are converted to a Batch
9234
+ var IntegrationOutputs = {
9235
+ CUSTOM_FLAGS: 'custom_flags',
9236
+ PARTNER_IDENTITIES: 'partner_identities'
9237
+ };
9250
9238
  var integrationMapping = {
9251
9239
  // Facebook / Meta
9252
9240
  fbclid: {
9253
9241
  mappedKey: 'Facebook.ClickId',
9254
- processor: facebookClickIdProcessor
9242
+ processor: facebookClickIdProcessor,
9243
+ output: IntegrationOutputs.CUSTOM_FLAGS
9255
9244
  },
9256
9245
  _fbp: {
9257
- mappedKey: 'Facebook.BrowserId'
9246
+ mappedKey: 'Facebook.BrowserId',
9247
+ output: IntegrationOutputs.CUSTOM_FLAGS
9258
9248
  },
9259
9249
  _fbc: {
9260
- mappedKey: 'Facebook.ClickId'
9250
+ mappedKey: 'Facebook.ClickId',
9251
+ output: IntegrationOutputs.CUSTOM_FLAGS
9261
9252
  },
9262
9253
  // Google
9263
9254
  gclid: {
9264
- mappedKey: 'GoogleEnhancedConversions.Gclid'
9255
+ mappedKey: 'GoogleEnhancedConversions.Gclid',
9256
+ output: IntegrationOutputs.CUSTOM_FLAGS
9265
9257
  },
9266
9258
  gbraid: {
9267
- mappedKey: 'GoogleEnhancedConversions.Gbraid'
9259
+ mappedKey: 'GoogleEnhancedConversions.Gbraid',
9260
+ output: IntegrationOutputs.CUSTOM_FLAGS
9268
9261
  },
9269
9262
  wbraid: {
9270
- mappedKey: 'GoogleEnhancedConversions.Wbraid'
9263
+ mappedKey: 'GoogleEnhancedConversions.Wbraid',
9264
+ output: IntegrationOutputs.CUSTOM_FLAGS
9265
+ },
9266
+ // TIKTOK
9267
+ ttclid: {
9268
+ mappedKey: 'TikTok.Callback',
9269
+ output: IntegrationOutputs.CUSTOM_FLAGS
9270
+ },
9271
+ _ttp: {
9272
+ mappedKey: 'tiktok_cookie_id',
9273
+ output: IntegrationOutputs.PARTNER_IDENTITIES
9271
9274
  }
9272
9275
  };
9273
9276
  var IntegrationCapture = /** @class */function () {
9274
9277
  function IntegrationCapture() {
9275
9278
  this.initialTimestamp = Date.now();
9279
+ // Cache filtered mappings for faster access
9280
+ this.filteredPartnerIdentityMappings = this.filterMappings(IntegrationOutputs.PARTNER_IDENTITIES);
9281
+ this.filteredCustomFlagMappings = this.filterMappings(IntegrationOutputs.CUSTOM_FLAGS);
9276
9282
  }
9277
9283
  /**
9278
9284
  * Captures Integration Ids from cookies and query params and stores them in clickIds object
@@ -9313,21 +9319,31 @@ var mParticle = (function () {
9313
9319
  * @returns {SDKEventCustomFlags} The custom flags.
9314
9320
  */
9315
9321
  IntegrationCapture.prototype.getClickIdsAsCustomFlags = function () {
9322
+ return this.getClickIds(this.clickIds, this.filteredCustomFlagMappings);
9323
+ };
9324
+ /**
9325
+ * Returns only the `partner_identities` mapped integration output.
9326
+ * @returns {Dictionary<string>} The partner identities.
9327
+ */
9328
+ IntegrationCapture.prototype.getClickIdsAsPartnerIdentities = function () {
9329
+ return this.getClickIds(this.clickIds, this.filteredPartnerIdentityMappings);
9330
+ };
9331
+ IntegrationCapture.prototype.getClickIds = function (clickIds, mappingList) {
9316
9332
  var _a;
9317
- var customFlags = {};
9318
- if (!this.clickIds) {
9319
- return customFlags;
9333
+ var mappedClickIds = {};
9334
+ if (!clickIds) {
9335
+ return mappedClickIds;
9320
9336
  }
9321
- for (var _i = 0, _b = Object.entries(this.clickIds); _i < _b.length; _i++) {
9337
+ for (var _i = 0, _b = Object.entries(clickIds); _i < _b.length; _i++) {
9322
9338
  var _c = _b[_i],
9323
9339
  key = _c[0],
9324
9340
  value = _c[1];
9325
- var mappedKey = (_a = integrationMapping[key]) === null || _a === void 0 ? void 0 : _a.mappedKey;
9341
+ var mappedKey = (_a = mappingList[key]) === null || _a === void 0 ? void 0 : _a.mappedKey;
9326
9342
  if (!isEmpty(mappedKey)) {
9327
- customFlags[mappedKey] = value;
9343
+ mappedClickIds[mappedKey] = value;
9328
9344
  }
9329
9345
  }
9330
- return customFlags;
9346
+ return mappedClickIds;
9331
9347
  };
9332
9348
  IntegrationCapture.prototype.applyProcessors = function (clickIds, url, timestamp) {
9333
9349
  var _a;
@@ -9345,6 +9361,12 @@ var mParticle = (function () {
9345
9361
  }
9346
9362
  return processedClickIds;
9347
9363
  };
9364
+ IntegrationCapture.prototype.filterMappings = function (outputType) {
9365
+ return Object.fromEntries(Object.entries(integrationMapping).filter(function (_a) {
9366
+ var value = _a[1];
9367
+ return value.output === outputType;
9368
+ }));
9369
+ };
9348
9370
  return IntegrationCapture;
9349
9371
  }();
9350
9372
 
@@ -9377,7 +9399,7 @@ var mParticle = (function () {
9377
9399
  this._Persistence = new _Persistence(this);
9378
9400
  this._Helpers = new Helpers(this);
9379
9401
  this._Events = new Events(this);
9380
- this._CookieSyncManager = new cookieSyncManager(this);
9402
+ this._CookieSyncManager = new CookieSyncManager(this);
9381
9403
  this._ServerModel = new ServerModel(this);
9382
9404
  this._Ecommerce = new Ecommerce(this);
9383
9405
  this._ForwardingStatsUploader = new forwardingStatsUploader(this);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@mparticle/web-sdk",
3
- "version": "2.31.1",
3
+ "version": "2.32.1",
4
4
  "description": "mParticle core SDK for web applications",
5
5
  "license": "Apache-2.0",
6
6
  "keywords": [
@@ -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 sendAliasRequest (mpInstance: MParticleWebSDK, aliasRequest: IAliasRequest, aliasCallback: IAliasCallback) {
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;
@@ -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: IPixelConfig[];
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
  );