@mparticle/web-sdk 2.18.2 → 2.19.0

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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@mparticle/web-sdk",
3
- "version": "2.18.2",
3
+ "version": "2.19.0",
4
4
  "description": "mParticle core SDK for web applications",
5
5
  "license": "Apache-2.0",
6
6
  "keywords": [
@@ -1,15 +1,51 @@
1
1
  import Constants from './constants';
2
2
  import Types from './types';
3
3
  import { BatchUploader } from './batchUploader';
4
+ import {
5
+ MParticleUser,
6
+ MParticleWebSDK,
7
+ MPForwarder,
8
+ SDKEvent,
9
+ } from './sdkRuntimeModels';
10
+ import KitBlocker from './kitBlocking';
11
+ import { Dictionary } from './utils';
12
+ import { IUploadObject } from './serverModel';
4
13
 
5
- var Messages = Constants.Messages;
14
+ const Messages = Constants.Messages;
6
15
 
7
- export default function APIClient(mpInstance, kitBlocker) {
16
+ export type ForwardingStatsData = Dictionary<any>;
17
+
18
+ export interface IAPIClient {
19
+ uploader: BatchUploader | null;
20
+ queueEventForBatchUpload: (event: SDKEvent) => void;
21
+ shouldEnableBatching: () => boolean;
22
+ processQueuedEvents: () => void;
23
+ appendUserInfoToEvents: (user: MParticleUser, events: SDKEvent[]) => void;
24
+ sendEventToServer: (event: SDKEvent, _options?: Dictionary<any>) => void;
25
+ sendSingleEventToServer: (event: SDKEvent) => void;
26
+ sendBatchForwardingStatsToServer: (
27
+ forwardingStatsData: ForwardingStatsData,
28
+ xhr: XMLHttpRequest
29
+ ) => void;
30
+ sendSingleForwardingStatsToServer: (
31
+ forwardingStatsData: ForwardingStatsData
32
+ ) => void;
33
+ prepareForwardingStats: (
34
+ forwarder: MPForwarder,
35
+ event: IUploadObject
36
+ ) => void;
37
+ }
38
+
39
+ export default function APIClient(
40
+ this: IAPIClient,
41
+ mpInstance: MParticleWebSDK,
42
+ kitBlocker: KitBlocker
43
+ ) {
8
44
  this.uploader = null;
9
- var self = this;
10
- this.queueEventForBatchUpload = function(event) {
45
+ const self = this;
46
+ this.queueEventForBatchUpload = function(event: SDKEvent) {
11
47
  if (!this.uploader) {
12
- var millis = mpInstance._Helpers.getFeatureFlag(
48
+ const millis = mpInstance._Helpers.getFeatureFlag(
13
49
  Constants.FeatureFlags.EventBatchingIntervalMillis
14
50
  );
15
51
  this.uploader = new BatchUploader(mpInstance, millis);
@@ -22,7 +58,7 @@ export default function APIClient(mpInstance, kitBlocker) {
22
58
  this.shouldEnableBatching = function() {
23
59
  // Returns a string of a number that must be parsed
24
60
  // Invalid strings will be parsed to NaN which is falsey
25
- var eventsV3Percentage = parseInt(
61
+ const eventsV3Percentage = parseInt(
26
62
  mpInstance._Helpers.getFeatureFlag(Constants.FeatureFlags.EventsV3),
27
63
  10
28
64
  );
@@ -31,20 +67,20 @@ export default function APIClient(mpInstance, kitBlocker) {
31
67
  return false;
32
68
  }
33
69
 
34
- var rampNumber = mpInstance._Helpers.getRampNumber(
70
+ const rampNumber = mpInstance._Helpers.getRampNumber(
35
71
  mpInstance._Store.deviceId
36
72
  );
37
73
  return eventsV3Percentage >= rampNumber;
38
74
  };
39
75
 
40
76
  this.processQueuedEvents = function() {
41
- var mpid,
77
+ let mpid,
42
78
  currentUser = mpInstance.Identity.getCurrentUser();
43
79
  if (currentUser) {
44
80
  mpid = currentUser.getMPID();
45
81
  }
46
82
  if (mpInstance._Store.eventQueue.length && mpid) {
47
- var localQueueCopy = mpInstance._Store.eventQueue;
83
+ const localQueueCopy = mpInstance._Store.eventQueue;
48
84
  mpInstance._Store.eventQueue = [];
49
85
  this.appendUserInfoToEvents(currentUser, localQueueCopy);
50
86
  localQueueCopy.forEach(function(event) {
@@ -62,10 +98,10 @@ export default function APIClient(mpInstance, kitBlocker) {
62
98
  };
63
99
 
64
100
  this.sendEventToServer = function(event, _options) {
65
- var defaultOptions = {
101
+ const defaultOptions = {
66
102
  shouldUploadEvent: true,
67
103
  };
68
- var options = mpInstance._Helpers.extend(defaultOptions, _options);
104
+ const options = mpInstance._Helpers.extend(defaultOptions, _options);
69
105
 
70
106
  if (mpInstance._Store.webviewBridgeEnabled) {
71
107
  mpInstance._NativeSdkHelpers.sendToNative(
@@ -75,7 +111,7 @@ export default function APIClient(mpInstance, kitBlocker) {
75
111
  return;
76
112
  }
77
113
 
78
- var mpid,
114
+ let mpid,
79
115
  currentUser = mpInstance.Identity.getCurrentUser();
80
116
  if (currentUser) {
81
117
  mpid = currentUser.getMPID();
@@ -126,7 +162,7 @@ export default function APIClient(mpInstance, kitBlocker) {
126
162
  if (event.EventDataType === Types.MessageType.Media) {
127
163
  return;
128
164
  }
129
- var xhr,
165
+ let xhr,
130
166
  xhrCallback = function() {
131
167
  if (xhr.readyState === 4) {
132
168
  mpInstance.Logger.verbose(
@@ -153,7 +189,9 @@ export default function APIClient(mpInstance, kitBlocker) {
153
189
  );
154
190
  xhr.send(
155
191
  JSON.stringify(
156
- mpInstance._ServerModel.convertEventToDTO(event)
192
+ mpInstance._ServerModel.convertEventToDTO(
193
+ event as IUploadObject
194
+ )
157
195
  )
158
196
  );
159
197
  } catch (e) {
@@ -165,7 +203,8 @@ export default function APIClient(mpInstance, kitBlocker) {
165
203
  };
166
204
 
167
205
  this.sendBatchForwardingStatsToServer = function(forwardingStatsData, xhr) {
168
- var url, data;
206
+ let url;
207
+ let data;
169
208
  try {
170
209
  url = mpInstance._Helpers.createServiceUrl(
171
210
  mpInstance._Store.SDKConfig.v2SecureServiceUrl,
@@ -188,9 +227,10 @@ export default function APIClient(mpInstance, kitBlocker) {
188
227
  };
189
228
 
190
229
  this.sendSingleForwardingStatsToServer = function(forwardingStatsData) {
191
- var url, data;
230
+ let url;
231
+ let data;
192
232
  try {
193
- var xhrCallback = function() {
233
+ const xhrCallback = function() {
194
234
  if (xhr.readyState === 4) {
195
235
  if (xhr.status === 202) {
196
236
  mpInstance.Logger.verbose(
@@ -201,7 +241,7 @@ export default function APIClient(mpInstance, kitBlocker) {
201
241
  }
202
242
  }
203
243
  };
204
- var xhr = mpInstance._Helpers.createXHR(xhrCallback);
244
+ const xhr = mpInstance._Helpers.createXHR(xhrCallback);
205
245
  url = mpInstance._Helpers.createServiceUrl(
206
246
  mpInstance._Store.SDKConfig.v1SecureServiceUrl,
207
247
  mpInstance._Store.devToken
@@ -220,8 +260,8 @@ export default function APIClient(mpInstance, kitBlocker) {
220
260
  };
221
261
 
222
262
  this.prepareForwardingStats = function(forwarder, event) {
223
- var forwardingStatsData,
224
- queue = mpInstance._Forwarders.getForwarderStatsQueue();
263
+ let forwardingStatsData;
264
+ const queue = mpInstance._Forwarders.getForwarderStatsQueue();
225
265
 
226
266
  if (forwarder && forwarder.isVisible) {
227
267
  forwardingStatsData = {
@@ -9,17 +9,35 @@ import { convertEvents } from './sdkToEventsApiConverter';
9
9
  import Types from './types';
10
10
  import { isEmpty } from './utils';
11
11
 
12
+ /**
13
+ * BatchUploader contains all the logic to upload batches to mParticle.
14
+ * It queues events as they come in and at set intervals turns them into batches.
15
+ * It then attempts to upload them to mParticle.
16
+ *
17
+ * These uploads happen on an interval basis using window.fetch or XHR
18
+ * requests, depending on what is available in the browser.
19
+ *
20
+ * Uploads can also be triggered on browser visibility/focus changes via an
21
+ * event listener, which then uploads to mPartice via the browser's Beacon API.
22
+ */
23
+
12
24
  export class BatchUploader {
13
- //we upload JSON, but this content type is required to avoid a CORS preflight request
25
+ // We upload JSON, but this content type is required to avoid a CORS preflight request
14
26
  static readonly CONTENT_TYPE: string = 'text/plain;charset=UTF-8';
15
27
  static readonly MINIMUM_INTERVAL_MILLIS: number = 500;
16
28
  uploadIntervalMillis: number;
17
- pendingEvents: SDKEvent[];
18
- pendingUploads: Batch[];
29
+ eventsQueuedForProcessing: SDKEvent[];
30
+ batchesQueuedForProcessing: Batch[];
19
31
  mpInstance: MParticleWebSDK;
20
32
  uploadUrl: string;
21
33
  batchingEnabled: boolean;
34
+ private uploader: AsyncUploader;
22
35
 
36
+ /**
37
+ * Creates an instance of a BatchUploader
38
+ * @param {MParticleWebSDK} mpInstance - the mParticle SDK instance
39
+ * @param {number} uploadInterval - the desired upload interval in milliseconds
40
+ */
23
41
  constructor(mpInstance: MParticleWebSDK, uploadInterval: number) {
24
42
  this.mpInstance = mpInstance;
25
43
  this.uploadIntervalMillis = uploadInterval;
@@ -28,8 +46,8 @@ export class BatchUploader {
28
46
  if (this.uploadIntervalMillis < BatchUploader.MINIMUM_INTERVAL_MILLIS) {
29
47
  this.uploadIntervalMillis = BatchUploader.MINIMUM_INTERVAL_MILLIS;
30
48
  }
31
- this.pendingEvents = [];
32
- this.pendingUploads = [];
49
+ this.eventsQueuedForProcessing = [];
50
+ this.batchesQueuedForProcessing = [];
33
51
 
34
52
  const { SDKConfig, devToken } = this.mpInstance._Store;
35
53
  const baseUrl = this.mpInstance._Helpers.createServiceUrl(
@@ -38,15 +56,20 @@ export class BatchUploader {
38
56
  );
39
57
  this.uploadUrl = `${baseUrl}/events`;
40
58
 
41
- setTimeout(() => {
42
- this.prepareAndUpload(true, false);
43
- }, this.uploadIntervalMillis);
59
+ this.uploader = window.fetch
60
+ ? new FetchUploader(this.uploadUrl)
61
+ : new XHRUploader(this.uploadUrl);
62
+
63
+ this.triggerUploadInterval(true, false);
44
64
  this.addEventListeners();
45
65
  }
46
66
 
67
+ // Adds listeners to be used trigger Navigator.sendBeacon if the browser
68
+ // loses focus for any reason, such as closing browser tab or minimizing window
47
69
  private addEventListeners() {
48
70
  const _this = this;
49
71
 
72
+ // visibility change is a document property, not window
50
73
  document.addEventListener('visibilitychange', () => {
51
74
  _this.prepareAndUpload(false, _this.isBeaconAvailable());
52
75
  });
@@ -65,16 +88,32 @@ export class BatchUploader {
65
88
  return false;
66
89
  }
67
90
 
91
+ // Triggers a setTimeout for prepareAndUpload
92
+ private triggerUploadInterval(
93
+ triggerFuture: boolean = false,
94
+ useBeacon: boolean = false
95
+ ): void {
96
+ setTimeout(() => {
97
+ this.prepareAndUpload(triggerFuture, useBeacon);
98
+ }, this.uploadIntervalMillis);
99
+ }
100
+
101
+ /**
102
+ * This method will queue a single Event which will eventually be processed into a Batch
103
+ * @param event event that should be queued
104
+ */
68
105
  queueEvent(event: SDKEvent): void {
69
106
  if (!isEmpty(event)) {
70
- this.pendingEvents.push(event);
107
+ this.eventsQueuedForProcessing.push(event);
71
108
  this.mpInstance.Logger.verbose(
72
109
  `Queuing event: ${JSON.stringify(event)}`
73
110
  );
74
111
  this.mpInstance.Logger.verbose(
75
- `Queued event count: ${this.pendingEvents.length}`
112
+ `Queued event count: ${this.eventsQueuedForProcessing.length}`
76
113
  );
77
114
 
115
+ // TODO: Remove this check once the v2 code path is removed
116
+ // https://go.mparticle.com/work/SQDSDKS-3720
78
117
  if (
79
118
  !this.batchingEnabled ||
80
119
  Types.TriggerUploadType[event.EventDataType]
@@ -93,7 +132,7 @@ export class BatchUploader {
93
132
  * @param sdkEvents current pending events
94
133
  * @param defaultUser the user to reference for events that are missing data
95
134
  */
96
- private static createNewUploads(
135
+ private static createNewBatches(
97
136
  sdkEvents: SDKEvent[],
98
137
  defaultUser: MParticleUser,
99
138
  mpInstance: MParticleWebSDK
@@ -141,9 +180,8 @@ export class BatchUploader {
141
180
  mpInstance._Store.SDKConfig.onCreateBatch;
142
181
 
143
182
  if (onCreateBatchCallback) {
144
- uploadBatchObject = onCreateBatchCallback(
145
- uploadBatchObject
146
- );
183
+ uploadBatchObject =
184
+ onCreateBatchCallback(uploadBatchObject);
147
185
  if (uploadBatchObject) {
148
186
  uploadBatchObject.modified = true;
149
187
  } else {
@@ -169,112 +207,122 @@ export class BatchUploader {
169
207
  * @param triggerFuture whether to trigger the loop again - for manual/forced uploads this should be false
170
208
  * @param useBeacon whether to use the beacon API - used when the page is being unloaded
171
209
  */
172
- private async prepareAndUpload(triggerFuture: boolean, useBeacon: boolean) {
210
+ private async prepareAndUpload(
211
+ triggerFuture: boolean,
212
+ useBeacon: boolean
213
+ ): Promise<void> {
173
214
  const currentUser = this.mpInstance.Identity.getCurrentUser();
174
215
 
175
- const currentEvents = this.pendingEvents;
176
- this.pendingEvents = [];
177
- const newUploads = BatchUploader.createNewUploads(
216
+ const currentEvents = this.eventsQueuedForProcessing;
217
+ this.eventsQueuedForProcessing = [];
218
+
219
+ const newBatches = BatchUploader.createNewBatches(
178
220
  currentEvents,
179
221
  currentUser,
180
222
  this.mpInstance
181
223
  );
182
- if (newUploads && newUploads.length) {
183
- this.pendingUploads.push(...newUploads);
224
+ if (!isEmpty(newBatches)) {
225
+ this.batchesQueuedForProcessing.push(...newBatches);
184
226
  }
185
227
 
186
- const currentUploads = this.pendingUploads;
187
- this.pendingUploads = [];
188
- const remainingUploads: Batch[] = await this.upload(
189
- this.mpInstance.Logger,
190
- currentUploads,
191
- useBeacon
192
- );
193
- if (remainingUploads && remainingUploads.length) {
194
- this.pendingUploads.unshift(...remainingUploads);
228
+ const batchesToUpload = this.batchesQueuedForProcessing;
229
+ const batchesThatDidNotUpload: Batch[] = [];
230
+ this.batchesQueuedForProcessing = [];
231
+
232
+ // Create an array of promises as we try to upload each batch indvidually
233
+ const promises: Promise<Batch>[] = batchesToUpload.map((upload) => {
234
+ return this.upload(this.mpInstance.Logger, upload, useBeacon);
235
+ });
236
+
237
+ // Iterate through fulfilled promises and store any remaining batches
238
+ // for future re-transmission attempts
239
+ if (!isEmpty(promises)) {
240
+ Promise.all(promises)
241
+ .then((batchResponses) => {
242
+ batchResponses.forEach((batch) =>
243
+ !isEmpty(batch)
244
+ ? batchesThatDidNotUpload.push(batch)
245
+ : null
246
+ );
247
+ })
248
+ .catch((error) => {
249
+ this.mpInstance.Logger.error(
250
+ `Error processing batches during upload attempt: ${error}`
251
+ );
252
+ })
253
+ .finally(() => {
254
+ // Any batches that did not upload should be put back into the queue for processing
255
+ if (!isEmpty(batchesThatDidNotUpload)) {
256
+ this.batchesQueuedForProcessing.unshift(
257
+ ...batchesThatDidNotUpload
258
+ );
259
+ }
260
+ });
195
261
  }
196
262
 
197
263
  if (triggerFuture) {
198
- setTimeout(() => {
199
- this.prepareAndUpload(true, false);
200
- }, this.uploadIntervalMillis);
264
+ this.triggerUploadInterval(triggerFuture, false);
201
265
  }
202
266
  }
203
267
 
204
268
  private async upload(
205
269
  logger: SDKLoggerApi,
206
- _uploads: Batch[],
270
+ batch: Batch,
207
271
  useBeacon: boolean
208
- ): Promise<Batch[]> {
209
- let uploader;
210
-
211
- // Filter out any batches that don't have events
212
- const uploads = _uploads.filter(upload => !isEmpty(upload.events));
213
-
214
- if (isEmpty(uploads)) {
272
+ ): Promise<Batch | null> {
273
+ if (isEmpty(batch) || isEmpty(batch.events)) {
215
274
  return null;
216
275
  }
217
276
 
218
- logger.verbose(`Uploading batches: ${JSON.stringify(uploads)}`);
219
- logger.verbose(`Batch count: ${uploads.length}`);
220
-
221
- for (let i = 0; i < uploads.length; i++) {
222
- const fetchPayload: fetchPayload = {
223
- method: 'POST',
224
- headers: {
225
- Accept: BatchUploader.CONTENT_TYPE,
226
- 'Content-Type': 'text/plain;charset=UTF-8',
227
- },
228
- body: JSON.stringify(uploads[i]),
229
- };
277
+ logger.verbose(`Uploading batches: ${JSON.stringify(batch)}`);
278
+
279
+ const fetchPayload: fetchPayload = {
280
+ method: 'POST',
281
+ headers: {
282
+ Accept: BatchUploader.CONTENT_TYPE,
283
+ 'Content-Type': 'text/plain;charset=UTF-8',
284
+ },
285
+ body: JSON.stringify(batch),
286
+ };
287
+
288
+ // TODO: Make beacon its own function
289
+ // beacon is only used on onbeforeunload onpagehide events
290
+ if (useBeacon && this.isBeaconAvailable()) {
291
+ let blob = new Blob([fetchPayload.body], {
292
+ type: 'text/plain;charset=UTF-8',
293
+ });
294
+ navigator.sendBeacon(this.uploadUrl, blob);
295
+ } else {
296
+ try {
297
+ const response = await this.uploader.upload(fetchPayload);
298
+
299
+ // TODO: Should we make this a switch statement instead?
300
+ if (response.status >= 200 && response.status < 300) {
301
+ logger.verbose(
302
+ `Upload success for request ID: ${batch.source_request_id}`
303
+ );
230
304
 
231
- // beacon is only used on onbeforeunload onpagehide events
232
- if (useBeacon && this.isBeaconAvailable()) {
233
- let blob = new Blob([fetchPayload.body], {
234
- type: 'text/plain;charset=UTF-8',
235
- });
236
- navigator.sendBeacon(this.uploadUrl, blob);
237
- } else {
238
- if (!uploader) {
239
- if (window.fetch) {
240
- uploader = new FetchUploader(this.uploadUrl, logger);
241
- } else {
242
- uploader = new XHRUploader(this.uploadUrl, logger);
243
- }
244
- }
245
- try {
246
- const response = await uploader.upload(
247
- fetchPayload,
248
- uploads,
249
- i
305
+ return null;
306
+ } else if (response.status >= 500 || response.status === 429) {
307
+ logger.error(
308
+ `HTTP error status ${response.status} received`
250
309
  );
251
310
 
252
- if (response.status >= 200 && response.status < 300) {
253
- logger.verbose(
254
- `Upload success for request ID: ${uploads[i].source_request_id}`
255
- );
256
- } else if (
257
- response.status >= 500 ||
258
- response.status === 429
259
- ) {
260
- logger.error(
261
- `HTTP error status ${response.status} received`
262
- );
263
- //server error, add back current events and try again later
264
- return uploads.slice(i, uploads.length);
265
- } else if (response.status >= 401) {
266
- logger.error(
267
- `HTTP error status ${response.status} while uploading - please verify your API key.`
268
- );
269
- //if we're getting a 401, assume we'll keep getting a 401 and clear the uploads.
270
- return null;
271
- }
272
- } catch (e) {
311
+ // Server error, return current batch and try again later
312
+ return batch;
313
+ } else if (response.status >= 401) {
273
314
  logger.error(
274
- `Error sending event to mParticle servers. ${e}`
315
+ `HTTP error status ${response.status} while uploading - please verify your API key.`
275
316
  );
276
- return uploads.slice(i, uploads.length);
317
+ // if we're getting a 401, assume we'll keep getting a 401
318
+ // so return the upload so it can be stored for later use
319
+ return batch;
277
320
  }
321
+ } catch (error) {
322
+ logger.error(
323
+ `Error sending event to mParticle servers. ${error}`
324
+ );
325
+ return batch;
278
326
  }
279
327
  }
280
328
  return null;
@@ -283,34 +331,24 @@ export class BatchUploader {
283
331
 
284
332
  abstract class AsyncUploader {
285
333
  url: string;
286
- logger: SDKLoggerApi;
334
+ public abstract upload(fetchPayload: fetchPayload): Promise<XHRResponse>;
287
335
 
288
- constructor(url: string, logger: SDKLoggerApi) {
336
+ constructor(url: string) {
289
337
  this.url = url;
290
- this.logger = logger;
291
338
  }
292
339
  }
293
340
 
294
341
  class FetchUploader extends AsyncUploader {
295
- private async upload(
296
- fetchPayload: fetchPayload,
297
- uploads: Batch[],
298
- i: number
299
- ) {
342
+ public async upload(fetchPayload: fetchPayload): Promise<XHRResponse> {
300
343
  const response: XHRResponse = await fetch(this.url, fetchPayload);
301
344
  return response;
302
345
  }
303
346
  }
304
347
 
305
348
  class XHRUploader extends AsyncUploader {
306
- private async upload(
307
- fetchPayload: fetchPayload,
308
- uploads: Batch[],
309
- i: number
310
- ) {
349
+ public async upload(fetchPayload: fetchPayload): Promise<XHRResponse> {
311
350
  const response: XHRResponse = await this.makeRequest(
312
351
  this.url,
313
- this.logger,
314
352
  fetchPayload.body
315
353
  );
316
354
  return response;
@@ -318,7 +356,6 @@ class XHRUploader extends AsyncUploader {
318
356
 
319
357
  private async makeRequest(
320
358
  url: string,
321
- logger: SDKLoggerApi,
322
359
  data: string
323
360
  ): Promise<XMLHttpRequest> {
324
361
  const xhr: XMLHttpRequest = new XMLHttpRequest();
@@ -0,0 +1,89 @@
1
+ // TODO: Migrate this to Consent.ts when that is created
2
+ import { ConsentState, PrivacyConsentState } from '@mparticle/web-sdk';
3
+
4
+ export interface IGDPRConsentObject {
5
+ purpose: string;
6
+ }
7
+
8
+ export interface ICCPAConsentObject {
9
+ purpose: string;
10
+ }
11
+
12
+ export interface IConsentJSONObject {
13
+ gdpr?: Partial<IGDPRConsentObject>;
14
+ ccpa?: Partial<ICCPAConsentObject>;
15
+ }
16
+
17
+ interface ICreatePrivacyConsentFunction {
18
+ (
19
+ consented: boolean,
20
+ timestamp?: number,
21
+ consentDocument?: string,
22
+ location?: string,
23
+ hardwareId?: string
24
+ ): PrivacyConsentState | null;
25
+ }
26
+
27
+ // TODO: Refactor this with Consent Namespace in @types/mparticle-web-sdk
28
+ // https://go.mparticle.com/work/SQDSDKS-5009
29
+ export interface SDKConsentApi {
30
+ createGDPRConsent: ICreatePrivacyConsentFunction;
31
+ createCCPAConsent: ICreatePrivacyConsentFunction;
32
+ createConsentState: (consentState?: ConsentState) => ConsentState;
33
+ ConsentSerialization: IConsentSerialization;
34
+ createPrivacyConsent: ICreatePrivacyConsentFunction;
35
+ }
36
+
37
+ export interface IConsentSerialization {
38
+ toMinifiedJsonObject: (state: ConsentState) => IConsentJSONObject;
39
+ fromMinifiedJsonObject: (json: IConsentJSONObject) => ConsentState;
40
+ }
41
+
42
+ // TODO: Resolve discrepency between ConsentState and SDKConsentState
43
+ // https://go.mparticle.com/work/SQDSDKS-5009
44
+ export interface SDKConsentState
45
+ extends Omit<ConsentState, 'getGDPRConsentState' | 'getCCPAConsentState'> {
46
+ getGDPRConsentState(): SDKGDPRConsentState;
47
+ getCCPAConsentState(): SDKCCPAConsentState;
48
+ }
49
+
50
+ export interface SDKGDPRConsentState {
51
+ [key: string]: SDKConsentStateData;
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 interface SDKCCPAConsentState extends SDKConsentStateData {}
69
+
70
+ export interface IPrivacyV2DTO {
71
+ c: boolean; // Consented
72
+ ts: number; // Timestamp
73
+ d: string; // Document
74
+ l: string; // Location
75
+ h: string; // HardwareID
76
+ }
77
+
78
+ export interface IGDPRConsentStateDTO {
79
+ [key: string]: IPrivacyV2DTO;
80
+ }
81
+
82
+ export interface ICCPAConsentStateDTO {
83
+ data_sale_opt_out: IPrivacyV2DTO;
84
+ }
85
+
86
+ export interface IConsentStateDTO {
87
+ gdpr?: IGDPRConsentStateDTO;
88
+ ccpa?: ICCPAConsentStateDTO;
89
+ }
@@ -7,15 +7,15 @@ import * as EventsApi from '@mparticle/event-models';
7
7
 
8
8
  const mockFunction = function () {
9
9
  return null;
10
- }
10
+ };
11
11
  export default class _BatchValidator {
12
12
  private getMPInstance() {
13
13
  return {
14
14
  // Certain Helper, Store, and Identity properties need to be mocked to be used in the `returnBatch` method
15
15
  _Helpers: {
16
- sanitizeAttributes: window.mParticle.getInstance()._Helpers
17
- .sanitizeAttributes,
18
- generateUniqueId: function() {
16
+ sanitizeAttributes:
17
+ window.mParticle.getInstance()._Helpers.sanitizeAttributes,
18
+ generateUniqueId: function () {
19
19
  return 'mockId';
20
20
  },
21
21
  extend: window.mParticle.getInstance()._Helpers.extend,
@@ -28,6 +28,11 @@ export default class _BatchValidator {
28
28
  _resetForTests: mockFunction,
29
29
  _APIClient: null,
30
30
  _Consent: null,
31
+ _Forwarders: null,
32
+ _NativeSdkHelpers: null,
33
+ _Persistence: null,
34
+ _preInit: null,
35
+ Consent: null,
31
36
  _ServerModel: null,
32
37
  _SessionManager: null,
33
38
  _Store: {