@mparticle/web-sdk 2.17.3 → 2.18.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.
@@ -1,30 +1,156 @@
1
+ import { Batch } from '@mparticle/event-models';
2
+ import { Context } from '@mparticle/event-models';
3
+ import {
4
+ DataPlanConfig,
5
+ MPID,
6
+ IdentifyRequest,
7
+ IdentityCallback,
8
+ SDKEventCustomFlags,
9
+ } from '@mparticle/web-sdk';
1
10
  import Constants from './constants';
11
+ import {
12
+ DataPlanResult,
13
+ Kit,
14
+ KitBlockerOptions,
15
+ KitConfigs,
16
+ LogLevelType,
17
+ MParticleWebSDK,
18
+ MPForwarder,
19
+ SDKConsentState,
20
+ SDKDataPlan,
21
+ SDKEvent,
22
+ SDKGeoLocation,
23
+ SDKInitConfig,
24
+ SDKProduct,
25
+ } from './sdkRuntimeModels';
26
+ import { isNumber, isDataPlanSlug, Dictionary } from './utils';
27
+
28
+ // This represents the runtime configuration of the SDK AFTER
29
+ // initialization has been complete and all settings and
30
+ // configurations have been stitched together.
31
+ export interface SDKConfig {
32
+ isDevelopmentMode?: boolean;
33
+ logger: {
34
+ error?(msg);
35
+ warning?(msg);
36
+ verbose?(msg);
37
+ };
38
+ onCreateBatch(batch: Batch): Batch;
39
+ customFlags?: SDKEventCustomFlags;
40
+ dataPlan: SDKDataPlan;
41
+ dataPlanOptions: KitBlockerOptions; // when the user provides their own data plan
42
+ dataPlanResult?: DataPlanResult; // when the data plan comes from the server via /config
43
+
44
+ appName?: string;
45
+ appVersion?: string;
46
+ package?: string;
47
+ flags?: { [key: string]: string | number | boolean };
48
+ kitConfigs: KitConfigs[];
49
+ kits: Dictionary<Kit>;
50
+ logLevel?: LogLevelType;
51
+ cookieDomain?: string;
52
+ maxCookieSize?: number | undefined;
53
+ minWebviewBridgeVersion: 1 | 2 | undefined;
54
+ identifyRequest: IdentifyRequest;
55
+ identityCallback: IdentityCallback;
56
+ integrationDelayTimeout: number;
57
+
58
+ aliasMaxWindow: number;
59
+ deviceId?: string;
60
+ forceHttps?: boolean;
61
+ aliasUrl?: string;
62
+ configUrl?: string;
63
+ identityUrl?: string;
64
+ isIOS?: boolean;
65
+ maxProducts: number;
66
+ requestConfig?: boolean;
67
+ sessionTimeout?: number;
68
+ useNativeSdk?: boolean;
69
+ useCookieStorage?: boolean;
70
+ v1SecureServiceUrl?: string;
71
+ v2SecureServiceUrl?: string;
72
+ v3SecureServiceUrl?: string;
73
+ }
74
+
75
+ function createSDKConfig(config: SDKInitConfig): SDKConfig {
76
+ // TODO: Refactor to create a default config object
77
+ const sdkConfig = {} as SDKConfig;
2
78
 
3
- function createSDKConfig(config) {
4
- var sdkConfig = {};
5
- for (var prop in Constants.DefaultConfig) {
79
+ for (const prop in Constants.DefaultConfig) {
6
80
  if (Constants.DefaultConfig.hasOwnProperty(prop)) {
7
81
  sdkConfig[prop] = Constants.DefaultConfig[prop];
8
82
  }
9
83
  }
10
84
 
11
85
  if (config) {
12
- for (prop in config) {
86
+ for (const prop in config) {
13
87
  if (config.hasOwnProperty(prop)) {
14
88
  sdkConfig[prop] = config[prop];
15
89
  }
16
90
  }
17
91
  }
18
92
 
19
- for (prop in Constants.DefaultUrls) {
93
+ for (const prop in Constants.DefaultUrls) {
20
94
  sdkConfig[prop] = Constants.DefaultUrls[prop];
21
95
  }
22
96
 
23
97
  return sdkConfig;
24
98
  }
25
99
 
26
- export default function Store(config, mpInstance) {
27
- var defaultStore = {
100
+ // TODO: Placeholder Types, MigrationData is temporary and will be removed in the future to reduce SDK size
101
+ export type PixelConfiguration = Dictionary;
102
+ export type MigrationData = Dictionary;
103
+ export type ServerSettings = Dictionary;
104
+
105
+ // Temporary Interface until Store can be refactored as a class
106
+ export interface IStore {
107
+ isEnabled: boolean;
108
+ sessionAttributes: Dictionary;
109
+ currentSessionMPIDs: MPID[];
110
+ consentState: SDKConsentState | null;
111
+ sessionId: string | null;
112
+ isFirstRun: boolean;
113
+ clientId: string;
114
+ deviceId: string;
115
+ devToken: string | null;
116
+ migrationData: MigrationData;
117
+ serverSettings: ServerSettings;
118
+ dateLastEventSent: number | null;
119
+ sessionStartDate: number | null;
120
+ currentPosition: SDKGeoLocation | null;
121
+ isTracking: boolean;
122
+ watchPositionId: number | null;
123
+ cartProducts: SDKProduct[];
124
+ eventQueue: SDKEvent[];
125
+ currencyCode: string | null;
126
+ globalTimer: number | null;
127
+ context: Context | null;
128
+ configurationLoaded: boolean;
129
+ identityCallInFlight: boolean;
130
+ SDKConfig: Partial<SDKConfig>;
131
+ migratingToIDSyncCookies: boolean; // TODO: Remove when we archive Web SDK v1
132
+ nonCurrentUserMPIDs: Record<MPID, Dictionary>;
133
+ identifyCalled: boolean;
134
+ isLoggedIn: boolean;
135
+ cookieSyncDates: Dictionary<number>;
136
+ integrationAttributes: Dictionary<Dictionary<string>>;
137
+ requireDelay: boolean;
138
+ isLocalStorageAvailable: boolean | null;
139
+ storageName: string | null;
140
+ prodStorageName: string | null;
141
+ activeForwarders: MPForwarder[];
142
+ kits: Dictionary<MPForwarder>;
143
+ configuredForwarders: MPForwarder[];
144
+ pixelConfigurations: PixelConfiguration[];
145
+ integrationDelayTimeoutStart: number; // UNIX Timestamp
146
+ }
147
+
148
+ export default function Store(
149
+ this: IStore,
150
+ config: SDKInitConfig,
151
+ mpInstance: MParticleWebSDK
152
+ ) {
153
+ const defaultStore: Partial<IStore> = {
28
154
  isEnabled: true,
29
155
  sessionAttributes: {},
30
156
  currentSessionMPIDs: [],
@@ -45,7 +171,7 @@ export default function Store(config, mpInstance) {
45
171
  eventQueue: [],
46
172
  currencyCode: null,
47
173
  globalTimer: null,
48
- context: '',
174
+ context: null,
49
175
  configurationLoaded: false,
50
176
  identityCallInFlight: false,
51
177
  SDKConfig: {},
@@ -113,14 +239,9 @@ export default function Store(config, mpInstance) {
113
239
  this.SDKConfig.logLevel = config.logLevel;
114
240
  }
115
241
 
116
- if (config.hasOwnProperty('useNativeSdk')) {
117
- this.SDKConfig.useNativeSdk = config.useNativeSdk;
118
- } else {
119
- this.SDKConfig.useNativeSdk = false;
120
- }
121
- if (config.hasOwnProperty('kits')) {
122
- this.SDKConfig.kits = config.kits;
123
- }
242
+ this.SDKConfig.useNativeSdk = !!config.useNativeSdk;
243
+
244
+ this.SDKConfig.kits = config.kits || {};
124
245
 
125
246
  if (config.hasOwnProperty('isIOS')) {
126
247
  this.SDKConfig.isIOS = config.isIOS;
@@ -177,8 +298,8 @@ export default function Store(config, mpInstance) {
177
298
  } else {
178
299
  mpInstance.Logger.warning(
179
300
  'The optional callback must be a function. You tried entering a(n) ' +
180
- typeof callback,
181
- ' . Callback not set. Please set your callback again.'
301
+ typeof callback +
302
+ ' . Callback not set. Please set your callback again.'
182
303
  );
183
304
  }
184
305
  }
@@ -200,32 +321,29 @@ export default function Store(config, mpInstance) {
200
321
  PlanVersion: null,
201
322
  PlanId: null,
202
323
  };
203
- if (config.dataPlan.hasOwnProperty('planId')) {
204
- if (typeof config.dataPlan.planId === 'string') {
205
- if (mpInstance._Helpers.isSlug(config.dataPlan.planId)) {
206
- this.SDKConfig.dataPlan.PlanId = config.dataPlan.planId;
207
- } else {
208
- mpInstance.Logger.error(
209
- 'Your data plan id must be in a slug format'
210
- );
211
- }
324
+
325
+ const dataPlan = config.dataPlan as DataPlanConfig;
326
+ if (dataPlan.planId) {
327
+ if (isDataPlanSlug(dataPlan.planId)) {
328
+ this.SDKConfig.dataPlan.PlanId = dataPlan.planId;
212
329
  } else {
213
330
  mpInstance.Logger.error(
214
- 'Your data plan id must be a string'
331
+ 'Your data plan id must be a string and match the data plan slug format (i.e. under_case_slug)'
215
332
  );
216
333
  }
217
334
  }
218
335
 
219
- if (config.dataPlan.hasOwnProperty('planVersion')) {
220
- if (typeof config.dataPlan.planVersion === 'number') {
221
- this.SDKConfig.dataPlan.PlanVersion =
222
- config.dataPlan.planVersion;
336
+ if (dataPlan.planVersion) {
337
+ if (isNumber(dataPlan.planVersion)) {
338
+ this.SDKConfig.dataPlan.PlanVersion = dataPlan.planVersion;
223
339
  } else {
224
340
  mpInstance.Logger.error(
225
341
  'Your data plan version must be a number'
226
342
  );
227
343
  }
228
344
  }
345
+ } else {
346
+ this.SDKConfig.dataPlan = {};
229
347
  }
230
348
 
231
349
  if (config.hasOwnProperty('forceHttps')) {
@@ -235,9 +353,7 @@ export default function Store(config, mpInstance) {
235
353
  }
236
354
 
237
355
  // Some forwarders require custom flags on initialization, so allow them to be set using config object
238
- if (config.hasOwnProperty('customFlags')) {
239
- this.SDKConfig.customFlags = config.customFlags;
240
- }
356
+ this.SDKConfig.customFlags = config.customFlags || {};
241
357
 
242
358
  if (config.hasOwnProperty('minWebviewBridgeVersion')) {
243
359
  this.SDKConfig.minWebviewBridgeVersion =
@@ -3,6 +3,7 @@ let mParticle = {
3
3
  getAppName: returnString,
4
4
  getAppVersion: returnString,
5
5
  getDeviceId: returnString,
6
+ getEnvironment: returnString,
6
7
  getVersion: returnString,
7
8
  init: voidFunction,
8
9
  logError: voidFunction,
package/src/types.js CHANGED
@@ -361,6 +361,11 @@ var ApplicationTransitionType = {
361
361
  AppInit: 1,
362
362
  };
363
363
 
364
+ const Environment = {
365
+ Production: 'production',
366
+ Development: 'development',
367
+ };
368
+
364
369
  export default {
365
370
  MessageType: MessageType,
366
371
  EventType: EventType,
@@ -371,4 +376,5 @@ export default {
371
376
  ProductActionType: ProductActionType,
372
377
  PromotionActionType: PromotionActionType,
373
378
  TriggerUploadType: TriggerUploadType,
379
+ Environment,
374
380
  };
package/src/utils.ts CHANGED
@@ -1,5 +1,10 @@
1
+ import slugify from 'slugify';
2
+
1
3
  type valueof<T> = T[keyof T];
2
4
 
5
+ // Placeholder for Dictionary-like Types
6
+ export type Dictionary<V = any> = Record<string, V>;
7
+
3
8
  const inArray = (items: any[], name: string): boolean => {
4
9
  let i = 0;
5
10
 
@@ -44,6 +49,16 @@ const parseNumber = (value: string | number): number => {
44
49
  return isNaN(floatValue) ? 0 : floatValue;
45
50
  };
46
51
 
52
+ const parseStringOrNumber = (
53
+ value: string | number
54
+ ): string | number | null => {
55
+ if (isStringOrNumber(value)) {
56
+ return value;
57
+ } else {
58
+ return null;
59
+ }
60
+ };
61
+
47
62
  // FIXME: REFACTOR for V3
48
63
  // only used in store.js to sanitize server-side formatting of
49
64
  // booleans when checking for `isDevelopmentMode`
@@ -70,6 +85,17 @@ const converted = (s: string): string => {
70
85
  return s;
71
86
  };
72
87
 
88
+ const isString = (value: any): boolean => typeof value === 'string';
89
+ const isNumber = (value: any): boolean => typeof value === 'number';
90
+ const isFunction = (fn: any): boolean => typeof fn === 'function';
91
+
92
+ // TODO: Refactor this to a regex
93
+ const isDataPlanSlug = (str: string): boolean =>
94
+ isString(str) && str === slugify(str);
95
+
96
+ const isStringOrNumber = (value: any): boolean =>
97
+ isString(value) || isNumber(value);
98
+
73
99
  export {
74
100
  valueof,
75
101
  converted,
@@ -77,6 +103,12 @@ export {
77
103
  findKeyInObject,
78
104
  inArray,
79
105
  isObject,
106
+ isStringOrNumber,
80
107
  parseNumber,
108
+ parseStringOrNumber,
81
109
  returnConvertedBoolean,
110
+ isString,
111
+ isNumber,
112
+ isFunction,
113
+ isDataPlanSlug,
82
114
  };
package/src/validators.ts CHANGED
@@ -1,8 +1,7 @@
1
1
  import Types from './types';
2
- import { isObject } from './utils';
2
+ import { isFunction, isNumber, isObject, isStringOrNumber, valueof } from './utils';
3
3
  import Constants from './constants';
4
4
  import { IdentityApiData } from '@mparticle/web-sdk';
5
- import { valueof } from './utils';
6
5
 
7
6
  type IdentityAPIMethod = 'login' | 'logout' | 'identify' | 'modify';
8
7
 
@@ -12,10 +11,17 @@ type ValidationIdentitiesReturn = {
12
11
  };
13
12
 
14
13
  const Validators = {
14
+ // From ./utils
15
+ // Utility Functions for backwards compatability
16
+ isNumber,
17
+ isFunction,
18
+ isStringOrNumber,
19
+
15
20
  isValidAttributeValue: function(value: any): boolean {
16
21
  return value !== undefined && !isObject(value) && !Array.isArray(value);
17
22
  },
18
23
 
24
+ // Validator Functions
19
25
  // Neither null nor undefined can be a valid Key
20
26
  isValidKeyValue: function(key: any): boolean {
21
27
  return Boolean(
@@ -26,18 +32,6 @@ const Validators = {
26
32
  );
27
33
  },
28
34
 
29
- isStringOrNumber: function(value: any): boolean {
30
- return typeof value === 'string' || typeof value === 'number';
31
- },
32
-
33
- isNumber: function(value: any): boolean {
34
- return typeof value === 'number';
35
- },
36
-
37
- isFunction: (fn: any): boolean => {
38
- return typeof fn === 'function';
39
- },
40
-
41
35
  validateIdentities: function(
42
36
  identityApiData: IdentityApiData,
43
37
  method?: IdentityAPIMethod