@mparticle/web-sdk 2.20.3 → 2.21.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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@mparticle/web-sdk",
3
- "version": "2.20.3",
3
+ "version": "2.21.1",
4
4
  "description": "mParticle core SDK for web applications",
5
5
  "license": "Apache-2.0",
6
6
  "keywords": [
@@ -29,18 +29,23 @@
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
31
  "build:test-bundle": "cross-env TESTTYPE=main ENVIRONMENT=prod rollup --config rollup.test.config.js",
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",
33
- "build:rollup:cjs": "rollup --config test/integrations/cjs/rollup/rollup.config.js && npm run test:karma:rollup:cjs",
34
- "build:webpack:cjs": "webpack --config test/integrations/cjs/webpack/webpack.config.js && npm run test:karma:webpack:cjs",
35
- "build:rollup:module": "rollup --config test/integrations/module/rollup/rollup.config.js && npm run test:karma:rollup:module",
36
- "build:webpack:module": "webpack --config test/integrations/module/webpack/webpack.config.js && npm run test:karma:webpack:module",
32
+ "build:browserify:cjs": "browserify test/integrations/cjs/browserify/index.js -o test/integrations/cjs/dist/browserify-output.js",
33
+ "build:rollup:cjs": "rollup --config test/integrations/cjs/rollup/rollup.config.js",
34
+ "build:webpack:cjs": "webpack --config test/integrations/cjs/webpack/webpack.config.js",
35
+ "build:rollup:module": "rollup --config test/integrations/module/rollup/rollup.config.js",
36
+ "build:webpack:module": "webpack --config test/integrations/module/webpack/webpack.config.js",
37
37
  "build:ts": "tsc -p .",
38
38
  "test": "npm run build && npm run build:test-bundle && cross-env DEBUG=false karma start test/karma.config.js",
39
39
  "test:debug": "cross-env DEBUG=true karma start test/karma.config.js",
40
40
  "test:stub": "cross-env TESTTYPE=stub ENVIRONMENT=prod rollup --config rollup.test.config.js && karma start test/stub/karma.stub.config.js",
41
41
  "test:integrations": "npm run test:requirejs && npm run test:integrations:cjs && npm run test:integrations:module",
42
- "test:integrations:cjs": "npm run build:browserify:cjs && npm run build:webpack:cjs && npm run build:rollup:cjs",
43
- "test:integrations:module": "npm run build:webpack:module && npm run build:rollup:module",
42
+ "test:integrations:cjs": "npm run test:integrations:cjs:browserfy && npm run test:integrations:cjs:webpack && npm run test:integrations:cjs:rollup",
43
+ "test:integrations:cjs:browserfy": "npm run build:browserify:cjs && npm run test:karma:browserify:cjs",
44
+ "test:integrations:cjs:webpack": "npm run build:webpack:cjs && npm run test:karma:webpack:cjs",
45
+ "test:integrations:cjs:rollup": "npm run build:rollup:cjs && npm run test:karma:rollup:cjs",
46
+ "test:integrations:module": "npm run test:integrations:module:webpack && npm run test:integrations:module:rollup",
47
+ "test:integrations:module:webpack": "npm run build:webpack:module && npm run test:karma:webpack:module",
48
+ "test:integrations:module:rollup": "npm run build:rollup:module && npm run test:karma:rollup:module",
44
49
  "test:requirejs": "npm run test:requirejs:before && npm run test:requirejs:after",
45
50
  "test:requirejs:before": "cross-env FILE_ORDER=before_mp karma start test/integrations/requirejs/karma.requirejs.config.js",
46
51
  "test:requirejs:after": "cross-env FILE_ORDER=after_mp karma start test/integrations/requirejs/karma.requirejs.config.js",
@@ -49,6 +54,8 @@
49
54
  "test:karma:rollup:cjs": "cross-env BUNDLER=rollup karma start test/integrations/cjs/karma.rollup.config.js",
50
55
  "test:karma:webpack:module": "cross-env BUNDLER=webpack karma start test/integrations/module/karma.webpack.config.js",
51
56
  "test:karma:rollup:module": "cross-env BUNDLER=rollup karma start test/integrations/module/karma.rollup.config.js",
57
+ "test:jest": "jest --config jest.config.js",
58
+ "test:jest:watch": "jest --config jest.config.js --watch",
52
59
  "watch": "cross-env ENVIRONMENT=dev BUILD=iife rollup --config rollup.config.js -w",
53
60
  "watch:all": "cross-env ENVIRONMENT=prod BUILDALL=true rollup --config rollup.config.js -w",
54
61
  "watch:tests": "cross-env ENVIRONMENT=dev TESTTYPE=main rollup --config rollup.test.config.js -w",
@@ -76,15 +83,17 @@
76
83
  "@babel/preset-typescript": "^7.6.0",
77
84
  "@mparticle/data-planning-models": "^0.1.0",
78
85
  "@mparticle/event-models": "^1.1.6",
79
- "@rollup/plugin-json": "^4.1.0",
80
- "@rollup/plugin-typescript": "^8.3.3",
81
86
  "@rollup/plugin-babel": "6.0.3",
82
87
  "@rollup/plugin-commonjs": "22.0.2",
88
+ "@rollup/plugin-json": "^4.1.0",
83
89
  "@rollup/plugin-node-resolve": "13.3.0",
90
+ "@rollup/plugin-typescript": "^8.3.3",
84
91
  "@semantic-release/changelog": "^5.0.1",
85
92
  "@semantic-release/exec": "^5.0.0",
86
93
  "@semantic-release/git": "^9.0.0",
87
94
  "@types/chai": "^4.2.3",
95
+ "@types/jest": "^29.5.1",
96
+ "@types/jest-expect-message": "^1.1.0",
88
97
  "@types/mocha": "^9.0.0",
89
98
  "@types/mparticle__web-sdk": "^2.16.1",
90
99
  "@types/node": "^18.7.11",
@@ -98,6 +107,7 @@
98
107
  "eslint-plugin-prettier": "3.4.1",
99
108
  "fetch-mock": "^7.5.1",
100
109
  "gts": "^3.1.0",
110
+ "jest": "^29.5.0",
101
111
  "karma": "^6.3.2",
102
112
  "karma-chai": "^0.1.0",
103
113
  "karma-chrome-launcher": "^3.1.0",
@@ -115,6 +125,7 @@
115
125
  "shelljs": "^0.8.4",
116
126
  "should": "^7.1.0",
117
127
  "sinon": "^11.0.0",
128
+ "ts-jest": "^29.1.0",
118
129
  "tslib": "^2.1.0",
119
130
  "typescript": "^5.0.2",
120
131
  "uglify-js": "^3.4.9",
@@ -1,4 +1,5 @@
1
1
  import { Batch } from '@mparticle/event-models';
2
+ import Constants from './constants';
2
3
  import {
3
4
  SDKEvent,
4
5
  MParticleUser,
@@ -7,12 +8,17 @@ import {
7
8
  } from './sdkRuntimeModels';
8
9
  import { convertEvents } from './sdkToEventsApiConverter';
9
10
  import Types from './types';
10
- import { isEmpty } from './utils';
11
+ import { getRampNumber, isEmpty } from './utils';
12
+ import { SessionStorageVault, LocalStorageVault } from './vault';
11
13
 
12
14
  /**
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.
15
+ * BatchUploader contains all the logic to store/retrieve events and batches
16
+ * to/from persistence, and upload batches to mParticle.
17
+ * It queues events as they come in, storing them in persistence, then at set
18
+ * intervals turns them into batches and transfers between event and batch
19
+ * persistence.
20
+ * It then attempts to upload them to mParticle, purging batch persistence if
21
+ * the upload is successful
16
22
  *
17
23
  * These uploads happen on an interval basis using window.fetch or XHR
18
24
  * requests, depending on what is available in the browser.
@@ -31,6 +37,9 @@ export class BatchUploader {
31
37
  mpInstance: MParticleWebSDK;
32
38
  uploadUrl: string;
33
39
  batchingEnabled: boolean;
40
+ private eventVault: SessionStorageVault<SDKEvent[]>;
41
+ private batchVault: LocalStorageVault<Batch[]>;
42
+ private offlineStorageEnabled: boolean = false;
34
43
  private uploader: AsyncUploader;
35
44
 
36
45
  /**
@@ -46,9 +55,38 @@ export class BatchUploader {
46
55
  if (this.uploadIntervalMillis < BatchUploader.MINIMUM_INTERVAL_MILLIS) {
47
56
  this.uploadIntervalMillis = BatchUploader.MINIMUM_INTERVAL_MILLIS;
48
57
  }
58
+
59
+ // Events will be queued during `queueEvents` method
49
60
  this.eventsQueuedForProcessing = [];
61
+
62
+ // Batch queue should start empty and will be populated during
63
+ // `prepareAndUpload` method, either via Local Storage or after
64
+ // new batches are created.
50
65
  this.batchesQueuedForProcessing = [];
51
66
 
67
+ // Cache Offline Storage Availability boolean
68
+ // so that we don't have to check it every time
69
+ this.offlineStorageEnabled = this.isOfflineStorageAvailable();
70
+
71
+ if (this.offlineStorageEnabled) {
72
+ this.eventVault = new SessionStorageVault<SDKEvent[]>(
73
+ `${mpInstance._Store.storageName}-events`,
74
+ {
75
+ logger: mpInstance.Logger,
76
+ }
77
+ );
78
+
79
+ this.batchVault = new LocalStorageVault<Batch[]>(
80
+ `${mpInstance._Store.storageName}-batches`,
81
+ {
82
+ logger: mpInstance.Logger,
83
+ }
84
+ );
85
+
86
+ // Load Events from Session Storage in case we have any in storage
87
+ this.eventsQueuedForProcessing.push(...this.eventVault.retrieve());
88
+ }
89
+
52
90
  const { SDKConfig, devToken } = this.mpInstance._Store;
53
91
  const baseUrl = this.mpInstance._Helpers.createServiceUrl(
54
92
  SDKConfig.v3SecureServiceUrl,
@@ -64,6 +102,29 @@ export class BatchUploader {
64
102
  this.addEventListeners();
65
103
  }
66
104
 
105
+ private isOfflineStorageAvailable(): boolean {
106
+ const {
107
+ _Helpers: { getFeatureFlag },
108
+ _Store: { deviceId },
109
+ } = this.mpInstance;
110
+
111
+ const offlineStorageFeatureFlagValue = getFeatureFlag(
112
+ Constants.FeatureFlags.OfflineStorage
113
+ );
114
+
115
+ const offlineStoragePercentage = parseInt(
116
+ offlineStorageFeatureFlagValue,
117
+ 10
118
+ );
119
+
120
+ const rampNumber = getRampNumber(deviceId);
121
+
122
+ // TODO: Handle cases where Local Storage is unavailable
123
+ // Potentially shared between Vault and Persistence as well
124
+ // https://go.mparticle.com/work/SQDSDKS-5022
125
+ return offlineStoragePercentage >= rampNumber;
126
+ }
127
+
67
128
  // Adds listeners to be used trigger Navigator.sendBeacon if the browser
68
129
  // loses focus for any reason, such as closing browser tab or minimizing window
69
130
  private addEventListeners() {
@@ -102,9 +163,12 @@ export class BatchUploader {
102
163
  * This method will queue a single Event which will eventually be processed into a Batch
103
164
  * @param event event that should be queued
104
165
  */
105
- queueEvent(event: SDKEvent): void {
166
+ public queueEvent(event: SDKEvent): void {
106
167
  if (!isEmpty(event)) {
107
168
  this.eventsQueuedForProcessing.push(event);
169
+ if (this.offlineStorageEnabled && this.eventVault) {
170
+ this.eventVault.store(this.eventsQueuedForProcessing);
171
+ }
108
172
  this.mpInstance.Logger.verbose(
109
173
  `Queuing event: ${JSON.stringify(event)}`
110
174
  );
@@ -214,14 +278,32 @@ export class BatchUploader {
214
278
  // Fetch current user so that events can be grouped by MPID
215
279
  const currentUser = this.mpInstance.Identity.getCurrentUser();
216
280
 
217
- const currentEvents = this.eventsQueuedForProcessing;
281
+ const currentEvents: SDKEvent[] = this.eventsQueuedForProcessing;
282
+
218
283
  this.eventsQueuedForProcessing = [];
284
+ if (this.offlineStorageEnabled && this.eventVault) {
285
+ this.eventVault.store([]);
286
+ }
219
287
 
220
- const newBatches = BatchUploader.createNewBatches(
221
- currentEvents,
222
- currentUser,
223
- this.mpInstance
224
- );
288
+ let newBatches: Batch[] = [];
289
+ if (!isEmpty(currentEvents)) {
290
+ newBatches = BatchUploader.createNewBatches(
291
+ currentEvents,
292
+ currentUser,
293
+ this.mpInstance
294
+ );
295
+ }
296
+
297
+ // Top Load any older Batches from Offline Storage so they go out first
298
+ if (this.offlineStorageEnabled && this.batchVault) {
299
+ this.batchesQueuedForProcessing.unshift(
300
+ ...this.batchVault.retrieve()
301
+ );
302
+
303
+ // Remove batches from local storage before transmit to
304
+ // prevent duplication
305
+ this.batchVault.purge();
306
+ }
225
307
 
226
308
  if (!isEmpty(newBatches)) {
227
309
  this.batchesQueuedForProcessing.push(...newBatches);
@@ -231,6 +313,13 @@ export class BatchUploader {
231
313
  const batchesToUpload = this.batchesQueuedForProcessing;
232
314
  this.batchesQueuedForProcessing = [];
233
315
 
316
+ // If `useBeacon` is true, the browser has been closed suddently
317
+ // so we should save `batchesToUpload` to Offline Storage before
318
+ // an upload is attempted.
319
+ if (useBeacon && this.offlineStorageEnabled && this.batchVault) {
320
+ this.batchVault.store(batchesToUpload);
321
+ }
322
+
234
323
  const batchesThatDidNotUpload = await this.uploadBatches(
235
324
  this.mpInstance.Logger,
236
325
  batchesToUpload,
@@ -245,6 +334,19 @@ export class BatchUploader {
245
334
  this.batchesQueuedForProcessing.unshift(...batchesThatDidNotUpload);
246
335
  }
247
336
 
337
+ // Update Offline Storage with current state of batch queue
338
+ if (!useBeacon && this.offlineStorageEnabled && this.batchVault) {
339
+ // Note: since beacon is "Fire and forget" it will empty `batchesThatDidNotUplod`
340
+ // regardless of whether the batches were successfully uploaded or not. We should
341
+ // therefore NOT overwrite Offline Storage when beacon returns, so that we can retry
342
+ // uploading saved batches at a later time. Batches should only be removed from
343
+ // Local Storage once we can confirm they are successfully uploaded.
344
+ this.batchVault.store(this.batchesQueuedForProcessing);
345
+
346
+ // Clear batch queue since everything should be in Offline Storage
347
+ this.batchesQueuedForProcessing = [];
348
+ }
349
+
248
350
  if (triggerFuture) {
249
351
  this.triggerUploadInterval(triggerFuture, false);
250
352
  }
package/src/constants.ts CHANGED
@@ -161,6 +161,7 @@ const Constants = {
161
161
  ReportBatching: 'reportBatching',
162
162
  EventsV3: 'eventsV3',
163
163
  EventBatchingIntervalMillis: 'eventBatchingIntervalMillis',
164
+ OfflineStorage: 'offlineStorage',
164
165
  },
165
166
  DefaultInstance: 'default_instance',
166
167
  } as const;
package/src/identity.js CHANGED
@@ -1563,29 +1563,15 @@ export default function Identity(mpInstance) {
1563
1563
  mpInstance._Store.currentSessionMPIDs
1564
1564
  );
1565
1565
 
1566
- //if there is any previous migration data
1567
- if (Object.keys(mpInstance._Store.migrationData).length) {
1568
- newIdentitiesByType =
1569
- mpInstance._Store.migrationData.userIdentities ||
1570
- {};
1571
- var userAttributes =
1572
- mpInstance._Store.migrationData.userAttributes ||
1573
- {};
1574
- mpInstance._Persistence.saveUserAttributesToPersistence(
1575
- identityApiResult.mpid,
1576
- userAttributes
1566
+ if (
1567
+ identityApiData &&
1568
+ identityApiData.userIdentities &&
1569
+ Object.keys(identityApiData.userIdentities).length
1570
+ ) {
1571
+ newIdentitiesByType = self.IdentityRequest.combineUserIdentities(
1572
+ incomingMpidUIByName,
1573
+ identityApiData.userIdentities
1577
1574
  );
1578
- } else {
1579
- if (
1580
- identityApiData &&
1581
- identityApiData.userIdentities &&
1582
- Object.keys(identityApiData.userIdentities).length
1583
- ) {
1584
- newIdentitiesByType = self.IdentityRequest.combineUserIdentities(
1585
- incomingMpidUIByName,
1586
- identityApiData.userIdentities
1587
- );
1588
- }
1589
1575
  }
1590
1576
 
1591
1577
  mpInstance._Persistence.saveUserIdentitiesToPersistence(
@@ -4,8 +4,9 @@ import ServerModel from './serverModel';
4
4
  import { SDKEvent, BaseEvent, MParticleWebSDK } from './sdkRuntimeModels';
5
5
  import { convertEvents } from './sdkToEventsApiConverter';
6
6
  import * as EventsApi from '@mparticle/event-models';
7
+ import { Batch } from '@mparticle/event-models';
7
8
 
8
- const mockFunction = function () {
9
+ const mockFunction = function() {
9
10
  return null;
10
11
  };
11
12
  export default class _BatchValidator {
@@ -13,12 +14,12 @@ export default class _BatchValidator {
13
14
  return {
14
15
  // Certain Helper, Store, and Identity properties need to be mocked to be used in the `returnBatch` method
15
16
  _Helpers: {
16
- sanitizeAttributes:
17
- window.mParticle.getInstance()._Helpers.sanitizeAttributes,
18
- generateHash: function () {
17
+ sanitizeAttributes: window.mParticle.getInstance()._Helpers
18
+ .sanitizeAttributes,
19
+ generateHash: function() {
19
20
  return 'mockHash';
20
21
  },
21
- generateUniqueId: function () {
22
+ generateUniqueId: function() {
22
23
  return 'mockId';
23
24
  },
24
25
  extend: window.mParticle.getInstance()._Helpers.extend,
@@ -49,7 +50,6 @@ export default class _BatchValidator {
49
50
  consentState: null,
50
51
  clientId: null,
51
52
  deviceId: null,
52
- migrationData: {},
53
53
  serverSettings: {},
54
54
  dateLastEventSent: null,
55
55
  sessionStartDate: null,
@@ -63,7 +63,6 @@ export default class _BatchValidator {
63
63
  context: null,
64
64
  configurationLoaded: false,
65
65
  identityCallInFlight: false,
66
- migratingToIDSyncCookies: false,
67
66
  nonCurrentUserMPIDs: {},
68
67
  identifyCalled: false,
69
68
  isLoggedIn: false,
@@ -119,16 +118,19 @@ export default class _BatchValidator {
119
118
  } as MParticleWebSDK;
120
119
  }
121
120
 
122
- returnBatch(event: BaseEvent) {
121
+ private createSDKEventFunction(event): SDKEvent {
122
+ return new ServerModel(this.getMPInstance()).createEventObject(event);
123
+ }
124
+
125
+ public returnBatch(events: BaseEvent | BaseEvent[]): Batch | null {
123
126
  const mpInstance = this.getMPInstance();
124
- const sdkEvent: SDKEvent = new ServerModel(
125
- mpInstance
126
- ).createEventObject(event);
127
- const batch: EventsApi.Batch | null = convertEvents(
128
- '0',
129
- [sdkEvent],
130
- mpInstance as any
131
- );
127
+
128
+ const sdkEvents: SDKEvent[] = Array.isArray(events)
129
+ ? events.map(event => this.createSDKEventFunction(event))
130
+ : [this.createSDKEventFunction(events)];
131
+
132
+ const batch: Batch = convertEvents('0', sdkEvents, mpInstance as any);
133
+
132
134
  return batch;
133
135
  }
134
136
  }
@@ -28,7 +28,6 @@ import Store from './store';
28
28
  import Logger from './logger';
29
29
  import Persistence from './persistence';
30
30
  import Events from './events';
31
- import Migrations from './migrations';
32
31
  import Forwarders from './forwarders';
33
32
  import ServerModel from './serverModel';
34
33
  import ForwardingStatsUploader from './forwardingStatsUploader';
@@ -59,7 +58,6 @@ export default function mParticleInstance(instanceName) {
59
58
  // These classes are for internal use only. Not documented for public consumption
60
59
  this._instanceName = instanceName;
61
60
  this._NativeSdkHelpers = new NativeSdkHelpers(this);
62
- this._Migrations = new Migrations(this);
63
61
  this._SessionManager = new SessionManager(this);
64
62
  this._Persistence = new Persistence(this);
65
63
  this._Helpers = new Helpers(this);
@@ -1345,9 +1343,6 @@ function completeSDKInitialization(apiKey, config, mpInstance) {
1345
1343
  mpInstance._Store.configurationLoaded = true;
1346
1344
 
1347
1345
  if (!mpInstance._Store.webviewBridgeEnabled) {
1348
- // Migrate any cookies from previous versions to current cookie version
1349
- mpInstance._Migrations.migrate();
1350
-
1351
1346
  // Load any settings/identities/attributes from cookie or localStorage
1352
1347
  mpInstance._Persistence.initializeStorage();
1353
1348
  }
@@ -1398,15 +1393,6 @@ function completeSDKInitialization(apiKey, config, mpInstance) {
1398
1393
  };
1399
1394
  }
1400
1395
 
1401
- // If migrating from pre-IDSync to IDSync, a sessionID will exist and an identify request will not have been fired, so we need this check
1402
- if (mpInstance._Store.migratingToIDSyncCookies) {
1403
- mpInstance.Identity.identify(
1404
- mpInstance._Store.SDKConfig.identifyRequest,
1405
- mpInstance._Store.SDKConfig.identityCallback
1406
- );
1407
- mpInstance._Store.migratingToIDSyncCookies = false;
1408
- }
1409
-
1410
1396
  currentUser = mpInstance.Identity.getCurrentUser();
1411
1397
 
1412
1398
  if (
@@ -1556,7 +1542,9 @@ function runPreConfigFetchInitialization(mpInstance, apiKey, config) {
1556
1542
  Messages.InformationMessages.StartingInitialization
1557
1543
  );
1558
1544
 
1559
- //check to see if localStorage is available for migrating purposes
1545
+ // Check to see if localStorage is available before main configuration runs
1546
+ // since we will need this for the current implementation of user persistence
1547
+ // TODO: Refactor this when we refactor User Identity Persistence
1560
1548
  try {
1561
1549
  mpInstance._Store.isLocalStorageAvailable = mpInstance._Persistence.determineLocalStorageAvailability(
1562
1550
  window.localStorage
@@ -98,16 +98,10 @@ export interface IPersistence {
98
98
  expires: string,
99
99
  domain: string,
100
100
  maxCookieSize: number
101
- ): void;
101
+ ): string;
102
102
  findPrevCookiesBasedOnUI(identityApiData: IdentityApiData): void;
103
- encodePersistence(persistance: IPersistenceMinified): string;
104
- decodePersistence(persistance: IPersistenceMinified): string;
105
- replaceCommasWithPipes(string: string): string;
106
- replacePipesWithCommas(string: string): string;
107
- replaceApostrophesWithQuotes(string: string): string;
108
- replaceQuotesWithApostrophes(string: string): string;
109
- createCookieString(string: string): string;
110
- revertCookieString(string: string): string;
103
+ encodePersistence(persistence: IPersistenceMinified): string;
104
+ decodePersistence(persistenceString: string): string;
111
105
  getCookieDomain(): string;
112
106
  getDomain(doc: string, locationHostname: string): string;
113
107
  getUserIdentities(mpid: MPID): UserIdentities;
@@ -1,5 +1,6 @@
1
1
  import Constants from './constants';
2
2
  import Polyfill from './polyfill';
3
+ import * as Utils from './utils';
3
4
 
4
5
  var Base64 = Polyfill.Base64,
5
6
  Messages = Constants.Messages,
@@ -760,13 +761,15 @@ export default function _Persistence(mpInstance) {
760
761
  }
761
762
  }
762
763
 
763
- return self.createCookieString(JSON.stringify(persistence));
764
+ return Utils.createCookieString(JSON.stringify(persistence));
764
765
  };
765
766
 
767
+ // TODO: This should actually be decodePersistenceString or
768
+ // we should refactor this to take a string and return an object
766
769
  this.decodePersistence = function(persistence) {
767
770
  try {
768
771
  if (persistence) {
769
- persistence = JSON.parse(self.revertCookieString(persistence));
772
+ persistence = JSON.parse(Utils.revertCookieString(persistence));
770
773
  if (
771
774
  mpInstance._Helpers.isObject(persistence) &&
772
775
  Object.keys(persistence).length
@@ -817,34 +820,6 @@ export default function _Persistence(mpInstance) {
817
820
  }
818
821
  };
819
822
 
820
- this.replaceCommasWithPipes = function(string) {
821
- return string.replace(/,/g, '|');
822
- };
823
-
824
- this.replacePipesWithCommas = function(string) {
825
- return string.replace(/\|/g, ',');
826
- };
827
-
828
- this.replaceApostrophesWithQuotes = function(string) {
829
- return string.replace(/\'/g, '"');
830
- };
831
-
832
- this.replaceQuotesWithApostrophes = function(string) {
833
- return string.replace(/\"/g, "'");
834
- };
835
-
836
- this.createCookieString = function(string) {
837
- return self.replaceCommasWithPipes(
838
- self.replaceQuotesWithApostrophes(string)
839
- );
840
- };
841
-
842
- this.revertCookieString = function(string) {
843
- return self.replacePipesWithCommas(
844
- self.replaceApostrophesWithQuotes(string)
845
- );
846
- };
847
-
848
823
  this.getCookieDomain = function() {
849
824
  if (mpInstance._Store.SDKConfig.cookieDomain) {
850
825
  return mpInstance._Store.SDKConfig.cookieDomain;
@@ -142,7 +142,11 @@ export interface MParticleWebSDK {
142
142
  _NativeSdkHelpers: any; // TODO: Set up API
143
143
  _Persistence: IPersistence;
144
144
  _preInit: any; // TODO: Set up API
145
- _resetForTests(MPConfig?: SDKInitConfig): void;
145
+ _resetForTests(
146
+ MPConfig?: SDKInitConfig,
147
+ keepPersistence?: boolean,
148
+ instance?: MParticleWebSDK
149
+ ): void;
146
150
  init(apiKey: string, config: SDKInitConfig, instanceName?: string): void;
147
151
  getAppName(): string;
148
152
  getAppVersion(): string;
package/src/store.ts CHANGED
@@ -97,9 +97,9 @@ function createSDKConfig(config: SDKInitConfig): SDKConfig {
97
97
  return sdkConfig;
98
98
  }
99
99
 
100
- // TODO: Placeholder Types, MigrationData is temporary and will be removed in the future to reduce SDK size
100
+ // TODO: Placeholder Types to be filled in as we migrate more modules
101
+ // to TypeScript
101
102
  export type PixelConfiguration = Dictionary;
102
- export type MigrationData = Dictionary;
103
103
  export type ServerSettings = Dictionary;
104
104
  export type SessionAttributes = Dictionary;
105
105
  export type IntegrationAttributes = Dictionary<Dictionary<string>>;
@@ -122,7 +122,6 @@ export interface IStore {
122
122
  clientId: string;
123
123
  deviceId: string;
124
124
  devToken: string | null;
125
- migrationData: MigrationData;
126
125
  serverSettings: ServerSettings;
127
126
  dateLastEventSent: Date;
128
127
  sessionStartDate: Date;
@@ -137,7 +136,6 @@ export interface IStore {
137
136
  configurationLoaded: boolean;
138
137
  identityCallInFlight: boolean;
139
138
  SDKConfig: Partial<SDKConfig>;
140
- migratingToIDSyncCookies: boolean; // TODO: Remove when we archive Web SDK v1
141
139
  nonCurrentUserMPIDs: Record<MPID, Dictionary>;
142
140
  identifyCalled: boolean;
143
141
  isLoggedIn: boolean;
@@ -173,7 +171,6 @@ export default function Store(
173
171
  clientId: null,
174
172
  deviceId: null,
175
173
  devToken: null,
176
- migrationData: {},
177
174
  serverSettings: {},
178
175
  dateLastEventSent: null,
179
176
  sessionStartDate: null,
@@ -188,7 +185,6 @@ export default function Store(
188
185
  configurationLoaded: false,
189
186
  identityCallInFlight: false,
190
187
  SDKConfig: {},
191
- migratingToIDSyncCookies: false,
192
188
  nonCurrentUserMPIDs: {},
193
189
  identifyCalled: false,
194
190
  isLoggedIn: false,
@@ -223,10 +219,9 @@ export default function Store(
223
219
  this.deviceId = config.deviceId;
224
220
  }
225
221
  if (config.hasOwnProperty('isDevelopmentMode')) {
226
- this.SDKConfig.isDevelopmentMode =
227
- mpInstance._Helpers.returnConvertedBoolean(
228
- config.isDevelopmentMode
229
- );
222
+ this.SDKConfig.isDevelopmentMode = mpInstance._Helpers.returnConvertedBoolean(
223
+ config.isDevelopmentMode
224
+ );
230
225
  } else {
231
226
  this.SDKConfig.isDevelopmentMode = false;
232
227
  }
@@ -444,5 +439,12 @@ export default function Store(
444
439
  ) {
445
440
  this.SDKConfig.flags[Constants.FeatureFlags.ReportBatching] = false;
446
441
  }
442
+ if (
443
+ !this.SDKConfig.flags.hasOwnProperty(
444
+ Constants.FeatureFlags.OfflineStorage
445
+ )
446
+ ) {
447
+ this.SDKConfig.flags[Constants.FeatureFlags.OfflineStorage] = 0;
448
+ }
447
449
  }
448
450
  }
package/src/utils.ts CHANGED
@@ -5,6 +5,12 @@ type valueof<T> = T[keyof T];
5
5
  // Placeholder for Dictionary-like Types
6
6
  export type Dictionary<V = any> = Record<string, V>;
7
7
 
8
+ const createCookieString = (value: string): string =>
9
+ replaceCommasWithPipes(replaceQuotesWithApostrophes(value));
10
+
11
+ const revertCookieString = (value: string): string =>
12
+ replacePipesWithCommas(replaceApostrophesWithQuotes(value));
13
+
8
14
  const inArray = (items: any[], name: string): boolean => {
9
15
  let i = 0;
10
16
 
@@ -134,6 +140,16 @@ const parseStringOrNumber = (
134
140
  }
135
141
  };
136
142
 
143
+ const replaceCommasWithPipes = (value: string): string => value.replace(/,/g, '|');
144
+
145
+ const replacePipesWithCommas = (value: string): string => value.replace(/\|/g, ',');
146
+
147
+ const replaceApostrophesWithQuotes = (value: string): string =>
148
+ value.replace(/\'/g, '"');
149
+
150
+ const replaceQuotesWithApostrophes = (value: string): string =>
151
+ value.replace(/\"/g, "'");
152
+
137
153
  // FIXME: REFACTOR for V3
138
154
  // only used in store.js to sanitize server-side formatting of
139
155
  // booleans when checking for `isDevelopmentMode`
@@ -172,6 +188,8 @@ const isEmpty = (value: Dictionary<any> | null | undefined): boolean =>
172
188
  value == null || !(Object.keys(value) || value).length;
173
189
 
174
190
  export {
191
+ createCookieString,
192
+ revertCookieString,
175
193
  valueof,
176
194
  converted,
177
195
  decoded,
@@ -184,6 +202,10 @@ export {
184
202
  isStringOrNumber,
185
203
  parseNumber,
186
204
  parseStringOrNumber,
205
+ replaceCommasWithPipes,
206
+ replacePipesWithCommas,
207
+ replaceApostrophesWithQuotes,
208
+ replaceQuotesWithApostrophes,
187
209
  returnConvertedBoolean,
188
210
  isString,
189
211
  isNumber,