@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/dist/mparticle.common.js +55 -46
- package/dist/mparticle.esm.js +55 -46
- package/dist/mparticle.js +230 -298
- package/package.json +21 -10
- package/src/batchUploader.ts +113 -11
- package/src/constants.ts +1 -0
- package/src/identity.js +8 -22
- package/src/mockBatchCreator.ts +18 -16
- package/src/mp-instance.js +3 -15
- package/src/persistence.interfaces.ts +3 -9
- package/src/persistence.js +5 -30
- package/src/sdkRuntimeModels.ts +5 -1
- package/src/store.ts +12 -10
- package/src/utils.ts +22 -0
- package/src/vault.ts +51 -39
- package/src/migrations.js +0 -279
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@mparticle/web-sdk",
|
|
3
|
-
"version": "2.
|
|
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
|
|
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
|
|
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
|
|
43
|
-
"test:integrations:
|
|
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",
|
package/src/batchUploader.ts
CHANGED
|
@@ -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
|
|
14
|
-
*
|
|
15
|
-
* It
|
|
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
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
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
package/src/identity.js
CHANGED
|
@@ -1563,29 +1563,15 @@ export default function Identity(mpInstance) {
|
|
|
1563
1563
|
mpInstance._Store.currentSessionMPIDs
|
|
1564
1564
|
);
|
|
1565
1565
|
|
|
1566
|
-
|
|
1567
|
-
|
|
1568
|
-
|
|
1569
|
-
|
|
1570
|
-
|
|
1571
|
-
|
|
1572
|
-
|
|
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(
|
package/src/mockBatchCreator.ts
CHANGED
|
@@ -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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
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
|
}
|
package/src/mp-instance.js
CHANGED
|
@@ -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
|
-
//
|
|
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
|
-
):
|
|
101
|
+
): string;
|
|
102
102
|
findPrevCookiesBasedOnUI(identityApiData: IdentityApiData): void;
|
|
103
|
-
encodePersistence(
|
|
104
|
-
decodePersistence(
|
|
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;
|
package/src/persistence.js
CHANGED
|
@@ -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
|
|
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(
|
|
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;
|
package/src/sdkRuntimeModels.ts
CHANGED
|
@@ -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(
|
|
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
|
|
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
|
-
|
|
228
|
-
|
|
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,
|