@mparticle/web-sdk 2.19.2 → 2.19.3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/mparticle.js CHANGED
@@ -725,7 +725,7 @@ var mParticle = (function () {
725
725
  Environment: Environment
726
726
  };
727
727
 
728
- var version = "2.19.2";
728
+ var version = "2.19.3";
729
729
 
730
730
  var Constants = {
731
731
  sdkVersion: version,
@@ -2111,12 +2111,27 @@ var mParticle = (function () {
2111
2111
  }
2112
2112
  }
2113
2113
 
2114
+ /**
2115
+ * BatchUploader contains all the logic to upload batches to mParticle.
2116
+ * It queues events as they come in and at set intervals turns them into batches.
2117
+ * It then attempts to upload them to mParticle.
2118
+ *
2119
+ * These uploads happen on an interval basis using window.fetch or XHR
2120
+ * requests, depending on what is available in the browser.
2121
+ *
2122
+ * Uploads can also be triggered on browser visibility/focus changes via an
2123
+ * event listener, which then uploads to mPartice via the browser's Beacon API.
2124
+ */
2125
+
2114
2126
  var BatchUploader =
2115
2127
  /** @class */
2116
2128
  function () {
2129
+ /**
2130
+ * Creates an instance of a BatchUploader
2131
+ * @param {MParticleWebSDK} mpInstance - the mParticle SDK instance
2132
+ * @param {number} uploadInterval - the desired upload interval in milliseconds
2133
+ */
2117
2134
  function BatchUploader(mpInstance, uploadInterval) {
2118
- var _this_1 = this;
2119
-
2120
2135
  this.mpInstance = mpInstance;
2121
2136
  this.uploadIntervalMillis = uploadInterval;
2122
2137
  this.batchingEnabled = uploadInterval >= BatchUploader.MINIMUM_INTERVAL_MILLIS;
@@ -2125,8 +2140,8 @@ var mParticle = (function () {
2125
2140
  this.uploadIntervalMillis = BatchUploader.MINIMUM_INTERVAL_MILLIS;
2126
2141
  }
2127
2142
 
2128
- this.pendingEvents = [];
2129
- this.pendingUploads = [];
2143
+ this.eventsQueuedForProcessing = [];
2144
+ this.batchesQueuedForProcessing = [];
2130
2145
  var _a = this.mpInstance._Store,
2131
2146
  SDKConfig = _a.SDKConfig,
2132
2147
  devToken = _a.devToken;
@@ -2134,14 +2149,16 @@ var mParticle = (function () {
2134
2149
  var baseUrl = this.mpInstance._Helpers.createServiceUrl(SDKConfig.v3SecureServiceUrl, devToken);
2135
2150
 
2136
2151
  this.uploadUrl = "".concat(baseUrl, "/events");
2137
- setTimeout(function () {
2138
- _this_1.prepareAndUpload(true, false);
2139
- }, this.uploadIntervalMillis);
2152
+ this.uploader = window.fetch ? new FetchUploader(this.uploadUrl) : new XHRUploader(this.uploadUrl);
2153
+ this.triggerUploadInterval(true, false);
2140
2154
  this.addEventListeners();
2141
- }
2155
+ } // Adds listeners to be used trigger Navigator.sendBeacon if the browser
2156
+ // loses focus for any reason, such as closing browser tab or minimizing window
2157
+
2142
2158
 
2143
2159
  BatchUploader.prototype.addEventListeners = function () {
2144
- var _this = this;
2160
+ var _this = this; // visibility change is a document property, not window
2161
+
2145
2162
 
2146
2163
  document.addEventListener('visibilitychange', function () {
2147
2164
  _this.prepareAndUpload(false, _this.isBeaconAvailable());
@@ -2160,13 +2177,36 @@ var mParticle = (function () {
2160
2177
  }
2161
2178
 
2162
2179
  return false;
2180
+ }; // Triggers a setTimeout for prepareAndUpload
2181
+
2182
+
2183
+ BatchUploader.prototype.triggerUploadInterval = function (triggerFuture, useBeacon) {
2184
+ var _this_1 = this;
2185
+
2186
+ if (triggerFuture === void 0) {
2187
+ triggerFuture = false;
2188
+ }
2189
+
2190
+ if (useBeacon === void 0) {
2191
+ useBeacon = false;
2192
+ }
2193
+
2194
+ setTimeout(function () {
2195
+ _this_1.prepareAndUpload(triggerFuture, useBeacon);
2196
+ }, this.uploadIntervalMillis);
2163
2197
  };
2198
+ /**
2199
+ * This method will queue a single Event which will eventually be processed into a Batch
2200
+ * @param event event that should be queued
2201
+ */
2202
+
2164
2203
 
2165
2204
  BatchUploader.prototype.queueEvent = function (event) {
2166
2205
  if (!isEmpty(event)) {
2167
- this.pendingEvents.push(event);
2206
+ this.eventsQueuedForProcessing.push(event);
2168
2207
  this.mpInstance.Logger.verbose("Queuing event: ".concat(JSON.stringify(event)));
2169
- this.mpInstance.Logger.verbose("Queued event count: ".concat(this.pendingEvents.length));
2208
+ this.mpInstance.Logger.verbose("Queued event count: ".concat(this.eventsQueuedForProcessing.length)); // TODO: Remove this check once the v2 code path is removed
2209
+ // https://go.mparticle.com/work/SQDSDKS-3720
2170
2210
 
2171
2211
  if (!this.batchingEnabled || Types.TriggerUploadType[event.EventDataType]) {
2172
2212
  this.prepareAndUpload(false, false);
@@ -2184,7 +2224,7 @@ var mParticle = (function () {
2184
2224
  */
2185
2225
 
2186
2226
 
2187
- BatchUploader.createNewUploads = function (sdkEvents, defaultUser, mpInstance) {
2227
+ BatchUploader.createNewBatches = function (sdkEvents, defaultUser, mpInstance) {
2188
2228
  if (!defaultUser || !sdkEvents || !sdkEvents.length) {
2189
2229
  return null;
2190
2230
  } //bucket by MPID, and then by session, ordered by timestamp
@@ -2264,41 +2304,40 @@ var mParticle = (function () {
2264
2304
 
2265
2305
  BatchUploader.prototype.prepareAndUpload = function (triggerFuture, useBeacon) {
2266
2306
  return __awaiter(this, void 0, void 0, function () {
2267
- var currentUser, currentEvents, newUploads, currentUploads, remainingUploads;
2307
+ var currentUser, currentEvents, newBatches, batchesToUpload, batchesThatDidNotUpload;
2268
2308
 
2269
2309
  var _a, _b;
2270
2310
 
2271
- var _this_1 = this;
2272
-
2273
2311
  return __generator(this, function (_c) {
2274
2312
  switch (_c.label) {
2275
2313
  case 0:
2276
2314
  currentUser = this.mpInstance.Identity.getCurrentUser();
2277
- currentEvents = this.pendingEvents;
2278
- this.pendingEvents = [];
2279
- newUploads = BatchUploader.createNewUploads(currentEvents, currentUser, this.mpInstance);
2315
+ currentEvents = this.eventsQueuedForProcessing;
2316
+ this.eventsQueuedForProcessing = [];
2317
+ newBatches = BatchUploader.createNewBatches(currentEvents, currentUser, this.mpInstance);
2280
2318
 
2281
- if (newUploads && newUploads.length) {
2282
- (_a = this.pendingUploads).push.apply(_a, newUploads);
2319
+ if (!isEmpty(newBatches)) {
2320
+ (_a = this.batchesQueuedForProcessing).push.apply(_a, newBatches);
2283
2321
  }
2284
2322
 
2285
- currentUploads = this.pendingUploads;
2286
- this.pendingUploads = [];
2323
+ batchesToUpload = this.batchesQueuedForProcessing;
2324
+ this.batchesQueuedForProcessing = [];
2287
2325
  return [4
2288
2326
  /*yield*/
2289
- , this.upload(this.mpInstance.Logger, currentUploads, useBeacon)];
2327
+ , this.uploadBatches(this.mpInstance.Logger, batchesToUpload, useBeacon)];
2290
2328
 
2291
2329
  case 1:
2292
- remainingUploads = _c.sent();
2330
+ batchesThatDidNotUpload = _c.sent(); // Batches that do not successfully upload are added back to the process queue
2331
+ // in the order they were created so that we can attempt re-transmission in
2332
+ // the same sequence. This is to prevent any potential data corruption.
2293
2333
 
2294
- if (remainingUploads && remainingUploads.length) {
2295
- (_b = this.pendingUploads).unshift.apply(_b, remainingUploads);
2334
+ if (!isEmpty(batchesThatDidNotUpload)) {
2335
+ // TODO: https://go.mparticle.com/work/SQDSDKS-5165
2336
+ (_b = this.batchesQueuedForProcessing).unshift.apply(_b, batchesThatDidNotUpload);
2296
2337
  }
2297
2338
 
2298
2339
  if (triggerFuture) {
2299
- setTimeout(function () {
2300
- _this_1.prepareAndUpload(true, false);
2301
- }, this.uploadIntervalMillis);
2340
+ this.triggerUploadInterval(triggerFuture, false);
2302
2341
  }
2303
2342
 
2304
2343
  return [2
@@ -2307,16 +2346,18 @@ var mParticle = (function () {
2307
2346
  }
2308
2347
  });
2309
2348
  });
2310
- };
2349
+ }; // TODO: Refactor to use logger as a class method
2350
+ // https://go.mparticle.com/work/SQDSDKS-5167
2351
+
2311
2352
 
2312
- BatchUploader.prototype.upload = function (logger, _uploads, useBeacon) {
2353
+ BatchUploader.prototype.uploadBatches = function (logger, batches, useBeacon) {
2313
2354
  return __awaiter(this, void 0, void 0, function () {
2314
- var uploader, uploads, i, fetchPayload, blob, response, e_1;
2355
+ var uploads, i, fetchPayload, blob, response, e_1;
2315
2356
  return __generator(this, function (_a) {
2316
2357
  switch (_a.label) {
2317
2358
  case 0:
2318
- uploads = _uploads.filter(function (upload) {
2319
- return !isEmpty(upload.events);
2359
+ uploads = batches.filter(function (batch) {
2360
+ return !isEmpty(batch.events);
2320
2361
  });
2321
2362
 
2322
2363
  if (isEmpty(uploads)) {
@@ -2333,7 +2374,7 @@ var mParticle = (function () {
2333
2374
  case 1:
2334
2375
  if (!(i < uploads.length)) return [3
2335
2376
  /*break*/
2336
- , 7];
2377
+ , 6];
2337
2378
  fetchPayload = {
2338
2379
  method: 'POST',
2339
2380
  headers: {
@@ -2351,33 +2392,22 @@ var mParticle = (function () {
2351
2392
  navigator.sendBeacon(this.uploadUrl, blob);
2352
2393
  return [3
2353
2394
  /*break*/
2354
- , 6];
2395
+ , 5];
2355
2396
 
2356
2397
  case 2:
2357
- if (!uploader) {
2358
- if (window.fetch) {
2359
- uploader = new FetchUploader(this.uploadUrl, logger);
2360
- } else {
2361
- uploader = new XHRUploader(this.uploadUrl, logger);
2362
- }
2363
- }
2364
-
2365
- _a.label = 3;
2366
-
2367
- case 3:
2368
- _a.trys.push([3, 5,, 6]);
2398
+ _a.trys.push([2, 4,, 5]);
2369
2399
 
2370
2400
  return [4
2371
2401
  /*yield*/
2372
- , uploader.upload(fetchPayload, uploads, i)];
2402
+ , this.uploader.upload(fetchPayload)];
2373
2403
 
2374
- case 4:
2404
+ case 3:
2375
2405
  response = _a.sent();
2376
2406
 
2377
2407
  if (response.status >= 200 && response.status < 300) {
2378
2408
  logger.verbose("Upload success for request ID: ".concat(uploads[i].source_request_id));
2379
2409
  } else if (response.status >= 500 || response.status === 429) {
2380
- logger.error("HTTP error status ".concat(response.status, " received")); //server error, add back current events and try again later
2410
+ logger.error("HTTP error status ".concat(response.status, " received")); // Server error, add back current batches and try again later
2381
2411
 
2382
2412
  return [2
2383
2413
  /*return*/
@@ -2388,33 +2418,37 @@ var mParticle = (function () {
2388
2418
  return [2
2389
2419
  /*return*/
2390
2420
  , null];
2421
+ } else {
2422
+ // In case there is an HTTP error we did not anticipate.
2423
+ console.error("HTTP error status ".concat(response.status, " while uploading events."), response);
2424
+ throw new Error("Uncaught HTTP Error ".concat(response.status, ". Batch upload will be re-attempted."));
2391
2425
  }
2392
2426
 
2393
2427
  return [3
2394
2428
  /*break*/
2395
- , 6];
2429
+ , 5];
2396
2430
 
2397
- case 5:
2431
+ case 4:
2398
2432
  e_1 = _a.sent();
2399
2433
  logger.error("Error sending event to mParticle servers. ".concat(e_1));
2400
2434
  return [2
2401
2435
  /*return*/
2402
2436
  , uploads.slice(i, uploads.length)];
2403
2437
 
2404
- case 6:
2438
+ case 5:
2405
2439
  i++;
2406
2440
  return [3
2407
2441
  /*break*/
2408
2442
  , 1];
2409
2443
 
2410
- case 7:
2444
+ case 6:
2411
2445
  return [2
2412
2446
  /*return*/
2413
2447
  , null];
2414
2448
  }
2415
2449
  });
2416
2450
  });
2417
- }; //we upload JSON, but this content type is required to avoid a CORS preflight request
2451
+ }; // We upload JSON, but this content type is required to avoid a CORS preflight request
2418
2452
 
2419
2453
 
2420
2454
  BatchUploader.CONTENT_TYPE = 'text/plain;charset=UTF-8';
@@ -2425,9 +2459,8 @@ var mParticle = (function () {
2425
2459
  var AsyncUploader =
2426
2460
  /** @class */
2427
2461
  function () {
2428
- function AsyncUploader(url, logger) {
2462
+ function AsyncUploader(url) {
2429
2463
  this.url = url;
2430
- this.logger = logger;
2431
2464
  }
2432
2465
 
2433
2466
  return AsyncUploader;
@@ -2442,7 +2475,7 @@ var mParticle = (function () {
2442
2475
  return _super !== null && _super.apply(this, arguments) || this;
2443
2476
  }
2444
2477
 
2445
- FetchUploader.prototype.upload = function (fetchPayload, uploads, i) {
2478
+ FetchUploader.prototype.upload = function (fetchPayload) {
2446
2479
  return __awaiter(this, void 0, void 0, function () {
2447
2480
  var response;
2448
2481
  return __generator(this, function (_a) {
@@ -2474,7 +2507,7 @@ var mParticle = (function () {
2474
2507
  return _super !== null && _super.apply(this, arguments) || this;
2475
2508
  }
2476
2509
 
2477
- XHRUploader.prototype.upload = function (fetchPayload, uploads, i) {
2510
+ XHRUploader.prototype.upload = function (fetchPayload) {
2478
2511
  return __awaiter(this, void 0, void 0, function () {
2479
2512
  var response;
2480
2513
  return __generator(this, function (_a) {
@@ -2482,7 +2515,7 @@ var mParticle = (function () {
2482
2515
  case 0:
2483
2516
  return [4
2484
2517
  /*yield*/
2485
- , this.makeRequest(this.url, this.logger, fetchPayload.body)];
2518
+ , this.makeRequest(this.url, fetchPayload.body)];
2486
2519
 
2487
2520
  case 1:
2488
2521
  response = _a.sent();
@@ -2494,7 +2527,7 @@ var mParticle = (function () {
2494
2527
  });
2495
2528
  };
2496
2529
 
2497
- XHRUploader.prototype.makeRequest = function (url, logger, data) {
2530
+ XHRUploader.prototype.makeRequest = function (url, data) {
2498
2531
  return __awaiter(this, void 0, void 0, function () {
2499
2532
  var xhr;
2500
2533
  return __generator(this, function (_a) {
@@ -3172,6 +3205,11 @@ var mParticle = (function () {
3172
3205
  return filteredUserAttributes;
3173
3206
  };
3174
3207
 
3208
+ this.isFilteredUserAttribute = function (userAttributeKey, filterList) {
3209
+ var hashedUserAttribute = self.generateHash(userAttributeKey);
3210
+ return filterList && self.inArray(filterList, hashedUserAttribute);
3211
+ };
3212
+
3175
3213
  this.isEventType = function (type) {
3176
3214
  for (var prop in Types.EventType) {
3177
3215
  if (Types.EventType.hasOwnProperty(prop)) {
@@ -6150,6 +6188,10 @@ var mParticle = (function () {
6150
6188
 
6151
6189
  function Forwarders(mpInstance, kitBlocker) {
6152
6190
  var self = this;
6191
+ var UserAttributeActionTypes = {
6192
+ setUserAttribute: 'setUserAttribute',
6193
+ removeUserAttribute: 'removeUserAttribute'
6194
+ };
6153
6195
 
6154
6196
  this.initForwarders = function (userIdentities, forwardingStatsCallback) {
6155
6197
  var user = mpInstance.Identity.getCurrentUser();
@@ -6384,26 +6426,34 @@ var mParticle = (function () {
6384
6426
  }
6385
6427
  };
6386
6428
 
6387
- this.callSetUserAttributeOnForwarders = function (key, value) {
6388
- if (kitBlocker && kitBlocker.isAttributeKeyBlocked(key)) {
6429
+ this.handleForwarderUserAttributes = function (functionNameKey, key, value) {
6430
+ if (kitBlocker && kitBlocker.isAttributeKeyBlocked(key) || !mpInstance._Store.activeForwarders.length) {
6389
6431
  return;
6390
6432
  }
6391
6433
 
6392
- if (mpInstance._Store.activeForwarders.length) {
6393
- mpInstance._Store.activeForwarders.forEach(function (forwarder) {
6394
- if (forwarder.setUserAttribute && forwarder.userAttributeFilters && !mpInstance._Helpers.inArray(forwarder.userAttributeFilters, mpInstance._Helpers.generateHash(key))) {
6395
- try {
6396
- var result = forwarder.setUserAttribute(key, value);
6434
+ mpInstance._Store.activeForwarders.forEach(function (forwarder) {
6435
+ var forwarderFunction = forwarder[functionNameKey];
6397
6436
 
6398
- if (result) {
6399
- mpInstance.Logger.verbose(result);
6400
- }
6401
- } catch (e) {
6402
- mpInstance.Logger.error(e);
6403
- }
6437
+ if (!forwarderFunction || mpInstance._Helpers.isFilteredUserAttribute(key, forwarder.userAttributeFilters)) {
6438
+ return;
6439
+ }
6440
+
6441
+ try {
6442
+ var result;
6443
+
6444
+ if (functionNameKey === UserAttributeActionTypes.setUserAttribute) {
6445
+ result = forwarder.setUserAttribute(key, value);
6446
+ } else if (functionNameKey === UserAttributeActionTypes.removeUserAttribute) {
6447
+ result = forwarder.removeUserAttribute(key);
6404
6448
  }
6405
- });
6406
- }
6449
+
6450
+ if (result) {
6451
+ mpInstance.Logger.verbose(result);
6452
+ }
6453
+ } catch (e) {
6454
+ mpInstance.Logger.error(e);
6455
+ }
6456
+ });
6407
6457
  };
6408
6458
 
6409
6459
  this.setForwarderUserIdentities = function (userIdentities) {
@@ -7608,7 +7658,7 @@ var mParticle = (function () {
7608
7658
 
7609
7659
  mpInstance._Forwarders.initForwarders(self.IdentityAPI.getCurrentUser().getUserIdentities(), mpInstance._APIClient.prepareForwardingStats);
7610
7660
 
7611
- mpInstance._Forwarders.callSetUserAttributeOnForwarders(key, newValue);
7661
+ mpInstance._Forwarders.handleForwarderUserAttributes('setUserAttribute', key, newValue);
7612
7662
  }
7613
7663
  }
7614
7664
  },
@@ -7677,7 +7727,7 @@ var mParticle = (function () {
7677
7727
 
7678
7728
  mpInstance._Forwarders.initForwarders(self.IdentityAPI.getCurrentUser().getUserIdentities(), mpInstance._APIClient.prepareForwardingStats);
7679
7729
 
7680
- mpInstance._Forwarders.applyToForwarders('removeUserAttribute', key);
7730
+ mpInstance._Forwarders.handleForwarderUserAttributes('removeUserAttribute', key, null);
7681
7731
  }
7682
7732
  },
7683
7733
 
@@ -7755,7 +7805,7 @@ var mParticle = (function () {
7755
7805
 
7756
7806
  mpInstance._Forwarders.initForwarders(self.IdentityAPI.getCurrentUser().getUserIdentities(), mpInstance._APIClient.prepareForwardingStats);
7757
7807
 
7758
- mpInstance._Forwarders.callSetUserAttributeOnForwarders(key, arrayCopy);
7808
+ mpInstance._Forwarders.handleForwarderUserAttributes('setUserAttribute', key, arrayCopy);
7759
7809
  }
7760
7810
  },
7761
7811
 
@@ -7778,7 +7828,7 @@ var mParticle = (function () {
7778
7828
  if (userAttributes) {
7779
7829
  for (var prop in userAttributes) {
7780
7830
  if (userAttributes.hasOwnProperty(prop)) {
7781
- mpInstance._Forwarders.applyToForwarders('removeUserAttribute', prop);
7831
+ mpInstance._Forwarders.handleForwarderUserAttributes('removeUserAttribute', prop, null);
7782
7832
  }
7783
7833
 
7784
7834
  this.removeUserAttribute(prop);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@mparticle/web-sdk",
3
- "version": "2.19.2",
3
+ "version": "2.19.3",
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 && cross-env TESTTYPE=main ENVIRONMENT=prod rollup --config rollup.test.config.js && cross-env DEBUG=false karma start test/karma.config.js",
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",