@mparticle/web-sdk 2.25.3 → 2.26.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.
@@ -36,11 +36,13 @@ import Consent from './consent';
36
36
  import KitBlocker from './kitBlocking';
37
37
  import ConfigAPIClient from './configAPIClient';
38
38
  import IdentityAPIClient from './identityApiClient';
39
+ import { isEmpty, isFunction } from './utils';
39
40
  import { LocalStorageVault } from './vault';
40
41
  import { removeExpiredIdentityCacheDates } from './identity-utils';
41
42
 
42
- var Messages = Constants.Messages,
43
- HTTPCodes = Constants.HTTPCodes;
43
+ const { Messages, HTTPCodes, FeatureFlags } = Constants;
44
+ const { ReportBatching } = FeatureFlags;
45
+ const { StartingInitialization } = Messages.InformationMessages;
44
46
 
45
47
  /**
46
48
  * <p>All of the following methods can be called on the primary mParticle class. In version 2.10.0, we introduced <a href="https://docs.mparticle.com/developers/sdk/web/multiple-instances/">multiple instances</a>. If you are using multiple instances (self hosted environments only), you should call these methods on each instance.</p>
@@ -289,7 +291,7 @@ export default function mParticleInstance(instanceName) {
289
291
  * @param {Function} [callback] A callback function that is called when the location is either allowed or rejected by the user. A position object of schema {coords: {latitude: number, longitude: number}} is passed to the callback
290
292
  */
291
293
  this.startTrackingLocation = function(callback) {
292
- if (!self._Helpers.Validators.isFunction(callback)) {
294
+ if (!isFunction(callback)) {
293
295
  self.Logger.warning(
294
296
  'Warning: Location tracking is triggered, but not including a callback into the `startTrackingLocation` may result in events logged too quickly and not being associated with a location.'
295
297
  );
@@ -1292,189 +1294,66 @@ function completeSDKInitialization(apiKey, config, mpInstance) {
1292
1294
 
1293
1295
  mpInstance._APIClient = new APIClient(mpInstance, kitBlocker);
1294
1296
  mpInstance._Forwarders = new Forwarders(mpInstance, kitBlocker);
1295
- if (config.flags) {
1296
- if (
1297
- config.flags.hasOwnProperty(
1298
- Constants.FeatureFlags.EventBatchingIntervalMillis
1299
- )
1300
- ) {
1301
- mpInstance._Store.SDKConfig.flags[
1302
- Constants.FeatureFlags.EventBatchingIntervalMillis
1303
- ] =
1304
- config.flags[
1305
- Constants.FeatureFlags.EventBatchingIntervalMillis
1306
- ];
1307
- }
1308
- }
1309
-
1310
- // add a new function to apply items to the store that require config to be returned
1311
- mpInstance._Store.storageName = mpInstance._Helpers.createMainStorageName(
1312
- config.workspaceToken
1313
- );
1314
- mpInstance._Store.prodStorageName = mpInstance._Helpers.createProductStorageName(
1315
- config.workspaceToken
1316
- );
1317
-
1318
- // idCache is instantiated here as opposed to when _Identity is instantiated
1319
- // because it depends on _Store.storageName, which is not sent until above
1320
- // because it is a setting on config which returns asyncronously
1321
- // in self hosted mode
1322
- mpInstance._Identity.idCache = new LocalStorageVault(
1323
- `${mpInstance._Store.storageName}-id-cache`,
1324
- {
1325
- logger: mpInstance.Logger,
1326
- }
1327
- );
1297
+ mpInstance._Store.processConfig(config);
1328
1298
 
1299
+ mpInstance._Identity.idCache = createIdentityCache(mpInstance);
1329
1300
  removeExpiredIdentityCacheDates(mpInstance._Identity.idCache);
1330
1301
 
1331
- if (config.hasOwnProperty('workspaceToken')) {
1332
- mpInstance._Store.SDKConfig.workspaceToken = config.workspaceToken;
1302
+ // Web View Bridge is used for cases where the Web SDK is loaded within an iOS or Android device's
1303
+ // Web View. The Web SDK simply acts as a passthrough to the mParticle Native SDK. It is not
1304
+ // responsible for sending events directly to mParticle's servers. The Web SDK will not initialize
1305
+ // persistence or Identity directly.
1306
+ if (mpInstance._Store.webviewBridgeEnabled) {
1307
+ mpInstance._NativeSdkHelpers.initializeSessionAttributes(apiKey);
1333
1308
  } else {
1334
- mpInstance.Logger.warning(
1335
- 'You should have a workspaceToken on your config object for security purposes.'
1336
- );
1337
- }
1309
+ // Main SDK initialization flow
1338
1310
 
1339
- if (config.hasOwnProperty('requiredWebviewBridgeName')) {
1340
- mpInstance._Store.SDKConfig.requiredWebviewBridgeName =
1341
- config.requiredWebviewBridgeName;
1342
- } else if (config.hasOwnProperty('workspaceToken')) {
1343
- mpInstance._Store.SDKConfig.requiredWebviewBridgeName =
1344
- config.workspaceToken;
1345
- }
1346
- mpInstance._Store.webviewBridgeEnabled = mpInstance._NativeSdkHelpers.isWebviewEnabled(
1347
- mpInstance._Store.SDKConfig.requiredWebviewBridgeName,
1348
- mpInstance._Store.SDKConfig.minWebviewBridgeVersion
1349
- );
1350
-
1351
- mpInstance._Store.configurationLoaded = true;
1352
-
1353
- // https://go.mparticle.com/work/SQDSDKS-6044
1354
- if (!mpInstance._Store.webviewBridgeEnabled) {
1355
1311
  // Load any settings/identities/attributes from cookie or localStorage
1356
1312
  mpInstance._Persistence.initializeStorage();
1357
- }
1358
1313
 
1359
- if (mpInstance._Store.webviewBridgeEnabled) {
1360
- mpInstance._NativeSdkHelpers.sendToNative(
1361
- Constants.NativeSdkPaths.SetSessionAttribute,
1362
- JSON.stringify({ key: '$src_env', value: 'webview' })
1363
- );
1364
- if (apiKey) {
1365
- mpInstance._NativeSdkHelpers.sendToNative(
1366
- Constants.NativeSdkPaths.SetSessionAttribute,
1367
- JSON.stringify({ key: '$src_key', value: apiKey })
1368
- );
1369
- }
1370
- } else {
1371
- var currentUser;
1314
+ // Set up user identitiy variables for later use
1315
+ const currentUser = mpInstance.Identity.getCurrentUser();
1316
+ const currentUserMPID = currentUser ? currentUser.getMPID() : null;
1317
+ const currentUserIdentities = currentUser
1318
+ ? currentUser.getUserIdentities().userIdentities
1319
+ : {};
1372
1320
 
1373
- // If no initialIdentityRequest is passed in, we set the user identities to what is currently in cookies for the identify request
1374
- if (
1375
- (mpInstance._Helpers.isObject(
1376
- mpInstance._Store.SDKConfig.identifyRequest
1377
- ) &&
1378
- mpInstance._Helpers.isObject(
1379
- mpInstance._Store.SDKConfig.identifyRequest.userIdentities
1380
- ) &&
1381
- Object.keys(
1382
- mpInstance._Store.SDKConfig.identifyRequest.userIdentities
1383
- ).length === 0) ||
1384
- !mpInstance._Store.SDKConfig.identifyRequest
1385
- ) {
1386
- var modifiedUIforIdentityRequest = {};
1387
-
1388
- currentUser = mpInstance.Identity.getCurrentUser();
1389
- if (currentUser) {
1390
- var identities =
1391
- currentUser.getUserIdentities().userIdentities || {};
1392
- for (var identityKey in identities) {
1393
- if (identities.hasOwnProperty(identityKey)) {
1394
- modifiedUIforIdentityRequest[identityKey] =
1395
- identities[identityKey];
1396
- }
1397
- }
1398
- }
1399
-
1400
- mpInstance._Store.SDKConfig.identifyRequest = {
1401
- userIdentities: modifiedUIforIdentityRequest,
1402
- };
1403
- }
1404
-
1405
- currentUser = mpInstance.Identity.getCurrentUser();
1321
+ mpInstance._Store.SDKConfig.identifyRequest = mpInstance._Store.hasInvalidIdentifyRequest()
1322
+ ? { userIdentities: currentUserIdentities }
1323
+ : mpInstance._Store.SDKConfig.identifyRequest;
1406
1324
 
1407
- if (
1408
- mpInstance._Helpers.getFeatureFlag(
1409
- Constants.FeatureFlags.ReportBatching
1410
- )
1411
- ) {
1325
+ if (mpInstance._Helpers.getFeatureFlag(ReportBatching)) {
1412
1326
  mpInstance._ForwardingStatsUploader.startForwardingStatsTimer();
1413
1327
  }
1328
+
1414
1329
  mpInstance._Forwarders.processForwarders(
1415
1330
  config,
1416
1331
  mpInstance._APIClient.prepareForwardingStats
1417
1332
  );
1418
-
1419
1333
  mpInstance._Forwarders.processPixelConfigs(config);
1420
1334
 
1335
+ // Checks if session is created, resumed, or needs to be ended
1336
+ // Logs a session start or session end event accordingly
1421
1337
  mpInstance._SessionManager.initialize();
1422
1338
  mpInstance._Events.logAST();
1423
1339
 
1424
- // Call mParticle._Store.SDKConfig.identityCallback when identify was not called due to a reload or a sessionId already existing
1425
- // Any identity callback should always be ran regardless if an identity call is made
1426
- if (
1427
- !mpInstance._Store.identifyCalled &&
1428
- mpInstance._Store.SDKConfig.identityCallback &&
1429
- currentUser &&
1430
- currentUser.getMPID()
1431
- ) {
1432
- mpInstance._Store.SDKConfig.identityCallback({
1433
- httpCode: HTTPCodes.activeSession,
1434
- getUser: function() {
1435
- return mpInstance._Identity.mParticleUser(
1436
- currentUser.getMPID()
1437
- );
1438
- },
1439
- getPreviousUser: function() {
1440
- var users = mpInstance.Identity.getUsers();
1441
- var mostRecentUser = users.shift();
1442
- if (
1443
- mostRecentUser &&
1444
- currentUser &&
1445
- mostRecentUser.getMPID() === currentUser.getMPID()
1446
- ) {
1447
- mostRecentUser = users.shift();
1448
- }
1449
- return mostRecentUser || null;
1450
- },
1451
- body: {
1452
- mpid: currentUser.getMPID(),
1453
- is_logged_in: mpInstance._Store.isLoggedIn,
1454
- matched_identities: currentUser.getUserIdentities()
1455
- .userIdentities,
1456
- context: null,
1457
- is_ephemeral: false,
1458
- },
1459
- });
1460
- }
1340
+ processIdentityCallback(
1341
+ mpInstance,
1342
+ currentUser,
1343
+ currentUserMPID,
1344
+ currentUserIdentities
1345
+ );
1461
1346
  }
1462
1347
 
1463
1348
  mpInstance._Store.isInitialized = true;
1464
- // Call any functions that are waiting for the library to be initialized
1465
- if (
1466
- mpInstance._preInit.readyQueue &&
1467
- mpInstance._preInit.readyQueue.length
1468
- ) {
1469
- mpInstance._preInit.readyQueue.forEach(function(readyQueueItem) {
1470
- if (mpInstance._Helpers.Validators.isFunction(readyQueueItem)) {
1471
- readyQueueItem();
1472
- } else if (Array.isArray(readyQueueItem)) {
1473
- processPreloadedItem(readyQueueItem, mpInstance);
1474
- }
1475
- });
1476
1349
 
1477
- mpInstance._preInit.readyQueue = [];
1350
+ // Call any functions that are waiting for the library to be initialized
1351
+ try {
1352
+ mpInstance._preInit.readyQueue = processReadyQueue(
1353
+ mpInstance._preInit.readyQueue
1354
+ );
1355
+ } catch (error) {
1356
+ mpInstance.Logger.error(error);
1478
1357
  }
1479
1358
 
1480
1359
  // https://go.mparticle.com/work/SQDSDKS-6040
@@ -1544,13 +1423,17 @@ function createKitBlocker(config, mpInstance) {
1544
1423
  return kitBlocker;
1545
1424
  }
1546
1425
 
1426
+ function createIdentityCache(mpInstance) {
1427
+ return new LocalStorageVault(`${mpInstance._Store.storageName}-id-cache`, {
1428
+ logger: mpInstance.Logger,
1429
+ });
1430
+ }
1431
+
1547
1432
  function runPreConfigFetchInitialization(mpInstance, apiKey, config) {
1548
1433
  mpInstance.Logger = new Logger(config);
1549
1434
  mpInstance._Store = new Store(config, mpInstance, apiKey);
1550
1435
  window.mParticle.Store = mpInstance._Store;
1551
- mpInstance.Logger.verbose(
1552
- Messages.InformationMessages.StartingInitialization
1553
- );
1436
+ mpInstance.Logger.verbose(StartingInitialization);
1554
1437
 
1555
1438
  // Check to see if localStorage is available before main configuration runs
1556
1439
  // since we will need this for the current implementation of user persistence
@@ -1567,30 +1450,84 @@ function runPreConfigFetchInitialization(mpInstance, apiKey, config) {
1567
1450
  }
1568
1451
  }
1569
1452
 
1570
- function processPreloadedItem(readyQueueItem, mpInstance) {
1571
- var args = readyQueueItem,
1572
- method = args.splice(0, 1)[0];
1453
+ function processIdentityCallback(
1454
+ mpInstance,
1455
+ currentUser,
1456
+ currentUserMPID,
1457
+ currentUserIdentities
1458
+ ) {
1459
+ // https://go.mparticle.com/work/SQDSDKS-6323
1460
+ // Call mParticle._Store.SDKConfig.identityCallback when identify was not called
1461
+ // due to a reload or a sessionId already existing
1462
+ // Any identity callback should always be ran regardless if an identity call
1463
+ // is made
1464
+ if (
1465
+ !mpInstance._Store.identifyCalled &&
1466
+ mpInstance._Store.SDKConfig.identityCallback &&
1467
+ currentUser &&
1468
+ currentUserMPID
1469
+ ) {
1470
+ mpInstance._Store.SDKConfig.identityCallback({
1471
+ httpCode: HTTPCodes.activeSession,
1472
+ getUser: function() {
1473
+ return mpInstance._Identity.mParticleUser(currentUserMPID);
1474
+ },
1475
+ getPreviousUser: function() {
1476
+ const users = mpInstance.Identity.getUsers();
1477
+ let mostRecentUser = users.shift();
1478
+ const mostRecentUserMPID = mostRecentUser.getMPID();
1479
+ if (mostRecentUser && mostRecentUserMPID === currentUserMPID) {
1480
+ mostRecentUser = users.shift();
1481
+ }
1482
+ return mostRecentUser || null;
1483
+ },
1484
+ body: {
1485
+ mpid: currentUserMPID,
1486
+ is_logged_in: mpInstance._Store.isLoggedIn,
1487
+ matched_identities: currentUserIdentities,
1488
+ context: null,
1489
+ is_ephemeral: false,
1490
+ },
1491
+ });
1492
+ }
1493
+ }
1494
+
1495
+ function processPreloadedItem(readyQueueItem) {
1496
+ const args = readyQueueItem;
1497
+ const method = args.splice(0, 1)[0];
1573
1498
  // if the first argument is a method on the base mParticle object, run it
1574
1499
  if (mParticle[args[0]]) {
1575
1500
  mParticle[method].apply(this, args);
1576
1501
  // otherwise, the method is on either eCommerce or Identity objects, ie. "eCommerce.setCurrencyCode", "Identity.login"
1577
1502
  } else {
1578
- var methodArray = method.split('.');
1503
+ const methodArray = method.split('.');
1579
1504
  try {
1580
1505
  var computedMPFunction = mParticle;
1581
- for (var i = 0; i < methodArray.length; i++) {
1582
- var currentMethod = methodArray[i];
1506
+ for (let i = 0; i < methodArray.length; i++) {
1507
+ const currentMethod = methodArray[i];
1583
1508
  computedMPFunction = computedMPFunction[currentMethod];
1584
1509
  }
1585
1510
  computedMPFunction.apply(this, args);
1586
1511
  } catch (e) {
1587
- mpInstance.Logger.verbose(
1588
- 'Unable to compute proper mParticle function ' + e
1589
- );
1512
+ throw new Error('Unable to compute proper mParticle function ' + e);
1590
1513
  }
1591
1514
  }
1592
1515
  }
1593
1516
 
1517
+ function processReadyQueue(readyQueue) {
1518
+ if (!isEmpty(readyQueue)) {
1519
+ readyQueue.forEach(function(readyQueueItem) {
1520
+ if (isFunction(readyQueueItem)) {
1521
+ readyQueueItem();
1522
+ } else if (Array.isArray(readyQueueItem)) {
1523
+ processPreloadedItem(readyQueueItem);
1524
+ }
1525
+ });
1526
+
1527
+ return [];
1528
+ }
1529
+ }
1530
+
1594
1531
  function queueIfNotInitialized(func, self) {
1595
1532
  if (!self.isInitialized()) {
1596
1533
  self.ready(function() {
@@ -7,6 +7,24 @@ var iosBridgeNameBase = 'mParticle';
7
7
 
8
8
  export default function NativeSdkHelpers(mpInstance) {
9
9
  var self = this;
10
+ this.initializeSessionAttributes = function(apiKey) {
11
+ const { SetSessionAttribute } = Constants.NativeSdkPaths;
12
+ const env = JSON.stringify({
13
+ key: '$src_env',
14
+ value: 'webview',
15
+ });
16
+
17
+ const key = JSON.stringify({
18
+ key: '$src_key',
19
+ value: apiKey,
20
+ });
21
+
22
+ self.sendToNative(SetSessionAttribute, env);
23
+ if (apiKey) {
24
+ self.sendToNative(SetSessionAttribute, key);
25
+ }
26
+ };
27
+
10
28
  this.isBridgeV2Available = function(bridgeName) {
11
29
  if (!bridgeName) {
12
30
  return false;
@@ -1,6 +1,11 @@
1
1
  import * as EventsApi from '@mparticle/event-models';
2
2
  import { DataPlanVersion } from '@mparticle/data-planning-models';
3
- import { MPConfiguration, IdentityApiData } from '@mparticle/web-sdk';
3
+ import {
4
+ MPConfiguration,
5
+ IdentityApiData,
6
+ MPID,
7
+ Callback,
8
+ } from '@mparticle/web-sdk';
4
9
  import { IStore } from './store';
5
10
  import Validators from './validators';
6
11
  import { Dictionary, valueof } from './utils';
@@ -246,20 +251,29 @@ export interface SDKIdentityApi {
246
251
 
247
252
  export interface SDKHelpersApi {
248
253
  canLog?(): boolean;
249
- createServiceUrl(arg0: string, arg1: string): void;
254
+ createMainStorageName?(workspaceToken: string): string;
255
+ createProductStorageName?(workspaceToken: string): string;
256
+ createServiceUrl(url: string, devToken?: string): void;
250
257
  createXHR?(cb: () => void): XMLHttpRequest;
251
258
  extend?(...args: any[]);
252
259
  parseNumber?(value: string | number): number;
253
260
  generateUniqueId();
254
261
  generateHash?(value: string): string;
255
- getFeatureFlag?(feature: string); // TODO: Feature Constants should be converted to enum
262
+ // https://go.mparticle.com/work/SQDSDKS-6317
263
+ getFeatureFlag?(feature: string): boolean | string; // TODO: Feature Constants should be converted to enum
256
264
  isDelayedByIntegration?(
257
265
  delayedIntegrations: Dictionary<boolean>,
258
266
  timeoutStart: number,
259
267
  now: number
260
268
  ): boolean;
261
269
  isObject?(item: any);
262
- returnConvertedBoolean(data: string | boolean | number): boolean;
270
+ invokeCallback?(
271
+ callback: Callback,
272
+ code: string,
273
+ body: string,
274
+ mParticleUser?: MParticleUser,
275
+ previousMpid?: MPID
276
+ ): void;
263
277
  sanitizeAttributes?(
264
278
  attrs: Dictionary<string>,
265
279
  name: string
@@ -47,6 +47,7 @@ export default function SessionManager(
47
47
  // https://go.mparticle.com/work/SQDSDKS-6045
48
48
  const persistence: IPersistenceMinified = mpInstance._Persistence.getPersistence();
49
49
  if (persistence && !persistence.cu) {
50
+ // https://go.mparticle.com/work/SQDSDKS-6323
50
51
  mpInstance.Identity.identify(
51
52
  mpInstance._Store.SDKConfig.identifyRequest,
52
53
  mpInstance._Store.SDKConfig.identityCallback