@mparticle/web-sdk 2.19.2 → 2.20.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/dist/mparticle.common.js +60 -19
- package/dist/mparticle.esm.js +60 -19
- package/dist/mparticle.js +249 -125
- package/package.json +3 -2
- package/src/batchUploader.ts +100 -63
- package/src/forwarders.js +181 -92
- package/src/helpers.js +5 -0
- package/src/identity.js +10 -6
- package/src/mockBatchCreator.ts +1 -0
- package/src/mp-instance.js +2 -0
- package/src/persistence.interfaces.ts +138 -0
- package/src/persistence.js +3 -0
- package/src/sdkRuntimeModels.ts +3 -1
- package/src/store.ts +9 -3
- package/src/vault.ts +21 -74
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@mparticle/web-sdk",
|
|
3
|
-
"version": "2.
|
|
3
|
+
"version": "2.20.0",
|
|
4
4
|
"description": "mParticle core SDK for web applications",
|
|
5
5
|
"license": "Apache-2.0",
|
|
6
6
|
"keywords": [
|
|
@@ -28,13 +28,14 @@
|
|
|
28
28
|
"build:esm": "cross-env ENVIRONMENT=prod BUILD=esm rollup --config rollup.config.js",
|
|
29
29
|
"build:stub": "cross-env ENVIRONMENT=prod BUILD=stub rollup --config rollup.config.js",
|
|
30
30
|
"build:snippet": "uglifyjs snippet.js -nm -o snippet.min.js",
|
|
31
|
+
"build:test-bundle": "cross-env TESTTYPE=main ENVIRONMENT=prod rollup --config rollup.test.config.js",
|
|
31
32
|
"build:browserify:cjs": "browserify test/integrations/cjs/browserify/index.js -o test/integrations/cjs/dist/browserify-output.js && npm run test:karma:browserify:cjs",
|
|
32
33
|
"build:rollup:cjs": "rollup --config test/integrations/cjs/rollup/rollup.config.js && npm run test:karma:rollup:cjs",
|
|
33
34
|
"build:webpack:cjs": "webpack --config test/integrations/cjs/webpack/webpack.config.js && npm run test:karma:webpack:cjs",
|
|
34
35
|
"build:rollup:module": "rollup --config test/integrations/module/rollup/rollup.config.js && npm run test:karma:rollup:module",
|
|
35
36
|
"build:webpack:module": "webpack --config test/integrations/module/webpack/webpack.config.js && npm run test:karma:webpack:module",
|
|
36
37
|
"build:ts": "tsc -p .",
|
|
37
|
-
"test": "npm run build &&
|
|
38
|
+
"test": "npm run build && npm run build:test-bundle && cross-env DEBUG=false karma start test/karma.config.js",
|
|
38
39
|
"test:debug": "cross-env DEBUG=true karma start test/karma.config.js",
|
|
39
40
|
"test:stub": "cross-env TESTTYPE=stub ENVIRONMENT=prod rollup --config rollup.test.config.js && karma start test/stub/karma.stub.config.js",
|
|
40
41
|
"test:integrations": "npm run test:requirejs && npm run test:integrations:cjs && npm run test:integrations:module",
|
package/src/batchUploader.ts
CHANGED
|
@@ -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
|
-
//
|
|
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
|
-
|
|
18
|
-
|
|
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.
|
|
32
|
-
this.
|
|
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
|
-
|
|
42
|
-
this.
|
|
43
|
-
|
|
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.
|
|
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.
|
|
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
|
|
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 =
|
|
145
|
-
uploadBatchObject
|
|
146
|
-
);
|
|
183
|
+
uploadBatchObject =
|
|
184
|
+
onCreateBatchCallback(uploadBatchObject);
|
|
147
185
|
if (uploadBatchObject) {
|
|
148
186
|
uploadBatchObject.modified = true;
|
|
149
187
|
} else {
|
|
@@ -169,47 +207,58 @@ 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(
|
|
210
|
+
private async prepareAndUpload(
|
|
211
|
+
triggerFuture: boolean,
|
|
212
|
+
useBeacon: boolean
|
|
213
|
+
): Promise<void> {
|
|
214
|
+
// Fetch current user so that events can be grouped by MPID
|
|
173
215
|
const currentUser = this.mpInstance.Identity.getCurrentUser();
|
|
174
216
|
|
|
175
|
-
const currentEvents = this.
|
|
176
|
-
this.
|
|
177
|
-
|
|
217
|
+
const currentEvents = this.eventsQueuedForProcessing;
|
|
218
|
+
this.eventsQueuedForProcessing = [];
|
|
219
|
+
|
|
220
|
+
const newBatches = BatchUploader.createNewBatches(
|
|
178
221
|
currentEvents,
|
|
179
222
|
currentUser,
|
|
180
223
|
this.mpInstance
|
|
181
224
|
);
|
|
182
|
-
|
|
183
|
-
|
|
225
|
+
|
|
226
|
+
if (!isEmpty(newBatches)) {
|
|
227
|
+
this.batchesQueuedForProcessing.push(...newBatches);
|
|
184
228
|
}
|
|
185
229
|
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
230
|
+
// Clear out pending batches to avoid any potential duplication
|
|
231
|
+
const batchesToUpload = this.batchesQueuedForProcessing;
|
|
232
|
+
this.batchesQueuedForProcessing = [];
|
|
233
|
+
|
|
234
|
+
const batchesThatDidNotUpload = await this.uploadBatches(
|
|
189
235
|
this.mpInstance.Logger,
|
|
190
|
-
|
|
236
|
+
batchesToUpload,
|
|
191
237
|
useBeacon
|
|
192
238
|
);
|
|
193
|
-
|
|
194
|
-
|
|
239
|
+
|
|
240
|
+
// Batches that do not successfully upload are added back to the process queue
|
|
241
|
+
// in the order they were created so that we can attempt re-transmission in
|
|
242
|
+
// the same sequence. This is to prevent any potential data corruption.
|
|
243
|
+
if (!isEmpty(batchesThatDidNotUpload)) {
|
|
244
|
+
// TODO: https://go.mparticle.com/work/SQDSDKS-5165
|
|
245
|
+
this.batchesQueuedForProcessing.unshift(...batchesThatDidNotUpload);
|
|
195
246
|
}
|
|
196
247
|
|
|
197
248
|
if (triggerFuture) {
|
|
198
|
-
|
|
199
|
-
this.prepareAndUpload(true, false);
|
|
200
|
-
}, this.uploadIntervalMillis);
|
|
249
|
+
this.triggerUploadInterval(triggerFuture, false);
|
|
201
250
|
}
|
|
202
251
|
}
|
|
203
252
|
|
|
204
|
-
|
|
253
|
+
// TODO: Refactor to use logger as a class method
|
|
254
|
+
// https://go.mparticle.com/work/SQDSDKS-5167
|
|
255
|
+
private async uploadBatches(
|
|
205
256
|
logger: SDKLoggerApi,
|
|
206
|
-
|
|
257
|
+
batches: Batch[],
|
|
207
258
|
useBeacon: boolean
|
|
208
|
-
): Promise<Batch[]> {
|
|
209
|
-
let uploader;
|
|
210
|
-
|
|
259
|
+
): Promise<Batch[] | null> {
|
|
211
260
|
// Filter out any batches that don't have events
|
|
212
|
-
const uploads =
|
|
261
|
+
const uploads = batches.filter((batch) => !isEmpty(batch.events));
|
|
213
262
|
|
|
214
263
|
if (isEmpty(uploads)) {
|
|
215
264
|
return null;
|
|
@@ -235,19 +284,8 @@ export class BatchUploader {
|
|
|
235
284
|
});
|
|
236
285
|
navigator.sendBeacon(this.uploadUrl, blob);
|
|
237
286
|
} 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
287
|
try {
|
|
246
|
-
const response = await uploader.upload(
|
|
247
|
-
fetchPayload,
|
|
248
|
-
uploads,
|
|
249
|
-
i
|
|
250
|
-
);
|
|
288
|
+
const response = await this.uploader.upload(fetchPayload);
|
|
251
289
|
|
|
252
290
|
if (response.status >= 200 && response.status < 300) {
|
|
253
291
|
logger.verbose(
|
|
@@ -260,7 +298,7 @@ export class BatchUploader {
|
|
|
260
298
|
logger.error(
|
|
261
299
|
`HTTP error status ${response.status} received`
|
|
262
300
|
);
|
|
263
|
-
//
|
|
301
|
+
// Server error, add back current batches and try again later
|
|
264
302
|
return uploads.slice(i, uploads.length);
|
|
265
303
|
} else if (response.status >= 401) {
|
|
266
304
|
logger.error(
|
|
@@ -268,6 +306,16 @@ export class BatchUploader {
|
|
|
268
306
|
);
|
|
269
307
|
//if we're getting a 401, assume we'll keep getting a 401 and clear the uploads.
|
|
270
308
|
return null;
|
|
309
|
+
} else {
|
|
310
|
+
// In case there is an HTTP error we did not anticipate.
|
|
311
|
+
console.error(
|
|
312
|
+
`HTTP error status ${response.status} while uploading events.`,
|
|
313
|
+
response
|
|
314
|
+
);
|
|
315
|
+
|
|
316
|
+
throw new Error(
|
|
317
|
+
`Uncaught HTTP Error ${response.status}. Batch upload will be re-attempted.`
|
|
318
|
+
);
|
|
271
319
|
}
|
|
272
320
|
} catch (e) {
|
|
273
321
|
logger.error(
|
|
@@ -283,34 +331,24 @@ export class BatchUploader {
|
|
|
283
331
|
|
|
284
332
|
abstract class AsyncUploader {
|
|
285
333
|
url: string;
|
|
286
|
-
|
|
334
|
+
public abstract upload(fetchPayload: fetchPayload): Promise<XHRResponse>;
|
|
287
335
|
|
|
288
|
-
constructor(url: string
|
|
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
|
-
|
|
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
|
-
|
|
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();
|
package/src/forwarders.js
CHANGED
|
@@ -1,8 +1,15 @@
|
|
|
1
1
|
import Types from './types';
|
|
2
2
|
import filteredMparticleUser from './filteredMparticleUser';
|
|
3
|
+
import { isEmpty } from './utils';
|
|
3
4
|
|
|
4
5
|
export default function Forwarders(mpInstance, kitBlocker) {
|
|
5
6
|
var self = this;
|
|
7
|
+
|
|
8
|
+
const UserAttributeActionTypes = {
|
|
9
|
+
setUserAttribute: 'setUserAttribute',
|
|
10
|
+
removeUserAttribute: 'removeUserAttribute',
|
|
11
|
+
};
|
|
12
|
+
|
|
6
13
|
this.initForwarders = function(userIdentities, forwardingStatsCallback) {
|
|
7
14
|
var user = mpInstance.Identity.getCurrentUser();
|
|
8
15
|
if (
|
|
@@ -53,7 +60,6 @@ export default function Forwarders(mpInstance, kitBlocker) {
|
|
|
53
60
|
user ? user.getAllUserAttributes() : {},
|
|
54
61
|
forwarder.userAttributeFilters
|
|
55
62
|
);
|
|
56
|
-
|
|
57
63
|
if (!forwarder.initialized) {
|
|
58
64
|
forwarder.logger = mpInstance.Logger;
|
|
59
65
|
forwarder.init(
|
|
@@ -387,33 +393,47 @@ export default function Forwarders(mpInstance, kitBlocker) {
|
|
|
387
393
|
}
|
|
388
394
|
};
|
|
389
395
|
|
|
390
|
-
this.
|
|
391
|
-
if (
|
|
396
|
+
this.handleForwarderUserAttributes = function(functionNameKey, key, value) {
|
|
397
|
+
if (
|
|
398
|
+
(kitBlocker && kitBlocker.isAttributeKeyBlocked(key)) ||
|
|
399
|
+
!mpInstance._Store.activeForwarders.length
|
|
400
|
+
) {
|
|
392
401
|
return;
|
|
393
402
|
}
|
|
394
403
|
|
|
395
|
-
|
|
396
|
-
|
|
404
|
+
mpInstance._Store.activeForwarders.forEach(function(forwarder) {
|
|
405
|
+
const forwarderFunction = forwarder[functionNameKey];
|
|
406
|
+
if (
|
|
407
|
+
!forwarderFunction ||
|
|
408
|
+
mpInstance._Helpers.isFilteredUserAttribute(
|
|
409
|
+
key,
|
|
410
|
+
forwarder.userAttributeFilters
|
|
411
|
+
)
|
|
412
|
+
) {
|
|
413
|
+
return;
|
|
414
|
+
}
|
|
415
|
+
try {
|
|
416
|
+
let result;
|
|
417
|
+
|
|
397
418
|
if (
|
|
398
|
-
|
|
399
|
-
|
|
400
|
-
!mpInstance._Helpers.inArray(
|
|
401
|
-
forwarder.userAttributeFilters,
|
|
402
|
-
mpInstance._Helpers.generateHash(key)
|
|
403
|
-
)
|
|
419
|
+
functionNameKey ===
|
|
420
|
+
UserAttributeActionTypes.setUserAttribute
|
|
404
421
|
) {
|
|
405
|
-
|
|
406
|
-
|
|
422
|
+
result = forwarder.setUserAttribute(key, value);
|
|
423
|
+
} else if (
|
|
424
|
+
functionNameKey ===
|
|
425
|
+
UserAttributeActionTypes.removeUserAttribute
|
|
426
|
+
) {
|
|
427
|
+
result = forwarder.removeUserAttribute(key);
|
|
428
|
+
}
|
|
407
429
|
|
|
408
|
-
|
|
409
|
-
|
|
410
|
-
}
|
|
411
|
-
} catch (e) {
|
|
412
|
-
mpInstance.Logger.error(e);
|
|
413
|
-
}
|
|
430
|
+
if (result) {
|
|
431
|
+
mpInstance.Logger.verbose(result);
|
|
414
432
|
}
|
|
415
|
-
})
|
|
416
|
-
|
|
433
|
+
} catch (e) {
|
|
434
|
+
mpInstance.Logger.error(e);
|
|
435
|
+
}
|
|
436
|
+
});
|
|
417
437
|
};
|
|
418
438
|
|
|
419
439
|
this.setForwarderUserIdentities = function(userIdentities) {
|
|
@@ -504,19 +524,59 @@ export default function Forwarders(mpInstance, kitBlocker) {
|
|
|
504
524
|
mpInstance._Persistence.forwardingStatsBatches.forwardingStatsEventQueue = queue;
|
|
505
525
|
};
|
|
506
526
|
|
|
507
|
-
|
|
527
|
+
// Processing forwarders is a 2 step process:
|
|
528
|
+
// 1. Configure the kit
|
|
529
|
+
// 2. Initialize the kit
|
|
530
|
+
// There are 2 types of kits:
|
|
531
|
+
// 1. UI-enabled kits
|
|
532
|
+
// 2. Sideloaded kits.
|
|
533
|
+
this.processForwarders = function(config, forwardingStatsCallback) {
|
|
534
|
+
if (!config) {
|
|
535
|
+
mpInstance.Logger.warning(
|
|
536
|
+
'No config was passed. Cannot process forwarders'
|
|
537
|
+
);
|
|
538
|
+
} else {
|
|
539
|
+
this.processUIEnabledKits(config);
|
|
540
|
+
this.processSideloadedKits(config);
|
|
541
|
+
|
|
542
|
+
self.initForwarders(
|
|
543
|
+
mpInstance._Store.SDKConfig.identifyRequest.userIdentities,
|
|
544
|
+
forwardingStatsCallback
|
|
545
|
+
);
|
|
546
|
+
}
|
|
547
|
+
};
|
|
548
|
+
|
|
549
|
+
// These are kits that are enabled via the mParticle UI.
|
|
550
|
+
// A kit that is UI-enabled will have a kit configuration that returns from
|
|
551
|
+
// the server, or in rare cases, is passed in by the developer.
|
|
552
|
+
// The kit configuration will be compared with the kit constructors to determine
|
|
553
|
+
// if there is a match before being initialized.
|
|
554
|
+
// Only kits that are configured properly can be active and used for kit forwarding.
|
|
555
|
+
this.processUIEnabledKits = function(config) {
|
|
556
|
+
try {
|
|
557
|
+
if (Array.isArray(config.kitConfigs) && config.kitConfigs.length) {
|
|
558
|
+
config.kitConfigs.forEach(function(kitConfig) {
|
|
559
|
+
self.configureUIEnabledKit(kitConfig);
|
|
560
|
+
});
|
|
561
|
+
}
|
|
562
|
+
} catch (e) {
|
|
563
|
+
mpInstance.Logger.error(
|
|
564
|
+
'MP Kits not configured propertly. Kits may not be initialized. ' +
|
|
565
|
+
e
|
|
566
|
+
);
|
|
567
|
+
}
|
|
568
|
+
};
|
|
569
|
+
|
|
570
|
+
this.configureUIEnabledKit = function(configuration) {
|
|
508
571
|
var newForwarder = null,
|
|
509
572
|
config = configuration,
|
|
510
573
|
forwarders = {};
|
|
511
574
|
|
|
512
|
-
//
|
|
513
|
-
if (
|
|
514
|
-
mpInstance._Helpers.isObject(mpInstance._Store.SDKConfig.kits) &&
|
|
515
|
-
Object.keys(mpInstance._Store.SDKConfig.kits).length > 0
|
|
516
|
-
) {
|
|
575
|
+
// If there are kits inside of mpInstance._Store.SDKConfig.kits, then mParticle is self hosted
|
|
576
|
+
if (!isEmpty(mpInstance._Store.SDKConfig.kits)) {
|
|
517
577
|
forwarders = mpInstance._Store.SDKConfig.kits;
|
|
518
578
|
// otherwise mParticle is loaded via script tag
|
|
519
|
-
} else if (mpInstance._preInit.forwarderConstructors
|
|
579
|
+
} else if (!isEmpty(mpInstance._preInit.forwarderConstructors)) {
|
|
520
580
|
mpInstance._preInit.forwarderConstructors.forEach(function(
|
|
521
581
|
forwarder
|
|
522
582
|
) {
|
|
@@ -532,38 +592,10 @@ export default function Forwarders(mpInstance, kitBlocker) {
|
|
|
532
592
|
config.isSandbox ===
|
|
533
593
|
mpInstance._Store.SDKConfig.isDevelopmentMode
|
|
534
594
|
) {
|
|
535
|
-
newForwarder =
|
|
536
|
-
|
|
537
|
-
|
|
538
|
-
|
|
539
|
-
newForwarder.hasSandbox = config.hasDebugString === 'true';
|
|
540
|
-
newForwarder.isVisible = config.isVisible;
|
|
541
|
-
newForwarder.settings = config.settings;
|
|
542
|
-
|
|
543
|
-
newForwarder.eventNameFilters = config.eventNameFilters;
|
|
544
|
-
newForwarder.eventTypeFilters = config.eventTypeFilters;
|
|
545
|
-
newForwarder.attributeFilters = config.attributeFilters;
|
|
546
|
-
|
|
547
|
-
newForwarder.screenNameFilters = config.screenNameFilters;
|
|
548
|
-
newForwarder.screenNameFilters = config.screenNameFilters;
|
|
549
|
-
newForwarder.screenAttributeFilters =
|
|
550
|
-
config.screenAttributeFilters;
|
|
551
|
-
|
|
552
|
-
newForwarder.userIdentityFilters =
|
|
553
|
-
config.userIdentityFilters;
|
|
554
|
-
newForwarder.userAttributeFilters =
|
|
555
|
-
config.userAttributeFilters;
|
|
556
|
-
|
|
557
|
-
newForwarder.filteringEventAttributeValue =
|
|
558
|
-
config.filteringEventAttributeValue;
|
|
559
|
-
newForwarder.filteringUserAttributeValue =
|
|
560
|
-
config.filteringUserAttributeValue;
|
|
561
|
-
newForwarder.eventSubscriptionId =
|
|
562
|
-
config.eventSubscriptionId;
|
|
563
|
-
newForwarder.filteringConsentRuleValues =
|
|
564
|
-
config.filteringConsentRuleValues;
|
|
565
|
-
newForwarder.excludeAnonymousUser =
|
|
566
|
-
config.excludeAnonymousUser;
|
|
595
|
+
newForwarder = this.returnConfiguredKit(
|
|
596
|
+
forwarders[name],
|
|
597
|
+
config
|
|
598
|
+
);
|
|
567
599
|
|
|
568
600
|
mpInstance._Store.configuredForwarders.push(newForwarder);
|
|
569
601
|
break;
|
|
@@ -572,6 +604,84 @@ export default function Forwarders(mpInstance, kitBlocker) {
|
|
|
572
604
|
}
|
|
573
605
|
};
|
|
574
606
|
|
|
607
|
+
// Sideloaded kits are not configured in the UI and do not have kit configurations
|
|
608
|
+
// They are automatically added to active forwarders.
|
|
609
|
+
|
|
610
|
+
// TODO: Sideloading kits currently requires the use of a register method
|
|
611
|
+
// which requires an object on which to be registered.
|
|
612
|
+
// In the future, when all kits are moved to the config rather than
|
|
613
|
+
// there being a separate process for MP configured kits and
|
|
614
|
+
// sideloaded kits, this will need to be refactored.
|
|
615
|
+
this.processSideloadedKits = function(config) {
|
|
616
|
+
try {
|
|
617
|
+
if (Array.isArray(config.sideloadedKits)) {
|
|
618
|
+
const sideloadedKits = { kits: {} };
|
|
619
|
+
// First register each kit's constructor onto sideloadedKits,
|
|
620
|
+
// which is typed { kits: Dictionary<constructor> }.
|
|
621
|
+
// The constructors are keyed by the name of the kit.
|
|
622
|
+
config.sideloadedKits.forEach(function(sideloadedKit) {
|
|
623
|
+
sideloadedKit.register(sideloadedKits);
|
|
624
|
+
});
|
|
625
|
+
|
|
626
|
+
// Then configure each kit
|
|
627
|
+
for (const registeredKitKey in sideloadedKits.kits) {
|
|
628
|
+
const kitConstructor =
|
|
629
|
+
sideloadedKits.kits[registeredKitKey];
|
|
630
|
+
self.configureSideloadedKit(kitConstructor);
|
|
631
|
+
}
|
|
632
|
+
}
|
|
633
|
+
} catch (e) {
|
|
634
|
+
mpInstance.Logger.error(
|
|
635
|
+
'Sideloaded Kits not configured propertly. Kits may not be initialized. ' +
|
|
636
|
+
e
|
|
637
|
+
);
|
|
638
|
+
}
|
|
639
|
+
};
|
|
640
|
+
|
|
641
|
+
// kits can be included via mParticle UI, or via sideloaded kit config API
|
|
642
|
+
this.configureSideloadedKit = function(kitConstructor) {
|
|
643
|
+
mpInstance._Store.configuredForwarders.push(
|
|
644
|
+
this.returnConfiguredKit(kitConstructor)
|
|
645
|
+
);
|
|
646
|
+
};
|
|
647
|
+
|
|
648
|
+
this.returnConfiguredKit = function(forwarder, config = {}) {
|
|
649
|
+
const newForwarder = new forwarder.constructor();
|
|
650
|
+
newForwarder.id = config.moduleId;
|
|
651
|
+
|
|
652
|
+
// TODO: isSandbox, hasSandbox is never used in any kit or in core SDK.
|
|
653
|
+
// isVisibleInvestigate is only used in 1 place. It is always true if
|
|
654
|
+
// it is sent to JS. Investigate further to determine if these can be removed.
|
|
655
|
+
// https://go.mparticle.com/work/SQDSDKS-5156
|
|
656
|
+
newForwarder.isSandbox = config.isDebug || config.isSandbox;
|
|
657
|
+
newForwarder.hasSandbox = config.hasDebugString === 'true';
|
|
658
|
+
newForwarder.isVisible = config.isVisible || true;
|
|
659
|
+
newForwarder.settings = config.settings || {};
|
|
660
|
+
|
|
661
|
+
newForwarder.eventNameFilters = config.eventNameFilters || [];
|
|
662
|
+
newForwarder.eventTypeFilters = config.eventTypeFilters || [];
|
|
663
|
+
newForwarder.attributeFilters = config.attributeFilters || [];
|
|
664
|
+
|
|
665
|
+
newForwarder.screenNameFilters = config.screenNameFilters || [];
|
|
666
|
+
newForwarder.screenAttributeFilters =
|
|
667
|
+
config.screenAttributeFilters || [];
|
|
668
|
+
|
|
669
|
+
newForwarder.userIdentityFilters = config.userIdentityFilters || [];
|
|
670
|
+
newForwarder.userAttributeFilters = config.userAttributeFilters || [];
|
|
671
|
+
|
|
672
|
+
newForwarder.filteringEventAttributeValue =
|
|
673
|
+
config.filteringEventAttributeValue || {};
|
|
674
|
+
newForwarder.filteringUserAttributeValue =
|
|
675
|
+
config.filteringUserAttributeValue || {};
|
|
676
|
+
newForwarder.eventSubscriptionId = config.eventSubscriptionId || null;
|
|
677
|
+
newForwarder.filteringConsentRuleValues =
|
|
678
|
+
config.filteringConsentRuleValues || {};
|
|
679
|
+
newForwarder.excludeAnonymousUser =
|
|
680
|
+
config.excludeAnonymousUser || false;
|
|
681
|
+
|
|
682
|
+
return newForwarder;
|
|
683
|
+
};
|
|
684
|
+
|
|
575
685
|
this.configurePixel = function(settings) {
|
|
576
686
|
if (
|
|
577
687
|
settings.isDebug ===
|
|
@@ -583,39 +693,18 @@ export default function Forwarders(mpInstance, kitBlocker) {
|
|
|
583
693
|
}
|
|
584
694
|
};
|
|
585
695
|
|
|
586
|
-
this.
|
|
587
|
-
|
|
588
|
-
|
|
589
|
-
|
|
590
|
-
|
|
591
|
-
|
|
592
|
-
try {
|
|
593
|
-
if (
|
|
594
|
-
Array.isArray(config.kitConfigs) &&
|
|
595
|
-
config.kitConfigs.length
|
|
596
|
-
) {
|
|
597
|
-
config.kitConfigs.forEach(function(kitConfig) {
|
|
598
|
-
self.configureForwarder(kitConfig);
|
|
599
|
-
});
|
|
600
|
-
}
|
|
601
|
-
|
|
602
|
-
if (
|
|
603
|
-
Array.isArray(config.pixelConfigs) &&
|
|
604
|
-
config.pixelConfigs.length
|
|
605
|
-
) {
|
|
606
|
-
config.pixelConfigs.forEach(function(pixelConfig) {
|
|
607
|
-
self.configurePixel(pixelConfig);
|
|
608
|
-
});
|
|
609
|
-
}
|
|
610
|
-
self.initForwarders(
|
|
611
|
-
mpInstance._Store.SDKConfig.identifyRequest.userIdentities,
|
|
612
|
-
forwardingStatsCallback
|
|
613
|
-
);
|
|
614
|
-
} catch (e) {
|
|
615
|
-
mpInstance.Logger.error(
|
|
616
|
-
'Config was not parsed propertly. Forwarders may not be initialized.'
|
|
617
|
-
);
|
|
696
|
+
this.processPixelConfigs = function(config) {
|
|
697
|
+
try {
|
|
698
|
+
if (!isEmpty(config.pixelConfigs)) {
|
|
699
|
+
config.pixelConfigs.forEach(function(pixelConfig) {
|
|
700
|
+
self.configurePixel(pixelConfig);
|
|
701
|
+
});
|
|
618
702
|
}
|
|
703
|
+
} catch (e) {
|
|
704
|
+
mpInstance.Logger.error(
|
|
705
|
+
'Cookie Sync configs not configured propertly. Cookie Sync may not be initialized. ' +
|
|
706
|
+
e
|
|
707
|
+
);
|
|
619
708
|
}
|
|
620
709
|
};
|
|
621
710
|
}
|
package/src/helpers.js
CHANGED
|
@@ -387,6 +387,11 @@ export default function Helpers(mpInstance) {
|
|
|
387
387
|
return filteredUserAttributes;
|
|
388
388
|
};
|
|
389
389
|
|
|
390
|
+
this.isFilteredUserAttribute = function(userAttributeKey, filterList) {
|
|
391
|
+
const hashedUserAttribute = self.generateHash(userAttributeKey);
|
|
392
|
+
return filterList && self.inArray(filterList, hashedUserAttribute);
|
|
393
|
+
};
|
|
394
|
+
|
|
390
395
|
this.isEventType = function(type) {
|
|
391
396
|
for (var prop in Types.EventType) {
|
|
392
397
|
if (Types.EventType.hasOwnProperty(prop)) {
|