@mparticle/web-sdk 2.24.0 → 2.25.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/mparticle.common.js +45 -22
- package/dist/mparticle.esm.js +45 -22
- package/dist/mparticle.js +196 -38
- package/package.json +1 -1
- package/src/constants.ts +5 -0
- package/src/identity-utils.ts +247 -0
- package/src/identity.js +81 -33
- package/src/identityApiClient.js +5 -2
- package/src/mockBatchCreator.ts +2 -2
- package/src/mp-instance.js +17 -0
- package/src/mparticle-instance-manager.js +1 -1
- package/src/sdkRuntimeModels.ts +5 -1
- package/src/store.ts +3 -0
- package/src/validators.ts +1 -2
|
@@ -0,0 +1,247 @@
|
|
|
1
|
+
import Constants, { ONE_DAY_IN_SECONDS, MILLIS_IN_ONE_SEC } from './constants';
|
|
2
|
+
import { Dictionary, parseNumber, isObject, generateHash } from './utils';
|
|
3
|
+
import { BaseVault } from './vault';
|
|
4
|
+
import Types from './types';
|
|
5
|
+
import { IdentityApiData, UserIdentities, IdentityCallback } from '@mparticle/web-sdk';
|
|
6
|
+
import { IdentityAPIMethod, MParticleWebSDK } from './sdkRuntimeModels';
|
|
7
|
+
|
|
8
|
+
const { Identify, Modify, Login, Logout } = Constants.IdentityMethods;
|
|
9
|
+
|
|
10
|
+
export type IParseCachedIdentityResponse = (
|
|
11
|
+
cachedIdentity: ICachedIdentityCall,
|
|
12
|
+
mpid: string,
|
|
13
|
+
callback: IdentityCallback,
|
|
14
|
+
identityApiData: IdentityApiData,
|
|
15
|
+
identityMethod: string,
|
|
16
|
+
knownIdentities: IKnownIdentities,
|
|
17
|
+
fromCachedIdentity: boolean
|
|
18
|
+
) => void
|
|
19
|
+
|
|
20
|
+
export interface IKnownIdentities extends UserIdentities {
|
|
21
|
+
device_application_stamp?: string;
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
export interface ICachedIdentityCall {
|
|
25
|
+
responseText: string;
|
|
26
|
+
status: number;
|
|
27
|
+
expireTimestamp: number;
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
export const cacheOrClearIdCache = (
|
|
31
|
+
method: string,
|
|
32
|
+
knownIdentities: IKnownIdentities,
|
|
33
|
+
idCache: BaseVault<Dictionary<ICachedIdentityCall>>,
|
|
34
|
+
xhr: XMLHttpRequest,
|
|
35
|
+
parsingCachedResponse: boolean,
|
|
36
|
+
): void => {
|
|
37
|
+
// when parsing a response that has already been cached, simply return instead of attempting another cache
|
|
38
|
+
if (parsingCachedResponse) { return; }
|
|
39
|
+
|
|
40
|
+
const CACHE_HEADER = 'x-mp-max-age';
|
|
41
|
+
|
|
42
|
+
// default the expire timestamp to one day in milliseconds unless a header comes back
|
|
43
|
+
let now = new Date().getTime();
|
|
44
|
+
let expireTimestamp = now + ONE_DAY_IN_SECONDS * MILLIS_IN_ONE_SEC;
|
|
45
|
+
if (xhr.getAllResponseHeaders().includes(CACHE_HEADER)) {
|
|
46
|
+
expireTimestamp =
|
|
47
|
+
now + (parseNumber(xhr.getResponseHeader(CACHE_HEADER)) * MILLIS_IN_ONE_SEC);
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
switch (method) {
|
|
51
|
+
case Login:
|
|
52
|
+
case Identify:
|
|
53
|
+
cacheIdentityRequest(
|
|
54
|
+
method,
|
|
55
|
+
knownIdentities,
|
|
56
|
+
expireTimestamp,
|
|
57
|
+
idCache,
|
|
58
|
+
xhr
|
|
59
|
+
);
|
|
60
|
+
break;
|
|
61
|
+
case Modify:
|
|
62
|
+
case Logout:
|
|
63
|
+
idCache.purge();
|
|
64
|
+
break;
|
|
65
|
+
}
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
export const cacheIdentityRequest = (
|
|
69
|
+
method: IdentityAPIMethod,
|
|
70
|
+
identities: IKnownIdentities,
|
|
71
|
+
expireTimestamp: number,
|
|
72
|
+
idCache: BaseVault<Dictionary<ICachedIdentityCall>>,
|
|
73
|
+
xhr: XMLHttpRequest
|
|
74
|
+
): void => {
|
|
75
|
+
const cache: Dictionary<ICachedIdentityCall> = idCache.retrieve() || ({} as Dictionary<ICachedIdentityCall>);
|
|
76
|
+
const cacheKey = concatenateIdentities(method, identities);
|
|
77
|
+
const hashedKey = generateHash(cacheKey);
|
|
78
|
+
|
|
79
|
+
cache[hashedKey] = { responseText: xhr.responseText, status: xhr.status, expireTimestamp};
|
|
80
|
+
idCache.store(cache);
|
|
81
|
+
};
|
|
82
|
+
|
|
83
|
+
// We need to ensure that identities are concatenated in a deterministic way, so
|
|
84
|
+
// we sort the identities based on their enum.
|
|
85
|
+
// we create an array, set the user identity at the index of the user identity type
|
|
86
|
+
export const concatenateIdentities = (
|
|
87
|
+
method: IdentityAPIMethod,
|
|
88
|
+
userIdentities: IKnownIdentities
|
|
89
|
+
): string => {
|
|
90
|
+
const DEVICE_APPLICATION_STAMP = 'device_application_stamp';
|
|
91
|
+
// set DAS first since it is not an official identity type
|
|
92
|
+
let cacheKey: string = `${method}:${DEVICE_APPLICATION_STAMP}=${userIdentities.device_application_stamp};`;
|
|
93
|
+
const idLength: number = Object.keys(userIdentities).length;
|
|
94
|
+
let concatenatedIdentities: string = '';
|
|
95
|
+
|
|
96
|
+
if (idLength) {
|
|
97
|
+
let userIDArray: Array<string> = new Array();
|
|
98
|
+
// create an array where each index is equal to the user identity type
|
|
99
|
+
for (let key in userIdentities) {
|
|
100
|
+
if (key === DEVICE_APPLICATION_STAMP) {
|
|
101
|
+
continue;
|
|
102
|
+
} else {
|
|
103
|
+
userIDArray[Types.IdentityType.getIdentityType(key)] =
|
|
104
|
+
userIdentities[key];
|
|
105
|
+
}
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
concatenatedIdentities = userIDArray.reduce(
|
|
109
|
+
(prevValue: string, currentValue: string, index: number) => {
|
|
110
|
+
const idName: string = Types.IdentityType.getIdentityName(index);
|
|
111
|
+
return `${prevValue}${idName}=${currentValue};`;
|
|
112
|
+
},
|
|
113
|
+
cacheKey
|
|
114
|
+
);
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
return concatenatedIdentities;
|
|
118
|
+
};
|
|
119
|
+
|
|
120
|
+
export const hasValidCachedIdentity = (
|
|
121
|
+
method: IdentityAPIMethod,
|
|
122
|
+
proposedUserIdentities: IKnownIdentities,
|
|
123
|
+
idCache?: BaseVault<Dictionary<ICachedIdentityCall>>
|
|
124
|
+
): boolean => {
|
|
125
|
+
// There is an edge case where multiple identity calls are taking place
|
|
126
|
+
// before identify fires, so there may not be a cache. See what happens when
|
|
127
|
+
// the ? in idCache is removed to the following test
|
|
128
|
+
// "queued events contain login mpid instead of identify mpid when calling
|
|
129
|
+
// login immediately after mParticle initializes"
|
|
130
|
+
const cache = idCache?.retrieve();
|
|
131
|
+
|
|
132
|
+
// if there is no cache, then there is no valid cached identity
|
|
133
|
+
if (!cache) {
|
|
134
|
+
return false;
|
|
135
|
+
}
|
|
136
|
+
|
|
137
|
+
const cacheKey: string = concatenateIdentities(
|
|
138
|
+
method,
|
|
139
|
+
proposedUserIdentities
|
|
140
|
+
);
|
|
141
|
+
const hashedKey = generateHash(cacheKey);
|
|
142
|
+
|
|
143
|
+
// if cache doesn't have the cacheKey, there is no valid cached identity
|
|
144
|
+
if (!cache.hasOwnProperty(hashedKey)) {
|
|
145
|
+
return false;
|
|
146
|
+
}
|
|
147
|
+
|
|
148
|
+
// If there is a valid cache key, compare the expireTimestamp to the current time.
|
|
149
|
+
// If the current time is greater than the expireTimestamp, it is not a valid
|
|
150
|
+
// cached identity.
|
|
151
|
+
const expireTimestamp = cache[hashedKey].expireTimestamp;
|
|
152
|
+
|
|
153
|
+
if (expireTimestamp < new Date().getTime()) {
|
|
154
|
+
return false;
|
|
155
|
+
} else {
|
|
156
|
+
return true;
|
|
157
|
+
}
|
|
158
|
+
};
|
|
159
|
+
|
|
160
|
+
export const getCachedIdentity = (
|
|
161
|
+
method: IdentityAPIMethod,
|
|
162
|
+
proposedUserIdentities: IKnownIdentities,
|
|
163
|
+
idCache: BaseVault<Dictionary<ICachedIdentityCall>>
|
|
164
|
+
): ICachedIdentityCall | null => {
|
|
165
|
+
const cacheKey: string = concatenateIdentities(
|
|
166
|
+
method,
|
|
167
|
+
proposedUserIdentities
|
|
168
|
+
);
|
|
169
|
+
const hashedKey = generateHash(cacheKey);
|
|
170
|
+
|
|
171
|
+
const cache = idCache.retrieve();
|
|
172
|
+
const cachedIdentity = cache ? cache[hashedKey] : null;
|
|
173
|
+
|
|
174
|
+
return cachedIdentity;
|
|
175
|
+
};
|
|
176
|
+
|
|
177
|
+
// https://go.mparticle.com/work/SQDSDKS-6079
|
|
178
|
+
export const createKnownIdentities = (
|
|
179
|
+
identityApiData: IdentityApiData,
|
|
180
|
+
deviceId: string
|
|
181
|
+
): IKnownIdentities => {
|
|
182
|
+
const identitiesResult: IKnownIdentities = {};
|
|
183
|
+
|
|
184
|
+
if (isObject(identityApiData?.userIdentities)) {
|
|
185
|
+
for (let identity in identityApiData.userIdentities) {
|
|
186
|
+
identitiesResult[identity] =
|
|
187
|
+
identityApiData.userIdentities[identity];
|
|
188
|
+
}
|
|
189
|
+
}
|
|
190
|
+
identitiesResult.device_application_stamp = deviceId;
|
|
191
|
+
|
|
192
|
+
return identitiesResult;
|
|
193
|
+
};
|
|
194
|
+
|
|
195
|
+
export const removeExpiredIdentityCacheDates = (idCache: BaseVault<Dictionary<ICachedIdentityCall>>) => {
|
|
196
|
+
const cache: Dictionary<ICachedIdentityCall> = idCache.retrieve() || {} as Dictionary<ICachedIdentityCall>;
|
|
197
|
+
|
|
198
|
+
const currentTime: number = new Date().getTime();
|
|
199
|
+
|
|
200
|
+
// Iterate over the cache and remove any key/value pairs that are expired
|
|
201
|
+
for (let key in cache) {
|
|
202
|
+
if (cache[key].expireTimestamp < currentTime) {
|
|
203
|
+
delete cache[key];
|
|
204
|
+
}
|
|
205
|
+
};
|
|
206
|
+
|
|
207
|
+
idCache.store(cache);
|
|
208
|
+
}
|
|
209
|
+
|
|
210
|
+
export const tryCacheIdentity = (
|
|
211
|
+
knownIdentities: IKnownIdentities,
|
|
212
|
+
idCache: BaseVault<Dictionary<ICachedIdentityCall>>,
|
|
213
|
+
parseIdentityResponse: IParseCachedIdentityResponse,
|
|
214
|
+
mpid: string,
|
|
215
|
+
callback: IdentityCallback,
|
|
216
|
+
identityApiData: IdentityApiData,
|
|
217
|
+
identityMethod: IdentityAPIMethod
|
|
218
|
+
): boolean => {
|
|
219
|
+
// https://go.mparticle.com/work/SQDSDKS-6095
|
|
220
|
+
const shouldReturnCachedIdentity = hasValidCachedIdentity(
|
|
221
|
+
identityMethod,
|
|
222
|
+
knownIdentities,
|
|
223
|
+
idCache
|
|
224
|
+
);
|
|
225
|
+
|
|
226
|
+
// If Identity is cached, then immediately parse the identity response
|
|
227
|
+
if (shouldReturnCachedIdentity) {
|
|
228
|
+
const cachedIdentity = getCachedIdentity(
|
|
229
|
+
identityMethod,
|
|
230
|
+
knownIdentities,
|
|
231
|
+
idCache
|
|
232
|
+
);
|
|
233
|
+
|
|
234
|
+
parseIdentityResponse(
|
|
235
|
+
cachedIdentity,
|
|
236
|
+
mpid,
|
|
237
|
+
callback,
|
|
238
|
+
identityApiData,
|
|
239
|
+
identityMethod,
|
|
240
|
+
knownIdentities,
|
|
241
|
+
true
|
|
242
|
+
);
|
|
243
|
+
|
|
244
|
+
return true;
|
|
245
|
+
}
|
|
246
|
+
return false;
|
|
247
|
+
}
|
package/src/identity.js
CHANGED
|
@@ -1,13 +1,20 @@
|
|
|
1
1
|
import Constants from './constants';
|
|
2
2
|
import Types from './types';
|
|
3
|
+
import {
|
|
4
|
+
cacheOrClearIdCache,
|
|
5
|
+
createKnownIdentities,
|
|
6
|
+
tryCacheIdentity,
|
|
7
|
+
} from './identity-utils';
|
|
3
8
|
|
|
4
9
|
var Messages = Constants.Messages,
|
|
5
10
|
HTTPCodes = Constants.HTTPCodes;
|
|
6
11
|
|
|
7
|
-
const { Identify, Modify } = Constants.IdentityMethods;
|
|
12
|
+
const { Identify, Modify, Login, Logout } = Constants.IdentityMethods;
|
|
8
13
|
|
|
9
14
|
export default function Identity(mpInstance) {
|
|
10
15
|
var self = this;
|
|
16
|
+
this.idCache = null;
|
|
17
|
+
|
|
11
18
|
this.checkIdentitySwap = function(
|
|
12
19
|
previousMPID,
|
|
13
20
|
currentMPID,
|
|
@@ -24,24 +31,6 @@ export default function Identity(mpInstance) {
|
|
|
24
31
|
};
|
|
25
32
|
|
|
26
33
|
this.IdentityRequest = {
|
|
27
|
-
createKnownIdentities: function(identityApiData, deviceId) {
|
|
28
|
-
var identitiesResult = {};
|
|
29
|
-
|
|
30
|
-
if (
|
|
31
|
-
identityApiData &&
|
|
32
|
-
identityApiData.userIdentities &&
|
|
33
|
-
mpInstance._Helpers.isObject(identityApiData.userIdentities)
|
|
34
|
-
) {
|
|
35
|
-
for (var identity in identityApiData.userIdentities) {
|
|
36
|
-
identitiesResult[identity] =
|
|
37
|
-
identityApiData.userIdentities[identity];
|
|
38
|
-
}
|
|
39
|
-
}
|
|
40
|
-
identitiesResult.device_application_stamp = deviceId;
|
|
41
|
-
|
|
42
|
-
return identitiesResult;
|
|
43
|
-
},
|
|
44
|
-
|
|
45
34
|
preProcessIdentityRequest: function(identityApiData, callback, method) {
|
|
46
35
|
mpInstance.Logger.verbose(
|
|
47
36
|
Messages.InformationMessages.StartingLogEvent + ': ' + method
|
|
@@ -103,7 +92,7 @@ export default function Identity(mpInstance) {
|
|
|
103
92
|
request_id: mpInstance._Helpers.generateUniqueId(),
|
|
104
93
|
request_timestamp_ms: new Date().getTime(),
|
|
105
94
|
previous_mpid: mpid || null,
|
|
106
|
-
known_identities:
|
|
95
|
+
known_identities: createKnownIdentities(
|
|
107
96
|
identityApiData,
|
|
108
97
|
deviceId
|
|
109
98
|
),
|
|
@@ -246,7 +235,7 @@ export default function Identity(mpInstance) {
|
|
|
246
235
|
preProcessResult = mpInstance._Identity.IdentityRequest.preProcessIdentityRequest(
|
|
247
236
|
identityApiData,
|
|
248
237
|
callback,
|
|
249
|
-
|
|
238
|
+
Identify
|
|
250
239
|
);
|
|
251
240
|
if (currentUser) {
|
|
252
241
|
mpid = currentUser.getMPID();
|
|
@@ -262,6 +251,25 @@ export default function Identity(mpInstance) {
|
|
|
262
251
|
mpInstance._Store.context,
|
|
263
252
|
mpid
|
|
264
253
|
);
|
|
254
|
+
if (
|
|
255
|
+
mpInstance._Helpers.getFeatureFlag(
|
|
256
|
+
Constants.FeatureFlags.CacheIdentity
|
|
257
|
+
)
|
|
258
|
+
) {
|
|
259
|
+
const successfullyCachedIdentity = tryCacheIdentity(
|
|
260
|
+
identityApiRequest.known_identities,
|
|
261
|
+
self.idCache,
|
|
262
|
+
self.parseIdentityResponse,
|
|
263
|
+
mpid,
|
|
264
|
+
callback,
|
|
265
|
+
identityApiData,
|
|
266
|
+
Identify
|
|
267
|
+
);
|
|
268
|
+
|
|
269
|
+
if (successfullyCachedIdentity) {
|
|
270
|
+
return;
|
|
271
|
+
}
|
|
272
|
+
}
|
|
265
273
|
|
|
266
274
|
if (mpInstance._Helpers.canLog()) {
|
|
267
275
|
if (mpInstance._Store.webviewBridgeEnabled) {
|
|
@@ -281,11 +289,12 @@ export default function Identity(mpInstance) {
|
|
|
281
289
|
} else {
|
|
282
290
|
mpInstance._IdentityAPIClient.sendIdentityRequest(
|
|
283
291
|
identityApiRequest,
|
|
284
|
-
|
|
292
|
+
Identify,
|
|
285
293
|
callback,
|
|
286
294
|
identityApiData,
|
|
287
295
|
self.parseIdentityResponse,
|
|
288
|
-
mpid
|
|
296
|
+
mpid,
|
|
297
|
+
identityApiRequest.known_identities
|
|
289
298
|
);
|
|
290
299
|
}
|
|
291
300
|
} else {
|
|
@@ -319,7 +328,7 @@ export default function Identity(mpInstance) {
|
|
|
319
328
|
preProcessResult = mpInstance._Identity.IdentityRequest.preProcessIdentityRequest(
|
|
320
329
|
identityApiData,
|
|
321
330
|
callback,
|
|
322
|
-
|
|
331
|
+
Logout
|
|
323
332
|
);
|
|
324
333
|
if (currentUser) {
|
|
325
334
|
mpid = currentUser.getMPID();
|
|
@@ -355,7 +364,7 @@ export default function Identity(mpInstance) {
|
|
|
355
364
|
} else {
|
|
356
365
|
mpInstance._IdentityAPIClient.sendIdentityRequest(
|
|
357
366
|
identityApiRequest,
|
|
358
|
-
|
|
367
|
+
Logout,
|
|
359
368
|
callback,
|
|
360
369
|
identityApiData,
|
|
361
370
|
self.parseIdentityResponse,
|
|
@@ -408,8 +417,9 @@ export default function Identity(mpInstance) {
|
|
|
408
417
|
preProcessResult = mpInstance._Identity.IdentityRequest.preProcessIdentityRequest(
|
|
409
418
|
identityApiData,
|
|
410
419
|
callback,
|
|
411
|
-
|
|
420
|
+
Login
|
|
412
421
|
);
|
|
422
|
+
|
|
413
423
|
if (currentUser) {
|
|
414
424
|
mpid = currentUser.getMPID();
|
|
415
425
|
}
|
|
@@ -425,6 +435,26 @@ export default function Identity(mpInstance) {
|
|
|
425
435
|
mpid
|
|
426
436
|
);
|
|
427
437
|
|
|
438
|
+
if (
|
|
439
|
+
mpInstance._Helpers.getFeatureFlag(
|
|
440
|
+
Constants.FeatureFlags.CacheIdentity
|
|
441
|
+
)
|
|
442
|
+
) {
|
|
443
|
+
const successfullyCachedIdentity = tryCacheIdentity(
|
|
444
|
+
identityApiRequest.known_identities,
|
|
445
|
+
self.idCache,
|
|
446
|
+
self.parseIdentityResponse,
|
|
447
|
+
mpid,
|
|
448
|
+
callback,
|
|
449
|
+
identityApiData,
|
|
450
|
+
Login
|
|
451
|
+
);
|
|
452
|
+
|
|
453
|
+
if (successfullyCachedIdentity) {
|
|
454
|
+
return;
|
|
455
|
+
}
|
|
456
|
+
}
|
|
457
|
+
|
|
428
458
|
if (mpInstance._Helpers.canLog()) {
|
|
429
459
|
if (mpInstance._Store.webviewBridgeEnabled) {
|
|
430
460
|
mpInstance._NativeSdkHelpers.sendToNative(
|
|
@@ -443,11 +473,12 @@ export default function Identity(mpInstance) {
|
|
|
443
473
|
} else {
|
|
444
474
|
mpInstance._IdentityAPIClient.sendIdentityRequest(
|
|
445
475
|
identityApiRequest,
|
|
446
|
-
|
|
476
|
+
Login,
|
|
447
477
|
callback,
|
|
448
478
|
identityApiData,
|
|
449
479
|
self.parseIdentityResponse,
|
|
450
|
-
mpid
|
|
480
|
+
mpid,
|
|
481
|
+
identityApiRequest.known_identities
|
|
451
482
|
);
|
|
452
483
|
}
|
|
453
484
|
} else {
|
|
@@ -481,7 +512,7 @@ export default function Identity(mpInstance) {
|
|
|
481
512
|
preProcessResult = mpInstance._Identity.IdentityRequest.preProcessIdentityRequest(
|
|
482
513
|
identityApiData,
|
|
483
514
|
callback,
|
|
484
|
-
|
|
515
|
+
Modify
|
|
485
516
|
);
|
|
486
517
|
if (currentUser) {
|
|
487
518
|
mpid = currentUser.getMPID();
|
|
@@ -520,11 +551,12 @@ export default function Identity(mpInstance) {
|
|
|
520
551
|
} else {
|
|
521
552
|
mpInstance._IdentityAPIClient.sendIdentityRequest(
|
|
522
553
|
identityApiRequest,
|
|
523
|
-
|
|
554
|
+
Modify,
|
|
524
555
|
callback,
|
|
525
556
|
identityApiData,
|
|
526
557
|
self.parseIdentityResponse,
|
|
527
|
-
mpid
|
|
558
|
+
mpid,
|
|
559
|
+
identityApiRequest.known_identities
|
|
528
560
|
);
|
|
529
561
|
}
|
|
530
562
|
} else {
|
|
@@ -1423,7 +1455,9 @@ export default function Identity(mpInstance) {
|
|
|
1423
1455
|
previousMPID,
|
|
1424
1456
|
callback,
|
|
1425
1457
|
identityApiData,
|
|
1426
|
-
method
|
|
1458
|
+
method,
|
|
1459
|
+
knownIdentities,
|
|
1460
|
+
parsingCachedResponse
|
|
1427
1461
|
) {
|
|
1428
1462
|
var prevUser = mpInstance.Identity.getUser(previousMPID),
|
|
1429
1463
|
newUser,
|
|
@@ -1478,6 +1512,20 @@ export default function Identity(mpInstance) {
|
|
|
1478
1512
|
}
|
|
1479
1513
|
|
|
1480
1514
|
if (xhr.status === 200) {
|
|
1515
|
+
if (
|
|
1516
|
+
mpInstance._Helpers.getFeatureFlag(
|
|
1517
|
+
Constants.FeatureFlags.CacheIdentity
|
|
1518
|
+
)
|
|
1519
|
+
) {
|
|
1520
|
+
cacheOrClearIdCache(
|
|
1521
|
+
method,
|
|
1522
|
+
knownIdentities,
|
|
1523
|
+
self.idCache,
|
|
1524
|
+
xhr,
|
|
1525
|
+
parsingCachedResponse
|
|
1526
|
+
);
|
|
1527
|
+
}
|
|
1528
|
+
|
|
1481
1529
|
if (method === Modify) {
|
|
1482
1530
|
newIdentitiesByType = mpInstance._Identity.IdentityRequest.combineUserIdentities(
|
|
1483
1531
|
previousUIByName,
|
|
@@ -1715,7 +1763,7 @@ export default function Identity(mpInstance) {
|
|
|
1715
1763
|
var currentUserInMemory, userIdentityChangeEvent;
|
|
1716
1764
|
|
|
1717
1765
|
if (!mpid) {
|
|
1718
|
-
if (method !==
|
|
1766
|
+
if (method !== Modify) {
|
|
1719
1767
|
return;
|
|
1720
1768
|
}
|
|
1721
1769
|
}
|
package/src/identityApiClient.js
CHANGED
|
@@ -66,7 +66,8 @@ export default function IdentityAPIClient(mpInstance) {
|
|
|
66
66
|
callback,
|
|
67
67
|
originalIdentityApiData,
|
|
68
68
|
parseIdentityResponse,
|
|
69
|
-
mpid
|
|
69
|
+
mpid,
|
|
70
|
+
knownIdentities
|
|
70
71
|
) {
|
|
71
72
|
var xhr,
|
|
72
73
|
previousMPID,
|
|
@@ -80,7 +81,9 @@ export default function IdentityAPIClient(mpInstance) {
|
|
|
80
81
|
previousMPID,
|
|
81
82
|
callback,
|
|
82
83
|
originalIdentityApiData,
|
|
83
|
-
method
|
|
84
|
+
method,
|
|
85
|
+
knownIdentities,
|
|
86
|
+
false
|
|
84
87
|
);
|
|
85
88
|
}
|
|
86
89
|
};
|
package/src/mockBatchCreator.ts
CHANGED
|
@@ -12,7 +12,7 @@ const mockFunction = function() {
|
|
|
12
12
|
};
|
|
13
13
|
export default class _BatchValidator {
|
|
14
14
|
private getMPInstance() {
|
|
15
|
-
return {
|
|
15
|
+
return ({
|
|
16
16
|
// Certain Helper, Store, and Identity properties need to be mocked to be used in the `returnBatch` method
|
|
17
17
|
_Helpers: {
|
|
18
18
|
sanitizeAttributes: window.mParticle.getInstance()._Helpers
|
|
@@ -119,7 +119,7 @@ export default class _BatchValidator {
|
|
|
119
119
|
logLevel: 'none',
|
|
120
120
|
setPosition: mockFunction,
|
|
121
121
|
upload: mockFunction,
|
|
122
|
-
} as MParticleWebSDK;
|
|
122
|
+
} as unknown) as MParticleWebSDK;
|
|
123
123
|
}
|
|
124
124
|
|
|
125
125
|
private createSDKEventFunction(event): SDKEvent {
|
package/src/mp-instance.js
CHANGED
|
@@ -36,6 +36,8 @@ import Consent from './consent';
|
|
|
36
36
|
import KitBlocker from './kitBlocking';
|
|
37
37
|
import ConfigAPIClient from './configAPIClient';
|
|
38
38
|
import IdentityAPIClient from './identityApiClient';
|
|
39
|
+
import { LocalStorageVault } from './vault';
|
|
40
|
+
import { removeExpiredIdentityCacheDates } from './identity-utils';
|
|
39
41
|
|
|
40
42
|
var Messages = Constants.Messages,
|
|
41
43
|
HTTPCodes = Constants.HTTPCodes;
|
|
@@ -1302,12 +1304,27 @@ function completeSDKInitialization(apiKey, config, mpInstance) {
|
|
|
1302
1304
|
}
|
|
1303
1305
|
}
|
|
1304
1306
|
|
|
1307
|
+
// add a new function to apply items to the store that require config to be returned
|
|
1305
1308
|
mpInstance._Store.storageName = mpInstance._Helpers.createMainStorageName(
|
|
1306
1309
|
config.workspaceToken
|
|
1307
1310
|
);
|
|
1308
1311
|
mpInstance._Store.prodStorageName = mpInstance._Helpers.createProductStorageName(
|
|
1309
1312
|
config.workspaceToken
|
|
1310
1313
|
);
|
|
1314
|
+
|
|
1315
|
+
// idCache is instantiated here as opposed to when _Identity is instantiated
|
|
1316
|
+
// because it depends on _Store.storageName, which is not sent until above
|
|
1317
|
+
// because it is a setting on config which returns asyncronously
|
|
1318
|
+
// in self hosted mode
|
|
1319
|
+
mpInstance._Identity.idCache = new LocalStorageVault(
|
|
1320
|
+
`${mpInstance._Store.storageName}-id-cache`,
|
|
1321
|
+
{
|
|
1322
|
+
logger: mpInstance.Logger,
|
|
1323
|
+
}
|
|
1324
|
+
);
|
|
1325
|
+
|
|
1326
|
+
removeExpiredIdentityCacheDates(mpInstance._Identity.idCache);
|
|
1327
|
+
|
|
1311
1328
|
if (config.hasOwnProperty('workspaceToken')) {
|
|
1312
1329
|
mpInstance._Store.SDKConfig.workspaceToken = config.workspaceToken;
|
|
1313
1330
|
} else {
|
|
@@ -355,7 +355,7 @@ function mParticle() {
|
|
|
355
355
|
};
|
|
356
356
|
|
|
357
357
|
this.Identity = {
|
|
358
|
-
HTTPCodes:
|
|
358
|
+
HTTPCodes: Constants.HTTPCodes,
|
|
359
359
|
aliasUsers: function(aliasRequest, callback) {
|
|
360
360
|
self.getInstance().Identity.aliasUsers(aliasRequest, callback);
|
|
361
361
|
},
|
package/src/sdkRuntimeModels.ts
CHANGED
|
@@ -3,7 +3,7 @@ import { DataPlanVersion } from '@mparticle/data-planning-models';
|
|
|
3
3
|
import { MPConfiguration, IdentityApiData } from '@mparticle/web-sdk';
|
|
4
4
|
import { IStore } from './store';
|
|
5
5
|
import Validators from './validators';
|
|
6
|
-
import { Dictionary } from './utils';
|
|
6
|
+
import { Dictionary, valueof } from './utils';
|
|
7
7
|
import { IServerModel } from './serverModel';
|
|
8
8
|
import { IKitConfigs } from './configAPIClient';
|
|
9
9
|
import { SDKConsentApi, SDKConsentState } from './consent';
|
|
@@ -11,6 +11,7 @@ import { IPersistence } from './persistence.interfaces';
|
|
|
11
11
|
import { IMPSideloadedKit } from './sideloadedKit';
|
|
12
12
|
import { ISessionManager } from './sessionManager';
|
|
13
13
|
import { Kit, MPForwarder } from './forwarders.interfaces';
|
|
14
|
+
import Constants from './constants';
|
|
14
15
|
|
|
15
16
|
// TODO: Resolve this with version in @mparticle/web-sdk
|
|
16
17
|
export type SDKEventCustomFlags = Dictionary<any>;
|
|
@@ -52,6 +53,8 @@ export interface SDKEvent {
|
|
|
52
53
|
LaunchReferral?: string;
|
|
53
54
|
}
|
|
54
55
|
|
|
56
|
+
export type IdentityAPIMethod = valueof<typeof Constants.IdentityMethods>;
|
|
57
|
+
|
|
55
58
|
export interface SDKGeoLocation {
|
|
56
59
|
lat: number | string;
|
|
57
60
|
lng: number | string;
|
|
@@ -238,6 +241,7 @@ export interface SDKIdentityApi {
|
|
|
238
241
|
login;
|
|
239
242
|
logout;
|
|
240
243
|
modify;
|
|
244
|
+
getUser(mpid: string): MParticleUser;
|
|
241
245
|
}
|
|
242
246
|
|
|
243
247
|
export interface SDKHelpersApi {
|
package/src/store.ts
CHANGED
|
@@ -116,6 +116,7 @@ export interface IFeatureFlags {
|
|
|
116
116
|
eventBatchingIntervalMillis?: number;
|
|
117
117
|
offlineStorage?: string;
|
|
118
118
|
directURLRouting?: boolean;
|
|
119
|
+
cacheIdentity?: boolean;
|
|
119
120
|
}
|
|
120
121
|
|
|
121
122
|
// Temporary Interface until Store can be refactored as a class
|
|
@@ -429,6 +430,7 @@ export function processFlags(
|
|
|
429
430
|
EventBatchingIntervalMillis,
|
|
430
431
|
OfflineStorage,
|
|
431
432
|
DirectUrlRouting,
|
|
433
|
+
CacheIdentity,
|
|
432
434
|
} = Constants.FeatureFlags;
|
|
433
435
|
|
|
434
436
|
if (!config.flags) {
|
|
@@ -443,6 +445,7 @@ export function processFlags(
|
|
|
443
445
|
Constants.DefaultConfig.uploadInterval;
|
|
444
446
|
flags[OfflineStorage] = config.flags[OfflineStorage] || '0';
|
|
445
447
|
flags[DirectUrlRouting] = config.flags[DirectUrlRouting] === 'True';
|
|
448
|
+
flags[CacheIdentity] = config.flags[CacheIdentity] === 'True';
|
|
446
449
|
|
|
447
450
|
return flags;
|
|
448
451
|
}
|
package/src/validators.ts
CHANGED
|
@@ -8,8 +8,7 @@ import {
|
|
|
8
8
|
} from './utils';
|
|
9
9
|
import Constants from './constants';
|
|
10
10
|
import { IdentityApiData } from '@mparticle/web-sdk';
|
|
11
|
-
|
|
12
|
-
type IdentityAPIMethod = 'login' | 'logout' | 'identify' | 'modify';
|
|
11
|
+
import { IdentityAPIMethod } from './sdkRuntimeModels';
|
|
13
12
|
|
|
14
13
|
type ValidationIdentitiesReturn = {
|
|
15
14
|
valid: boolean;
|