mimz-react-native-tracker 1.0.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/src/index.js ADDED
@@ -0,0 +1,47 @@
1
+ /**
2
+ * Mimz React Native Tracker SDK
3
+ *
4
+ * Analytics tracking SDK for React Native apps.
5
+ * This is the native equivalent of the Mimz web tracking script.
6
+ *
7
+ * @module mimz-react-native-tracker
8
+ *
9
+ * @example
10
+ * // 1. Install dependencies:
11
+ * // npm install mimz-react-native-tracker @react-native-async-storage/async-storage
12
+ *
13
+ * // 2. Initialize in your App.js or entry file:
14
+ * import AsyncStorage from '@react-native-async-storage/async-storage';
15
+ * import MimzTracker from 'mimz-react-native-tracker';
16
+ *
17
+ * // In your app startup:
18
+ * await MimzTracker.init({
19
+ * clientId: 'YOUR_MIMZ_CLIENT_ID', // From Mimz dashboard
20
+ * backendUrl: 'https://your-mimz-backend.com',
21
+ * asyncStorage: AsyncStorage,
22
+ * appName: 'MyApp',
23
+ * appVersion: '1.0.0',
24
+ * });
25
+ *
26
+ * // 3. Track deep links (for UTM tracking):
27
+ * MimzTracker.trackDeepLink('myapp://open?utm_source=facebook&utm_campaign=promo');
28
+ *
29
+ * // 4. Track screen views:
30
+ * MimzTracker.trackScreenView('HomeScreen');
31
+ *
32
+ * // 5. Track events:
33
+ * MimzTracker.trackEvent('add_to_cart', { productId: '123', price: 29.99 });
34
+ *
35
+ * // 6. Track conversions:
36
+ * MimzTracker.trackConversion({ productName: 'Premium Plan', value: 49.99 });
37
+ *
38
+ * // 7. Track contacts:
39
+ * MimzTracker.trackContact({ email: 'user@example.com', name: 'John', phone: '+123456' });
40
+ *
41
+ * // 8. Flush on app background:
42
+ * MimzTracker.flush();
43
+ */
44
+
45
+ const tracker = require('./tracker');
46
+
47
+ module.exports = tracker;
package/src/network.js ADDED
@@ -0,0 +1,134 @@
1
+ /**
2
+ * MimzNetwork - Network layer for sending tracking data to the Mimz backend
3
+ * Replaces browser fetch/sendBeacon with React Native compatible fetch
4
+ */
5
+
6
+ const DEFAULT_TIMEOUT_MS = 5000;
7
+ const MAX_RETRY_ATTEMPTS = 2;
8
+ const RETRY_DELAY_MS = 1000;
9
+
10
+ let backendUrl = '';
11
+
12
+ /**
13
+ * Initialize the network layer with the backend URL
14
+ * @param {string} url - The Mimz backend base URL (e.g., https://mimz-backend.onrender.com)
15
+ */
16
+ const init = (url) => {
17
+ // Normalize: remove trailing slash
18
+ backendUrl = url.replace(/\/+$/, '');
19
+ };
20
+
21
+ /**
22
+ * Send data to the Mimz backend with timeout and retry
23
+ * @param {string} endpoint - API endpoint path (e.g., /api/visitors/add-visitors)
24
+ * @param {object} data - The payload to send
25
+ * @param {object} options - Optional configuration
26
+ * @param {number} options.timeout - Request timeout in ms (default: 5000)
27
+ * @param {number} options.retries - Number of retry attempts (default: 2)
28
+ * @returns {Promise<object|null>} - The response data or null on failure
29
+ */
30
+ const post = async (endpoint, data, options = {}) => {
31
+ const { timeout = DEFAULT_TIMEOUT_MS, retries = MAX_RETRY_ATTEMPTS } = options;
32
+
33
+ if (!backendUrl) {
34
+ console.warn('[MimzTracker] Backend URL not set. Call MimzTracker.init() first.');
35
+ return null;
36
+ }
37
+
38
+ const url = `${backendUrl}${endpoint}`;
39
+ let lastError = null;
40
+
41
+ for (let attempt = 0; attempt <= retries; attempt++) {
42
+ try {
43
+ const controller = typeof AbortController !== 'undefined' ? new AbortController() : null;
44
+ const timeoutId = controller ? setTimeout(() => controller.abort(), timeout) : null;
45
+
46
+ const response = await fetch(url, {
47
+ method: 'POST',
48
+ headers: {
49
+ 'Content-Type': 'application/json',
50
+ Accept: 'application/json',
51
+ 'X-Requested-With': 'MimzReactNativeSDK',
52
+ },
53
+ body: JSON.stringify(data),
54
+ signal: controller?.signal,
55
+ });
56
+
57
+ if (timeoutId) clearTimeout(timeoutId);
58
+
59
+ if (!response.ok) {
60
+ throw new Error(`Server responded with status ${response.status}: ${response.statusText}`);
61
+ }
62
+
63
+ const responseData = await response.json();
64
+ return responseData;
65
+ } catch (error) {
66
+ lastError = error;
67
+
68
+ if (error.name === 'AbortError') {
69
+ console.warn(`[MimzTracker] Request to ${endpoint} timed out (attempt ${attempt + 1}/${retries + 1})`);
70
+ } else {
71
+ console.warn(`[MimzTracker] Request to ${endpoint} failed (attempt ${attempt + 1}/${retries + 1}):`, error.message);
72
+ }
73
+
74
+ // Wait before retrying (skip delay on last attempt)
75
+ if (attempt < retries) {
76
+ await new Promise((resolve) => setTimeout(resolve, RETRY_DELAY_MS * (attempt + 1)));
77
+ }
78
+ }
79
+ }
80
+
81
+ console.error(`[MimzTracker] All ${retries + 1} attempts to ${endpoint} failed. Last error:`, lastError?.message);
82
+ return null;
83
+ };
84
+
85
+ /**
86
+ * Get data from the Mimz backend
87
+ * @param {string} endpoint - API endpoint path
88
+ * @param {object} params - Query parameters
89
+ * @returns {Promise<object|null>}
90
+ */
91
+ const get = async (endpoint, params = {}) => {
92
+ if (!backendUrl) {
93
+ console.warn('[MimzTracker] Backend URL not set.');
94
+ return null;
95
+ }
96
+
97
+ const queryString = Object.entries(params)
98
+ .filter(([, v]) => v != null)
99
+ .map(([k, v]) => `${encodeURIComponent(k)}=${encodeURIComponent(v)}`)
100
+ .join('&');
101
+
102
+ const url = `${backendUrl}${endpoint}${queryString ? '?' + queryString : ''}`;
103
+
104
+ try {
105
+ const controller = typeof AbortController !== 'undefined' ? new AbortController() : null;
106
+ const timeoutId = controller ? setTimeout(() => controller.abort(), DEFAULT_TIMEOUT_MS) : null;
107
+
108
+ const response = await fetch(url, {
109
+ method: 'GET',
110
+ headers: {
111
+ Accept: 'application/json',
112
+ 'X-Requested-With': 'MimzReactNativeSDK',
113
+ },
114
+ signal: controller?.signal,
115
+ });
116
+
117
+ if (timeoutId) clearTimeout(timeoutId);
118
+
119
+ if (!response.ok) {
120
+ throw new Error(`Server responded with status ${response.status}`);
121
+ }
122
+
123
+ return await response.json();
124
+ } catch (error) {
125
+ console.warn(`[MimzTracker] GET ${endpoint} failed:`, error.message);
126
+ return null;
127
+ }
128
+ };
129
+
130
+ module.exports = {
131
+ init,
132
+ post,
133
+ get,
134
+ };
package/src/storage.js ADDED
@@ -0,0 +1,117 @@
1
+ /**
2
+ * MimzStorage - Persistent storage adapter for React Native
3
+ * Replaces browser cookies/localStorage with AsyncStorage
4
+ */
5
+
6
+ let AsyncStorage = null;
7
+
8
+ /**
9
+ * Initialize the storage adapter with AsyncStorage instance
10
+ * @param {object} asyncStorageInstance - The AsyncStorage module from @react-native-async-storage/async-storage
11
+ */
12
+ const init = (asyncStorageInstance) => {
13
+ AsyncStorage = asyncStorageInstance;
14
+ };
15
+
16
+ /**
17
+ * Get a value from persistent storage
18
+ * @param {string} key
19
+ * @returns {Promise<string|null>}
20
+ */
21
+ const get = async (key) => {
22
+ if (!AsyncStorage) {
23
+ console.warn('[MimzTracker] AsyncStorage not initialized. Call MimzTracker.init() first.');
24
+ return null;
25
+ }
26
+ try {
27
+ const value = await AsyncStorage.getItem(`@mimz_${key}`);
28
+ return value;
29
+ } catch (error) {
30
+ console.warn(`[MimzTracker] Error reading "${key}" from storage:`, error.message);
31
+ return null;
32
+ }
33
+ };
34
+
35
+ /**
36
+ * Set a value in persistent storage
37
+ * @param {string} key
38
+ * @param {string} value
39
+ * @returns {Promise<void>}
40
+ */
41
+ const set = async (key, value) => {
42
+ if (!AsyncStorage) {
43
+ console.warn('[MimzTracker] AsyncStorage not initialized. Call MimzTracker.init() first.');
44
+ return;
45
+ }
46
+ try {
47
+ await AsyncStorage.setItem(`@mimz_${key}`, String(value));
48
+ } catch (error) {
49
+ console.warn(`[MimzTracker] Error writing "${key}" to storage:`, error.message);
50
+ }
51
+ };
52
+
53
+ /**
54
+ * Remove a value from persistent storage
55
+ * @param {string} key
56
+ * @returns {Promise<void>}
57
+ */
58
+ const remove = async (key) => {
59
+ if (!AsyncStorage) return;
60
+ try {
61
+ await AsyncStorage.removeItem(`@mimz_${key}`);
62
+ } catch (error) {
63
+ console.warn(`[MimzTracker] Error removing "${key}" from storage:`, error.message);
64
+ }
65
+ };
66
+
67
+ /**
68
+ * Get a JSON object from storage
69
+ * @param {string} key
70
+ * @returns {Promise<object|null>}
71
+ */
72
+ const getJSON = async (key) => {
73
+ const raw = await get(key);
74
+ if (!raw) return null;
75
+ try {
76
+ return JSON.parse(raw);
77
+ } catch {
78
+ return null;
79
+ }
80
+ };
81
+
82
+ /**
83
+ * Set a JSON object in storage
84
+ * @param {string} key
85
+ * @param {object} value
86
+ * @returns {Promise<void>}
87
+ */
88
+ const setJSON = async (key, value) => {
89
+ await set(key, JSON.stringify(value));
90
+ };
91
+
92
+ /**
93
+ * Clear all Mimz-related storage keys
94
+ * @returns {Promise<void>}
95
+ */
96
+ const clearAll = async () => {
97
+ if (!AsyncStorage) return;
98
+ try {
99
+ const allKeys = await AsyncStorage.getAllKeys();
100
+ const mimzKeys = allKeys.filter((key) => key.startsWith('@mimz_'));
101
+ if (mimzKeys.length > 0) {
102
+ await AsyncStorage.multiRemove(mimzKeys);
103
+ }
104
+ } catch (error) {
105
+ console.warn('[MimzTracker] Error clearing storage:', error.message);
106
+ }
107
+ };
108
+
109
+ module.exports = {
110
+ init,
111
+ get,
112
+ set,
113
+ remove,
114
+ getJSON,
115
+ setJSON,
116
+ clearAll,
117
+ };