@magicpixel/rn-mp-client-sdk 1.13.0 → 1.13.21
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/README.md +163 -14
- package/lib/commonjs/common/app-types.js.map +1 -1
- package/lib/commonjs/common/constants.js +11 -2
- package/lib/commonjs/common/constants.js.map +1 -1
- package/lib/commonjs/common/data-store.js +13 -30
- package/lib/commonjs/common/data-store.js.map +1 -1
- package/lib/commonjs/common/deeplink-helper.js +174 -0
- package/lib/commonjs/common/deeplink-helper.js.map +1 -0
- package/lib/commonjs/common/device-info-helper.js +168 -0
- package/lib/commonjs/common/device-info-helper.js.map +1 -0
- package/lib/commonjs/common/event-bus.js +39 -0
- package/lib/commonjs/common/event-bus.js.map +1 -1
- package/lib/commonjs/common/network-service.js +119 -15
- package/lib/commonjs/common/network-service.js.map +1 -1
- package/lib/commonjs/common/reporter.js +75 -14
- package/lib/commonjs/common/reporter.js.map +1 -1
- package/lib/commonjs/common/storage-helper.js +227 -0
- package/lib/commonjs/common/storage-helper.js.map +1 -0
- package/lib/commonjs/common/utils.js +62 -2
- package/lib/commonjs/common/utils.js.map +1 -1
- package/lib/commonjs/eedl/eedl.js +198 -44
- package/lib/commonjs/eedl/eedl.js.map +1 -1
- package/lib/commonjs/index.js +301 -54
- package/lib/commonjs/index.js.map +1 -1
- package/lib/commonjs/models/mp-client-sdk.js +17 -10
- package/lib/commonjs/models/mp-client-sdk.js.map +1 -1
- package/lib/commonjs/processors/data-element.processor.js +51 -7
- package/lib/commonjs/processors/data-element.processor.js.map +1 -1
- package/lib/commonjs/processors/visit-id.processor.js +78 -15
- package/lib/commonjs/processors/visit-id.processor.js.map +1 -1
- package/lib/module/common/app-types.js.map +1 -1
- package/lib/module/common/constants.js +11 -2
- package/lib/module/common/constants.js.map +1 -1
- package/lib/module/common/data-store.js +13 -30
- package/lib/module/common/data-store.js.map +1 -1
- package/lib/module/common/deeplink-helper.js +168 -0
- package/lib/module/common/deeplink-helper.js.map +1 -0
- package/lib/module/common/device-info-helper.js +161 -0
- package/lib/module/common/device-info-helper.js.map +1 -0
- package/lib/module/common/event-bus.js +39 -0
- package/lib/module/common/event-bus.js.map +1 -1
- package/lib/module/common/network-service.js +119 -15
- package/lib/module/common/network-service.js.map +1 -1
- package/lib/module/common/reporter.js +76 -14
- package/lib/module/common/reporter.js.map +1 -1
- package/lib/module/common/storage-helper.js +221 -0
- package/lib/module/common/storage-helper.js.map +1 -0
- package/lib/module/common/utils.js +63 -2
- package/lib/module/common/utils.js.map +1 -1
- package/lib/module/eedl/eedl.js +198 -44
- package/lib/module/eedl/eedl.js.map +1 -1
- package/lib/module/index.js +290 -53
- package/lib/module/index.js.map +1 -1
- package/lib/module/models/mp-client-sdk.js +16 -9
- package/lib/module/models/mp-client-sdk.js.map +1 -1
- package/lib/module/processors/data-element.processor.js +51 -7
- package/lib/module/processors/data-element.processor.js.map +1 -1
- package/lib/module/processors/visit-id.processor.js +78 -15
- package/lib/module/processors/visit-id.processor.js.map +1 -1
- package/lib/typescript/{common → src/common}/app-types.d.ts +30 -9
- package/lib/typescript/{common → src/common}/constants.d.ts +0 -1
- package/lib/typescript/{common → src/common}/data-store.d.ts +3 -8
- package/lib/typescript/src/common/deeplink-helper.d.ts +60 -0
- package/lib/typescript/src/common/device-info-helper.d.ts +54 -0
- package/lib/typescript/src/common/event-bus.d.ts +21 -0
- package/lib/typescript/src/common/network-service.d.ts +32 -0
- package/lib/typescript/{common → src/common}/reporter.d.ts +2 -1
- package/lib/typescript/src/common/storage-helper.d.ts +47 -0
- package/lib/typescript/{common → src/common}/utils.d.ts +25 -0
- package/lib/typescript/{eedl → src/eedl}/eedl.d.ts +43 -1
- package/lib/typescript/{index.d.ts → src/index.d.ts} +39 -5
- package/lib/typescript/{models → src/models}/mp-client-sdk.d.ts +7 -0
- package/lib/typescript/src/processors/visit-id.processor.d.ts +23 -0
- package/package.json +25 -36
- package/src/common/app-types.ts +33 -10
- package/src/common/constants.ts +0 -6
- package/src/common/data-store.ts +8 -30
- package/src/common/deeplink-helper.ts +181 -0
- package/src/common/device-info-helper.ts +190 -0
- package/src/common/event-bus.ts +39 -0
- package/src/common/network-service.ts +154 -21
- package/src/common/reporter.ts +97 -16
- package/src/common/storage-helper.ts +260 -0
- package/src/common/utils.ts +63 -2
- package/src/eedl/eedl.ts +225 -51
- package/src/index.tsx +346 -73
- package/src/models/mp-client-sdk.ts +8 -0
- package/src/processors/data-element.processor.ts +85 -7
- package/src/processors/visit-id.processor.ts +92 -22
- package/lib/commonjs/processors/trans-function.processor.js +0 -73
- package/lib/commonjs/processors/trans-function.processor.js.map +0 -1
- package/lib/module/processors/trans-function.processor.js +0 -66
- package/lib/module/processors/trans-function.processor.js.map +0 -1
- package/lib/typescript/common/event-bus.d.ts +0 -6
- package/lib/typescript/common/network-service.d.ts +0 -8
- package/lib/typescript/processors/trans-function.processor.d.ts +0 -12
- package/lib/typescript/processors/visit-id.processor.d.ts +0 -9
- package/src/processors/trans-function.processor.ts +0 -85
- /package/lib/typescript/{common → src/common}/logger.d.ts +0 -0
- /package/lib/typescript/{models → src/models}/geo-api-response.d.ts +0 -0
- /package/lib/typescript/{processors → src/processors}/data-element.processor.d.ts +0 -0
- /package/lib/typescript/{processors → src/processors}/geo-location.processor.d.ts +0 -0
- /package/lib/typescript/{processors → src/processors}/qc.processor.d.ts +0 -0
- /package/lib/typescript/{processors → src/processors}/tag.processor.d.ts +0 -0
package/src/index.tsx
CHANGED
|
@@ -1,3 +1,6 @@
|
|
|
1
|
+
// Polyfill for crypto.getRandomValues() required by ULID
|
|
2
|
+
import 'react-native-get-random-values';
|
|
3
|
+
|
|
1
4
|
import { MpDataLayerHelper } from './eedl/eedl';
|
|
2
5
|
import type {
|
|
3
6
|
AppCustomerInfo,
|
|
@@ -17,9 +20,22 @@ import { NetworkService } from './common/network-service';
|
|
|
17
20
|
import { EventBus } from './common/event-bus';
|
|
18
21
|
import { VisitIdProcessor } from './processors/visit-id.processor';
|
|
19
22
|
import { GeoLocationProcessor } from './processors/geo-location.processor';
|
|
23
|
+
import { DeviceInfoHelper } from './common/device-info-helper';
|
|
24
|
+
import { DeepLinkHelper } from './common/deeplink-helper';
|
|
25
|
+
import { StorageHelper } from './common/storage-helper';
|
|
20
26
|
|
|
21
27
|
const DL_INIT_EVENT = 'page_load';
|
|
22
28
|
|
|
29
|
+
// Maximum number of events to buffer before SDK is ready
|
|
30
|
+
const MAX_BUFFERED_EVENTS = 500;
|
|
31
|
+
|
|
32
|
+
// Type for buffered events
|
|
33
|
+
interface BufferedEvent {
|
|
34
|
+
type: 'pageLoad' | 'event';
|
|
35
|
+
name?: string; // event name for recordEvent
|
|
36
|
+
data: any;
|
|
37
|
+
}
|
|
38
|
+
|
|
23
39
|
class MagicPixelImpl {
|
|
24
40
|
private static dl: MpDataLayerHelper = new MpDataLayerHelper(
|
|
25
41
|
'mpDlEvent',
|
|
@@ -31,26 +47,131 @@ class MagicPixelImpl {
|
|
|
31
47
|
private static customerIdentifiers: MapLike = {};
|
|
32
48
|
|
|
33
49
|
private static deepLinkUrl: string | undefined = undefined;
|
|
50
|
+
private static orgId: string | undefined = undefined;
|
|
34
51
|
|
|
35
52
|
private static firstAppLaunch = true;
|
|
36
53
|
|
|
37
|
-
|
|
54
|
+
// SDK readiness state and event buffer
|
|
55
|
+
private static isReady = false;
|
|
56
|
+
private static isInitializing = false;
|
|
57
|
+
private static eventBuffer: BufferedEvent[] = [];
|
|
58
|
+
private static onInitFailureCallback: ((error: Error) => void) | undefined;
|
|
59
|
+
|
|
60
|
+
/**
|
|
61
|
+
* Initialize the MagicPixel SDK
|
|
62
|
+
* This method is synchronous - it stores config immediately and runs async setup in background
|
|
63
|
+
* Events called before async setup completes are buffered and processed once ready
|
|
64
|
+
* @param options SDK initialization options
|
|
65
|
+
*/
|
|
66
|
+
static init(options: SdkInitOptions): void {
|
|
67
|
+
// Guard against multiple init() calls
|
|
68
|
+
if (this.isReady) {
|
|
69
|
+
Logger.logDbg(
|
|
70
|
+
'MagicPixel SDK already initialized. Ignoring duplicate init() call.'
|
|
71
|
+
);
|
|
72
|
+
return;
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
if (this.isInitializing) {
|
|
76
|
+
Logger.logDbg(
|
|
77
|
+
'MagicPixel SDK initialization in progress. Ignoring duplicate init() call.'
|
|
78
|
+
);
|
|
79
|
+
return;
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
this.isInitializing = true;
|
|
83
|
+
|
|
84
|
+
// Sync setup - happens immediately
|
|
38
85
|
Logger.setLogLevel(options.logLevel ?? 'none');
|
|
86
|
+
this.orgId = options.orgId;
|
|
87
|
+
this.onInitFailureCallback = options.onInitFailure;
|
|
88
|
+
|
|
89
|
+
Logger.logDbg('MagicPixel SDK init started');
|
|
90
|
+
|
|
91
|
+
// Async setup - runs in background, events are buffered until complete
|
|
92
|
+
this.initAsync(options).catch((err) => {
|
|
93
|
+
Logger.logError('MagicPixel SDK initialization failed:', err);
|
|
94
|
+
Reporter.reportError('sdk_init', err);
|
|
95
|
+
|
|
96
|
+
// Reset initializing flag so developer can retry if needed
|
|
97
|
+
this.isInitializing = false;
|
|
98
|
+
|
|
99
|
+
// Call failure callback if provided
|
|
100
|
+
if (this.onInitFailureCallback) {
|
|
101
|
+
const error = err instanceof Error ? err : new Error(String(err));
|
|
102
|
+
this.onInitFailureCallback(error);
|
|
103
|
+
}
|
|
104
|
+
});
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
/**
|
|
108
|
+
* Shutdown the SDK and release all resources
|
|
109
|
+
* Call this when the app is closing or when you need to reinitialize the SDK
|
|
110
|
+
* After shutdown, you must call init() again to use the SDK
|
|
111
|
+
*/
|
|
112
|
+
static shutdown(): void {
|
|
113
|
+
Logger.logDbg('MagicPixel SDK shutting down...');
|
|
114
|
+
|
|
115
|
+
// Clean up deeplink listener and callback
|
|
116
|
+
DeepLinkHelper.cleanup();
|
|
117
|
+
|
|
118
|
+
// Clear all EventBus listeners to prevent duplicates on reinit
|
|
119
|
+
EventBus.clearAll();
|
|
120
|
+
|
|
121
|
+
// Clear session-scoped data element values (in-memory store)
|
|
122
|
+
StorageHelper.clearSessionStore();
|
|
123
|
+
|
|
124
|
+
// Clear event buffer
|
|
125
|
+
this.eventBuffer = [];
|
|
126
|
+
|
|
127
|
+
// Reset state flags
|
|
128
|
+
this.isReady = false;
|
|
129
|
+
this.isInitializing = false;
|
|
130
|
+
this.onInitFailureCallback = undefined;
|
|
131
|
+
|
|
132
|
+
// Reset customer data
|
|
133
|
+
this.customerInfo = undefined as any;
|
|
134
|
+
this.customerIdentifiers = {};
|
|
135
|
+
this.deepLinkUrl = undefined;
|
|
136
|
+
this.firstAppLaunch = true;
|
|
137
|
+
|
|
138
|
+
// Shutdown EEDL
|
|
139
|
+
this.dl.shutdown();
|
|
140
|
+
|
|
141
|
+
Logger.logDbg('MagicPixel SDK shutdown complete');
|
|
142
|
+
}
|
|
143
|
+
|
|
144
|
+
/**
|
|
145
|
+
* Async initialization - runs in background
|
|
146
|
+
*/
|
|
147
|
+
private static async initAsync(options: SdkInitOptions): Promise<void> {
|
|
39
148
|
await NetworkService.refreshClientSdkJson(options);
|
|
40
149
|
|
|
41
150
|
if (!DataStore.isDataStoreReady()) {
|
|
42
|
-
throw new Error(
|
|
151
|
+
throw new Error(
|
|
152
|
+
'MagicPixel SDK: DataStore not ready after config fetch. Initialization failed.'
|
|
153
|
+
);
|
|
43
154
|
}
|
|
44
155
|
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
156
|
+
// Initialize StorageHelper for data element storage duration
|
|
157
|
+
// This loads visitor-scoped values from AsyncStorage and clears expired ones (>30 days)
|
|
158
|
+
await StorageHelper.initialize();
|
|
159
|
+
|
|
160
|
+
// Auto-detect device info - always use detected values to prevent hardcoded values
|
|
161
|
+
const autoDetectedInfo = await DeviceInfoHelper.getAppInfo();
|
|
162
|
+
Logger.logDbg('Auto-detected device info:', autoDetectedInfo);
|
|
52
163
|
|
|
53
|
-
|
|
164
|
+
// Set device type from auto-detection (Expo/react-native-device-info)
|
|
165
|
+
// This is more reliable than dimension-based detection which fails on high-res phones
|
|
166
|
+
const detectedDeviceType = autoDetectedInfo.is_tablet ? 'tablet' : 'mobile';
|
|
167
|
+
DataStore.overrideDeviceType(detectedDeviceType);
|
|
168
|
+
Logger.logDbg('Device type set from auto-detection:', detectedDeviceType);
|
|
169
|
+
|
|
170
|
+
// Always use auto-detected app_version (ignore options.app_version)
|
|
171
|
+
this.setAppVersion(autoDetectedInfo.app_version);
|
|
172
|
+
|
|
173
|
+
// Set device info with auto-detected values (cannot be overridden)
|
|
174
|
+
await this.setDeviceInfo();
|
|
54
175
|
|
|
55
176
|
await VisitIdProcessor.init(options?.orgId);
|
|
56
177
|
|
|
@@ -62,9 +183,39 @@ class MagicPixelImpl {
|
|
|
62
183
|
Logger.logDbg('No facebook client id found. not setting');
|
|
63
184
|
}
|
|
64
185
|
|
|
186
|
+
// Auto-detect deeplink if app was opened via deeplink (e.g., ad click)
|
|
187
|
+
// Supports: custom schemes (myapp://), universal links (https://), app links, HTTP links
|
|
188
|
+
const initialDeepLink = await DeepLinkHelper.initialize((url, linkType) => {
|
|
189
|
+
try {
|
|
190
|
+
Logger.logDbg(`Deeplink detected (${linkType}):`, url);
|
|
191
|
+
|
|
192
|
+
// Store deeplink URL - will be attached to next page_load event
|
|
193
|
+
this.setDeepLinkUrl(url);
|
|
194
|
+
|
|
195
|
+
// Fire deeplink opened event
|
|
196
|
+
// URL params will be parsed and attached to page_load event automatically
|
|
197
|
+
this.recordEvent('deeplink_opened', {
|
|
198
|
+
deep_link_url: url,
|
|
199
|
+
link_type: linkType,
|
|
200
|
+
});
|
|
201
|
+
} catch (err) {
|
|
202
|
+
Logger.logError('Error processing deeplink:', err);
|
|
203
|
+
Reporter.reportError('deeplink_callback', err);
|
|
204
|
+
}
|
|
205
|
+
});
|
|
206
|
+
|
|
207
|
+
if (initialDeepLink) {
|
|
208
|
+
Logger.logDbg('App opened with initial deeplink:', initialDeepLink);
|
|
209
|
+
}
|
|
210
|
+
|
|
65
211
|
// Initialize EEDL with any global event listeners
|
|
66
212
|
await this.dl.init({});
|
|
67
213
|
|
|
214
|
+
// Set event deduplication window if specified (default is 5000ms)
|
|
215
|
+
if (typeof options.eventDeduplicationWindowMs !== 'undefined') {
|
|
216
|
+
this.dl.setDeduplicationWindow(options.eventDeduplicationWindowMs);
|
|
217
|
+
}
|
|
218
|
+
|
|
68
219
|
// Make geo location API call after initialization
|
|
69
220
|
try {
|
|
70
221
|
await GeoLocationProcessor.makeGeoLocationApiCall();
|
|
@@ -81,15 +232,14 @@ class MagicPixelImpl {
|
|
|
81
232
|
Logger.logDbg('Tracking Event:: ', eventName, 'with id:: ', eventId);
|
|
82
233
|
|
|
83
234
|
if (DataStore.shouldExecuteTMForEvent(eventName)) {
|
|
84
|
-
//
|
|
85
|
-
|
|
235
|
+
// Call runTM directly - no queuing, EEDL manages sequential processing
|
|
236
|
+
await this.runTM(
|
|
86
237
|
false,
|
|
87
238
|
`custom_event_${eventName}`,
|
|
88
239
|
eventName,
|
|
89
240
|
eventId,
|
|
90
241
|
eventDataModel
|
|
91
242
|
);
|
|
92
|
-
await this.checkAndFireTM();
|
|
93
243
|
}
|
|
94
244
|
});
|
|
95
245
|
|
|
@@ -100,9 +250,38 @@ class MagicPixelImpl {
|
|
|
100
250
|
}
|
|
101
251
|
|
|
102
252
|
this.ready();
|
|
253
|
+
|
|
254
|
+
// Mark SDK as ready and flush any buffered events
|
|
255
|
+
this.isReady = true;
|
|
256
|
+
this.isInitializing = false;
|
|
257
|
+
Logger.logDbg('SDK is ready, flushing event buffer');
|
|
258
|
+
this.flushEventBuffer();
|
|
103
259
|
}
|
|
104
260
|
|
|
105
261
|
static recordEvent(eventName: string, payload: MapLike): void {
|
|
262
|
+
// Buffer event if SDK is not ready yet
|
|
263
|
+
if (!this.isReady) {
|
|
264
|
+
Logger.logDbg(`SDK not ready, buffering event: ${eventName}`);
|
|
265
|
+
// Evict oldest event if buffer at capacity
|
|
266
|
+
if (this.eventBuffer.length >= MAX_BUFFERED_EVENTS) {
|
|
267
|
+
const evicted = this.eventBuffer.shift();
|
|
268
|
+
Logger.logDbg(
|
|
269
|
+
`Event buffer at capacity (${MAX_BUFFERED_EVENTS}), evicted oldest:`,
|
|
270
|
+
evicted?.type === 'event' ? evicted.name : 'pageLoad'
|
|
271
|
+
);
|
|
272
|
+
}
|
|
273
|
+
this.eventBuffer.push({
|
|
274
|
+
type: 'event',
|
|
275
|
+
name: eventName,
|
|
276
|
+
data: payload,
|
|
277
|
+
});
|
|
278
|
+
return;
|
|
279
|
+
}
|
|
280
|
+
|
|
281
|
+
this.processRecordEvent(eventName, payload);
|
|
282
|
+
}
|
|
283
|
+
|
|
284
|
+
private static processRecordEvent(eventName: string, payload: MapLike): void {
|
|
106
285
|
if (this.customerInfo) {
|
|
107
286
|
const newPayload: MapLike = {
|
|
108
287
|
...payload,
|
|
@@ -123,42 +302,36 @@ class MagicPixelImpl {
|
|
|
123
302
|
this.dl.ready();
|
|
124
303
|
}
|
|
125
304
|
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
305
|
+
/**
|
|
306
|
+
* Flush buffered events after SDK is ready
|
|
307
|
+
* Events are processed in the order they were received
|
|
308
|
+
*/
|
|
309
|
+
private static flushEventBuffer(): void {
|
|
310
|
+
if (this.eventBuffer.length === 0) {
|
|
311
|
+
Logger.logDbg('No buffered events to flush');
|
|
312
|
+
return;
|
|
313
|
+
}
|
|
129
314
|
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
'Payload:: ',
|
|
143
|
-
item.dcrPayload
|
|
144
|
-
);
|
|
145
|
-
await this.runTM(
|
|
146
|
-
item.sseOnly,
|
|
147
|
-
item.name,
|
|
148
|
-
item.dcrName,
|
|
149
|
-
item.eventId,
|
|
150
|
-
item.dcrPayload
|
|
151
|
-
);
|
|
152
|
-
}
|
|
153
|
-
} else {
|
|
154
|
-
Logger.logDbg(
|
|
155
|
-
'Tag Manager is processing or is not ready. This event will start after that'
|
|
156
|
-
);
|
|
315
|
+
Logger.logDbg(`Flushing ${this.eventBuffer.length} buffered event(s)`);
|
|
316
|
+
|
|
317
|
+
// Process all buffered events in order
|
|
318
|
+
while (this.eventBuffer.length > 0) {
|
|
319
|
+
const event = this.eventBuffer.shift()!;
|
|
320
|
+
|
|
321
|
+
if (event.type === 'pageLoad') {
|
|
322
|
+
Logger.logDbg(`Processing buffered page load: ${event.data.page_name}`);
|
|
323
|
+
this.processRecordPageLoad(event.data);
|
|
324
|
+
} else if (event.type === 'event') {
|
|
325
|
+
Logger.logDbg(`Processing buffered event: ${event.name}`);
|
|
326
|
+
this.processRecordEvent(event.name!, event.data);
|
|
157
327
|
}
|
|
158
|
-
} catch (err) {
|
|
159
|
-
Logger.logError('Error check and process tm', err);
|
|
160
|
-
Reporter.reportError('m:checkAndFireTM', err);
|
|
161
328
|
}
|
|
329
|
+
|
|
330
|
+
Logger.logDbg('Event buffer flushed');
|
|
331
|
+
}
|
|
332
|
+
|
|
333
|
+
static getDebugId(): string {
|
|
334
|
+
return DataStore.getDebugId();
|
|
162
335
|
}
|
|
163
336
|
|
|
164
337
|
private static async runTM(
|
|
@@ -178,9 +351,6 @@ class MagicPixelImpl {
|
|
|
178
351
|
eventData
|
|
179
352
|
);
|
|
180
353
|
|
|
181
|
-
// set tag manager in process status
|
|
182
|
-
DataStore.setTagManagerProcessing(true);
|
|
183
|
-
|
|
184
354
|
// process all the data elements and cache them for this run
|
|
185
355
|
await DataElementProcessor.processDataElements(
|
|
186
356
|
DataStore.getSdkDataElements(),
|
|
@@ -200,7 +370,12 @@ class MagicPixelImpl {
|
|
|
200
370
|
DataStore.setPrivacyCompliance(false);
|
|
201
371
|
}
|
|
202
372
|
} else {
|
|
203
|
-
|
|
373
|
+
// No privacy manager configured - default to true (tracking allowed)
|
|
374
|
+
Logger.logDbg(
|
|
375
|
+
'Set: PR Comp: ',
|
|
376
|
+
true,
|
|
377
|
+
'(no privacy manager configured)'
|
|
378
|
+
);
|
|
204
379
|
DataStore.setPrivacyCompliance(true);
|
|
205
380
|
}
|
|
206
381
|
|
|
@@ -236,6 +411,11 @@ class MagicPixelImpl {
|
|
|
236
411
|
[]
|
|
237
412
|
);
|
|
238
413
|
|
|
414
|
+
// Store developer payload (base64 encoded) for report
|
|
415
|
+
if (eventData) {
|
|
416
|
+
Reporter.reportDevPayload(eventData, evtId);
|
|
417
|
+
}
|
|
418
|
+
|
|
239
419
|
const validQCList = QcProcessor.processQc(
|
|
240
420
|
DataStore.getSdkQC(),
|
|
241
421
|
evtName,
|
|
@@ -247,15 +427,15 @@ class MagicPixelImpl {
|
|
|
247
427
|
|
|
248
428
|
TagProcessor.processTags(evtName, evtId)
|
|
249
429
|
.then(() => {
|
|
250
|
-
this._fireTM(sdk.s.ev, sdk.s.ev_id, evtName, evtId);
|
|
430
|
+
this._fireTM(sdk.s.ev, sdk.s.ev_id, evtName, evtId, eventData);
|
|
251
431
|
})
|
|
252
432
|
.catch((err) => {
|
|
253
433
|
Logger.logError('Error processing tag lists.', err);
|
|
254
434
|
Reporter.reportError('i::processTags', err);
|
|
255
|
-
this._fireTM(sdk.s.ev, sdk.s.ev_id, evtName, evtId);
|
|
435
|
+
this._fireTM(sdk.s.ev, sdk.s.ev_id, evtName, evtId, eventData);
|
|
256
436
|
});
|
|
257
437
|
} else {
|
|
258
|
-
this._fireTM(sdk.s.ev, sdk.s.ev_id, evtName, evtId);
|
|
438
|
+
this._fireTM(sdk.s.ev, sdk.s.ev_id, evtName, evtId, eventData);
|
|
259
439
|
}
|
|
260
440
|
} catch (runTMErr) {
|
|
261
441
|
Logger.logError('Error in runTM', runTMErr);
|
|
@@ -267,23 +447,25 @@ class MagicPixelImpl {
|
|
|
267
447
|
envName: string,
|
|
268
448
|
envId: string,
|
|
269
449
|
evtName: string,
|
|
270
|
-
evtId: string
|
|
450
|
+
evtId: string,
|
|
451
|
+
eventData?: Record<string, any>
|
|
271
452
|
): void {
|
|
272
453
|
// increment visit_depth if event name is page_load because that's the only way we can track page views in an app for now
|
|
273
454
|
if (evtName === DL_INIT_EVENT) {
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
});
|
|
277
|
-
} else {
|
|
278
|
-
this._fireTMPrivate(envName, envId, evtName, evtId);
|
|
455
|
+
// Synchronous increment - no race condition possible
|
|
456
|
+
VisitIdProcessor.incrementVisitDepth();
|
|
279
457
|
}
|
|
458
|
+
|
|
459
|
+
// Continue immediately after sync increment
|
|
460
|
+
this._fireTMPrivate(envName, envId, evtName, evtId, eventData);
|
|
280
461
|
}
|
|
281
462
|
|
|
282
463
|
private static _fireTMPrivate(
|
|
283
464
|
envName: string,
|
|
284
465
|
envId: string,
|
|
285
466
|
evtName: string,
|
|
286
|
-
evtId: string
|
|
467
|
+
evtId: string,
|
|
468
|
+
eventData?: Record<string, any>
|
|
287
469
|
): void {
|
|
288
470
|
if (DataStore.hasOneSSTTag() && DataStore.shouldFireSstForEvent(evtName)) {
|
|
289
471
|
Reporter.postSST(
|
|
@@ -292,20 +474,14 @@ class MagicPixelImpl {
|
|
|
292
474
|
envId,
|
|
293
475
|
DataStore.getSSTDownStream(),
|
|
294
476
|
evtName,
|
|
295
|
-
evtId
|
|
477
|
+
evtId,
|
|
478
|
+
eventData
|
|
296
479
|
).catch((err) => {
|
|
297
480
|
Reporter.reportError('l::postSST', err);
|
|
298
481
|
});
|
|
299
482
|
}
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
Utils.sleep(250).then(async () => {
|
|
303
|
-
try {
|
|
304
|
-
await this.checkAndFireTM();
|
|
305
|
-
} catch (err) {
|
|
306
|
-
Reporter.reportError('i::runTM', err);
|
|
307
|
-
}
|
|
308
|
-
});
|
|
483
|
+
// Note: EEDL handles queue progression via its own .finally() block
|
|
484
|
+
// No need to call processNext() here - it would be redundant
|
|
309
485
|
}
|
|
310
486
|
|
|
311
487
|
static setCustomerInfo(customerInfo: AppCustomerInfo): void {
|
|
@@ -321,7 +497,46 @@ class MagicPixelImpl {
|
|
|
321
497
|
this.deepLinkUrl = deepLinkUrl;
|
|
322
498
|
}
|
|
323
499
|
|
|
324
|
-
|
|
500
|
+
/**
|
|
501
|
+
* Set device info with auto-detected values
|
|
502
|
+
* Standard fields (os_version, device_model_name, package_name) are always auto-detected
|
|
503
|
+
* Optional customFields parameter allows adding custom tracking fields only
|
|
504
|
+
* @param customFields Optional custom fields to add (cannot override standard fields)
|
|
505
|
+
*/
|
|
506
|
+
static async setDeviceInfo(
|
|
507
|
+
customFields?: Record<string, any>
|
|
508
|
+
): Promise<void> {
|
|
509
|
+
// Always auto-detect standard device info (cannot be overridden)
|
|
510
|
+
const autoDetectedInfo = await DeviceInfoHelper.getAppInfo();
|
|
511
|
+
|
|
512
|
+
// Standard fields are always auto-detected to prevent hardcoded values
|
|
513
|
+
const deviceInfo: MpDeviceInfo = {
|
|
514
|
+
os_version: autoDetectedInfo.os_version,
|
|
515
|
+
device_model_name: autoDetectedInfo.device_model_name,
|
|
516
|
+
package_name: autoDetectedInfo.package_name,
|
|
517
|
+
};
|
|
518
|
+
|
|
519
|
+
// Add any custom fields (if provided)
|
|
520
|
+
if (customFields) {
|
|
521
|
+
// Filter out attempts to override standard fields
|
|
522
|
+
const allowedCustomFields = { ...customFields };
|
|
523
|
+
delete allowedCustomFields.os_version;
|
|
524
|
+
delete allowedCustomFields.device_model_name;
|
|
525
|
+
delete allowedCustomFields.package_name;
|
|
526
|
+
|
|
527
|
+
Object.assign(deviceInfo, allowedCustomFields);
|
|
528
|
+
|
|
529
|
+
if (
|
|
530
|
+
Object.keys(allowedCustomFields).length !==
|
|
531
|
+
Object.keys(customFields).length
|
|
532
|
+
) {
|
|
533
|
+
Logger.logDbg(
|
|
534
|
+
'Warning: Attempted to override standard device fields. Using auto-detected values instead.'
|
|
535
|
+
);
|
|
536
|
+
}
|
|
537
|
+
}
|
|
538
|
+
|
|
539
|
+
Logger.logDbg('Setting device info:', deviceInfo);
|
|
325
540
|
DataStore.setDeviceInfo(deviceInfo);
|
|
326
541
|
}
|
|
327
542
|
|
|
@@ -336,6 +551,35 @@ class MagicPixelImpl {
|
|
|
336
551
|
}
|
|
337
552
|
|
|
338
553
|
static recordPageLoad(pageLoadInfo: AppPageLoad): void {
|
|
554
|
+
// Buffer page load if SDK is not ready yet
|
|
555
|
+
if (!this.isReady) {
|
|
556
|
+
Logger.logDbg(
|
|
557
|
+
`SDK not ready, buffering page load: ${pageLoadInfo.page_name}`
|
|
558
|
+
);
|
|
559
|
+
// Evict oldest event if buffer at capacity
|
|
560
|
+
if (this.eventBuffer.length >= MAX_BUFFERED_EVENTS) {
|
|
561
|
+
const evicted = this.eventBuffer.shift();
|
|
562
|
+
Logger.logDbg(
|
|
563
|
+
`Event buffer at capacity (${MAX_BUFFERED_EVENTS}), evicted oldest:`,
|
|
564
|
+
evicted?.type === 'event' ? evicted.name : 'pageLoad'
|
|
565
|
+
);
|
|
566
|
+
}
|
|
567
|
+
this.eventBuffer.push({
|
|
568
|
+
type: 'pageLoad',
|
|
569
|
+
data: { ...pageLoadInfo }, // Clone to preserve original data
|
|
570
|
+
});
|
|
571
|
+
return;
|
|
572
|
+
}
|
|
573
|
+
|
|
574
|
+
this.processRecordPageLoad(pageLoadInfo);
|
|
575
|
+
}
|
|
576
|
+
|
|
577
|
+
private static processRecordPageLoad(pageLoadInfo: AppPageLoad): void {
|
|
578
|
+
// Retry visitor ID fetch if it failed during init (fire and forget)
|
|
579
|
+
VisitIdProcessor.retryVisitorIdIfNeeded().catch((err) => {
|
|
580
|
+
Logger.logError('Error retrying visitor ID fetch:', err);
|
|
581
|
+
});
|
|
582
|
+
|
|
339
583
|
pageLoadInfo.is_entry = this.firstAppLaunch ? 1 : 0;
|
|
340
584
|
|
|
341
585
|
// Use stored deepLinkUrl if it exists AND either:
|
|
@@ -345,6 +589,30 @@ class MagicPixelImpl {
|
|
|
345
589
|
pageLoadInfo.deep_link_url = this.deepLinkUrl;
|
|
346
590
|
}
|
|
347
591
|
|
|
592
|
+
// Set page_url for attribution framework
|
|
593
|
+
// Priority: deep_link_url (if present) > constructed URL (v_<orgId>://<screen_name>)
|
|
594
|
+
// Using deep_link_url allows urlp data elements to extract attribution params (gclid, fbclid, etc.)
|
|
595
|
+
if (pageLoadInfo.deep_link_url) {
|
|
596
|
+
pageLoadInfo.page_url = pageLoadInfo.deep_link_url;
|
|
597
|
+
Logger.logDbg(
|
|
598
|
+
'Setting page_url from deep_link_url:',
|
|
599
|
+
pageLoadInfo.page_url
|
|
600
|
+
);
|
|
601
|
+
} else if (this.orgId && pageLoadInfo.page_name) {
|
|
602
|
+
pageLoadInfo.page_url = `v_${this.orgId}://${pageLoadInfo.page_name}`;
|
|
603
|
+
Logger.logDbg(
|
|
604
|
+
'Setting page_url from orgId/page_name:',
|
|
605
|
+
pageLoadInfo.page_url
|
|
606
|
+
);
|
|
607
|
+
} else {
|
|
608
|
+
Logger.logDbg(
|
|
609
|
+
'Not setting page_url. No deep_link_url and orgId or page_name is missing. Org Id is: ',
|
|
610
|
+
this.orgId,
|
|
611
|
+
'page_name is: ',
|
|
612
|
+
pageLoadInfo.page_name
|
|
613
|
+
);
|
|
614
|
+
}
|
|
615
|
+
|
|
348
616
|
const deviceInfo = DataStore.getDeviceInfo();
|
|
349
617
|
|
|
350
618
|
if (this.customerInfo) {
|
|
@@ -352,7 +620,9 @@ class MagicPixelImpl {
|
|
|
352
620
|
...pageLoadInfo,
|
|
353
621
|
...this.customerInfo,
|
|
354
622
|
...(this.customerIdentifiers ?? {}),
|
|
355
|
-
|
|
623
|
+
page_params: Utils.parseQueryParamsToObject(
|
|
624
|
+
pageLoadInfo?.deep_link_url
|
|
625
|
+
),
|
|
356
626
|
};
|
|
357
627
|
|
|
358
628
|
if (deviceInfo) {
|
|
@@ -364,7 +634,9 @@ class MagicPixelImpl {
|
|
|
364
634
|
const newPayload: MapLike = {
|
|
365
635
|
...pageLoadInfo,
|
|
366
636
|
...(this.customerIdentifiers ?? {}),
|
|
367
|
-
|
|
637
|
+
page_params: Utils.parseQueryParamsToObject(
|
|
638
|
+
pageLoadInfo?.deep_link_url
|
|
639
|
+
),
|
|
368
640
|
};
|
|
369
641
|
|
|
370
642
|
if (deviceInfo) {
|
|
@@ -461,3 +733,4 @@ class MagicPixelImpl {
|
|
|
461
733
|
|
|
462
734
|
export const MagicPixelEventBus = EventBus;
|
|
463
735
|
export const MagicPixel = MagicPixelImpl;
|
|
736
|
+
export { DeepLinkHelper, DeepLinkType } from './common/deeplink-helper';
|
|
@@ -10,6 +10,14 @@ export interface ClientSdkDeItem {
|
|
|
10
10
|
fn?: (deHelper: any, input: any) => any;
|
|
11
11
|
isAsync?: boolean;
|
|
12
12
|
fnTOut?: number;
|
|
13
|
+
stDur?: DeStorageDuration; // storage duration
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
export enum DeStorageDuration {
|
|
17
|
+
NONE = 'NONE',
|
|
18
|
+
EVENT = 'EVENT',
|
|
19
|
+
SESSION = 'SESSION',
|
|
20
|
+
VISITOR = 'VISITOR',
|
|
13
21
|
}
|
|
14
22
|
|
|
15
23
|
export enum ParamResourceEncodingType {
|