rn-prodeeplinks 0.0.1 → 0.0.3

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
@@ -4,7 +4,7 @@
4
4
 
5
5
  > ⚠️ **License Required**: This package requires a valid license key purchased from our portal. Without a license key, the package will not function.
6
6
 
7
- > ℹ️ **Versioning**: Current version is 0.0.1 (in-progress). It will move to 1.x after stable.
7
+ > ℹ️ **Versioning**: Current version is 0.0.3 (in-progress). It will move to 1.x after stable.
8
8
 
9
9
  ## Features
10
10
 
@@ -130,6 +130,45 @@ const deepLink = new ProDeepLink({
130
130
  const result = await deepLink.getDeepLinkUrl();
131
131
  ```
132
132
 
133
+ ### Analytics & Tracking
134
+
135
+ This SDK can optionally send deep link analytics events to our tracking service.
136
+
137
+ - When a deep link is opened via React Native `Linking.getInitialURL()`, the SDK:
138
+ - Resolves the URL
139
+ - Collects device fingerprint data
140
+ - Sends an internal analytics event with the resolved short URL and fingerprint
141
+ - When a deep link is resolved via the fingerprint API, the SDK:
142
+ - Resolves the URL from the server
143
+ - Sends the same internal analytics event with the short URL and fingerprint
144
+
145
+ These internal events are handled by the SDK and are not part of the public API.
146
+
147
+ You can also send custom tracking events manually after calling `init`:
148
+
149
+ ```typescript
150
+ import {
151
+ trackAnalyticsEvent,
152
+ CustomDeepLinkAnalyticsEvent,
153
+ } from 'rn-prodeeplinks';
154
+
155
+ const event: CustomDeepLinkAnalyticsEvent = {
156
+ eventType: 'deeplink',
157
+ eventName: 'my_custom_event',
158
+ category: 'custom',
159
+ action: 'open',
160
+ label: 'My custom event',
161
+ properties: {
162
+ shortUrl: 'https://your-short-url',
163
+ foo: 'bar',
164
+ },
165
+ };
166
+
167
+ await trackAnalyticsEvent(event);
168
+ ```
169
+
170
+ The license key provided to `init` is automatically included in the request headers. You do not need to include the license key in the analytics event payload.
171
+
133
172
  ## API Reference
134
173
 
135
174
  ### Functions
@@ -182,6 +221,26 @@ getDeepLink((url) => {
182
221
  });
183
222
  ```
184
223
 
224
+ #### `trackAnalyticsEvent(event: CustomDeepLinkAnalyticsEvent): Promise<any>`
225
+
226
+ Sends a custom analytics event to the tracking service.
227
+
228
+ `init()` must be called successfully first; the stored license key from `init` is sent in the request headers.
229
+
230
+ **Parameters:**
231
+ - `event` (CustomDeepLinkAnalyticsEvent, required): Event describing what happened. You can use any `eventName` and add any custom properties.
232
+
233
+ **Example:**
234
+ ```typescript
235
+ await trackAnalyticsEvent({
236
+ eventType: 'deeplink',
237
+ eventName: 'button_click',
238
+ properties: {
239
+ buttonId: 'cta_start',
240
+ },
241
+ });
242
+ ```
243
+
185
244
  #### `isReady(): boolean`
186
245
 
187
246
  Checks if the package has been initialized with a license key.
@@ -234,24 +293,16 @@ License keys are **NOT FREE**. You must:
234
293
  - Invalid or expired license keys will result in API errors
235
294
  - License keys cannot be shared or reused without authorization
236
295
 
237
- ### Custom License Validate API (Optional)
238
- For environments with a custom auth API, the license validate endpoint is:
239
-
240
- POST {{base_url}}{{api_prefix}}/custom-deep-link/license/validate
296
+ ### Custom License Validation (Optional)
241
297
 
242
- Example (Postman):
298
+ In most cases you should rely on the built‑in license validation handled by this SDK.
299
+ If you have your own backend that integrates with our license service, you can:
243
300
 
244
- ```
245
- POST '{{base_url}}{{api_prefix}}/custom-deep-link/license/validate'
246
- --header 'Content-Type: application/json'
247
- --body '{
248
- "licenseKey": "{{license_key}}",
249
- "domain": "acme.com",
250
- "ipAddress": "103.21.149.10"
251
- }'
252
- ```
301
+ - Call your backend from your app
302
+ - Let your backend talk to our license service
303
+ - Use the result in your own business logic
253
304
 
254
- This package exposes a helper to call this endpoint if needed. It does not interfere with the main deep link resolution flow.
305
+ The exact backend endpoint and payload are specific to your environment and are intentionally not exposed in this README.
255
306
 
256
307
  ## Error Handling
257
308
 
package/lib/api.d.ts CHANGED
@@ -20,5 +20,5 @@ export declare function validateLicenseInit(licenseKey: string): Promise<{
20
20
  status?: number;
21
21
  data?: LicenseValidationApiResponse;
22
22
  }>;
23
- export declare function matchFingerprintCustom(payload: FingerprintMatchPayload, baseUrl?: string): Promise<FingerprintMatchResponse>;
24
- export declare function trackCustomDeepLinkEvent(event: CustomDeepLinkAnalyticsEvent): Promise<any>;
23
+ export declare function matchFingerprintCustom(payload: FingerprintMatchPayload, baseUrl?: string, licenseKey?: string): Promise<FingerprintMatchResponse>;
24
+ export declare function trackCustomDeepLinkEvent(event: CustomDeepLinkAnalyticsEvent, licenseKey?: string): Promise<any>;
package/lib/api.js CHANGED
@@ -26,7 +26,7 @@ async function fetchDeepLinkUrl(licenseKey, fingerprint, apiEndpoint, timeout =
26
26
  };
27
27
  }
28
28
  const PACKAGE_NAME = 'react-native-pro-deeplink';
29
- const PACKAGE_VERSION = '0.0.1';
29
+ const PACKAGE_VERSION = '0.0.3';
30
30
  const payload = {
31
31
  licenseKey,
32
32
  fingerprint: fingerprint,
@@ -39,13 +39,14 @@ async function fetchDeepLinkUrl(licenseKey, fingerprint, apiEndpoint, timeout =
39
39
  const timeoutId = setTimeout(() => controller.abort(), timeout);
40
40
  try {
41
41
  const PACKAGE_NAME = 'react-native-pro-deeplink';
42
- const PACKAGE_VERSION = '0.0.1';
42
+ const PACKAGE_VERSION = '0.0.3';
43
43
  const response = await fetch(endpoint, {
44
44
  method: 'POST',
45
45
  headers: {
46
46
  'Content-Type': 'application/json',
47
47
  'X-Package-Name': PACKAGE_NAME,
48
48
  'X-Package-Version': PACKAGE_VERSION,
49
+ 'x-license-key': licenseKey,
49
50
  },
50
51
  body: JSON.stringify(payload),
51
52
  signal: controller.signal,
@@ -129,7 +130,10 @@ async function validateLicenseCustom(licenseKey, opts) {
129
130
  };
130
131
  const res = await fetch(endpoint, {
131
132
  method: 'POST',
132
- headers: { 'Content-Type': 'application/json' },
133
+ headers: {
134
+ 'Content-Type': 'application/json',
135
+ 'x-license-key': licenseKey,
136
+ },
133
137
  body: JSON.stringify(body),
134
138
  });
135
139
  const json = (await res.json().catch(() => ({})));
@@ -168,7 +172,7 @@ async function validateLicenseInit(licenseKey) {
168
172
  };
169
173
  }
170
174
  }
171
- async function matchFingerprintCustom(payload, baseUrl) {
175
+ async function matchFingerprintCustom(payload, baseUrl, licenseKey) {
172
176
  try {
173
177
  const base = (baseUrl || CUSTOM_API_BASE_URL).trim().replace(/\/+$/, '');
174
178
  const endpoint = `${base}/custom-deep-link/fingerprint/match`;
@@ -176,6 +180,7 @@ async function matchFingerprintCustom(payload, baseUrl) {
176
180
  method: 'POST',
177
181
  headers: {
178
182
  'Content-Type': 'application/json',
183
+ ...(licenseKey ? { 'x-license-key': licenseKey } : {}),
179
184
  },
180
185
  body: JSON.stringify(payload),
181
186
  });
@@ -190,12 +195,13 @@ async function matchFingerprintCustom(payload, baseUrl) {
190
195
  };
191
196
  }
192
197
  }
193
- async function trackCustomDeepLinkEvent(event) {
198
+ async function trackCustomDeepLinkEvent(event, licenseKey) {
194
199
  try {
195
200
  const res = await fetch(ANALYTICS_ENDPOINT, {
196
201
  method: 'POST',
197
202
  headers: {
198
203
  'Content-Type': 'application/json',
204
+ ...(licenseKey ? { 'x-license-key': licenseKey } : {}),
199
205
  },
200
206
  body: JSON.stringify(event),
201
207
  });
@@ -26,8 +26,10 @@ async function generateDeviceFingerprint() {
26
26
  const isRooted = react_native_1.Platform.OS === 'android'
27
27
  ? (await (react_native_device_info_1.default.isDeviceRooted?.() ?? false))
28
28
  : false;
29
- // Get locale info
30
- const locale = react_native_device_info_1.default.getDeviceLocale?.() || Intl.DateTimeFormat().resolvedOptions().locale;
29
+ const deviceLocales = react_native_device_info_1.default.getDeviceLocales?.();
30
+ const locale = (Array.isArray(deviceLocales) && deviceLocales.length > 0
31
+ ? deviceLocales[0]
32
+ : Intl.DateTimeFormat().resolvedOptions().locale) || 'en';
31
33
  const language = (locale || '').split('-')[0] || 'en';
32
34
  const timezone = Intl.DateTimeFormat().resolvedOptions().timeZone;
33
35
  // Get network info
package/lib/index.d.ts CHANGED
@@ -1,4 +1,4 @@
1
- import { InitConfig, DeepLinkResponse } from './types';
1
+ import { InitConfig, DeepLinkResponse, CustomDeepLinkAnalyticsEvent } from './types';
2
2
  /**
3
3
  * Initialize the deep link package with license key
4
4
  * This must be called before using getDeepLink()
@@ -53,7 +53,8 @@ export declare function isReady(): boolean;
53
53
  * Useful for testing or logout scenarios
54
54
  */
55
55
  export declare function reset(): void;
56
- export type { InitConfig, DeepLinkResponse } from './types';
56
+ export declare function trackAnalyticsEvent(event: CustomDeepLinkAnalyticsEvent): Promise<any>;
57
+ export type { InitConfig, DeepLinkResponse, CustomDeepLinkAnalyticsEvent } from './types';
57
58
  export declare class ProDeepLink {
58
59
  private licenseKey;
59
60
  constructor(config: InitConfig);
@@ -64,5 +65,6 @@ declare const _default: {
64
65
  getDeepLink: typeof getDeepLink;
65
66
  isReady: typeof isReady;
66
67
  reset: typeof reset;
68
+ trackAnalyticsEvent: typeof trackAnalyticsEvent;
67
69
  };
68
70
  export default _default;
package/lib/index.js CHANGED
@@ -5,6 +5,7 @@ exports.init = init;
5
5
  exports.getDeepLink = getDeepLink;
6
6
  exports.isReady = isReady;
7
7
  exports.reset = reset;
8
+ exports.trackAnalyticsEvent = trackAnalyticsEvent;
8
9
  const fingerprint_1 = require("./fingerprint");
9
10
  const api_1 = require("./api");
10
11
  const license_1 = require("./license");
@@ -60,6 +61,25 @@ async function init(config) {
60
61
  };
61
62
  }
62
63
  }
64
+ async function trackDeepLinkResolved(url, source, fingerprint) {
65
+ const event = {
66
+ eventType: 'deeplink',
67
+ eventName: 'pro_track',
68
+ category: source,
69
+ action: 'open',
70
+ label: url,
71
+ properties: {
72
+ shortUrl: url,
73
+ source,
74
+ fingerprint,
75
+ },
76
+ };
77
+ try {
78
+ await trackAnalyticsEvent(event);
79
+ }
80
+ catch {
81
+ }
82
+ }
63
83
  /**
64
84
  * Get deep link URL from server
65
85
  * This function automatically handles device fingerprinting internally
@@ -95,6 +115,12 @@ async function getDeepLink(callback) {
95
115
  // First: try to read deep link via Linking (if app opened by URL)
96
116
  const initialUrl = await react_native_1.Linking.getInitialURL();
97
117
  if (initialUrl) {
118
+ try {
119
+ const fingerprint = await (0, fingerprint_1.generateDeviceFingerprint)();
120
+ await trackDeepLinkResolved(initialUrl, 'linking', fingerprint);
121
+ }
122
+ catch {
123
+ }
98
124
  if (callback)
99
125
  callback(initialUrl);
100
126
  return { success: true, url: initialUrl };
@@ -104,6 +130,13 @@ async function getDeepLink(callback) {
104
130
  // Fetch deep link URL from API with retry mechanism
105
131
  const result = await (0, api_1.fetchDeepLinkUrlWithRetry)(storedLicenseKey, fingerprint, 3, // retry attempts
106
132
  DEFAULT_API_ENDPOINT);
133
+ if (result.success && result.url) {
134
+ try {
135
+ await trackDeepLinkResolved(result.url, 'api', fingerprint);
136
+ }
137
+ catch {
138
+ }
139
+ }
107
140
  // Call callback if provided and result is successful
108
141
  if (callback && result.success && result.url) {
109
142
  callback(result.url);
@@ -136,6 +169,16 @@ function reset() {
136
169
  storedLicenseKey = null;
137
170
  isInitialized = false;
138
171
  }
172
+ async function trackAnalyticsEvent(event) {
173
+ if (!isInitialized || !storedLicenseKey) {
174
+ return {
175
+ success: false,
176
+ error: 'Please call init() first with your license key',
177
+ };
178
+ }
179
+ const { licenseKey: _ignored, ...payload } = event;
180
+ return (0, api_1.trackCustomDeepLinkEvent)(payload, storedLicenseKey);
181
+ }
139
182
  // Keep backward compatibility - export class for advanced users (optional)
140
183
  class ProDeepLink {
141
184
  constructor(config) {
@@ -154,9 +197,17 @@ class ProDeepLink {
154
197
  };
155
198
  }
156
199
  const fingerprint = await (0, fingerprint_1.generateDeviceFingerprint)();
157
- return await (0, api_1.fetchDeepLinkUrlWithRetry)(this.licenseKey, fingerprint, 3, DEFAULT_API_ENDPOINT);
200
+ const result = await (0, api_1.fetchDeepLinkUrlWithRetry)(this.licenseKey, fingerprint, 3, DEFAULT_API_ENDPOINT);
201
+ if (result.success && result.url) {
202
+ try {
203
+ await trackDeepLinkResolved(result.url, 'api', fingerprint);
204
+ }
205
+ catch {
206
+ }
207
+ }
208
+ return result;
158
209
  }
159
210
  }
160
211
  exports.ProDeepLink = ProDeepLink;
161
212
  // Export default
162
- exports.default = { init, getDeepLink, isReady, reset };
213
+ exports.default = { init, getDeepLink, isReady, reset, trackAnalyticsEvent };
package/lib/types.d.ts CHANGED
@@ -70,7 +70,7 @@ export interface CustomDeepLinkAnalyticsDeviceInfo {
70
70
  [key: string]: any;
71
71
  }
72
72
  export interface CustomDeepLinkAnalyticsEvent {
73
- licenseKey: string;
73
+ licenseKey?: string;
74
74
  eventType: string;
75
75
  eventName: string;
76
76
  category?: string;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "rn-prodeeplinks",
3
- "version": "0.0.1",
3
+ "version": "0.0.3",
4
4
  "description": "Secure deep linking package with license key validation and device fingerprinting for React Native",
5
5
  "main": "lib/index.js",
6
6
  "types": "lib/index.d.ts",