react-native-edgee 1.0.5 โ†’ 1.0.6

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 CHANGED
@@ -254,7 +254,7 @@ function SomeComponent() {
254
254
  <summary><strong>Expo Router</strong></summary>
255
255
 
256
256
  ```typescript
257
- import { EdgeeAutoTracker } from 'react-native-edgee';
257
+ import { EdgeeAutoTracker } from 'react-native-edgee/expo-router';
258
258
 
259
259
  export default function RootLayout() {
260
260
  return (
@@ -335,6 +335,89 @@ import { clearContextCache } from 'react-native-edgee';
335
335
  clearContextCache();
336
336
  ```
337
337
 
338
+ ## ๐Ÿงช Testing with EdgeeTestApp
339
+
340
+ The repository includes a test app (`EdgeeTestApp/`) that allows you to quickly test the SDK functionality without integrating it into your own app.
341
+
342
+ ### Running the Test App
343
+
344
+ 1. **Navigate to the test app directory:**
345
+ ```bash
346
+ cd EdgeeTestApp
347
+ ```
348
+
349
+ 2. **Install dependencies:**
350
+ ```bash
351
+ npm install
352
+ # or
353
+ yarn install
354
+ ```
355
+
356
+ 3. **For iOS - Install pods:**
357
+ ```bash
358
+ cd ios && pod install && cd ..
359
+ ```
360
+
361
+ 4. **Start Metro bundler:**
362
+ ```bash
363
+ npm start
364
+ # or
365
+ yarn start
366
+ ```
367
+
368
+ 5. **Run the app:**
369
+ ```bash
370
+ # iOS
371
+ npm run ios
372
+ # or
373
+ yarn ios
374
+
375
+ # Android
376
+ npm run android
377
+ # or
378
+ yarn android
379
+ ```
380
+
381
+ ### Using the Test App
382
+
383
+ The test app provides a simple UI to test all SDK features:
384
+
385
+ 1. **Set Edgee Host**: Enter your Edgee endpoint URL (defaults to `https://demo.edgee.app`)
386
+ - Click "Init" to initialize the SDK with your host
387
+
388
+ 2. **Test Events**:
389
+ - **Track Event**: Enter an event name and click "Track Event" to send a track event
390
+ - **Screen Event**: Click "Screen Event" to track a screen view
391
+ - **User Event**: Click "User Event" to send user identification data
392
+
393
+ 3. **Test Consent Management**:
394
+ - Click "Pending", "Granted", or "Denied" to set consent status
395
+ - Click "Get Consent" to view the current consent status
396
+
397
+ 4. **Monitor Status**: The status bar at the bottom shows the result of each action
398
+
399
+ ### Features Demonstrated
400
+
401
+ - โœ… SDK initialization with custom host
402
+ - โœ… Event tracking (track, screen, user)
403
+ - โœ… Consent management (pending, granted, denied)
404
+ - โœ… Native module availability detection
405
+ - โœ… Debug logging (enabled by default in test app)
406
+
407
+ ### Debug Mode
408
+
409
+ The test app has debug mode enabled by default, so you'll see detailed logs in Metro CLI:
410
+ - Event tracking logs
411
+ - Consent status changes
412
+ - Native context collection
413
+ - API request/response details
414
+
415
+ ### Notes
416
+
417
+ - The test app uses the local `react-native-edgee` package via `file:..` in `package.json`
418
+ - Make sure you've built the SDK (`npm run build` in the root directory) before running the test app
419
+ - Native modules are automatically available if you've set up the platform correctly
420
+
338
421
  ## ๐Ÿ” Troubleshooting
339
422
 
340
423
  ### Common Issues
@@ -423,4 +506,4 @@ MIT
423
506
  ## ๐Ÿ†˜ Support
424
507
 
425
508
  - **Issues**: [GitHub Issues](https://github.com/edgee-cloud/react-native-edgee/issues)
426
- - **Documentation**: [Edgee Docs](https://docs.edgee.cloud)
509
+ - **Documentation**: [Edgee Docs](https://docs.edgee.cloud)
package/dist/api.d.ts CHANGED
@@ -28,5 +28,12 @@ export type EdgeeScreenEvent = {
28
28
  export type EdgeeEvent = EdgeeTrackEvent | EdgeeUserEvent | EdgeeScreenEvent;
29
29
  export declare const createTrackEvent: (params: Omit<EdgeeTrackEvent, "type">) => EdgeeTrackEvent;
30
30
  export declare const createUserEvent: (params: Omit<EdgeeUserEvent, "type">) => EdgeeUserEvent;
31
- export declare const uploadEvent: (url: string, config: EdgeeConfig, event: EdgeeEvent) => Promise<Response>;
31
+ /**
32
+ * Sends a payload to the Edgee API with proper headers and handles the response
33
+ */
34
+ export declare const sendPayload: (config: EdgeeConfig, payload: any) => Promise<void>;
35
+ /**
36
+ * Sends an event to the Edgee API
37
+ */
38
+ export declare const uploadEvent: (config: EdgeeConfig, event: EdgeeEvent) => Promise<void>;
32
39
  export {};
package/dist/api.js CHANGED
@@ -1,6 +1,8 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.uploadEvent = exports.createUserEvent = exports.createTrackEvent = void 0;
3
+ exports.uploadEvent = exports.sendPayload = exports.createUserEvent = exports.createTrackEvent = void 0;
4
+ const edgee_store_1 = require("./core/edgee-store");
5
+ const utils_1 = require("./core/utils");
4
6
  var EventType;
5
7
  (function (EventType) {
6
8
  EventType["Track"] = "track";
@@ -21,91 +23,157 @@ const createUserEvent = (params) => {
21
23
  };
22
24
  };
23
25
  exports.createUserEvent = createUserEvent;
24
- const uploadEvent = async (url, config, event) => {
25
- const eventToSend = event;
26
- if (eventToSend.type === "track") {
27
- const event = {
28
- data_collection: {
29
- context: eventToSend.context,
30
- events: [
31
- {
32
- type: "track",
33
- data: {
34
- name: eventToSend.name,
35
- properties: eventToSend.data,
36
- },
37
- components: eventToSend.components,
38
- },
39
- ],
40
- },
41
- };
42
- if (config.debug) {
43
- // eslint-disable-next-line no-console
44
- console.log("[Edgee RN] sending", { url, event });
45
- }
46
- return await fetch(url, {
47
- method: "POST",
48
- headers: {
49
- "Content-Type": "application/json",
50
- ...(config.debug ? { "Edgee-Debug": "true" } : {}),
26
+ /**
27
+ * Builds the event payload structure for API requests
28
+ */
29
+ const buildEventPayload = (event) => {
30
+ const basePayload = {
31
+ data_collection: {
32
+ context: event.context,
33
+ events: [],
34
+ },
35
+ };
36
+ if (event.type === EventType.Track) {
37
+ basePayload.data_collection.events.push({
38
+ type: "track",
39
+ data: {
40
+ name: event.name,
41
+ properties: event.data,
51
42
  },
52
- body: JSON.stringify(event),
43
+ components: event.components,
53
44
  });
54
45
  }
55
- else if (eventToSend.type === "user") {
56
- const event = {
57
- data_collection: {
58
- context: eventToSend.context,
59
- events: [
60
- {
61
- type: "user",
62
- data: eventToSend.data,
63
- components: eventToSend.components,
64
- },
65
- ],
66
- },
67
- };
68
- if (config.debug) {
69
- // eslint-disable-next-line no-console
70
- console.log("[Edgee RN] sending", { url, event });
71
- }
72
- return await fetch(url, {
73
- method: "POST",
74
- headers: {
75
- "Content-Type": "application/json",
76
- ...(config.debug ? { "Edgee-Debug": "true" } : {}),
77
- },
78
- body: JSON.stringify(event),
46
+ else if (event.type === EventType.User) {
47
+ basePayload.data_collection.events.push({
48
+ type: "user",
49
+ data: event.data,
50
+ components: event.components,
79
51
  });
80
52
  }
81
- else if (eventToSend.type === "screen") {
82
- const event = {
83
- data_collection: {
84
- context: eventToSend.context,
85
- events: [
86
- {
87
- type: "track",
88
- data: { ...eventToSend.data, screen_name: eventToSend.name },
89
- components: eventToSend.components,
90
- },
91
- ],
92
- },
93
- };
94
- if (config.debug) {
95
- // eslint-disable-next-line no-console
96
- console.log("[Edgee RN] sending", { url, event });
97
- }
98
- return await fetch(url, {
99
- method: "POST",
100
- headers: {
101
- "Content-Type": "application/json",
102
- ...(config.debug ? { "Edgee-Debug": "true" } : {}),
103
- },
104
- body: JSON.stringify(event),
53
+ else if (event.type === EventType.Screen) {
54
+ basePayload.data_collection.events.push({
55
+ type: "track",
56
+ data: { ...event.data, screen_name: event.name },
57
+ components: event.components,
105
58
  });
106
59
  }
107
60
  else {
108
- throw new Error("Invalid event type");
61
+ throw new Error(`Invalid event type: ${event.type}`);
62
+ }
63
+ return basePayload;
64
+ };
65
+ /**
66
+ * Builds the Edgee-Cookie header string from edgeeId and userId
67
+ * Similar to the JS SDK cookie reconstruction logic
68
+ */
69
+ const buildCookieHeader = async (config) => {
70
+ const cookies = [];
71
+ const { edgeeId, userId } = await edgee_store_1.edgeeStore.getContext();
72
+ if (edgeeId) {
73
+ cookies.push(`${config.cookieName}=${edgeeId}`);
74
+ }
75
+ if (userId) {
76
+ cookies.push(`${config.cookieName}_u=${userId}`);
77
+ }
78
+ return cookies.length > 0 ? cookies.join("; ") : undefined;
79
+ };
80
+ /**
81
+ * Builds headers for API requests including Edgee-Cookie header
82
+ */
83
+ const buildHeaders = async (config) => {
84
+ const headers = {
85
+ "Content-Type": "application/json",
86
+ };
87
+ if (config.debug) {
88
+ headers["Edgee-Debug"] = "1";
109
89
  }
90
+ // Build and add Edgee-Cookie header from store
91
+ const cookieHeader = await buildCookieHeader(config);
92
+ if (cookieHeader) {
93
+ headers["Edgee-Cookie"] = cookieHeader;
94
+ }
95
+ return headers;
96
+ };
97
+ /**
98
+ * Sends a payload to the Edgee API with proper headers and handles the response
99
+ */
100
+ const sendPayload = async (config, payload) => {
101
+ const headers = await buildHeaders(config);
102
+ const url = `${config.host}/_edgee/event`;
103
+ const response = await fetch(url, {
104
+ method: "POST",
105
+ headers,
106
+ body: JSON.stringify(payload),
107
+ });
108
+ try {
109
+ const text = await response.text().catch(() => "");
110
+ if (text) {
111
+ try {
112
+ const data = JSON.parse(text);
113
+ await handleResponse(data, config);
114
+ }
115
+ catch (parseError) {
116
+ (0, utils_1.logError)("[Debug] Parsing response from Fetch to JSON failed.", parseError);
117
+ }
118
+ }
119
+ }
120
+ catch (error) {
121
+ (0, utils_1.logError)("[Debug] Failed to handle response.", error);
122
+ }
123
+ return;
124
+ };
125
+ exports.sendPayload = sendPayload;
126
+ /**
127
+ * Sends an event to the Edgee API
128
+ */
129
+ const uploadEvent = async (config, event) => {
130
+ const payload = buildEventPayload(event);
131
+ await (0, exports.sendPayload)(config, payload);
132
+ return;
110
133
  };
111
134
  exports.uploadEvent = uploadEvent;
135
+ /**
136
+ * Handles response data: stores IDs, handles cookies, and logs events
137
+ * Similar to the JS SDK handleResponse function
138
+ */
139
+ const handleResponse = async (data, config) => {
140
+ let events = data;
141
+ // Store edgeeId and userId from response
142
+ // Convert to string if needed (API might return numbers)
143
+ if (data.e) {
144
+ const edgeeId = String(data.e);
145
+ await edgee_store_1.edgeeStore.setEdgeeId(edgeeId);
146
+ if (config.debug) {
147
+ (0, utils_1.log)(config, `Set edgeeId: ${edgeeId}`);
148
+ }
149
+ }
150
+ if (data.u) {
151
+ const userId = String(data.u);
152
+ await edgee_store_1.edgeeStore.setUserId(userId);
153
+ if (config.debug) {
154
+ (0, utils_1.log)(config, `Set userId: ${userId}`);
155
+ }
156
+ }
157
+ // Handle cookies array (data.c)
158
+ // Note: In React Native, we don't have browser cookies, but we log them if debug is enabled
159
+ if (data.c && Array.isArray(data.c) && data.c.length > 0) {
160
+ for (const cookie of data.c) {
161
+ if (cookie.name && cookie.value) {
162
+ (0, utils_1.log)(config, "โ—‹ Set cookie: " + cookie.name + "=" + cookie.value);
163
+ }
164
+ // In React Native, cookies are typically handled by the app's cookie store
165
+ // If needed, you could store them in AsyncStorage or another storage mechanism
166
+ }
167
+ }
168
+ // Extract events if present
169
+ if (data.events) {
170
+ events = data.events;
171
+ }
172
+ // Log events if debug is enabled (matching JS SDK format)
173
+ if (events && Array.isArray(events) && events.length > 0) {
174
+ for (let i = 0; i < events.length; i++) {
175
+ (0, utils_1.log)(config, "โ—‹ " + events[i].type + " event (client):", events[i]);
176
+ }
177
+ }
178
+ return events;
179
+ };
package/dist/consent.d.ts CHANGED
@@ -1,4 +1,4 @@
1
- import type { ConsentStatus } from "./index";
1
+ export type ConsentStatus = "granted" | "denied" | "pending";
2
2
  /**
3
3
  * Simple consent manager that works with existing EdgeeClient
4
4
  * Stores consent status and provides utilities for consent management
@@ -35,10 +35,6 @@ export declare class EdgeeConsent {
35
35
  * Check if consent is pending
36
36
  */
37
37
  isPending(): boolean;
38
- /**
39
- * Check if we should allow tracking
40
- */
41
- canTrack(): boolean;
42
38
  /**
43
39
  * Listen for consent changes
44
40
  */
@@ -54,43 +50,3 @@ export declare class EdgeeConsent {
54
50
  * This allows you to manage consent across your app without passing it around
55
51
  */
56
52
  export declare const edgeeConsent: EdgeeConsent;
57
- /**
58
- * Consent utilities
59
- */
60
- export declare const ConsentUtils: {
61
- /**
62
- * Initialize consent (call this once in your app)
63
- */
64
- init(): Promise<void>;
65
- /**
66
- * Set consent status
67
- */
68
- setConsent(status: ConsentStatus): Promise<void>;
69
- /**
70
- * Get current consent
71
- */
72
- getConsent(): ConsentStatus | null;
73
- /**
74
- * Check if can track
75
- */
76
- canTrack(): boolean;
77
- /**
78
- * Check consent status
79
- */
80
- hasConsent(): boolean;
81
- isGranted(): boolean;
82
- isDenied(): boolean;
83
- isPending(): boolean;
84
- /**
85
- * Listen for changes
86
- */
87
- onChange(callback: (status: ConsentStatus | null) => void): () => void;
88
- /**
89
- * Reset consent
90
- */
91
- reset(): Promise<void>;
92
- /**
93
- * Send consent event to Edgee using the new consent method
94
- */
95
- sendConsentEvent(edgeeClient: any, status: ConsentStatus): Promise<void>;
96
- };
package/dist/consent.js CHANGED
@@ -3,8 +3,9 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
3
3
  return (mod && mod.__esModule) ? mod : { "default": mod };
4
4
  };
5
5
  Object.defineProperty(exports, "__esModule", { value: true });
6
- exports.ConsentUtils = exports.edgeeConsent = exports.EdgeeConsent = void 0;
6
+ exports.edgeeConsent = exports.EdgeeConsent = void 0;
7
7
  const async_storage_1 = __importDefault(require("@react-native-async-storage/async-storage"));
8
+ const utils_1 = require("./core/utils");
8
9
  const CONSENT_STORAGE_KEY = "_edgee_consent";
9
10
  /**
10
11
  * Simple consent manager that works with existing EdgeeClient
@@ -32,7 +33,7 @@ class EdgeeConsent {
32
33
  this.initialized = true;
33
34
  }
34
35
  catch (error) {
35
- console.warn("[Edgee Consent] Failed to load:", error);
36
+ (0, utils_1.logError)("Failed to load consent", error);
36
37
  this.initialized = true;
37
38
  }
38
39
  }
@@ -52,12 +53,12 @@ class EdgeeConsent {
52
53
  callback(status);
53
54
  }
54
55
  catch (error) {
55
- console.warn("[Edgee Consent] Callback error:", error);
56
+ (0, utils_1.logError)("Callback error", error);
56
57
  }
57
58
  });
58
59
  }
59
60
  catch (error) {
60
- console.warn("[Edgee Consent] Failed to store:", error);
61
+ (0, utils_1.logError)("Failed to store consent", error);
61
62
  }
62
63
  }
63
64
  /**
@@ -90,12 +91,6 @@ class EdgeeConsent {
90
91
  isPending() {
91
92
  return this.consentStatus === "pending";
92
93
  }
93
- /**
94
- * Check if we should allow tracking
95
- */
96
- canTrack() {
97
- return this.initialized && this.consentStatus === "granted";
98
- }
99
94
  /**
100
95
  * Listen for consent changes
101
96
  */
@@ -122,12 +117,12 @@ class EdgeeConsent {
122
117
  callback(null);
123
118
  }
124
119
  catch (error) {
125
- console.warn("[Edgee Consent] Callback error:", error);
120
+ (0, utils_1.logError)("Callback error", error);
126
121
  }
127
122
  });
128
123
  }
129
124
  catch (error) {
130
- console.warn("[Edgee Consent] Failed to clear:", error);
125
+ (0, utils_1.logError)("Failed to clear consent", error);
131
126
  }
132
127
  }
133
128
  isValidStatus(status) {
@@ -141,80 +136,3 @@ exports.EdgeeConsent = EdgeeConsent;
141
136
  * This allows you to manage consent across your app without passing it around
142
137
  */
143
138
  exports.edgeeConsent = new EdgeeConsent();
144
- /**
145
- * Consent utilities
146
- */
147
- exports.ConsentUtils = {
148
- /**
149
- * Initialize consent (call this once in your app)
150
- */
151
- async init() {
152
- return exports.edgeeConsent.init();
153
- },
154
- /**
155
- * Set consent status
156
- */
157
- async setConsent(status) {
158
- return exports.edgeeConsent.setConsent(status);
159
- },
160
- /**
161
- * Get current consent
162
- */
163
- getConsent() {
164
- return exports.edgeeConsent.getConsent();
165
- },
166
- /**
167
- * Check if can track
168
- */
169
- canTrack() {
170
- return exports.edgeeConsent.canTrack();
171
- },
172
- /**
173
- * Check consent status
174
- */
175
- hasConsent() {
176
- return exports.edgeeConsent.hasConsent();
177
- },
178
- isGranted() {
179
- return exports.edgeeConsent.isGranted();
180
- },
181
- isDenied() {
182
- return exports.edgeeConsent.isDenied();
183
- },
184
- isPending() {
185
- return exports.edgeeConsent.isPending();
186
- },
187
- /**
188
- * Listen for changes
189
- */
190
- onChange(callback) {
191
- return exports.edgeeConsent.onChange(callback);
192
- },
193
- /**
194
- * Reset consent
195
- */
196
- async reset() {
197
- return exports.edgeeConsent.reset();
198
- },
199
- /**
200
- * Send consent event to Edgee using the new consent method
201
- */
202
- async sendConsentEvent(edgeeClient, status) {
203
- try {
204
- // Use the new consent method if available
205
- if (edgeeClient.consent) {
206
- await edgeeClient.consent(status);
207
- }
208
- else {
209
- // Fallback: use track event with special consent flag
210
- await edgeeClient.track("_consent_update", {
211
- consent_status: status,
212
- timestamp: Date.now(),
213
- });
214
- }
215
- }
216
- catch (error) {
217
- console.warn("[Edgee Consent] Failed to send consent event:", error);
218
- }
219
- },
220
- };
@@ -1,3 +1,4 @@
1
+ import { EdgeeConfig } from "..";
1
2
  export interface EdgeeClientContext {
2
3
  screen_width: number;
3
4
  screen_height: number;
@@ -38,4 +39,4 @@ export interface EdgeeFullContext {
38
39
  /**
39
40
  * Get comprehensive context including native device information
40
41
  */
41
- export declare const getContext: (collectDeviceId?: boolean) => Promise<EdgeeFullContext>;
42
+ export declare const getContext: (config: EdgeeConfig) => Promise<EdgeeFullContext>;
@@ -3,21 +3,22 @@ Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.getContext = void 0;
4
4
  const react_native_1 = require("react-native");
5
5
  const native_context_1 = require("../native-context");
6
+ const utils_1 = require("./utils");
6
7
  /**
7
8
  * Get comprehensive context including native device information
8
9
  */
9
- const getContext = async (collectDeviceId = false) => {
10
+ const getContext = async (config) => {
10
11
  const initialUrl = await react_native_1.Linking.getInitialURL();
11
12
  const nativeContext = await (0, native_context_1.getNativeContext)();
12
13
  const url = initialUrl || `${(nativeContext === null || nativeContext === void 0 ? void 0 : nativeContext.bundleId) || "app"}://`;
13
14
  let clientContext;
14
15
  if ((0, native_context_1.isNativeModuleAvailable)()) {
15
16
  try {
16
- const nativeContext = await (0, native_context_1.getNativeContext)({ collectDeviceId });
17
+ const nativeContext = await (0, native_context_1.getNativeContext)({ collectDeviceId: config.collectDeviceId });
17
18
  clientContext = buildClientContextFromNative(nativeContext);
18
19
  }
19
20
  catch (error) {
20
- console.warn("Failed to get native context, falling back to basic context:", error);
21
+ (0, utils_1.logError)("Failed to get native context", error);
21
22
  clientContext = getFallbackClientContext();
22
23
  }
23
24
  }
@@ -1,10 +1,9 @@
1
- import AsyncStorage from "@react-native-async-storage/async-storage";
2
1
  import { EdgeeEvent } from "../api";
3
2
  export declare class EdgeeStore {
4
3
  edgeeId: string | null;
5
4
  userId: string | null;
6
- store: typeof AsyncStorage;
7
5
  pendingEvents: EdgeeEvent[];
6
+ initialized: boolean;
8
7
  constructor();
9
8
  init(): Promise<void>;
10
9
  getEdgeeId(): Promise<string | null>;
@@ -19,3 +18,8 @@ export declare class EdgeeStore {
19
18
  getPendingEvents(): Promise<EdgeeEvent[]>;
20
19
  clearEvents(): Promise<void>;
21
20
  }
21
+ /**
22
+ * Global edgee store instance
23
+ * This allows you to manage the edgee store across your app without passing it around
24
+ */
25
+ export declare const edgeeStore: EdgeeStore;