@magicpixel/rn-mp-client-sdk 0.11.0 → 1.12.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.
Files changed (104) hide show
  1. package/lib/commonjs/common/app-types.js.map +1 -1
  2. package/lib/commonjs/common/constants.js +5 -26
  3. package/lib/commonjs/common/constants.js.map +1 -1
  4. package/lib/commonjs/common/data-store.js +36 -117
  5. package/lib/commonjs/common/data-store.js.map +1 -1
  6. package/lib/commonjs/common/event-bus.js +3 -10
  7. package/lib/commonjs/common/event-bus.js.map +1 -1
  8. package/lib/commonjs/common/logger.js +22 -14
  9. package/lib/commonjs/common/logger.js.map +1 -1
  10. package/lib/commonjs/common/network-service.js +6 -21
  11. package/lib/commonjs/common/network-service.js.map +1 -1
  12. package/lib/commonjs/common/reporter.js +8 -31
  13. package/lib/commonjs/common/reporter.js.map +1 -1
  14. package/lib/commonjs/common/utils.js +64 -65
  15. package/lib/commonjs/common/utils.js.map +1 -1
  16. package/lib/commonjs/coverage/lcov-report/block-navigation.js +6 -19
  17. package/lib/commonjs/coverage/lcov-report/block-navigation.js.map +1 -1
  18. package/lib/commonjs/coverage/lcov-report/prettify.js +2 -182
  19. package/lib/commonjs/coverage/lcov-report/prettify.js.map +1 -1
  20. package/lib/commonjs/coverage/lcov-report/sorter.js +64 -94
  21. package/lib/commonjs/coverage/lcov-report/sorter.js.map +1 -1
  22. package/lib/commonjs/eedl/eedl.js +207 -84
  23. package/lib/commonjs/eedl/eedl.js.map +1 -1
  24. package/lib/commonjs/index.js +105 -94
  25. package/lib/commonjs/index.js.map +1 -1
  26. package/lib/commonjs/models/geo-api-response.js +2 -0
  27. package/lib/commonjs/models/geo-api-response.js.map +1 -0
  28. package/lib/commonjs/models/mp-client-sdk.js +3 -11
  29. package/lib/commonjs/models/mp-client-sdk.js.map +1 -1
  30. package/lib/commonjs/processors/data-element.processor.js +85 -80
  31. package/lib/commonjs/processors/data-element.processor.js.map +1 -1
  32. package/lib/commonjs/processors/geo-location.processor.js +70 -0
  33. package/lib/commonjs/processors/geo-location.processor.js.map +1 -0
  34. package/lib/commonjs/processors/qc.processor.js +2 -25
  35. package/lib/commonjs/processors/qc.processor.js.map +1 -1
  36. package/lib/commonjs/processors/tag.processor.js +17 -86
  37. package/lib/commonjs/processors/tag.processor.js.map +1 -1
  38. package/lib/commonjs/processors/trans-function.processor.js +5 -23
  39. package/lib/commonjs/processors/trans-function.processor.js.map +1 -1
  40. package/lib/commonjs/processors/visit-id.processor.js +4 -50
  41. package/lib/commonjs/processors/visit-id.processor.js.map +1 -1
  42. package/lib/module/common/app-types.js.map +1 -1
  43. package/lib/module/common/constants.js +4 -22
  44. package/lib/module/common/constants.js.map +1 -1
  45. package/lib/module/common/data-store.js +35 -108
  46. package/lib/module/common/data-store.js.map +1 -1
  47. package/lib/module/common/event-bus.js +3 -6
  48. package/lib/module/common/event-bus.js.map +1 -1
  49. package/lib/module/common/logger.js +22 -12
  50. package/lib/module/common/logger.js.map +1 -1
  51. package/lib/module/common/network-service.js +6 -11
  52. package/lib/module/common/network-service.js.map +1 -1
  53. package/lib/module/common/reporter.js +8 -19
  54. package/lib/module/common/reporter.js.map +1 -1
  55. package/lib/module/common/utils.js +63 -56
  56. package/lib/module/common/utils.js.map +1 -1
  57. package/lib/module/coverage/lcov-report/block-navigation.js +6 -19
  58. package/lib/module/coverage/lcov-report/block-navigation.js.map +1 -1
  59. package/lib/module/coverage/lcov-report/prettify.js +2 -182
  60. package/lib/module/coverage/lcov-report/prettify.js.map +1 -1
  61. package/lib/module/coverage/lcov-report/sorter.js +64 -94
  62. package/lib/module/coverage/lcov-report/sorter.js.map +1 -1
  63. package/lib/module/eedl/eedl.js +206 -76
  64. package/lib/module/eedl/eedl.js.map +1 -1
  65. package/lib/module/index.js +103 -57
  66. package/lib/module/index.js.map +1 -1
  67. package/lib/module/models/geo-api-response.js +2 -0
  68. package/lib/module/models/geo-api-response.js.map +1 -0
  69. package/lib/module/models/mp-client-sdk.js +0 -5
  70. package/lib/module/models/mp-client-sdk.js.map +1 -1
  71. package/lib/module/processors/data-element.processor.js +82 -71
  72. package/lib/module/processors/data-element.processor.js.map +1 -1
  73. package/lib/module/processors/geo-location.processor.js +63 -0
  74. package/lib/module/processors/geo-location.processor.js.map +1 -0
  75. package/lib/module/processors/qc.processor.js +2 -11
  76. package/lib/module/processors/qc.processor.js.map +1 -1
  77. package/lib/module/processors/tag.processor.js +17 -57
  78. package/lib/module/processors/tag.processor.js.map +1 -1
  79. package/lib/module/processors/trans-function.processor.js +5 -12
  80. package/lib/module/processors/trans-function.processor.js.map +1 -1
  81. package/lib/module/processors/visit-id.processor.js +4 -27
  82. package/lib/module/processors/visit-id.processor.js.map +1 -1
  83. package/lib/typescript/common/app-types.d.ts +4 -0
  84. package/lib/typescript/common/constants.d.ts +1 -0
  85. package/lib/typescript/common/data-store.d.ts +8 -0
  86. package/lib/typescript/common/logger.d.ts +5 -0
  87. package/lib/typescript/common/utils.d.ts +19 -0
  88. package/lib/typescript/eedl/eedl.d.ts +16 -5
  89. package/lib/typescript/index.d.ts +53 -0
  90. package/lib/typescript/models/geo-api-response.d.ts +12 -0
  91. package/lib/typescript/processors/data-element.processor.d.ts +10 -1
  92. package/lib/typescript/processors/geo-location.processor.d.ts +10 -0
  93. package/package.json +25 -10
  94. package/src/common/app-types.ts +4 -0
  95. package/src/common/constants.ts +2 -0
  96. package/src/common/data-store.ts +38 -0
  97. package/src/common/logger.ts +19 -3
  98. package/src/common/network-service.ts +2 -0
  99. package/src/common/utils.ts +58 -0
  100. package/src/eedl/eedl.ts +241 -18
  101. package/src/index.tsx +99 -3
  102. package/src/models/geo-api-response.ts +13 -0
  103. package/src/processors/data-element.processor.ts +140 -70
  104. package/src/processors/geo-location.processor.ts +91 -0
@@ -10,6 +10,7 @@ import { flatten, unflatten } from 'flat';
10
10
  import { EventBus } from './event-bus';
11
11
  import { Dimensions, ScaledSize } from 'react-native';
12
12
  import { URL } from 'react-native-url-polyfill';
13
+ import AsyncStorage from '@react-native-async-storage/async-storage';
13
14
 
14
15
  export class Utils {
15
16
  static triggerEvent(eventName: string, payload: any): void {
@@ -207,6 +208,63 @@ export class Utils {
207
208
  return Constants.LARGE_RANDOM_POOL();
208
209
  }
209
210
 
211
+ /**
212
+ * Make HTTP GET request - React Native implementation
213
+ * @param url URL to fetch
214
+ * @returns Promise with response data
215
+ */
216
+ static async getHttp<T>(url: string): Promise<T> {
217
+ try {
218
+ const response = await fetch(url, {
219
+ method: 'GET',
220
+ headers: {
221
+ 'Content-Type': 'application/json',
222
+ },
223
+ });
224
+
225
+ if (!response.ok) {
226
+ throw new Error(`HTTP error! status: ${response.status}`);
227
+ }
228
+
229
+ return await response.json();
230
+ } catch (error) {
231
+ Logger.logError('HTTP GET request failed:', error);
232
+ throw error;
233
+ }
234
+ }
235
+
236
+ /**
237
+ * Get value from AsyncStorage (React Native equivalent of sessionStorage)
238
+ * @param key Storage key
239
+ * @param defaultValue Default value if key not found
240
+ * @returns Promise with stored value or default
241
+ */
242
+ static async getValueFromAsyncStorage<T>(
243
+ key: string,
244
+ defaultValue: T
245
+ ): Promise<T> {
246
+ try {
247
+ const value = await AsyncStorage.getItem(key);
248
+ return value ? JSON.parse(value) : defaultValue;
249
+ } catch (error) {
250
+ Logger.logError('Error getting value from AsyncStorage:', error);
251
+ return defaultValue;
252
+ }
253
+ }
254
+
255
+ /**
256
+ * Set value to AsyncStorage (React Native equivalent of sessionStorage)
257
+ * @param key Storage key
258
+ * @param value Value to store
259
+ */
260
+ static async setValueToAsyncStorage(key: string, value: any): Promise<void> {
261
+ try {
262
+ await AsyncStorage.setItem(key, JSON.stringify(value));
263
+ } catch (error) {
264
+ Logger.logError('Error setting value to AsyncStorage:', error);
265
+ }
266
+ }
267
+
210
268
  static getSimpleDebugId(prefix?: string): string {
211
269
  return `${prefix ?? ''}${this.randomNumber(100000000, 99999999999)}`;
212
270
  }
package/src/eedl/eedl.ts CHANGED
@@ -1,22 +1,39 @@
1
1
  import { Utils } from '../common/utils';
2
2
  import type { EventProcessorFn, MapLike, TypedAny } from '../common/app-types';
3
3
  import { Logger } from '../common/logger';
4
+ import AsyncStorage from '@react-native-async-storage/async-storage';
5
+ import { customAlphabet } from 'nanoid/non-secure';
6
+
7
+ const eventsToPersist: Record<string, string> = {
8
+ user_info: '_mpPendingUserInfo',
9
+ mp_purchase: '_mpPendingPurchase',
10
+ };
11
+
12
+ // UUID v4 generator for React Native
13
+ const getUUIDV4 = customAlphabet(
14
+ '1234567890abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ',
15
+ 36
16
+ );
4
17
 
5
18
  export class MpDataLayerHelper {
6
19
  isReady = false;
7
20
  _masterDataLayer: MapLike = {};
21
+ _persistedVars: MapLike = {};
8
22
  eventProcessors: Record<string, any> = {};
9
23
  stateTracker: Array<any> = [];
10
24
  dlInitEvent: string;
11
25
  receivedInitialEvent = false;
12
26
  eventQueue: Array<any> = [];
27
+ private isEntryPoint = 0;
13
28
 
14
29
  constructor(
15
30
  private readonly dlEventName: string,
16
31
  private readonly dlInitMode: string,
17
- dlInitEvent: string
32
+ dlInitEvent: string,
33
+ private readonly storageKeyName: string = '_mpdls'
18
34
  ) {
19
35
  this.dlInitEvent = dlInitEvent;
36
+ this.resetEntryPointInfo();
20
37
 
21
38
  if (this.dlInitMode !== 'manual') {
22
39
  this.isReady = true;
@@ -27,7 +44,9 @@ export class MpDataLayerHelper {
27
44
  }
28
45
  }
29
46
 
30
- init(globalEventListeners: Record<string, EventProcessorFn>): void {
47
+ async init(
48
+ globalEventListeners: Record<string, EventProcessorFn>
49
+ ): Promise<void> {
31
50
  // register any global event listeners passed through to the init command
32
51
  const globalEventListenerKeys = Object.keys(globalEventListeners || {});
33
52
  if (globalEventListenerKeys?.length > 0) {
@@ -37,13 +56,34 @@ export class MpDataLayerHelper {
37
56
  }
38
57
  }
39
58
  }
59
+
60
+ // Load persisted events from AsyncStorage
61
+ for (const key of Object.keys(eventsToPersist)) {
62
+ try {
63
+ const persistedEvent = await AsyncStorage.getItem(eventsToPersist[key]);
64
+ if (persistedEvent) {
65
+ const event: { eventName: string; eventPayload: any } =
66
+ JSON.parse(persistedEvent);
67
+ this.pushEvent(event.eventName, event.eventPayload);
68
+ }
69
+ } catch (err) {
70
+ Logger.logError('Error parsing persisted event', err);
71
+ }
72
+ }
40
73
  }
41
74
 
42
75
  pushEvent(eventName: string, payload: MapLike): void {
43
76
  Logger.logDbg('EV Push Event:: ', JSON.stringify(payload));
44
- if (eventName === 'set') {
45
- // process regardless
46
- this.processQItems(eventName, payload);
77
+ if (
78
+ eventName === 'set' ||
79
+ eventName === 'persist' ||
80
+ eventName === 'clear' ||
81
+ eventName === 'user_info'
82
+ ) {
83
+ // process regardless - fire and forget for async operations
84
+ this.processQItems(eventName, payload).catch((err) =>
85
+ Logger.logError('Error processing event', err)
86
+ );
47
87
  } else {
48
88
  if (!this.receivedInitialEvent) {
49
89
  // set only if this is not true already
@@ -55,17 +95,28 @@ export class MpDataLayerHelper {
55
95
  } else if (!this.isReady) {
56
96
  this.eventQueue.push([eventName, payload]);
57
97
  } else {
58
- this.processQItems(eventName, payload);
98
+ // fire and forget for async operations
99
+ this.processQItems(eventName, payload).catch((err) =>
100
+ Logger.logError('Error processing event', err)
101
+ );
59
102
  }
60
103
  }
61
104
  }
62
105
 
63
- processQItems(eventName: string, payload: MapLike): void {
106
+ async processQItems(eventName: string, payload: MapLike): Promise<void> {
64
107
  try {
65
108
  if (eventName === 'set') {
66
109
  this.setDl(payload);
110
+ } else if (eventName === 'persist') {
111
+ await this.storeData(payload?.key, payload?.value);
112
+ } else if (eventName === 'clear') {
113
+ if (Array.isArray(payload) && payload.length > 0) {
114
+ await this.deleteData(payload as string[]);
115
+ }
116
+ } else if (eventName === 'user_info') {
117
+ this.setUserData(payload);
67
118
  } else {
68
- this.eventProcessor(eventName, payload);
119
+ await this.eventProcessor(eventName, payload);
69
120
  }
70
121
  /* Make sure nothing is written below this line. If you do so, remember to return on error conditions above */
71
122
  } catch (err) {
@@ -89,19 +140,166 @@ export class MpDataLayerHelper {
89
140
  return this._masterDataLayer;
90
141
  }
91
142
 
143
+ private setUserData(payload: {
144
+ pid?: string;
145
+ email?: string;
146
+ phone?: string;
147
+ country?: string;
148
+ city?: string;
149
+ state?: string;
150
+ fName?: string;
151
+ lName?: string;
152
+ zip?: string;
153
+ }): void {
154
+ if (
155
+ payload?.zip &&
156
+ payload?.zip?.length > 0 &&
157
+ payload?.zip?.indexOf('-') > -1
158
+ ) {
159
+ payload.zip = payload.zip.split('-')[0].trim();
160
+ }
161
+
162
+ const uif: any = {};
163
+ this._persistedVars = this._persistedVars || {};
164
+ this._persistedVars.uif = this._persistedVars.uif || {};
165
+
166
+ if (payload.pid) {
167
+ this._persistedVars.uif.user_pid = payload.pid;
168
+ uif.pid = payload.pid;
169
+ }
170
+
171
+ if (payload.email) {
172
+ this._persistedVars.uif.user_email = payload.email;
173
+ uif.e = payload.email;
174
+ }
175
+
176
+ if (payload.phone) {
177
+ this._persistedVars.uif.user_phone = payload.phone;
178
+ uif.p = payload.phone;
179
+ }
180
+
181
+ if (payload.country) {
182
+ this._persistedVars.uif.user_country = payload.country;
183
+ uif.cy = payload.country;
184
+ }
185
+
186
+ if (payload.city) {
187
+ this._persistedVars.uif.user_city = payload.city;
188
+ uif.ct = payload.city;
189
+ }
190
+
191
+ if (payload.state) {
192
+ this._persistedVars.uif.user_state = payload.state;
193
+ uif.st = payload.state;
194
+ }
195
+
196
+ if (payload.fName) {
197
+ this._persistedVars.uif.fn = payload.fName;
198
+ uif.fn = payload.fName;
199
+ }
200
+
201
+ if (payload.lName) {
202
+ this._persistedVars.uif.ln = payload.lName;
203
+ uif.ln = payload.lName;
204
+ }
205
+
206
+ if (payload.zip) {
207
+ this._persistedVars.uif.zip_code = payload.zip;
208
+ uif.z = payload.zip;
209
+ }
210
+
211
+ if (Object.keys(uif).length > 0) {
212
+ this.storeData('uif', uif);
213
+ }
214
+ }
215
+
216
+ private async deleteData(chips: string[]): Promise<void> {
217
+ const fullData = await this.getFullData();
218
+ for (const chip of chips) {
219
+ if (typeof chip === 'string') {
220
+ delete fullData[chip];
221
+ }
222
+ }
223
+ await this.storeFullData(fullData);
224
+ }
225
+
226
+ private async storeData(chip: string, value: any): Promise<void> {
227
+ if (typeof chip !== 'undefined' && typeof value !== 'undefined') {
228
+ const fullData = await this.getFullData();
229
+ fullData[chip] = value;
230
+ await this.storeFullData(fullData);
231
+ this._persistedVars[chip] = value;
232
+ } else {
233
+ Logger.logError('Both key and value are required for persisting data');
234
+ }
235
+ }
236
+
237
+ private async reloadPersistedVars(): Promise<void> {
238
+ this._persistedVars = await this.getFullData();
239
+ }
240
+
241
+ private async getFullData(): Promise<MapLike> {
242
+ try {
243
+ const storedData = await AsyncStorage.getItem(this.storageKeyName);
244
+ if (storedData) {
245
+ return JSON.parse(storedData);
246
+ }
247
+ } catch (err) {
248
+ Logger.logError('Error reloading persisted variables', err);
249
+ }
250
+ return {};
251
+ }
252
+
253
+ private async storeFullData(fullData: MapLike): Promise<void> {
254
+ this._persistedVars = fullData;
255
+ try {
256
+ await AsyncStorage.setItem(this.storageKeyName, JSON.stringify(fullData));
257
+ } catch (err) {
258
+ Logger.logError('Error storing data', err);
259
+ }
260
+ }
261
+
262
+ // private async getStoredData<T = any>(chip: string, defValue: T): Promise<T> {
263
+ // let value: T;
264
+ // try {
265
+ // const storedData = await AsyncStorage.getItem(this.storageKeyName);
266
+ // if (storedData) {
267
+ // const parsedData = JSON.parse(storedData);
268
+ // value = parsedData[chip];
269
+ // }
270
+ // } catch (err) {
271
+ // Logger.logError('Error parsing stored data', err);
272
+ // }
273
+ // return value ?? defValue;
274
+ // }
275
+
92
276
  /**
93
277
  * Private event processor. Idea is that whenever an event is detected, we create a copy of the master data layer,
94
278
  * add the event variables, and trigger the event requested when initializing the data layer helper
95
279
  * @param eventName
96
280
  * @param model
97
281
  */
98
- eventProcessor(eventName: string, model: TypedAny | undefined): void {
282
+ async eventProcessor(
283
+ eventName: string,
284
+ model: TypedAny | undefined
285
+ ): Promise<void> {
286
+ model = model ?? {};
287
+
99
288
  /**
100
289
  * The following If block clears the data layer when the initial event is received.
101
290
  * This is done to prevent value carry overs from one page to another in single page apps
102
291
  */
103
292
  if (eventName === 'reset' || eventName === this.dlInitEvent) {
104
293
  this.reset();
294
+
295
+ // add an init event based uuid to the core data model
296
+ model['page_load_uid'] = getUUIDV4();
297
+ model['is_entry_point'] = this.getIsEntryPointValue();
298
+ if (model['is_entry_point'] === 1) {
299
+ // Note: In React Native, we don't have document.referrer, so we'll use a placeholder
300
+ model['entry_point_referrer'] = '';
301
+ }
302
+
105
303
  this.setDl(model);
106
304
  model = undefined;
107
305
  }
@@ -114,6 +312,11 @@ export class MpDataLayerHelper {
114
312
  model = {};
115
313
  }
116
314
 
315
+ await this.reloadPersistedVars();
316
+
317
+ // get persisted values and add them into the event model
318
+ model['p'] = this._persistedVars ?? {};
319
+
117
320
  // generate a unique id for each event automatically
118
321
  model['ev._id'] = Utils.getUniqueID();
119
322
 
@@ -122,17 +325,21 @@ export class MpDataLayerHelper {
122
325
 
123
326
  model['ev._eventName'] = eventName;
124
327
 
328
+ model['ev._persistKey'] = eventsToPersist[eventName] || null;
329
+
125
330
  model = Utils.flattenObject(model);
126
331
 
127
332
  // create a clone of master data layer and merge event model to it
128
333
  const _clone = Object.assign({}, this._masterDataLayer, model);
129
334
  const eventTs = Date.now();
130
335
 
131
- const eventPayload = {
132
- eventName: eventName,
133
- eventTs: eventTs,
134
- model: _clone,
135
- };
336
+ const eventPayload = JSON.parse(
337
+ JSON.stringify({
338
+ eventName: eventName,
339
+ eventTs: eventTs,
340
+ model: _clone,
341
+ })
342
+ );
136
343
 
137
344
  // add to state tracker
138
345
  this.stateTracker.push(eventPayload);
@@ -202,7 +409,9 @@ export class MpDataLayerHelper {
202
409
  // drain queue only if the initial configured event has been received,
203
410
  // otherwise mark isReady but dont drain the queue. queue will be drained first when the init
204
411
  // event is received
205
- this.drainQueue();
412
+ this.drainQueue().catch((err) =>
413
+ Logger.logError('Error draining queue', err)
414
+ );
206
415
  } else {
207
416
  Logger.logDbg(
208
417
  `Initial event (${this.dlInitEvent}) NOT received. Events will be queued`
@@ -210,7 +419,7 @@ export class MpDataLayerHelper {
210
419
  }
211
420
  }
212
421
 
213
- drainQueue(): void {
422
+ async drainQueue(): Promise<void> {
214
423
  Logger.logDbg('drainQueue...');
215
424
  // create a copy of the array
216
425
  const _temp = [...this.eventQueue];
@@ -222,7 +431,7 @@ export class MpDataLayerHelper {
222
431
  );
223
432
  if (initialEventObjectIndex > -1) {
224
433
  // splice and execute it
225
- this.processQItems(
434
+ await this.processQItems(
226
435
  _temp[initialEventObjectIndex][0],
227
436
  _temp[initialEventObjectIndex][1]
228
437
  );
@@ -230,7 +439,21 @@ export class MpDataLayerHelper {
230
439
  }
231
440
  // continue with other items
232
441
  for (const item of _temp) {
233
- this.processQItems(item[0], item[1]);
442
+ await this.processQItems(item[0], item[1]);
234
443
  }
235
444
  }
445
+
446
+ getIsEntryPointValue(): number {
447
+ // In React Native, we'll use a simple approach for entry point tracking
448
+ // This could be enhanced with proper session storage implementation
449
+ const currentValue = this.isEntryPoint;
450
+ this.isEntryPoint = 0; // Reset after first use
451
+ return currentValue;
452
+ }
453
+
454
+ resetEntryPointInfo(): void {
455
+ // In React Native, we'll default to entry point = 1 for the first session
456
+ // This could be enhanced with proper referrer tracking if needed
457
+ this.isEntryPoint = 1;
458
+ }
236
459
  }
package/src/index.tsx CHANGED
@@ -16,6 +16,7 @@ import { QcProcessor } from './processors/qc.processor';
16
16
  import { NetworkService } from './common/network-service';
17
17
  import { EventBus } from './common/event-bus';
18
18
  import { VisitIdProcessor } from './processors/visit-id.processor';
19
+ import { GeoLocationProcessor } from './processors/geo-location.processor';
19
20
 
20
21
  const DL_INIT_EVENT = 'page_load';
21
22
 
@@ -23,7 +24,8 @@ class MagicPixelImpl {
23
24
  private static dl: MpDataLayerHelper = new MpDataLayerHelper(
24
25
  'mpDlEvent',
25
26
  'manual',
26
- DL_INIT_EVENT
27
+ DL_INIT_EVENT,
28
+ '_mpRnDataLayer'
27
29
  );
28
30
  private static customerInfo: AppCustomerInfo;
29
31
  private static customerIdentifiers: MapLike = {};
@@ -33,6 +35,7 @@ class MagicPixelImpl {
33
35
  private static firstAppLaunch = true;
34
36
 
35
37
  static async init(options: SdkInitOptions): Promise<void> {
38
+ Logger.setLogLevel(options.logLevel ?? 'none');
36
39
  await NetworkService.refreshClientSdkJson(options);
37
40
 
38
41
  if (!DataStore.isDataStoreReady()) {
@@ -59,6 +62,16 @@ class MagicPixelImpl {
59
62
  Logger.logDbg('No facebook client id found. not setting');
60
63
  }
61
64
 
65
+ // Initialize EEDL with any global event listeners
66
+ await this.dl.init({});
67
+
68
+ // Make geo location API call after initialization
69
+ try {
70
+ await GeoLocationProcessor.makeGeoLocationApiCall();
71
+ } catch (err) {
72
+ Logger.logError('Error making geo location API call:', err);
73
+ }
74
+
62
75
  MagicPixelEventBus.on('mpDlEvent', async (evtName, payload) => {
63
76
  Logger.logDbg('mpDlEvent:: ', evtName, JSON.stringify(payload));
64
77
  const eventName: string = payload.eventName;
@@ -280,7 +293,7 @@ class MagicPixelImpl {
280
293
  DataStore.getSSTDownStream(),
281
294
  evtName,
282
295
  evtId
283
- ).catch((err: any) => {
296
+ ).catch((err) => {
284
297
  Reporter.reportError('l::postSST', err);
285
298
  });
286
299
  }
@@ -325,7 +338,10 @@ class MagicPixelImpl {
325
338
  static recordPageLoad(pageLoadInfo: AppPageLoad): void {
326
339
  pageLoadInfo.is_entry = this.firstAppLaunch ? 1 : 0;
327
340
 
328
- if (this.deepLinkUrl) {
341
+ // Use stored deepLinkUrl if it exists AND either:
342
+ // - deep_link_url wasn't provided in pageLoadInfo, OR
343
+ // - deep_link_url is empty/falsy (defensive programming for developer mistakes)
344
+ if (this.deepLinkUrl && !pageLoadInfo.deep_link_url) {
329
345
  pageLoadInfo.deep_link_url = this.deepLinkUrl;
330
346
  }
331
347
 
@@ -361,6 +377,86 @@ class MagicPixelImpl {
361
377
  this.deepLinkUrl = undefined;
362
378
  this.firstAppLaunch = false;
363
379
  }
380
+
381
+ /**
382
+ * Set user information for tracking
383
+ * @param userInfo User information object
384
+ */
385
+ static setUserInfo(userInfo: {
386
+ pid?: string;
387
+ email?: string;
388
+ phone?: string;
389
+ country?: string;
390
+ city?: string;
391
+ state?: string;
392
+ fName?: string;
393
+ lName?: string;
394
+ zip?: string;
395
+ }): void {
396
+ this.dl.pushEvent('user_info', userInfo);
397
+ }
398
+
399
+ /**
400
+ * Persist custom data to storage
401
+ * @param key Storage key
402
+ * @param value Value to store
403
+ */
404
+ static persistData(key: string, value: any): void {
405
+ this.dl.pushEvent('persist', { key, value });
406
+ }
407
+
408
+ /**
409
+ * Clear specific persisted data
410
+ * @param keys Array of keys to clear
411
+ */
412
+ static clearPersistedData(keys: string[]): void {
413
+ this.dl.pushEvent('clear', keys);
414
+ }
415
+
416
+ /**
417
+ * Set data layer variables
418
+ * @param data Data to set in the data layer
419
+ */
420
+ static setDataLayer(data: MapLike): void {
421
+ this.dl.pushEvent('set', data);
422
+ }
423
+
424
+ /**
425
+ * Register a custom event processor
426
+ * @param eventType Event type to listen for
427
+ * @param processor Function to process the event
428
+ */
429
+ static registerEventProcessor(
430
+ eventType: string,
431
+ processor: (payload: any) => void
432
+ ): void {
433
+ this.dl.registerProcessor(eventType, processor);
434
+ }
435
+
436
+ /**
437
+ * Get current data layer state
438
+ * @returns Current data layer object
439
+ */
440
+ static getDataLayer(): MapLike {
441
+ return this.dl.getDl();
442
+ }
443
+
444
+ /**
445
+ * Get event state tracker
446
+ * @returns Array of all tracked events
447
+ */
448
+ static getEventState(): any[] {
449
+ return this.dl.getState();
450
+ }
451
+
452
+ /**
453
+ * Check if a specific event has happened
454
+ * @param eventName Event name to check
455
+ * @returns True if event has occurred
456
+ */
457
+ static hasEventHappened(eventName: string): boolean {
458
+ return this.dl.hasEventHappened(eventName);
459
+ }
364
460
  }
365
461
 
366
462
  export const MagicPixelEventBus = EventBus;
@@ -0,0 +1,13 @@
1
+ export interface GeoResponse {
2
+ ip: string;
3
+ city: string;
4
+ country: string;
5
+ region: string;
6
+ loc: string;
7
+ postal: string;
8
+ }
9
+
10
+ export interface GeoApiResponse {
11
+ status: 'OK' | 'KO';
12
+ info: GeoResponse;
13
+ }