@datalyr/react-native 1.1.1 → 1.2.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.
Files changed (42) hide show
  1. package/CHANGELOG.md +24 -141
  2. package/LICENSE +21 -0
  3. package/README.md +405 -217
  4. package/datalyr-react-native.podspec +31 -0
  5. package/ios/DatalyrNative.m +70 -0
  6. package/ios/DatalyrNative.swift +275 -0
  7. package/ios/DatalyrSKAdNetwork.m +26 -0
  8. package/lib/datalyr-sdk.d.ts +64 -3
  9. package/lib/datalyr-sdk.js +322 -3
  10. package/lib/index.d.ts +1 -0
  11. package/lib/index.js +4 -2
  12. package/lib/integrations/index.d.ts +6 -0
  13. package/lib/integrations/index.js +6 -0
  14. package/lib/integrations/meta-integration.d.ts +76 -0
  15. package/lib/integrations/meta-integration.js +218 -0
  16. package/lib/integrations/tiktok-integration.d.ts +82 -0
  17. package/lib/integrations/tiktok-integration.js +356 -0
  18. package/lib/native/DatalyrNativeBridge.d.ts +31 -0
  19. package/lib/native/DatalyrNativeBridge.js +168 -0
  20. package/lib/native/index.d.ts +5 -0
  21. package/lib/native/index.js +5 -0
  22. package/lib/types.d.ts +29 -0
  23. package/package.json +10 -5
  24. package/src/datalyr-sdk-expo.ts +957 -0
  25. package/src/datalyr-sdk.ts +419 -19
  26. package/src/expo.ts +38 -18
  27. package/src/index.ts +5 -2
  28. package/src/integrations/index.ts +7 -0
  29. package/src/integrations/meta-integration.ts +238 -0
  30. package/src/integrations/tiktok-integration.ts +360 -0
  31. package/src/native/DatalyrNativeBridge.ts +271 -0
  32. package/src/native/index.ts +11 -0
  33. package/src/types.ts +39 -0
  34. package/src/utils-expo.ts +25 -3
  35. package/src/utils-interface.ts +38 -0
  36. package/EXPO_INSTALL.md +0 -297
  37. package/INSTALL.md +0 -402
  38. package/examples/attribution-example.tsx +0 -377
  39. package/examples/auto-events-example.tsx +0 -403
  40. package/examples/example.tsx +0 -250
  41. package/examples/skadnetwork-example.tsx +0 -380
  42. package/examples/test-implementation.tsx +0 -163
@@ -0,0 +1,271 @@
1
+ /**
2
+ * Native Bridge for Meta and TikTok SDKs
3
+ * Uses bundled native modules instead of separate npm packages
4
+ */
5
+
6
+ import { NativeModules, Platform } from 'react-native';
7
+
8
+ interface DatalyrNativeModule {
9
+ // Meta SDK Methods
10
+ initializeMetaSDK(
11
+ appId: string,
12
+ clientToken: string | null,
13
+ advertiserTrackingEnabled: boolean
14
+ ): Promise<boolean>;
15
+ fetchDeferredAppLink(): Promise<string | null>;
16
+ logMetaEvent(
17
+ eventName: string,
18
+ valueToSum: number | null,
19
+ parameters: Record<string, any> | null
20
+ ): Promise<boolean>;
21
+ logMetaPurchase(
22
+ amount: number,
23
+ currency: string,
24
+ parameters: Record<string, any> | null
25
+ ): Promise<boolean>;
26
+ setMetaUserData(userData: Record<string, string | undefined>): Promise<boolean>;
27
+ clearMetaUserData(): Promise<boolean>;
28
+ updateMetaTrackingAuthorization(enabled: boolean): Promise<boolean>;
29
+
30
+ // TikTok SDK Methods
31
+ initializeTikTokSDK(
32
+ appId: string,
33
+ tiktokAppId: string,
34
+ accessToken: string | null,
35
+ debug: boolean
36
+ ): Promise<boolean>;
37
+ trackTikTokEvent(
38
+ eventName: string,
39
+ eventId: string | null,
40
+ properties: Record<string, any> | null
41
+ ): Promise<boolean>;
42
+ identifyTikTokUser(
43
+ externalId: string,
44
+ externalUserName: string,
45
+ phoneNumber: string,
46
+ email: string
47
+ ): Promise<boolean>;
48
+ logoutTikTok(): Promise<boolean>;
49
+ updateTikTokTrackingAuthorization(enabled: boolean): Promise<boolean>;
50
+
51
+ // SDK Availability
52
+ getSDKAvailability(): Promise<{ meta: boolean; tiktok: boolean }>;
53
+ }
54
+
55
+ // Native module is only available on iOS
56
+ const DatalyrNative: DatalyrNativeModule | null =
57
+ Platform.OS === 'ios' ? NativeModules.DatalyrNative : null;
58
+
59
+ /**
60
+ * Check if native module is available
61
+ */
62
+ export const isNativeModuleAvailable = (): boolean => {
63
+ return DatalyrNative !== null;
64
+ };
65
+
66
+ /**
67
+ * Get SDK availability status
68
+ */
69
+ export const getSDKAvailability = async (): Promise<{
70
+ meta: boolean;
71
+ tiktok: boolean;
72
+ }> => {
73
+ if (!DatalyrNative) {
74
+ return { meta: false, tiktok: false };
75
+ }
76
+
77
+ try {
78
+ return await DatalyrNative.getSDKAvailability();
79
+ } catch {
80
+ return { meta: false, tiktok: false };
81
+ }
82
+ };
83
+
84
+ // MARK: - Meta SDK Bridge
85
+
86
+ export const MetaNativeBridge = {
87
+ async initialize(
88
+ appId: string,
89
+ clientToken?: string,
90
+ advertiserTrackingEnabled: boolean = false
91
+ ): Promise<boolean> {
92
+ if (!DatalyrNative) return false;
93
+
94
+ try {
95
+ return await DatalyrNative.initializeMetaSDK(
96
+ appId,
97
+ clientToken || null,
98
+ advertiserTrackingEnabled
99
+ );
100
+ } catch (error) {
101
+ console.error('[Datalyr/MetaNative] Initialize failed:', error);
102
+ return false;
103
+ }
104
+ },
105
+
106
+ async fetchDeferredAppLink(): Promise<string | null> {
107
+ if (!DatalyrNative) return null;
108
+
109
+ try {
110
+ return await DatalyrNative.fetchDeferredAppLink();
111
+ } catch {
112
+ return null;
113
+ }
114
+ },
115
+
116
+ async logEvent(
117
+ eventName: string,
118
+ valueToSum?: number,
119
+ parameters?: Record<string, any>
120
+ ): Promise<boolean> {
121
+ if (!DatalyrNative) return false;
122
+
123
+ try {
124
+ return await DatalyrNative.logMetaEvent(
125
+ eventName,
126
+ valueToSum ?? null,
127
+ parameters || null
128
+ );
129
+ } catch (error) {
130
+ console.error('[Datalyr/MetaNative] Log event failed:', error);
131
+ return false;
132
+ }
133
+ },
134
+
135
+ async logPurchase(
136
+ amount: number,
137
+ currency: string,
138
+ parameters?: Record<string, any>
139
+ ): Promise<boolean> {
140
+ if (!DatalyrNative) return false;
141
+
142
+ try {
143
+ return await DatalyrNative.logMetaPurchase(amount, currency, parameters || null);
144
+ } catch (error) {
145
+ console.error('[Datalyr/MetaNative] Log purchase failed:', error);
146
+ return false;
147
+ }
148
+ },
149
+
150
+ async setUserData(userData: Record<string, string | undefined>): Promise<boolean> {
151
+ if (!DatalyrNative) return false;
152
+
153
+ try {
154
+ return await DatalyrNative.setMetaUserData(userData);
155
+ } catch (error) {
156
+ console.error('[Datalyr/MetaNative] Set user data failed:', error);
157
+ return false;
158
+ }
159
+ },
160
+
161
+ async clearUserData(): Promise<boolean> {
162
+ if (!DatalyrNative) return false;
163
+
164
+ try {
165
+ return await DatalyrNative.clearMetaUserData();
166
+ } catch (error) {
167
+ console.error('[Datalyr/MetaNative] Clear user data failed:', error);
168
+ return false;
169
+ }
170
+ },
171
+
172
+ async updateTrackingAuthorization(enabled: boolean): Promise<boolean> {
173
+ if (!DatalyrNative) return false;
174
+
175
+ try {
176
+ return await DatalyrNative.updateMetaTrackingAuthorization(enabled);
177
+ } catch (error) {
178
+ console.error('[Datalyr/MetaNative] Update tracking failed:', error);
179
+ return false;
180
+ }
181
+ },
182
+ };
183
+
184
+ // MARK: - TikTok SDK Bridge
185
+
186
+ export const TikTokNativeBridge = {
187
+ async initialize(
188
+ appId: string,
189
+ tiktokAppId: string,
190
+ accessToken?: string,
191
+ debug: boolean = false
192
+ ): Promise<boolean> {
193
+ if (!DatalyrNative) return false;
194
+
195
+ try {
196
+ return await DatalyrNative.initializeTikTokSDK(
197
+ appId,
198
+ tiktokAppId,
199
+ accessToken || null,
200
+ debug
201
+ );
202
+ } catch (error) {
203
+ console.error('[Datalyr/TikTokNative] Initialize failed:', error);
204
+ return false;
205
+ }
206
+ },
207
+
208
+ async trackEvent(
209
+ eventName: string,
210
+ eventId?: string,
211
+ properties?: Record<string, any>
212
+ ): Promise<boolean> {
213
+ if (!DatalyrNative) return false;
214
+
215
+ try {
216
+ return await DatalyrNative.trackTikTokEvent(
217
+ eventName,
218
+ eventId || null,
219
+ properties || null
220
+ );
221
+ } catch (error) {
222
+ console.error('[Datalyr/TikTokNative] Track event failed:', error);
223
+ return false;
224
+ }
225
+ },
226
+
227
+ async identify(
228
+ externalId?: string,
229
+ email?: string,
230
+ phone?: string
231
+ ): Promise<boolean> {
232
+ if (!DatalyrNative) return false;
233
+
234
+ // Only call if we have at least one value
235
+ if (!externalId && !email && !phone) return false;
236
+
237
+ try {
238
+ return await DatalyrNative.identifyTikTokUser(
239
+ externalId || '',
240
+ '', // externalUserName - not typically available
241
+ phone || '',
242
+ email || ''
243
+ );
244
+ } catch (error) {
245
+ console.error('[Datalyr/TikTokNative] Identify failed:', error);
246
+ return false;
247
+ }
248
+ },
249
+
250
+ async logout(): Promise<boolean> {
251
+ if (!DatalyrNative) return false;
252
+
253
+ try {
254
+ return await DatalyrNative.logoutTikTok();
255
+ } catch (error) {
256
+ console.error('[Datalyr/TikTokNative] Logout failed:', error);
257
+ return false;
258
+ }
259
+ },
260
+
261
+ async updateTrackingAuthorization(enabled: boolean): Promise<boolean> {
262
+ if (!DatalyrNative) return false;
263
+
264
+ try {
265
+ return await DatalyrNative.updateTikTokTrackingAuthorization(enabled);
266
+ } catch (error) {
267
+ console.error('[Datalyr/TikTokNative] Update tracking failed:', error);
268
+ return false;
269
+ }
270
+ },
271
+ };
@@ -0,0 +1,11 @@
1
+ /**
2
+ * Native Module Exports
3
+ */
4
+
5
+ export { SKAdNetworkBridge } from './SKAdNetworkBridge';
6
+ export {
7
+ isNativeModuleAvailable,
8
+ getSDKAvailability,
9
+ MetaNativeBridge,
10
+ TikTokNativeBridge,
11
+ } from './DatalyrNativeBridge';
package/src/types.ts CHANGED
@@ -7,6 +7,39 @@ export interface AutoEventConfig {
7
7
  sessionTimeoutMs?: number;
8
8
  }
9
9
 
10
+ // Meta (Facebook) SDK Configuration
11
+ export interface MetaConfig {
12
+ appId: string; // Facebook App ID
13
+ clientToken?: string; // Client Token for advanced features
14
+ enableDeferredDeepLink?: boolean; // Default: true
15
+ enableAppEvents?: boolean; // Default: true
16
+ advertiserTrackingEnabled?: boolean; // iOS ATT status (auto-detected if not set)
17
+ }
18
+
19
+ // TikTok SDK Configuration
20
+ export interface TikTokConfig {
21
+ appId: string; // Your App ID (for Datalyr)
22
+ tiktokAppId: string; // TikTok App ID
23
+ accessToken?: string; // Access Token for Events API
24
+ enableAppEvents?: boolean; // Default: true
25
+ }
26
+
27
+ // Deferred Deep Link Result (from platform SDKs)
28
+ export interface DeferredDeepLinkResult {
29
+ url?: string;
30
+ source?: string;
31
+ fbclid?: string;
32
+ ttclid?: string;
33
+ utmSource?: string;
34
+ utmMedium?: string;
35
+ utmCampaign?: string;
36
+ utmContent?: string;
37
+ utmTerm?: string;
38
+ campaignId?: string;
39
+ adsetId?: string;
40
+ adId?: string;
41
+ }
42
+
10
43
  // Core SDK Configuration
11
44
  export interface DatalyrConfig {
12
45
  apiKey: string; // Required for server-side tracking
@@ -33,6 +66,12 @@ export interface DatalyrConfig {
33
66
  retryDelay: number;
34
67
  };
35
68
  skadTemplate?: 'ecommerce' | 'gaming' | 'subscription';
69
+
70
+ // Meta (Facebook) SDK Configuration
71
+ meta?: MetaConfig;
72
+
73
+ // TikTok SDK Configuration
74
+ tiktok?: TikTokConfig;
36
75
  }
37
76
  // Event Types
38
77
  export interface EventData {
package/src/utils-expo.ts CHANGED
@@ -9,13 +9,16 @@ import { v4 as uuidv4 } from 'uuid';
9
9
  // Storage keys
10
10
  export const STORAGE_KEYS = {
11
11
  VISITOR_ID: '@datalyr/visitor_id',
12
+ ANONYMOUS_ID: '@datalyr/anonymous_id', // Persistent anonymous identifier
12
13
  SESSION_ID: '@datalyr/session_id',
13
14
  SESSION_START: '@datalyr/session_start',
14
15
  USER_ID: '@datalyr/user_id',
15
16
  USER_PROPERTIES: '@datalyr/user_properties',
17
+ EVENT_QUEUE: '@datalyr/event_queue',
16
18
  ATTRIBUTION_DATA: '@datalyr/attribution_data',
17
19
  INSTALL_TIME: '@datalyr/install_time',
18
20
  LAST_APP_VERSION: '@datalyr/last_app_version',
21
+ LAST_SESSION_TIME: '@datalyr/last_session_time',
19
22
  DEVICE_ID: '@datalyr/device_id',
20
23
  } as const;
21
24
 
@@ -136,17 +139,17 @@ const getOrCreateDeviceId = async (): Promise<string> => {
136
139
  }
137
140
  };
138
141
 
139
- // Visitor ID management
142
+ // Visitor ID management
140
143
  export const getOrCreateVisitorId = async (): Promise<string> => {
141
144
  try {
142
145
  let visitorId = await Storage.getItem<string>(STORAGE_KEYS.VISITOR_ID);
143
-
146
+
144
147
  if (!visitorId) {
145
148
  visitorId = generateUUID();
146
149
  await Storage.setItem(STORAGE_KEYS.VISITOR_ID, visitorId);
147
150
  debugLog('Created new visitor ID:', visitorId);
148
151
  }
149
-
152
+
150
153
  return visitorId;
151
154
  } catch (error) {
152
155
  errorLog('Error managing visitor ID:', error as Error);
@@ -154,6 +157,25 @@ export const getOrCreateVisitorId = async (): Promise<string> => {
154
157
  }
155
158
  };
156
159
 
160
+ // Anonymous ID management - persistent across app reinstalls
161
+ export const getOrCreateAnonymousId = async (): Promise<string> => {
162
+ try {
163
+ let anonymousId = await Storage.getItem<string>(STORAGE_KEYS.ANONYMOUS_ID);
164
+
165
+ if (!anonymousId) {
166
+ // Generate anonymous_id with anon_ prefix to match web SDK
167
+ anonymousId = `anon_${generateUUID()}`;
168
+ await Storage.setItem(STORAGE_KEYS.ANONYMOUS_ID, anonymousId);
169
+ debugLog('Created new anonymous ID:', anonymousId);
170
+ }
171
+
172
+ return anonymousId;
173
+ } catch (error) {
174
+ errorLog('Error managing anonymous ID:', error as Error);
175
+ return `anon_${generateUUID()}`;
176
+ }
177
+ };
178
+
157
179
  // Session management
158
180
  export const getOrCreateSessionId = async (): Promise<string> => {
159
181
  try {
@@ -0,0 +1,38 @@
1
+ /**
2
+ * Interface for SDK utilities
3
+ * Both utils.ts and utils-expo.ts implement this interface
4
+ */
5
+
6
+ import { DeviceInfo, FingerprintData } from './types';
7
+
8
+ export interface SDKUtils {
9
+ STORAGE_KEYS: {
10
+ VISITOR_ID: string;
11
+ ANONYMOUS_ID: string;
12
+ SESSION_ID: string;
13
+ USER_ID: string;
14
+ USER_PROPERTIES: string;
15
+ EVENT_QUEUE: string;
16
+ ATTRIBUTION_DATA: string;
17
+ LAST_SESSION_TIME: string;
18
+ };
19
+
20
+ generateUUID: () => string;
21
+ getOrCreateVisitorId: () => Promise<string>;
22
+ getOrCreateAnonymousId: () => Promise<string>;
23
+ getOrCreateSessionId: () => Promise<string>;
24
+ getDeviceInfo: () => Promise<DeviceInfo>;
25
+ createFingerprintData: () => Promise<FingerprintData>;
26
+ getNetworkType: () => string | Promise<string>;
27
+ validateEventName: (eventName: string) => boolean;
28
+ validateEventData: (eventData: any) => boolean;
29
+ debugLog: (message: string, ...args: any[]) => void;
30
+ errorLog: (message: string, error?: Error) => void;
31
+
32
+ Storage: {
33
+ setItem: (key: string, value: any) => Promise<void>;
34
+ getItem: <T>(key: string) => Promise<T | null>;
35
+ removeItem: (key: string) => Promise<void>;
36
+ clear?: () => Promise<void>;
37
+ };
38
+ }