@mparticle/web-sdk 2.18.3 → 2.19.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.
@@ -1,9 +1,129 @@
1
- export default function Consent(mpInstance) {
2
- var self = this;
3
- var CCPAPurpose = 'data_sale_opt_out';
1
+ import {
2
+ CCPAConsentState,
3
+ ConsentState,
4
+ GDPRConsentState,
5
+ PrivacyConsentState,
6
+ } from '@mparticle/web-sdk';
7
+ import { MParticleUser, MParticleWebSDK } from './sdkRuntimeModels';
8
+ import { Dictionary, isObject } from './utils';
4
9
 
5
- // this function is called when consent is required to determine if a cookie sync should happen, or a forwarder should be initialized
6
- this.isEnabledForUserConsent = function(consentRules, user) {
10
+ // Specifies to compiler that CCPAPurpose can only be one specific value
11
+ export const CCPAPurpose = 'data_sale_opt_out' as const;
12
+
13
+ export interface IMinifiedConsentJSONObject {
14
+ gdpr?: Dictionary<IPrivacyV2DTO>;
15
+ ccpa?: {
16
+ [CCPAPurpose]: IPrivacyV2DTO;
17
+ };
18
+ }
19
+
20
+ export interface ICreatePrivacyConsentFunction {
21
+ (
22
+ consented: boolean,
23
+ timestamp?: number,
24
+ consentDocument?: string,
25
+ location?: string,
26
+ hardwareId?: string
27
+ ): PrivacyConsentState | null;
28
+ }
29
+
30
+ // Represents Consent API defined as part of mPInstance
31
+ // TODO: Refactor this with Consent Namespace in @types/mparticle-web-sdk
32
+ // https://go.mparticle.com/work/SQDSDKS-5009
33
+ export interface SDKConsentApi {
34
+ createGDPRConsent: ICreatePrivacyConsentFunction;
35
+ createCCPAConsent: ICreatePrivacyConsentFunction;
36
+ createConsentState: (consentState?: ConsentState) => ConsentState;
37
+ ConsentSerialization: IConsentSerialization;
38
+ createPrivacyConsent: ICreatePrivacyConsentFunction;
39
+ }
40
+
41
+ export interface IConsentSerialization {
42
+ toMinifiedJsonObject: (state: ConsentState) => IMinifiedConsentJSONObject;
43
+ fromMinifiedJsonObject: (json: IMinifiedConsentJSONObject) => ConsentState;
44
+ }
45
+
46
+ // TODO: Resolve discrepency between ConsentState and SDKConsentState
47
+ // https://go.mparticle.com/work/SQDSDKS-5009
48
+ export interface SDKConsentState
49
+ extends Omit<ConsentState, 'getGDPRConsentState' | 'getCCPAConsentState'> {
50
+ getGDPRConsentState(): SDKGDPRConsentState;
51
+ getCCPAConsentState(): SDKCCPAConsentState;
52
+ }
53
+
54
+ // TODO: Resolve discrepency between ConsentState and SDKConsentState
55
+ // https://go.mparticle.com/work/SQDSDKS-5009
56
+ // Specifically PrivacyConsentState, GDPRConsentState and CCPAConsentState
57
+ // Treat all attributes as required, but we had to override this
58
+ // to be optional for a bugfix:
59
+ // https://github.com/mParticle/mparticle-web-sdk/commit/3b11ead79f25b417737442a4fabd6435750f46b8
60
+ export interface SDKConsentStateData {
61
+ Consented: boolean;
62
+ Timestamp?: number;
63
+ ConsentDocument?: string;
64
+ Location?: string;
65
+ HardwareId?: string;
66
+ }
67
+
68
+ export type SDKGDPRConsentState = Dictionary<SDKConsentStateData>;
69
+ export interface SDKCCPAConsentState extends SDKConsentStateData {}
70
+
71
+ export interface IPrivacyV2DTO {
72
+ c: boolean; // Consented
73
+ ts: number; // Timestamp
74
+ d: string; // Document
75
+ l: string; // Location
76
+ h: string; // HardwareID
77
+ }
78
+
79
+ export type IGDPRConsentStateV2DTO = Dictionary<IPrivacyV2DTO>;
80
+
81
+ export interface ICCPAConsentStateV2DTO {
82
+ [CCPAPurpose]: IPrivacyV2DTO;
83
+ }
84
+
85
+ // TODO: Remove when Deprecating V2
86
+ export interface IConsentStateV2DTO {
87
+ gdpr?: IGDPRConsentStateV2DTO;
88
+ ccpa?: ICCPAConsentStateV2DTO;
89
+ }
90
+
91
+ export interface IConsentRulesValues {
92
+ consentPurpose: string;
93
+ hasConsented: boolean;
94
+ }
95
+ export interface IConsentRules {
96
+ includeOnMatch: boolean;
97
+ values: IConsentRulesValues[];
98
+ }
99
+
100
+ // TODO: Remove this if we can safely deprecate `removeCCPAState`
101
+ export interface IConsentState extends ConsentState {
102
+ removeCCPAState: () => ConsentState;
103
+ }
104
+
105
+ // Represents Actual Interface for Consent Module
106
+ // TODO: Should eventually consolidate with SDKConsentStateApi
107
+ export interface IConsent {
108
+ isEnabledForUserConsent: (
109
+ consentRules: IConsentRules,
110
+ user: MParticleUser
111
+ ) => boolean;
112
+ createPrivacyConsent: ICreatePrivacyConsentFunction;
113
+ createConsentState: (consentState?: ConsentState) => ConsentState;
114
+ ConsentSerialization: IConsentSerialization;
115
+ }
116
+
117
+ export default function Consent(this: IConsent, mpInstance: MParticleWebSDK) {
118
+ const self = this;
119
+
120
+ // this function is called when consent is required to
121
+ // determine if a cookie sync should happen, or a
122
+ // forwarder should be initialized
123
+ this.isEnabledForUserConsent = function(
124
+ consentRules: IConsentRules,
125
+ user: MParticleUser
126
+ ): boolean {
7
127
  if (
8
128
  !consentRules ||
9
129
  !consentRules.values ||
@@ -15,20 +135,20 @@ export default function Consent(mpInstance) {
15
135
  return false;
16
136
  }
17
137
 
18
- var purposeHashes = {},
19
- consentState = user.getConsentState(),
20
- purposeHash;
138
+ const purposeHashes: Dictionary<boolean> = {};
139
+ const consentState: SDKConsentState = user.getConsentState();
140
+ let purposeHash: string;
141
+
21
142
  if (consentState) {
22
143
  // the server hashes consent purposes in the following way:
23
144
  // GDPR - '1' + purpose name
24
145
  // CCPA - '2data_sale_opt_out' (there is only 1 purpose of data_sale_opt_out for CCPA)
25
- var GDPRConsentHashPrefix = '1';
26
- var CCPAPurpose = 'data_sale_opt_out';
27
- var CCPAHashString = '2' + CCPAPurpose;
146
+ const GDPRConsentHashPrefix = '1';
147
+ const CCPAHashString = '2' + CCPAPurpose;
28
148
 
29
- var gdprConsentState = consentState.getGDPRConsentState();
149
+ const gdprConsentState = consentState.getGDPRConsentState();
30
150
  if (gdprConsentState) {
31
- for (var purpose in gdprConsentState) {
151
+ for (const purpose in gdprConsentState) {
32
152
  if (gdprConsentState.hasOwnProperty(purpose)) {
33
153
  purposeHash = mpInstance._Helpers
34
154
  .generateHash(GDPRConsentHashPrefix + purpose)
@@ -38,7 +158,7 @@ export default function Consent(mpInstance) {
38
158
  }
39
159
  }
40
160
  }
41
- var CCPAConsentState = consentState.getCCPAConsentState();
161
+ const CCPAConsentState = consentState.getCCPAConsentState();
42
162
  if (CCPAConsentState) {
43
163
  purposeHash = mpInstance._Helpers
44
164
  .generateHash(CCPAHashString)
@@ -46,24 +166,25 @@ export default function Consent(mpInstance) {
46
166
  purposeHashes[purposeHash] = CCPAConsentState.Consented;
47
167
  }
48
168
  }
49
- var isMatch = consentRules.values.some(function(consentRule) {
50
- var consentPurposeHash = consentRule.consentPurpose;
51
- var hasConsented = consentRule.hasConsented;
169
+ const isMatch = consentRules.values.some(function(consentRule) {
170
+ const consentPurposeHash = consentRule.consentPurpose;
171
+ const hasConsented = consentRule.hasConsented;
52
172
  if (purposeHashes.hasOwnProperty(consentPurposeHash)) {
53
173
  return purposeHashes[consentPurposeHash] === hasConsented;
54
174
  }
175
+ return false;
55
176
  });
56
177
 
57
178
  return consentRules.includeOnMatch === isMatch;
58
179
  };
59
180
 
60
181
  this.createPrivacyConsent = function(
61
- consented,
62
- timestamp,
63
- consentDocument,
64
- location,
65
- hardwareId
66
- ) {
182
+ consented: boolean,
183
+ timestamp?: number,
184
+ consentDocument?: string,
185
+ location?: string,
186
+ hardwareId?: string
187
+ ): PrivacyConsentState | null {
67
188
  if (typeof consented !== 'boolean') {
68
189
  mpInstance.Logger.error(
69
190
  'Consented boolean is required when constructing a Consent object.'
@@ -104,16 +225,16 @@ export default function Consent(mpInstance) {
104
225
  };
105
226
 
106
227
  this.ConsentSerialization = {
107
- toMinifiedJsonObject: function(state) {
108
- var jsonObject = {};
228
+ toMinifiedJsonObject(state: ConsentState): IMinifiedConsentJSONObject {
229
+ const jsonObject: Partial<IMinifiedConsentJSONObject> = {};
109
230
  if (state) {
110
- var gdprConsentState = state.getGDPRConsentState();
231
+ const gdprConsentState = state.getGDPRConsentState();
111
232
  if (gdprConsentState) {
112
- jsonObject.gdpr = {};
113
- for (var purpose in gdprConsentState) {
233
+ jsonObject.gdpr = {} as Dictionary<IPrivacyV2DTO>;
234
+ for (const purpose in gdprConsentState) {
114
235
  if (gdprConsentState.hasOwnProperty(purpose)) {
115
- var gdprConsent = gdprConsentState[purpose];
116
- jsonObject.gdpr[purpose] = {};
236
+ const gdprConsent = gdprConsentState[purpose];
237
+ jsonObject.gdpr[purpose] = {} as IPrivacyV2DTO;
117
238
  if (typeof gdprConsent.Consented === 'boolean') {
118
239
  jsonObject.gdpr[purpose].c =
119
240
  gdprConsent.Consented;
@@ -140,10 +261,11 @@ export default function Consent(mpInstance) {
140
261
  }
141
262
  }
142
263
 
143
- var ccpaConsentState = state.getCCPAConsentState();
264
+ const ccpaConsentState = state.getCCPAConsentState();
144
265
  if (ccpaConsentState) {
145
- jsonObject.ccpa = {};
146
- jsonObject.ccpa[CCPAPurpose] = {};
266
+ jsonObject.ccpa = {
267
+ [CCPAPurpose]: {} as IPrivacyV2DTO,
268
+ };
147
269
 
148
270
  if (typeof ccpaConsentState.Consented === 'boolean') {
149
271
  jsonObject.ccpa[CCPAPurpose].c =
@@ -170,12 +292,12 @@ export default function Consent(mpInstance) {
170
292
  return jsonObject;
171
293
  },
172
294
 
173
- fromMinifiedJsonObject: function(json) {
174
- var state = self.createConsentState();
295
+ fromMinifiedJsonObject(json: IMinifiedConsentJSONObject): ConsentState {
296
+ const state: ConsentState = self.createConsentState();
175
297
  if (json.gdpr) {
176
- for (var purpose in json.gdpr) {
298
+ for (const purpose in json.gdpr) {
177
299
  if (json.gdpr.hasOwnProperty(purpose)) {
178
- var gdprConsent = self.createPrivacyConsent(
300
+ const gdprConsent = self.createPrivacyConsent(
179
301
  json.gdpr[purpose].c,
180
302
  json.gdpr[purpose].ts,
181
303
  json.gdpr[purpose].d,
@@ -189,7 +311,7 @@ export default function Consent(mpInstance) {
189
311
 
190
312
  if (json.ccpa) {
191
313
  if (json.ccpa.hasOwnProperty(CCPAPurpose)) {
192
- var ccpaConsent = self.createPrivacyConsent(
314
+ const ccpaConsent = self.createPrivacyConsent(
193
315
  json.ccpa[CCPAPurpose].c,
194
316
  json.ccpa[CCPAPurpose].ts,
195
317
  json.ccpa[CCPAPurpose].d,
@@ -203,30 +325,45 @@ export default function Consent(mpInstance) {
203
325
  },
204
326
  };
205
327
 
206
- this.createConsentState = function(consentState) {
207
- var gdpr = {};
208
- var ccpa = {};
328
+ // TODO: Refactor this method into a constructor
329
+ this.createConsentState = function(
330
+ this: ConsentState,
331
+ consentState?: ConsentState
332
+ ): IConsentState {
333
+ let gdpr = {};
334
+ let ccpa = {};
209
335
 
210
336
  if (consentState) {
211
- setGDPRConsentState(consentState.getGDPRConsentState());
212
- setCCPAConsentState(consentState.getCCPAConsentState());
337
+ const consentStateCopy = self.createConsentState();
338
+ consentStateCopy.setGDPRConsentState(
339
+ consentState.getGDPRConsentState()
340
+ );
341
+ consentStateCopy.setCCPAConsentState(
342
+ consentState.getCCPAConsentState()
343
+ );
344
+
345
+ // TODO: Remove casting once `removeCCPAState` is removed;
346
+ return consentStateCopy as IConsentState;
213
347
  }
214
348
 
215
- function canonicalizeForDeduplication(purpose) {
349
+ function canonicalizeForDeduplication(purpose: string): string {
216
350
  if (typeof purpose !== 'string') {
217
351
  return null;
218
352
  }
219
- var trimmedPurpose = purpose.trim();
353
+
354
+ const trimmedPurpose = purpose.trim();
355
+
220
356
  if (!trimmedPurpose.length) {
221
357
  return null;
222
358
  }
359
+
223
360
  return trimmedPurpose.toLowerCase();
224
361
  }
225
362
 
226
363
  /**
227
364
  * Invoke these methods on a consent state object.
228
365
  * <p>
229
- * Usage: var consent = mParticle.Consent.createConsentState()
366
+ * Usage: const consent = mParticle.Consent.createConsentState()
230
367
  * <br>
231
368
  * consent.setGDPRCoonsentState()
232
369
  *
@@ -241,19 +378,24 @@ export default function Consent(mpInstance) {
241
378
  * @param gdprConsent [Object] A GDPR consent object created via mParticle.Consent.createGDPRConsent(...)
242
379
  */
243
380
 
244
- function addGDPRConsentState(purpose, gdprConsent) {
245
- var normalizedPurpose = canonicalizeForDeduplication(purpose);
381
+ function addGDPRConsentState(
382
+ this: ConsentState,
383
+ purpose: string,
384
+ gdprConsent: PrivacyConsentState
385
+ ): ConsentState {
386
+ const normalizedPurpose = canonicalizeForDeduplication(purpose);
246
387
  if (!normalizedPurpose) {
247
388
  mpInstance.Logger.error('Purpose must be a string.');
248
389
  return this;
249
390
  }
250
- if (!mpInstance._Helpers.isObject(gdprConsent)) {
391
+
392
+ if (!isObject(gdprConsent)) {
251
393
  mpInstance.Logger.error(
252
394
  'Invoked with a bad or empty consent object.'
253
395
  );
254
396
  return this;
255
397
  }
256
- var gdprConsentCopy = self.createPrivacyConsent(
398
+ const gdprConsentCopy = self.createPrivacyConsent(
257
399
  gdprConsent.Consented,
258
400
  gdprConsent.Timestamp,
259
401
  gdprConsent.ConsentDocument,
@@ -266,14 +408,20 @@ export default function Consent(mpInstance) {
266
408
  return this;
267
409
  }
268
410
 
269
- function setGDPRConsentState(gdprConsentState) {
411
+ function setGDPRConsentState(
412
+ this: ConsentState,
413
+ gdprConsentState: GDPRConsentState
414
+ ): ConsentState {
270
415
  if (!gdprConsentState) {
271
416
  gdpr = {};
272
- } else if (mpInstance._Helpers.isObject(gdprConsentState)) {
417
+ } else if (isObject(gdprConsentState)) {
273
418
  gdpr = {};
274
- for (var purpose in gdprConsentState) {
419
+ for (const purpose in gdprConsentState) {
275
420
  if (gdprConsentState.hasOwnProperty(purpose)) {
276
- addGDPRConsentState(purpose, gdprConsentState[purpose]);
421
+ this.addGDPRConsentState(
422
+ purpose,
423
+ gdprConsentState[purpose]
424
+ );
277
425
  }
278
426
  }
279
427
  }
@@ -287,8 +435,11 @@ export default function Consent(mpInstance) {
287
435
  * @param purpose [String] Data processing purpose that describes the type of processing done on the data subject’s data
288
436
  */
289
437
 
290
- function removeGDPRConsentState(purpose) {
291
- var normalizedPurpose = canonicalizeForDeduplication(purpose);
438
+ function removeGDPRConsentState(
439
+ this: ConsentState,
440
+ purpose: string
441
+ ): ConsentState {
442
+ const normalizedPurpose = canonicalizeForDeduplication(purpose);
292
443
  if (!normalizedPurpose) {
293
444
  return this;
294
445
  }
@@ -303,8 +454,8 @@ export default function Consent(mpInstance) {
303
454
  * @return {Object} A GDPR Consent State
304
455
  */
305
456
 
306
- function getGDPRConsentState() {
307
- return mpInstance._Helpers.extend({}, gdpr);
457
+ function getGDPRConsentState(): GDPRConsentState {
458
+ return Object.assign({}, gdpr);
308
459
  }
309
460
 
310
461
  /**
@@ -313,14 +464,17 @@ export default function Consent(mpInstance) {
313
464
  * @method setCCPAConsentState
314
465
  * @param {Object} ccpaConsent CCPA Consent State
315
466
  */
316
- function setCCPAConsentState(ccpaConsent) {
317
- if (!mpInstance._Helpers.isObject(ccpaConsent)) {
467
+ function setCCPAConsentState(
468
+ this: ConsentState,
469
+ ccpaConsent: CCPAConsentState
470
+ ) {
471
+ if (!isObject(ccpaConsent)) {
318
472
  mpInstance.Logger.error(
319
473
  'Invoked with a bad or empty CCPA consent object.'
320
474
  );
321
475
  return this;
322
476
  }
323
- var ccpaConsentCopy = self.createPrivacyConsent(
477
+ const ccpaConsentCopy = self.createPrivacyConsent(
324
478
  ccpaConsent.Consented,
325
479
  ccpaConsent.Timestamp,
326
480
  ccpaConsent.ConsentDocument,
@@ -339,7 +493,7 @@ export default function Consent(mpInstance) {
339
493
  * @method getCCPAConsentStatensent
340
494
  * @return {Object} A CCPA Consent State
341
495
  */
342
- function getCCPAConsentState() {
496
+ function getCCPAConsentState(): CCPAConsentState {
343
497
  return ccpa[CCPAPurpose];
344
498
  }
345
499
 
@@ -348,27 +502,29 @@ export default function Consent(mpInstance) {
348
502
  *
349
503
  * @method removeCCPAConsentState
350
504
  */
351
- function removeCCPAConsentState() {
505
+ function removeCCPAConsentState(this: ConsentState) {
352
506
  delete ccpa[CCPAPurpose];
353
507
  return this;
354
508
  }
355
509
 
356
- function removeCCPAState() {
510
+ // TODO: Can we remove this? It is deprecated.
511
+ function removeCCPAState(this: ConsentState) {
357
512
  mpInstance.Logger.warning(
358
513
  'removeCCPAState is deprecated and will be removed in a future release; use removeCCPAConsentState instead'
359
514
  );
515
+ // @ts-ignore
360
516
  return removeCCPAConsentState();
361
517
  }
362
518
 
363
519
  return {
364
- setGDPRConsentState: setGDPRConsentState,
365
- addGDPRConsentState: addGDPRConsentState,
366
- setCCPAConsentState: setCCPAConsentState,
367
- getCCPAConsentState: getCCPAConsentState,
368
- getGDPRConsentState: getGDPRConsentState,
369
- removeGDPRConsentState: removeGDPRConsentState,
370
- removeCCPAState: removeCCPAState,
371
- removeCCPAConsentState: removeCCPAConsentState,
520
+ setGDPRConsentState,
521
+ addGDPRConsentState,
522
+ setCCPAConsentState,
523
+ getCCPAConsentState,
524
+ getGDPRConsentState,
525
+ removeGDPRConsentState,
526
+ removeCCPAState, // TODO: Can we remove? This is deprecated
527
+ removeCCPAConsentState,
372
528
  };
373
529
  };
374
530
  }
@@ -4,7 +4,10 @@ var Messages = Constants.Messages;
4
4
 
5
5
  export default function cookieSyncManager(mpInstance) {
6
6
  var self = this;
7
+
8
+ // Public
7
9
  this.attemptCookieSync = function(previousMPID, mpid, mpidIsNotInCookies) {
10
+ // TODO: These should move inside the for loop
8
11
  var pixelConfig,
9
12
  lastSyncDateForModule,
10
13
  url,
@@ -12,6 +15,7 @@ export default function cookieSyncManager(mpInstance) {
12
15
  urlWithRedirect,
13
16
  requiresConsent;
14
17
 
18
+ // TODO: Make this exit quicker instead of nested
15
19
  if (mpid && !mpInstance._Store.webviewBridgeEnabled) {
16
20
  mpInstance._Store.pixelConfigurations.forEach(function(
17
21
  pixelSettings
@@ -20,6 +24,7 @@ export default function cookieSyncManager(mpInstance) {
20
24
  // set to true only if filteringConsenRuleValues.values.length exists
21
25
  requiresConsent = false;
22
26
 
27
+ // TODO: Replace with isEmpty
23
28
  if (
24
29
  pixelSettings.filteringConsentRuleValues &&
25
30
  pixelSettings.filteringConsentRuleValues.values &&
@@ -27,24 +32,40 @@ export default function cookieSyncManager(mpInstance) {
27
32
  ) {
28
33
  requiresConsent = true;
29
34
  }
35
+
30
36
  pixelConfig = {
37
+ // Kit Module ID
31
38
  moduleId: pixelSettings.moduleId,
39
+
40
+ // Tells you how often we should do a cookie sync (in days)
32
41
  frequencyCap: pixelSettings.frequencyCap,
42
+
43
+ // Url for cookie sync pixel
33
44
  pixelUrl: self.replaceAmp(pixelSettings.pixelUrl),
45
+
46
+ // TODO: Document requirements for redirectUrl
34
47
  redirectUrl: pixelSettings.redirectUrl
35
48
  ? self.replaceAmp(pixelSettings.redirectUrl)
36
49
  : null,
50
+
51
+ // Filtering rules as defined in UI
37
52
  filteringConsentRuleValues:
38
53
  pixelSettings.filteringConsentRuleValues,
39
54
  };
40
55
 
56
+ // TODO: combine replaceMPID and replaceAmp into sanitizeUrl function
41
57
  url = self.replaceMPID(pixelConfig.pixelUrl, mpid);
42
58
  redirect = pixelConfig.redirectUrl
43
59
  ? self.replaceMPID(pixelConfig.redirectUrl, mpid)
44
60
  : '';
45
61
  urlWithRedirect = url + encodeURIComponent(redirect);
62
+
63
+ // TODO: Refactor so that Persistence is only called once
64
+ // outside of the loop
46
65
  var persistence = mpInstance._Persistence.getPersistence();
47
66
 
67
+ // TODO: Is there a historic reason for checking for previousMPID?
68
+ // it does not appear to be passed in anywhere
48
69
  if (previousMPID && previousMPID !== mpid) {
49
70
  if (persistence && persistence[mpid]) {
50
71
  if (!persistence[mpid].csd) {
@@ -62,6 +83,8 @@ export default function cookieSyncManager(mpInstance) {
62
83
  }
63
84
  return;
64
85
  } else {
86
+ // TODO: Refactor to check for the inverse and exit early
87
+ // rather than nesting
65
88
  if (persistence[mpid]) {
66
89
  if (!persistence[mpid].csd) {
67
90
  persistence[mpid].csd = {};
@@ -77,9 +100,14 @@ export default function cookieSyncManager(mpInstance) {
77
100
  if (lastSyncDateForModule) {
78
101
  // Check to see if we need to refresh cookieSync
79
102
  if (
103
+ // TODO: Turn this into a convenience method for readability?
104
+ // We use similar comparisons elsewhere in the SDK,
105
+ // so perhaps we can make a time comparison convenience method
80
106
  new Date().getTime() >
81
107
  new Date(lastSyncDateForModule).getTime() +
82
108
  pixelConfig.frequencyCap *
109
+ // TODO: Turn these numbers into a constant so
110
+ // we can remember what this number is for
83
111
  60 *
84
112
  1000 *
85
113
  60 *
@@ -112,14 +140,18 @@ export default function cookieSyncManager(mpInstance) {
112
140
  }
113
141
  };
114
142
 
143
+ // Private
115
144
  this.replaceMPID = function(string, mpid) {
116
145
  return string.replace('%%mpid%%', mpid);
117
146
  };
118
147
 
148
+ // Private
149
+ // TODO: Rename function to replaceAmpWithAmpersand
119
150
  this.replaceAmp = function(string) {
120
151
  return string.replace(/&amp;/g, '&');
121
152
  };
122
153
 
154
+ // Private
123
155
  this.performCookieSync = function(
124
156
  url,
125
157
  moduleId,
@@ -132,9 +164,16 @@ export default function cookieSyncManager(mpInstance) {
132
164
  // if MPID is new to cookies, we should not try to perform the cookie sync
133
165
  // because a cookie sync can only occur once a user either consents or doesn't
134
166
  // we should not check if its enabled if the user has a blank consent
167
+ // TODO: We should do this check outside of this function
135
168
  if (requiresConsent && mpidIsNotInCookies) {
136
169
  return;
137
170
  }
171
+
172
+ // TODO: Refactor so that check is made outside of the function.
173
+ // Cache or store the boolean so that it only gets called once per
174
+ // cookie sync attempt per module.
175
+ // Currently, attemptCookieSync is called as a loop and therefore this
176
+ // function polls the user object and consent multiple times.
138
177
  if (
139
178
  mpInstance._Consent.isEnabledForUserConsent(
140
179
  filteringConsentRuleValues,
@@ -145,6 +184,7 @@ export default function cookieSyncManager(mpInstance) {
145
184
 
146
185
  mpInstance.Logger.verbose(Messages.InformationMessages.CookieSync);
147
186
  img.onload = function() {
187
+ // TODO: Break this out into a convenience method so we can unit test
148
188
  cookieSyncDates[moduleId.toString()] = new Date().getTime();
149
189
  mpInstance._Persistence.saveUserCookieSyncDatesToPersistence(
150
190
  mpid,
@@ -15,6 +15,9 @@ export default class _BatchValidator {
15
15
  _Helpers: {
16
16
  sanitizeAttributes:
17
17
  window.mParticle.getInstance()._Helpers.sanitizeAttributes,
18
+ generateHash: function () {
19
+ return 'mockHash';
20
+ },
18
21
  generateUniqueId: function () {
19
22
  return 'mockId';
20
23
  },
@@ -6,7 +6,7 @@ import Validators from './validators';
6
6
  import { Dictionary } from './utils';
7
7
  import { IServerModel } from './serverModel';
8
8
  import { IKitConfigs } from './configAPIClient';
9
- import { SDKConsentApi, SDKConsentState } from './consent.interfaces';
9
+ import { SDKConsentApi, SDKConsentState } from './consent';
10
10
 
11
11
  // TODO: Resolve this with version in @mparticle/web-sdk
12
12
  export type SDKEventCustomFlags = Dictionary<any>;
@@ -159,7 +159,7 @@ export interface MParticleWebSDK {
159
159
  eCommerce: any;
160
160
  logLevel: string;
161
161
  ProductActionType: SDKProductActionType;
162
- generateHash(value: string);
162
+ generateHash(value: string): string;
163
163
  isIOS?: boolean;
164
164
  }
165
165
 
@@ -228,6 +228,7 @@ export interface SDKHelpersApi {
228
228
  extend?(...args: any[]);
229
229
  parseNumber?(value: string | number): number;
230
230
  generateUniqueId();
231
+ generateHash?(value: string): string;
231
232
  getFeatureFlag?(feature: string); // TODO: Feature Constants should be converted to enum
232
233
  getRampNumber?(deviceId: string): number;
233
234
  isDelayedByIntegration?(
@@ -271,7 +272,7 @@ export interface SDKConfigApi {
271
272
  // https://go.mparticle.com/work/SQDSDKS-5033
272
273
  export interface MParticleUser {
273
274
  getMPID(): string;
274
- getConsentState(): any; // FIXME:
275
+ getConsentState(): SDKConsentState;
275
276
  getAllUserAttributes(): any; // FIXME;
276
277
  getUserIdentities(): IdentityApiData; // FIXME: Is this correct?
277
278
  }
@@ -13,7 +13,7 @@ import {
13
13
  SDKConsentState,
14
14
  SDKGDPRConsentState,
15
15
  SDKCCPAConsentState,
16
- } from './consent.interfaces';
16
+ } from './consent';
17
17
  import Types from './types';
18
18
  import { isEmpty } from './utils';
19
19