@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.
- package/dist/mparticle.common.js +70 -20
- package/dist/mparticle.esm.js +70 -20
- package/dist/mparticle.js +202 -141
- package/package.json +1 -1
- package/src/apiClient.ts +1 -1
- package/src/batchUploader.ts +146 -109
- package/src/{consent.js → consent.ts} +228 -72
- package/src/cookieSyncManager.js +40 -0
- package/src/mockBatchCreator.ts +3 -0
- package/src/sdkRuntimeModels.ts +4 -3
- package/src/sdkToEventsApiConverter.ts +1 -1
- package/src/serverModel.ts +34 -32
- package/src/store.ts +5 -4
- package/src/vault.ts +141 -0
- package/src/consent.interfaces.ts +0 -89
|
@@ -1,9 +1,129 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
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
|
-
|
|
6
|
-
|
|
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
|
-
|
|
19
|
-
|
|
20
|
-
|
|
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
|
-
|
|
26
|
-
|
|
27
|
-
var CCPAHashString = '2' + CCPAPurpose;
|
|
146
|
+
const GDPRConsentHashPrefix = '1';
|
|
147
|
+
const CCPAHashString = '2' + CCPAPurpose;
|
|
28
148
|
|
|
29
|
-
|
|
149
|
+
const gdprConsentState = consentState.getGDPRConsentState();
|
|
30
150
|
if (gdprConsentState) {
|
|
31
|
-
for (
|
|
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
|
-
|
|
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
|
-
|
|
50
|
-
|
|
51
|
-
|
|
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:
|
|
108
|
-
|
|
228
|
+
toMinifiedJsonObject(state: ConsentState): IMinifiedConsentJSONObject {
|
|
229
|
+
const jsonObject: Partial<IMinifiedConsentJSONObject> = {};
|
|
109
230
|
if (state) {
|
|
110
|
-
|
|
231
|
+
const gdprConsentState = state.getGDPRConsentState();
|
|
111
232
|
if (gdprConsentState) {
|
|
112
|
-
jsonObject.gdpr = {}
|
|
113
|
-
for (
|
|
233
|
+
jsonObject.gdpr = {} as Dictionary<IPrivacyV2DTO>;
|
|
234
|
+
for (const purpose in gdprConsentState) {
|
|
114
235
|
if (gdprConsentState.hasOwnProperty(purpose)) {
|
|
115
|
-
|
|
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
|
-
|
|
264
|
+
const ccpaConsentState = state.getCCPAConsentState();
|
|
144
265
|
if (ccpaConsentState) {
|
|
145
|
-
jsonObject.ccpa = {
|
|
146
|
-
|
|
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:
|
|
174
|
-
|
|
295
|
+
fromMinifiedJsonObject(json: IMinifiedConsentJSONObject): ConsentState {
|
|
296
|
+
const state: ConsentState = self.createConsentState();
|
|
175
297
|
if (json.gdpr) {
|
|
176
|
-
for (
|
|
298
|
+
for (const purpose in json.gdpr) {
|
|
177
299
|
if (json.gdpr.hasOwnProperty(purpose)) {
|
|
178
|
-
|
|
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
|
-
|
|
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
|
|
207
|
-
|
|
208
|
-
|
|
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
|
-
|
|
212
|
-
|
|
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
|
-
|
|
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:
|
|
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(
|
|
245
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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(
|
|
411
|
+
function setGDPRConsentState(
|
|
412
|
+
this: ConsentState,
|
|
413
|
+
gdprConsentState: GDPRConsentState
|
|
414
|
+
): ConsentState {
|
|
270
415
|
if (!gdprConsentState) {
|
|
271
416
|
gdpr = {};
|
|
272
|
-
} else if (
|
|
417
|
+
} else if (isObject(gdprConsentState)) {
|
|
273
418
|
gdpr = {};
|
|
274
|
-
for (
|
|
419
|
+
for (const purpose in gdprConsentState) {
|
|
275
420
|
if (gdprConsentState.hasOwnProperty(purpose)) {
|
|
276
|
-
addGDPRConsentState(
|
|
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(
|
|
291
|
-
|
|
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
|
|
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(
|
|
317
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
|
365
|
-
addGDPRConsentState
|
|
366
|
-
setCCPAConsentState
|
|
367
|
-
getCCPAConsentState
|
|
368
|
-
getGDPRConsentState
|
|
369
|
-
removeGDPRConsentState
|
|
370
|
-
removeCCPAState:
|
|
371
|
-
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
|
}
|
package/src/cookieSyncManager.js
CHANGED
|
@@ -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(/&/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,
|
package/src/mockBatchCreator.ts
CHANGED
|
@@ -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
|
},
|
package/src/sdkRuntimeModels.ts
CHANGED
|
@@ -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
|
|
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():
|
|
275
|
+
getConsentState(): SDKConsentState;
|
|
275
276
|
getAllUserAttributes(): any; // FIXME;
|
|
276
277
|
getUserIdentities(): IdentityApiData; // FIXME: Is this correct?
|
|
277
278
|
}
|