rn-prodeeplinks 0.0.1
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/LICENSE +22 -0
- package/README.md +330 -0
- package/lib/api.d.ts +24 -0
- package/lib/api.js +208 -0
- package/lib/fingerprint.d.ts +6 -0
- package/lib/fingerprint.js +86 -0
- package/lib/index.d.ts +68 -0
- package/lib/index.js +162 -0
- package/lib/license.d.ts +2 -0
- package/lib/license.js +14 -0
- package/lib/types.d.ts +158 -0
- package/lib/types.js +2 -0
- package/package.json +41 -0
package/LICENSE
ADDED
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2024
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
|
22
|
+
|
package/README.md
ADDED
|
@@ -0,0 +1,330 @@
|
|
|
1
|
+
# rn-prodeeplinks
|
|
2
|
+
|
|
3
|
+
**PAID PACKAGE** - Secure deep linking package for React Native with license key validation and device fingerprinting.
|
|
4
|
+
|
|
5
|
+
> â ī¸ **License Required**: This package requires a valid license key purchased from our portal. Without a license key, the package will not function.
|
|
6
|
+
|
|
7
|
+
> âšī¸ **Versioning**: Current version is 0.0.1 (in-progress). It will move to 1.x after stable.
|
|
8
|
+
|
|
9
|
+
## Features
|
|
10
|
+
|
|
11
|
+
- đ **License Key Protection** - Secure license key validation
|
|
12
|
+
- đ **Deep Link Management** - Server-side deep link URL management
|
|
13
|
+
- đĄī¸ **Code Protection** - Built-in protection against code extraction
|
|
14
|
+
- ⥠**Retry Mechanism** - Automatic retry with exponential backoff
|
|
15
|
+
- đ **TypeScript Support** - Full TypeScript definitions included
|
|
16
|
+
|
|
17
|
+
## Getting Started
|
|
18
|
+
|
|
19
|
+
### Step 1: Purchase License Key
|
|
20
|
+
|
|
21
|
+
Before using this package, you must purchase a license key from our portal. The license key will be provided after successful payment.
|
|
22
|
+
|
|
23
|
+
### Step 2: Installation
|
|
24
|
+
|
|
25
|
+
```bash
|
|
26
|
+
npm install rn-prodeeplinks
|
|
27
|
+
```
|
|
28
|
+
|
|
29
|
+
### Step 3: Install Peer Dependencies
|
|
30
|
+
|
|
31
|
+
This package requires the following peer dependencies:
|
|
32
|
+
|
|
33
|
+
```bash
|
|
34
|
+
npm install react-native-device-info @react-native-community/netinfo
|
|
35
|
+
```
|
|
36
|
+
|
|
37
|
+
## Usage
|
|
38
|
+
### Deep Link Resolution Flow
|
|
39
|
+
- First checks React Native Linking for an initial URL (if app opened via deep link).
|
|
40
|
+
- If none, calls fingerprint-based API to resolve server-managed deep link.
|
|
41
|
+
- If neither returns a URL, returns null.
|
|
42
|
+
|
|
43
|
+
### Basic Usage
|
|
44
|
+
|
|
45
|
+
```typescript
|
|
46
|
+
import { init, getDeepLink } from 'rn-prodeeplinks';
|
|
47
|
+
|
|
48
|
+
// Step 1: Initialize with your license key (obtained from our portal after payment)
|
|
49
|
+
const initResult = await init({
|
|
50
|
+
licenseKey: 'your-license-key-from-portal' // REQUIRED: Purchase from our portal
|
|
51
|
+
});
|
|
52
|
+
|
|
53
|
+
if (!initResult.success) {
|
|
54
|
+
console.error('Initialization failed:', initResult.error);
|
|
55
|
+
return;
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
// Step 2: Get deep link URL (Linking-first, then API, else null)
|
|
59
|
+
const result = await getDeepLink();
|
|
60
|
+
|
|
61
|
+
if (result.success && result.url) {
|
|
62
|
+
// Use the URL for deep linking
|
|
63
|
+
console.log('Deep link URL:', result.url);
|
|
64
|
+
// Use Linking.openURL(result.url) or your preferred method
|
|
65
|
+
} else {
|
|
66
|
+
// Either API error or flow returned null
|
|
67
|
+
console.log('No deep link available or error:', result.error);
|
|
68
|
+
}
|
|
69
|
+
```
|
|
70
|
+
|
|
71
|
+
### Using Callback
|
|
72
|
+
|
|
73
|
+
```typescript
|
|
74
|
+
import { init, getDeepLink } from 'rn-prodeeplinks';
|
|
75
|
+
|
|
76
|
+
// Initialize once
|
|
77
|
+
await init({ licenseKey: 'your-license-key-here' });
|
|
78
|
+
|
|
79
|
+
// Get deep link with callback
|
|
80
|
+
getDeepLink((url) => {
|
|
81
|
+
console.log('Deep link URL:', url);
|
|
82
|
+
// Handle the deep link URL
|
|
83
|
+
});
|
|
84
|
+
```
|
|
85
|
+
|
|
86
|
+
### Complete Example
|
|
87
|
+
|
|
88
|
+
```typescript
|
|
89
|
+
import { init, getDeepLink, isReady } from 'rn-prodeeplinks';
|
|
90
|
+
import { Linking } from 'react-native';
|
|
91
|
+
|
|
92
|
+
async function setupDeepLink() {
|
|
93
|
+
// Initialize with license key
|
|
94
|
+
const initResult = await init({
|
|
95
|
+
licenseKey: 'your-license-key-here'
|
|
96
|
+
});
|
|
97
|
+
|
|
98
|
+
if (!initResult.success) {
|
|
99
|
+
console.error('Failed to initialize:', initResult.error);
|
|
100
|
+
return;
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
// Check if ready
|
|
104
|
+
if (isReady()) {
|
|
105
|
+
// Get deep link
|
|
106
|
+
const result = await getDeepLink();
|
|
107
|
+
|
|
108
|
+
if (result.success && result.url) {
|
|
109
|
+
// Open the deep link
|
|
110
|
+
await Linking.openURL(result.url);
|
|
111
|
+
} else {
|
|
112
|
+
// If null, there is no deep link to process
|
|
113
|
+
console.log('Deep link unavailable:', result.error);
|
|
114
|
+
}
|
|
115
|
+
}
|
|
116
|
+
}
|
|
117
|
+
```
|
|
118
|
+
|
|
119
|
+
### Advanced Usage (Class-based - Optional)
|
|
120
|
+
|
|
121
|
+
For advanced users who prefer class-based approach:
|
|
122
|
+
|
|
123
|
+
```typescript
|
|
124
|
+
import { ProDeepLink } from 'rn-prodeeplinks';
|
|
125
|
+
|
|
126
|
+
const deepLink = new ProDeepLink({
|
|
127
|
+
licenseKey: 'your-license-key-here'
|
|
128
|
+
});
|
|
129
|
+
|
|
130
|
+
const result = await deepLink.getDeepLinkUrl();
|
|
131
|
+
```
|
|
132
|
+
|
|
133
|
+
## API Reference
|
|
134
|
+
|
|
135
|
+
### Functions
|
|
136
|
+
|
|
137
|
+
#### `init(config: InitConfig): Promise<{ success: boolean; error?: string }>`
|
|
138
|
+
|
|
139
|
+
Initializes the package with your license key. This must be called before using `getDeepLink()`.
|
|
140
|
+
|
|
141
|
+
**Parameters:**
|
|
142
|
+
- `config.licenseKey` (string, required): Your license key from the portal
|
|
143
|
+
|
|
144
|
+
**Returns:**
|
|
145
|
+
```typescript
|
|
146
|
+
{
|
|
147
|
+
success: boolean;
|
|
148
|
+
error?: string;
|
|
149
|
+
}
|
|
150
|
+
```
|
|
151
|
+
|
|
152
|
+
**Example:**
|
|
153
|
+
```typescript
|
|
154
|
+
const result = await init({ licenseKey: 'your-license-key' });
|
|
155
|
+
```
|
|
156
|
+
|
|
157
|
+
#### `getDeepLink(callback?: (url: string) => void): Promise<DeepLinkResponse>`
|
|
158
|
+
|
|
159
|
+
Fetches the deep link URL from the server.
|
|
160
|
+
|
|
161
|
+
**Parameters:**
|
|
162
|
+
- `callback` (optional): Callback function that receives the deep link URL when successful
|
|
163
|
+
|
|
164
|
+
**Returns:**
|
|
165
|
+
```typescript
|
|
166
|
+
{
|
|
167
|
+
success: boolean;
|
|
168
|
+
url?: string | null;
|
|
169
|
+
message?: string;
|
|
170
|
+
error?: string;
|
|
171
|
+
}
|
|
172
|
+
```
|
|
173
|
+
|
|
174
|
+
**Example:**
|
|
175
|
+
```typescript
|
|
176
|
+
// Using promise
|
|
177
|
+
const result = await getDeepLink();
|
|
178
|
+
|
|
179
|
+
// Using callback
|
|
180
|
+
getDeepLink((url) => {
|
|
181
|
+
console.log('Deep link:', url);
|
|
182
|
+
});
|
|
183
|
+
```
|
|
184
|
+
|
|
185
|
+
#### `isReady(): boolean`
|
|
186
|
+
|
|
187
|
+
Checks if the package has been initialized with a license key.
|
|
188
|
+
|
|
189
|
+
**Returns:** `boolean`
|
|
190
|
+
|
|
191
|
+
#### `reset(): void`
|
|
192
|
+
|
|
193
|
+
Resets/clears the stored license key. Useful for testing or logout scenarios.
|
|
194
|
+
|
|
195
|
+
### ProDeepLink Class (Advanced - Optional)
|
|
196
|
+
|
|
197
|
+
For users who prefer class-based approach:
|
|
198
|
+
|
|
199
|
+
#### Constructor
|
|
200
|
+
|
|
201
|
+
```typescript
|
|
202
|
+
new ProDeepLink(config: InitConfig)
|
|
203
|
+
```
|
|
204
|
+
|
|
205
|
+
**Config Options:**
|
|
206
|
+
- `licenseKey` (string, required): Your license key
|
|
207
|
+
|
|
208
|
+
#### Methods
|
|
209
|
+
|
|
210
|
+
##### `getDeepLinkUrl(): Promise<DeepLinkResponse>`
|
|
211
|
+
|
|
212
|
+
Fetches the deep link URL from the server.
|
|
213
|
+
|
|
214
|
+
## Security Features
|
|
215
|
+
|
|
216
|
+
1. **License Key Protection** - Secure license key validation and obfuscation
|
|
217
|
+
2. **Server-Side Validation** - All license validation happens on our secure server
|
|
218
|
+
3. **Secure API Endpoint** - All communication happens through our encrypted API endpoint
|
|
219
|
+
4. **Code Protection** - Built-in measures to prevent code extraction
|
|
220
|
+
|
|
221
|
+
## License Key
|
|
222
|
+
|
|
223
|
+
### Obtaining a License Key
|
|
224
|
+
|
|
225
|
+
License keys are **NOT FREE**. You must:
|
|
226
|
+
1. Visit our payment portal
|
|
227
|
+
2. Complete the purchase process
|
|
228
|
+
3. Receive your unique license key via email/portal
|
|
229
|
+
4. Use the license key to initialize this package
|
|
230
|
+
|
|
231
|
+
### License Validation
|
|
232
|
+
|
|
233
|
+
- License keys are validated on **every API call** to our server
|
|
234
|
+
- Invalid or expired license keys will result in API errors
|
|
235
|
+
- License keys cannot be shared or reused without authorization
|
|
236
|
+
|
|
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
|
|
241
|
+
|
|
242
|
+
Example (Postman):
|
|
243
|
+
|
|
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
|
+
```
|
|
253
|
+
|
|
254
|
+
This package exposes a helper to call this endpoint if needed. It does not interfere with the main deep link resolution flow.
|
|
255
|
+
|
|
256
|
+
## Error Handling
|
|
257
|
+
|
|
258
|
+
The package handles various error scenarios:
|
|
259
|
+
|
|
260
|
+
- Invalid license key
|
|
261
|
+
- Network timeouts
|
|
262
|
+
- API errors
|
|
263
|
+
|
|
264
|
+
All errors are returned in the `DeepLinkResponse` object with descriptive error messages.
|
|
265
|
+
|
|
266
|
+
## TypeScript Support
|
|
267
|
+
|
|
268
|
+
Full TypeScript definitions are included. Import types as needed:
|
|
269
|
+
|
|
270
|
+
```typescript
|
|
271
|
+
import { InitConfig, DeepLinkResponse } from 'rn-prodeeplinks';
|
|
272
|
+
```
|
|
273
|
+
|
|
274
|
+
**Available Types:**
|
|
275
|
+
- `InitConfig` - Configuration for initialization
|
|
276
|
+
- `DeepLinkResponse` - Response from getDeepLink()
|
|
277
|
+
|
|
278
|
+
## Troubleshooting
|
|
279
|
+
|
|
280
|
+
### License Key Errors
|
|
281
|
+
|
|
282
|
+
If you receive license key errors:
|
|
283
|
+
1. Ensure you've called `init()` before using `getDeepLink()`
|
|
284
|
+
2. Check that the license key is valid on our portal
|
|
285
|
+
3. Verify the license key hasn't expired
|
|
286
|
+
4. Make sure you're using the correct license key
|
|
287
|
+
|
|
288
|
+
### Network Errors
|
|
289
|
+
|
|
290
|
+
If you encounter network errors:
|
|
291
|
+
1. Check your internet connection
|
|
292
|
+
2. Verify you have proper network permissions
|
|
293
|
+
3. Check if our API endpoint is accessible from your network
|
|
294
|
+
4. Try again after a few moments (automatic retry is built-in)
|
|
295
|
+
|
|
296
|
+
### Initialization Errors
|
|
297
|
+
|
|
298
|
+
If initialization fails:
|
|
299
|
+
1. Make sure you're calling `init()` before `getDeepLink()`
|
|
300
|
+
2. Verify the license key is correct
|
|
301
|
+
3. Check that `isReady()` returns `true` before making API calls
|
|
302
|
+
|
|
303
|
+
## Payment & Licensing
|
|
304
|
+
|
|
305
|
+
This is a **paid package**. To use this package:
|
|
306
|
+
|
|
307
|
+
1. **Purchase**: Visit our payment portal and purchase a license
|
|
308
|
+
2. **Get License Key**: Receive your unique license key after payment
|
|
309
|
+
3. **Use Package**: Initialize the package with your license key using `init()`
|
|
310
|
+
4. **Server Validation**: Our server validates the license key on each request
|
|
311
|
+
|
|
312
|
+
### Important Notes
|
|
313
|
+
|
|
314
|
+
- â **No license key = Package will not work**
|
|
315
|
+
- â **Invalid license key = API calls will fail**
|
|
316
|
+
- â **Expired license key = Access denied**
|
|
317
|
+
- â **Not initialized = getDeepLink() will fail**
|
|
318
|
+
- â
**Valid license key + init() = Full access to all features**
|
|
319
|
+
- â
**API endpoint = Managed by us (no setup required)**
|
|
320
|
+
|
|
321
|
+
## Support
|
|
322
|
+
|
|
323
|
+
For support regarding:
|
|
324
|
+
- **License keys**: Contact our payment portal support
|
|
325
|
+
- **Technical issues**: Check the documentation or contact technical support
|
|
326
|
+
- **Payment issues**: Contact billing support
|
|
327
|
+
|
|
328
|
+
## License
|
|
329
|
+
|
|
330
|
+
This package is proprietary software. Unauthorized copying, distribution, or use without a valid license key is prohibited and may result in legal action.
|
package/lib/api.d.ts
ADDED
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
import { DeepLinkResponse, DeviceFingerprint, FingerprintMatchPayload, CustomDeepLinkAnalyticsEvent, LicenseValidationApiResponse, FingerprintMatchResponse } from './types';
|
|
2
|
+
/**
|
|
3
|
+
* Call API to get deep link URL
|
|
4
|
+
* This function sends device fingerprint and license key to server
|
|
5
|
+
*/
|
|
6
|
+
export declare function fetchDeepLinkUrl(licenseKey: string, fingerprint: DeviceFingerprint, apiEndpoint?: string, timeout?: number): Promise<DeepLinkResponse>;
|
|
7
|
+
/**
|
|
8
|
+
* Retry mechanism for API calls
|
|
9
|
+
*/
|
|
10
|
+
export declare function fetchDeepLinkUrlWithRetry(licenseKey: string, fingerprint: DeviceFingerprint, retryAttempts?: number, apiEndpoint?: string, timeout?: number): Promise<DeepLinkResponse>;
|
|
11
|
+
export declare function validateLicenseCustom(licenseKey: string, opts?: {
|
|
12
|
+
baseUrl?: string;
|
|
13
|
+
apiPrefix?: string;
|
|
14
|
+
domain?: string;
|
|
15
|
+
ipAddress?: string;
|
|
16
|
+
}): Promise<LicenseValidationApiResponse>;
|
|
17
|
+
export declare function validateLicenseInit(licenseKey: string): Promise<{
|
|
18
|
+
success: boolean;
|
|
19
|
+
error?: string;
|
|
20
|
+
status?: number;
|
|
21
|
+
data?: LicenseValidationApiResponse;
|
|
22
|
+
}>;
|
|
23
|
+
export declare function matchFingerprintCustom(payload: FingerprintMatchPayload, baseUrl?: string): Promise<FingerprintMatchResponse>;
|
|
24
|
+
export declare function trackCustomDeepLinkEvent(event: CustomDeepLinkAnalyticsEvent): Promise<any>;
|
package/lib/api.js
ADDED
|
@@ -0,0 +1,208 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.fetchDeepLinkUrl = fetchDeepLinkUrl;
|
|
4
|
+
exports.fetchDeepLinkUrlWithRetry = fetchDeepLinkUrlWithRetry;
|
|
5
|
+
exports.validateLicenseCustom = validateLicenseCustom;
|
|
6
|
+
exports.validateLicenseInit = validateLicenseInit;
|
|
7
|
+
exports.matchFingerprintCustom = matchFingerprintCustom;
|
|
8
|
+
exports.trackCustomDeepLinkEvent = trackCustomDeepLinkEvent;
|
|
9
|
+
const license_1 = require("./license");
|
|
10
|
+
const DEFAULT_API_ENDPOINT = 'https://api.prodeeplink.com/v1/deeplink';
|
|
11
|
+
const CUSTOM_API_BASE_URL = 'https://api.prodeeplinks.com';
|
|
12
|
+
const ANALYTICS_ENDPOINT = 'https://s.finprim.com/custom-deep-link/track/event';
|
|
13
|
+
/**
|
|
14
|
+
* Call API to get deep link URL
|
|
15
|
+
* This function sends device fingerprint and license key to server
|
|
16
|
+
*/
|
|
17
|
+
async function fetchDeepLinkUrl(licenseKey, fingerprint, apiEndpoint, timeout = 10000) {
|
|
18
|
+
const endpoint = apiEndpoint || DEFAULT_API_ENDPOINT;
|
|
19
|
+
try {
|
|
20
|
+
// Validate license key format first
|
|
21
|
+
const validation = (0, license_1.validateLicenseKeyFormat)(licenseKey);
|
|
22
|
+
if (!validation.isValid) {
|
|
23
|
+
return {
|
|
24
|
+
success: false,
|
|
25
|
+
error: validation.message || 'Invalid license key',
|
|
26
|
+
};
|
|
27
|
+
}
|
|
28
|
+
const PACKAGE_NAME = 'react-native-pro-deeplink';
|
|
29
|
+
const PACKAGE_VERSION = '0.0.1';
|
|
30
|
+
const payload = {
|
|
31
|
+
licenseKey,
|
|
32
|
+
fingerprint: fingerprint,
|
|
33
|
+
packageName: PACKAGE_NAME,
|
|
34
|
+
packageVersion: PACKAGE_VERSION,
|
|
35
|
+
timestamp: Date.now(),
|
|
36
|
+
};
|
|
37
|
+
// Make API call with timeout
|
|
38
|
+
const controller = new AbortController();
|
|
39
|
+
const timeoutId = setTimeout(() => controller.abort(), timeout);
|
|
40
|
+
try {
|
|
41
|
+
const PACKAGE_NAME = 'react-native-pro-deeplink';
|
|
42
|
+
const PACKAGE_VERSION = '0.0.1';
|
|
43
|
+
const response = await fetch(endpoint, {
|
|
44
|
+
method: 'POST',
|
|
45
|
+
headers: {
|
|
46
|
+
'Content-Type': 'application/json',
|
|
47
|
+
'X-Package-Name': PACKAGE_NAME,
|
|
48
|
+
'X-Package-Version': PACKAGE_VERSION,
|
|
49
|
+
},
|
|
50
|
+
body: JSON.stringify(payload),
|
|
51
|
+
signal: controller.signal,
|
|
52
|
+
});
|
|
53
|
+
clearTimeout(timeoutId);
|
|
54
|
+
if (!response.ok) {
|
|
55
|
+
const errorData = await response.json().catch(() => ({}));
|
|
56
|
+
return {
|
|
57
|
+
success: false,
|
|
58
|
+
error: errorData.message || `API error: ${response.status}`,
|
|
59
|
+
};
|
|
60
|
+
}
|
|
61
|
+
const data = await response.json();
|
|
62
|
+
if (data.success && data.url) {
|
|
63
|
+
return {
|
|
64
|
+
success: true,
|
|
65
|
+
url: data.url,
|
|
66
|
+
message: data.message,
|
|
67
|
+
};
|
|
68
|
+
}
|
|
69
|
+
else {
|
|
70
|
+
return {
|
|
71
|
+
success: false,
|
|
72
|
+
error: data.message || 'No URL returned from API',
|
|
73
|
+
};
|
|
74
|
+
}
|
|
75
|
+
}
|
|
76
|
+
catch (fetchError) {
|
|
77
|
+
clearTimeout(timeoutId);
|
|
78
|
+
if (fetchError.name === 'AbortError') {
|
|
79
|
+
return {
|
|
80
|
+
success: false,
|
|
81
|
+
error: 'Request timeout',
|
|
82
|
+
};
|
|
83
|
+
}
|
|
84
|
+
throw fetchError;
|
|
85
|
+
}
|
|
86
|
+
}
|
|
87
|
+
catch (error) {
|
|
88
|
+
console.error('Error fetching deep link URL:', error);
|
|
89
|
+
return {
|
|
90
|
+
success: false,
|
|
91
|
+
error: error.message || 'Failed to fetch deep link URL',
|
|
92
|
+
};
|
|
93
|
+
}
|
|
94
|
+
}
|
|
95
|
+
/**
|
|
96
|
+
* Retry mechanism for API calls
|
|
97
|
+
*/
|
|
98
|
+
async function fetchDeepLinkUrlWithRetry(licenseKey, fingerprint, retryAttempts = 3, apiEndpoint, timeout = 10000) {
|
|
99
|
+
let lastError = null;
|
|
100
|
+
for (let attempt = 1; attempt <= retryAttempts; attempt++) {
|
|
101
|
+
const result = await fetchDeepLinkUrl(licenseKey, fingerprint, apiEndpoint, timeout);
|
|
102
|
+
if (result.success) {
|
|
103
|
+
return result;
|
|
104
|
+
}
|
|
105
|
+
lastError = result;
|
|
106
|
+
// Don't retry on license validation errors
|
|
107
|
+
if (result.error?.includes('license') || result.error?.includes('Invalid')) {
|
|
108
|
+
return result;
|
|
109
|
+
}
|
|
110
|
+
// Wait before retry (exponential backoff)
|
|
111
|
+
if (attempt < retryAttempts) {
|
|
112
|
+
await new Promise(resolve => setTimeout(resolve, 1000 * attempt));
|
|
113
|
+
}
|
|
114
|
+
}
|
|
115
|
+
return lastError || {
|
|
116
|
+
success: false,
|
|
117
|
+
error: 'Failed after retries',
|
|
118
|
+
};
|
|
119
|
+
}
|
|
120
|
+
async function validateLicenseCustom(licenseKey, opts) {
|
|
121
|
+
try {
|
|
122
|
+
const base = (opts?.baseUrl || '').trim();
|
|
123
|
+
const prefix = (opts?.apiPrefix || '').trim();
|
|
124
|
+
const endpoint = `${base}${prefix}/custom-deep-link/license/validate`;
|
|
125
|
+
const body = {
|
|
126
|
+
licenseKey,
|
|
127
|
+
domain: opts?.domain || '',
|
|
128
|
+
ipAddress: opts?.ipAddress || '',
|
|
129
|
+
};
|
|
130
|
+
const res = await fetch(endpoint, {
|
|
131
|
+
method: 'POST',
|
|
132
|
+
headers: { 'Content-Type': 'application/json' },
|
|
133
|
+
body: JSON.stringify(body),
|
|
134
|
+
});
|
|
135
|
+
const json = (await res.json().catch(() => ({})));
|
|
136
|
+
return json;
|
|
137
|
+
}
|
|
138
|
+
catch (e) {
|
|
139
|
+
return { success: false, error: e?.message || 'License validate failed' };
|
|
140
|
+
}
|
|
141
|
+
}
|
|
142
|
+
async function validateLicenseInit(licenseKey) {
|
|
143
|
+
try {
|
|
144
|
+
const endpoint = `${CUSTOM_API_BASE_URL}/custom-deep-link/license/validate`;
|
|
145
|
+
const res = await fetch(endpoint, {
|
|
146
|
+
method: 'POST',
|
|
147
|
+
headers: {
|
|
148
|
+
'Content-Type': 'application/json',
|
|
149
|
+
'x-license-key': licenseKey,
|
|
150
|
+
},
|
|
151
|
+
body: JSON.stringify({ licenseKey }),
|
|
152
|
+
});
|
|
153
|
+
const data = (await res.json().catch(() => ({})));
|
|
154
|
+
if (!res.ok) {
|
|
155
|
+
const message = data?.message || data?.error || 'License validation failed';
|
|
156
|
+
return { success: false, error: message, status: res.status, data };
|
|
157
|
+
}
|
|
158
|
+
if (!data.success || !data.valid) {
|
|
159
|
+
const message = data?.message || data?.error || 'License is not valid';
|
|
160
|
+
return { success: false, error: message, status: res.status, data };
|
|
161
|
+
}
|
|
162
|
+
return { success: true, status: res.status, data };
|
|
163
|
+
}
|
|
164
|
+
catch (e) {
|
|
165
|
+
return {
|
|
166
|
+
success: false,
|
|
167
|
+
error: e?.message || 'License validation request failed',
|
|
168
|
+
};
|
|
169
|
+
}
|
|
170
|
+
}
|
|
171
|
+
async function matchFingerprintCustom(payload, baseUrl) {
|
|
172
|
+
try {
|
|
173
|
+
const base = (baseUrl || CUSTOM_API_BASE_URL).trim().replace(/\/+$/, '');
|
|
174
|
+
const endpoint = `${base}/custom-deep-link/fingerprint/match`;
|
|
175
|
+
const res = await fetch(endpoint, {
|
|
176
|
+
method: 'POST',
|
|
177
|
+
headers: {
|
|
178
|
+
'Content-Type': 'application/json',
|
|
179
|
+
},
|
|
180
|
+
body: JSON.stringify(payload),
|
|
181
|
+
});
|
|
182
|
+
const data = (await res.json().catch(() => ({})));
|
|
183
|
+
return data;
|
|
184
|
+
}
|
|
185
|
+
catch (e) {
|
|
186
|
+
return {
|
|
187
|
+
matched: false,
|
|
188
|
+
matchConfidence: 0,
|
|
189
|
+
...(e ? { error: e?.message || 'Fingerprint match failed' } : {}),
|
|
190
|
+
};
|
|
191
|
+
}
|
|
192
|
+
}
|
|
193
|
+
async function trackCustomDeepLinkEvent(event) {
|
|
194
|
+
try {
|
|
195
|
+
const res = await fetch(ANALYTICS_ENDPOINT, {
|
|
196
|
+
method: 'POST',
|
|
197
|
+
headers: {
|
|
198
|
+
'Content-Type': 'application/json',
|
|
199
|
+
},
|
|
200
|
+
body: JSON.stringify(event),
|
|
201
|
+
});
|
|
202
|
+
const data = await res.json().catch(() => ({}));
|
|
203
|
+
return data;
|
|
204
|
+
}
|
|
205
|
+
catch (e) {
|
|
206
|
+
return { success: false, error: e?.message || 'Analytics event tracking failed' };
|
|
207
|
+
}
|
|
208
|
+
}
|
|
@@ -0,0 +1,86 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
3
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
|
+
};
|
|
5
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
+
exports.generateDeviceFingerprint = generateDeviceFingerprint;
|
|
7
|
+
const react_native_device_info_1 = __importDefault(require("react-native-device-info"));
|
|
8
|
+
const react_native_1 = require("react-native");
|
|
9
|
+
const netinfo_1 = __importDefault(require("@react-native-community/netinfo"));
|
|
10
|
+
/**
|
|
11
|
+
* Generate device fingerprint for deep link matching
|
|
12
|
+
* Collects all device information required for fingerprint matching
|
|
13
|
+
*/
|
|
14
|
+
async function generateDeviceFingerprint() {
|
|
15
|
+
try {
|
|
16
|
+
const { width, height } = react_native_1.Dimensions.get('window');
|
|
17
|
+
const screenResolution = `${width}x${height}`;
|
|
18
|
+
// Get device info
|
|
19
|
+
const deviceId = await react_native_device_info_1.default.getUniqueId();
|
|
20
|
+
const deviceModel = react_native_device_info_1.default.getModel();
|
|
21
|
+
const manufacturer = react_native_1.Platform.OS === 'android' ? await react_native_device_info_1.default.getManufacturer() : 'Apple';
|
|
22
|
+
const osVersion = react_native_device_info_1.default.getSystemVersion();
|
|
23
|
+
const appVersion = react_native_device_info_1.default.getVersion();
|
|
24
|
+
const buildNumber = react_native_device_info_1.default.getBuildNumber();
|
|
25
|
+
const isSimulator = await react_native_device_info_1.default.isEmulator();
|
|
26
|
+
const isRooted = react_native_1.Platform.OS === 'android'
|
|
27
|
+
? (await (react_native_device_info_1.default.isDeviceRooted?.() ?? false))
|
|
28
|
+
: false;
|
|
29
|
+
// Get locale info
|
|
30
|
+
const locale = react_native_device_info_1.default.getDeviceLocale?.() || Intl.DateTimeFormat().resolvedOptions().locale;
|
|
31
|
+
const language = (locale || '').split('-')[0] || 'en';
|
|
32
|
+
const timezone = Intl.DateTimeFormat().resolvedOptions().timeZone;
|
|
33
|
+
// Get network info
|
|
34
|
+
const netInfo = await netinfo_1.default.fetch();
|
|
35
|
+
const connectionType = netInfo.type;
|
|
36
|
+
const carrier = react_native_1.Platform.OS === 'ios' ? await react_native_device_info_1.default.getCarrier() : undefined;
|
|
37
|
+
// Get IP address (if available)
|
|
38
|
+
let ipAddress;
|
|
39
|
+
try {
|
|
40
|
+
// Prefer device info API if available
|
|
41
|
+
ipAddress = await (react_native_device_info_1.default.getIpAddress?.() ?? undefined);
|
|
42
|
+
// Fallback to network info if not available
|
|
43
|
+
if (!ipAddress && netInfo.details && 'ipAddress' in netInfo.details) {
|
|
44
|
+
ipAddress = netInfo.details.ipAddress;
|
|
45
|
+
}
|
|
46
|
+
}
|
|
47
|
+
catch (error) {
|
|
48
|
+
console.warn('Could not get IP address:', error);
|
|
49
|
+
}
|
|
50
|
+
const fingerprint = {
|
|
51
|
+
platform: react_native_1.Platform.OS,
|
|
52
|
+
osVersion,
|
|
53
|
+
deviceId,
|
|
54
|
+
deviceModel,
|
|
55
|
+
manufacturer,
|
|
56
|
+
screenResolution,
|
|
57
|
+
screenWidth: width,
|
|
58
|
+
screenHeight: height,
|
|
59
|
+
timezone,
|
|
60
|
+
language,
|
|
61
|
+
locale,
|
|
62
|
+
appVersion: `${appVersion} (${buildNumber})`,
|
|
63
|
+
carrier,
|
|
64
|
+
connectionType: connectionType || undefined,
|
|
65
|
+
isSimulator,
|
|
66
|
+
isRooted,
|
|
67
|
+
ipAddress,
|
|
68
|
+
};
|
|
69
|
+
return fingerprint;
|
|
70
|
+
}
|
|
71
|
+
catch (error) {
|
|
72
|
+
console.error('Error generating device fingerprint:', error);
|
|
73
|
+
// Return minimal fingerprint on error
|
|
74
|
+
const { width, height } = react_native_1.Dimensions.get('window');
|
|
75
|
+
return {
|
|
76
|
+
platform: react_native_1.Platform.OS,
|
|
77
|
+
osVersion: react_native_1.Platform.Version.toString(),
|
|
78
|
+
deviceId: 'unknown',
|
|
79
|
+
deviceModel: 'unknown',
|
|
80
|
+
screenResolution: `${width}x${height}`,
|
|
81
|
+
screenWidth: width,
|
|
82
|
+
screenHeight: height,
|
|
83
|
+
appVersion: 'unknown',
|
|
84
|
+
};
|
|
85
|
+
}
|
|
86
|
+
}
|
package/lib/index.d.ts
ADDED
|
@@ -0,0 +1,68 @@
|
|
|
1
|
+
import { InitConfig, DeepLinkResponse } from './types';
|
|
2
|
+
/**
|
|
3
|
+
* Initialize the deep link package with license key
|
|
4
|
+
* This must be called before using getDeepLink()
|
|
5
|
+
*
|
|
6
|
+
* @param config - Configuration object containing license key
|
|
7
|
+
* @returns Object with success status and optional error message
|
|
8
|
+
*
|
|
9
|
+
* @example
|
|
10
|
+
* ```typescript
|
|
11
|
+
* import { init } from 'rn-prodeeplinks';
|
|
12
|
+
*
|
|
13
|
+
* const result = await init({ licenseKey: 'your-license-key-here' });
|
|
14
|
+
* if (result.success) {
|
|
15
|
+
* console.log('Initialized successfully');
|
|
16
|
+
* }
|
|
17
|
+
* ```
|
|
18
|
+
*/
|
|
19
|
+
export declare function init(config: InitConfig): Promise<{
|
|
20
|
+
success: boolean;
|
|
21
|
+
error?: string;
|
|
22
|
+
}>;
|
|
23
|
+
/**
|
|
24
|
+
* Get deep link URL from server
|
|
25
|
+
* This function automatically handles device fingerprinting internally
|
|
26
|
+
*
|
|
27
|
+
* @param callback - Optional callback function that receives the deep link URL
|
|
28
|
+
* @returns Promise with deep link response
|
|
29
|
+
*
|
|
30
|
+
* @example
|
|
31
|
+
* ```typescript
|
|
32
|
+
* import { getDeepLink } from 'rn-prodeeplinks';
|
|
33
|
+
*
|
|
34
|
+
* // Using promise
|
|
35
|
+
* const result = await getDeepLink();
|
|
36
|
+
* if (result.success && result.url) {
|
|
37
|
+
* console.log('Deep link:', result.url);
|
|
38
|
+
* }
|
|
39
|
+
*
|
|
40
|
+
* // Using callback
|
|
41
|
+
* getDeepLink((url) => {
|
|
42
|
+
* console.log('Deep link:', url);
|
|
43
|
+
* });
|
|
44
|
+
* ```
|
|
45
|
+
*/
|
|
46
|
+
export declare function getDeepLink(callback?: (url: string) => void): Promise<DeepLinkResponse>;
|
|
47
|
+
/**
|
|
48
|
+
* Check if the package is initialized
|
|
49
|
+
*/
|
|
50
|
+
export declare function isReady(): boolean;
|
|
51
|
+
/**
|
|
52
|
+
* Reset/clear the stored license key
|
|
53
|
+
* Useful for testing or logout scenarios
|
|
54
|
+
*/
|
|
55
|
+
export declare function reset(): void;
|
|
56
|
+
export type { InitConfig, DeepLinkResponse } from './types';
|
|
57
|
+
export declare class ProDeepLink {
|
|
58
|
+
private licenseKey;
|
|
59
|
+
constructor(config: InitConfig);
|
|
60
|
+
getDeepLinkUrl(): Promise<DeepLinkResponse>;
|
|
61
|
+
}
|
|
62
|
+
declare const _default: {
|
|
63
|
+
init: typeof init;
|
|
64
|
+
getDeepLink: typeof getDeepLink;
|
|
65
|
+
isReady: typeof isReady;
|
|
66
|
+
reset: typeof reset;
|
|
67
|
+
};
|
|
68
|
+
export default _default;
|
package/lib/index.js
ADDED
|
@@ -0,0 +1,162 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.ProDeepLink = void 0;
|
|
4
|
+
exports.init = init;
|
|
5
|
+
exports.getDeepLink = getDeepLink;
|
|
6
|
+
exports.isReady = isReady;
|
|
7
|
+
exports.reset = reset;
|
|
8
|
+
const fingerprint_1 = require("./fingerprint");
|
|
9
|
+
const api_1 = require("./api");
|
|
10
|
+
const license_1 = require("./license");
|
|
11
|
+
const react_native_1 = require("react-native");
|
|
12
|
+
// Global state to store license key and configuration
|
|
13
|
+
let storedLicenseKey = null;
|
|
14
|
+
let isInitialized = false;
|
|
15
|
+
// Hardcoded API endpoint - user doesn't need to know about this
|
|
16
|
+
const DEFAULT_API_ENDPOINT = 'https://api.prodeeplink.com/v1/deeplink';
|
|
17
|
+
/**
|
|
18
|
+
* Initialize the deep link package with license key
|
|
19
|
+
* This must be called before using getDeepLink()
|
|
20
|
+
*
|
|
21
|
+
* @param config - Configuration object containing license key
|
|
22
|
+
* @returns Object with success status and optional error message
|
|
23
|
+
*
|
|
24
|
+
* @example
|
|
25
|
+
* ```typescript
|
|
26
|
+
* import { init } from 'rn-prodeeplinks';
|
|
27
|
+
*
|
|
28
|
+
* const result = await init({ licenseKey: 'your-license-key-here' });
|
|
29
|
+
* if (result.success) {
|
|
30
|
+
* console.log('Initialized successfully');
|
|
31
|
+
* }
|
|
32
|
+
* ```
|
|
33
|
+
*/
|
|
34
|
+
async function init(config) {
|
|
35
|
+
try {
|
|
36
|
+
const validation = (0, license_1.validateLicenseKeyFormat)(config.licenseKey);
|
|
37
|
+
if (!validation.isValid) {
|
|
38
|
+
return {
|
|
39
|
+
success: false,
|
|
40
|
+
error: validation.message || 'Invalid license key',
|
|
41
|
+
};
|
|
42
|
+
}
|
|
43
|
+
const remoteValidation = await (0, api_1.validateLicenseInit)(config.licenseKey);
|
|
44
|
+
if (!remoteValidation.success) {
|
|
45
|
+
return {
|
|
46
|
+
success: false,
|
|
47
|
+
error: remoteValidation.error || 'License validation failed',
|
|
48
|
+
};
|
|
49
|
+
}
|
|
50
|
+
storedLicenseKey = config.licenseKey;
|
|
51
|
+
isInitialized = true;
|
|
52
|
+
return {
|
|
53
|
+
success: true,
|
|
54
|
+
};
|
|
55
|
+
}
|
|
56
|
+
catch (error) {
|
|
57
|
+
return {
|
|
58
|
+
success: false,
|
|
59
|
+
error: error.message || 'Failed to initialize',
|
|
60
|
+
};
|
|
61
|
+
}
|
|
62
|
+
}
|
|
63
|
+
/**
|
|
64
|
+
* Get deep link URL from server
|
|
65
|
+
* This function automatically handles device fingerprinting internally
|
|
66
|
+
*
|
|
67
|
+
* @param callback - Optional callback function that receives the deep link URL
|
|
68
|
+
* @returns Promise with deep link response
|
|
69
|
+
*
|
|
70
|
+
* @example
|
|
71
|
+
* ```typescript
|
|
72
|
+
* import { getDeepLink } from 'rn-prodeeplinks';
|
|
73
|
+
*
|
|
74
|
+
* // Using promise
|
|
75
|
+
* const result = await getDeepLink();
|
|
76
|
+
* if (result.success && result.url) {
|
|
77
|
+
* console.log('Deep link:', result.url);
|
|
78
|
+
* }
|
|
79
|
+
*
|
|
80
|
+
* // Using callback
|
|
81
|
+
* getDeepLink((url) => {
|
|
82
|
+
* console.log('Deep link:', url);
|
|
83
|
+
* });
|
|
84
|
+
* ```
|
|
85
|
+
*/
|
|
86
|
+
async function getDeepLink(callback) {
|
|
87
|
+
// Check if initialized
|
|
88
|
+
if (!isInitialized || !storedLicenseKey) {
|
|
89
|
+
return {
|
|
90
|
+
success: false,
|
|
91
|
+
error: 'Please call init() first with your license key',
|
|
92
|
+
};
|
|
93
|
+
}
|
|
94
|
+
try {
|
|
95
|
+
// First: try to read deep link via Linking (if app opened by URL)
|
|
96
|
+
const initialUrl = await react_native_1.Linking.getInitialURL();
|
|
97
|
+
if (initialUrl) {
|
|
98
|
+
if (callback)
|
|
99
|
+
callback(initialUrl);
|
|
100
|
+
return { success: true, url: initialUrl };
|
|
101
|
+
}
|
|
102
|
+
// Generate device fingerprint internally (user doesn't need to know about this)
|
|
103
|
+
const fingerprint = await (0, fingerprint_1.generateDeviceFingerprint)();
|
|
104
|
+
// Fetch deep link URL from API with retry mechanism
|
|
105
|
+
const result = await (0, api_1.fetchDeepLinkUrlWithRetry)(storedLicenseKey, fingerprint, 3, // retry attempts
|
|
106
|
+
DEFAULT_API_ENDPOINT);
|
|
107
|
+
// Call callback if provided and result is successful
|
|
108
|
+
if (callback && result.success && result.url) {
|
|
109
|
+
callback(result.url);
|
|
110
|
+
}
|
|
111
|
+
// If API didn't return a usable URL, return null as per requirements
|
|
112
|
+
if (!result.success || !result.url) {
|
|
113
|
+
return { success: true, url: null, message: 'No deep link available' };
|
|
114
|
+
}
|
|
115
|
+
return result;
|
|
116
|
+
}
|
|
117
|
+
catch (error) {
|
|
118
|
+
console.error('Error in getDeepLink:', error);
|
|
119
|
+
return {
|
|
120
|
+
success: false,
|
|
121
|
+
error: error.message || 'Unknown error occurred',
|
|
122
|
+
};
|
|
123
|
+
}
|
|
124
|
+
}
|
|
125
|
+
/**
|
|
126
|
+
* Check if the package is initialized
|
|
127
|
+
*/
|
|
128
|
+
function isReady() {
|
|
129
|
+
return isInitialized && storedLicenseKey !== null;
|
|
130
|
+
}
|
|
131
|
+
/**
|
|
132
|
+
* Reset/clear the stored license key
|
|
133
|
+
* Useful for testing or logout scenarios
|
|
134
|
+
*/
|
|
135
|
+
function reset() {
|
|
136
|
+
storedLicenseKey = null;
|
|
137
|
+
isInitialized = false;
|
|
138
|
+
}
|
|
139
|
+
// Keep backward compatibility - export class for advanced users (optional)
|
|
140
|
+
class ProDeepLink {
|
|
141
|
+
constructor(config) {
|
|
142
|
+
const validation = (0, license_1.validateLicenseKeyFormat)(config.licenseKey);
|
|
143
|
+
if (!validation.isValid) {
|
|
144
|
+
throw new Error(validation.message || 'Invalid license key');
|
|
145
|
+
}
|
|
146
|
+
this.licenseKey = config.licenseKey;
|
|
147
|
+
}
|
|
148
|
+
async getDeepLinkUrl() {
|
|
149
|
+
const remoteValidation = await (0, api_1.validateLicenseInit)(this.licenseKey);
|
|
150
|
+
if (!remoteValidation.success) {
|
|
151
|
+
return {
|
|
152
|
+
success: false,
|
|
153
|
+
error: remoteValidation.error || 'License validation failed',
|
|
154
|
+
};
|
|
155
|
+
}
|
|
156
|
+
const fingerprint = await (0, fingerprint_1.generateDeviceFingerprint)();
|
|
157
|
+
return await (0, api_1.fetchDeepLinkUrlWithRetry)(this.licenseKey, fingerprint, 3, DEFAULT_API_ENDPOINT);
|
|
158
|
+
}
|
|
159
|
+
}
|
|
160
|
+
exports.ProDeepLink = ProDeepLink;
|
|
161
|
+
// Export default
|
|
162
|
+
exports.default = { init, getDeepLink, isReady, reset };
|
package/lib/license.d.ts
ADDED
package/lib/license.js
ADDED
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.validateLicenseKeyFormat = validateLicenseKeyFormat;
|
|
4
|
+
function validateLicenseKeyFormat(licenseKey) {
|
|
5
|
+
if (!licenseKey || typeof licenseKey !== 'string' || !licenseKey.trim()) {
|
|
6
|
+
return {
|
|
7
|
+
isValid: false,
|
|
8
|
+
message: 'License key is required',
|
|
9
|
+
};
|
|
10
|
+
}
|
|
11
|
+
return {
|
|
12
|
+
isValid: true,
|
|
13
|
+
};
|
|
14
|
+
}
|
package/lib/types.d.ts
ADDED
|
@@ -0,0 +1,158 @@
|
|
|
1
|
+
export interface DeviceFingerprint {
|
|
2
|
+
platform: 'ios' | 'android';
|
|
3
|
+
osVersion: string;
|
|
4
|
+
deviceId: string;
|
|
5
|
+
deviceModel: string;
|
|
6
|
+
manufacturer?: string;
|
|
7
|
+
screenResolution: string;
|
|
8
|
+
screenWidth: number;
|
|
9
|
+
screenHeight: number;
|
|
10
|
+
timezone?: string;
|
|
11
|
+
language?: string;
|
|
12
|
+
locale?: string;
|
|
13
|
+
appVersion: string;
|
|
14
|
+
carrier?: string;
|
|
15
|
+
connectionType?: string;
|
|
16
|
+
isSimulator?: boolean;
|
|
17
|
+
isRooted?: boolean;
|
|
18
|
+
ipAddress?: string;
|
|
19
|
+
}
|
|
20
|
+
export interface InitConfig {
|
|
21
|
+
licenseKey: string;
|
|
22
|
+
apiBaseUrl?: string;
|
|
23
|
+
apiPrefix?: string;
|
|
24
|
+
domain?: string;
|
|
25
|
+
}
|
|
26
|
+
export interface DeepLinkConfig {
|
|
27
|
+
licenseKey: string;
|
|
28
|
+
apiEndpoint: string;
|
|
29
|
+
timeout?: number;
|
|
30
|
+
retryAttempts?: number;
|
|
31
|
+
}
|
|
32
|
+
export interface DeepLinkResponse {
|
|
33
|
+
success: boolean;
|
|
34
|
+
url?: string | null;
|
|
35
|
+
message?: string;
|
|
36
|
+
error?: string;
|
|
37
|
+
}
|
|
38
|
+
export interface LicenseValidationResult {
|
|
39
|
+
isValid: boolean;
|
|
40
|
+
message?: string;
|
|
41
|
+
}
|
|
42
|
+
export interface FingerprintBasicPayload {
|
|
43
|
+
userAgent: string;
|
|
44
|
+
language: string;
|
|
45
|
+
platform: string;
|
|
46
|
+
screenResolution: string;
|
|
47
|
+
timezone: string;
|
|
48
|
+
timezoneOffset: number;
|
|
49
|
+
}
|
|
50
|
+
export interface FingerprintNetworkPayload {
|
|
51
|
+
ipAddress: string;
|
|
52
|
+
connectionType: string;
|
|
53
|
+
}
|
|
54
|
+
export interface FingerprintDevicePayload {
|
|
55
|
+
deviceModel: string;
|
|
56
|
+
osVersion: string;
|
|
57
|
+
appVersion: string;
|
|
58
|
+
}
|
|
59
|
+
export interface FingerprintMatchPayload {
|
|
60
|
+
basic: FingerprintBasicPayload;
|
|
61
|
+
network: FingerprintNetworkPayload;
|
|
62
|
+
device: FingerprintDevicePayload;
|
|
63
|
+
userId?: string;
|
|
64
|
+
}
|
|
65
|
+
export interface CustomDeepLinkAnalyticsDeviceInfo {
|
|
66
|
+
userAgent?: string;
|
|
67
|
+
language?: string;
|
|
68
|
+
screenResolution?: string;
|
|
69
|
+
platform?: string;
|
|
70
|
+
[key: string]: any;
|
|
71
|
+
}
|
|
72
|
+
export interface CustomDeepLinkAnalyticsEvent {
|
|
73
|
+
licenseKey: string;
|
|
74
|
+
eventType: string;
|
|
75
|
+
eventName: string;
|
|
76
|
+
category?: string;
|
|
77
|
+
action?: string;
|
|
78
|
+
label?: string;
|
|
79
|
+
value?: number;
|
|
80
|
+
properties?: {
|
|
81
|
+
[key: string]: any;
|
|
82
|
+
};
|
|
83
|
+
sessionId?: string;
|
|
84
|
+
userId?: string;
|
|
85
|
+
pageUrl?: string;
|
|
86
|
+
pageTitle?: string;
|
|
87
|
+
deviceInfo?: CustomDeepLinkAnalyticsDeviceInfo;
|
|
88
|
+
[key: string]: any;
|
|
89
|
+
}
|
|
90
|
+
export interface LicenseFeatures {
|
|
91
|
+
maxLinksPerMonth: number;
|
|
92
|
+
maxDomains: number;
|
|
93
|
+
analyticsLevel: string;
|
|
94
|
+
customBranding: boolean;
|
|
95
|
+
webhookSupport: boolean;
|
|
96
|
+
whiteLabel: boolean;
|
|
97
|
+
apiAccess: boolean;
|
|
98
|
+
rateLimitPerMinute: number;
|
|
99
|
+
[key: string]: any;
|
|
100
|
+
}
|
|
101
|
+
export interface LicenseUsageCurrentMonth {
|
|
102
|
+
linksCreated: number;
|
|
103
|
+
clicks: number;
|
|
104
|
+
apiCalls: number;
|
|
105
|
+
lastReset: string;
|
|
106
|
+
[key: string]: any;
|
|
107
|
+
}
|
|
108
|
+
export interface LicenseUsage {
|
|
109
|
+
totalLinksCreated: number;
|
|
110
|
+
totalClicks: number;
|
|
111
|
+
totalApiCalls: number;
|
|
112
|
+
currentMonth: LicenseUsageCurrentMonth;
|
|
113
|
+
[key: string]: any;
|
|
114
|
+
}
|
|
115
|
+
export interface LicenseData {
|
|
116
|
+
tier: string;
|
|
117
|
+
features: LicenseFeatures;
|
|
118
|
+
validUntil: string;
|
|
119
|
+
usage: LicenseUsage;
|
|
120
|
+
[key: string]: any;
|
|
121
|
+
}
|
|
122
|
+
export interface LicenseValidationApiResponse {
|
|
123
|
+
success: boolean;
|
|
124
|
+
valid?: boolean;
|
|
125
|
+
data?: LicenseData;
|
|
126
|
+
[key: string]: any;
|
|
127
|
+
}
|
|
128
|
+
export interface FingerprintMatchInstallInfo {
|
|
129
|
+
_id: string;
|
|
130
|
+
linkId: string;
|
|
131
|
+
installedAt: string;
|
|
132
|
+
timeToInstall: number;
|
|
133
|
+
[key: string]: any;
|
|
134
|
+
}
|
|
135
|
+
export interface DeepLinkContextMetadata {
|
|
136
|
+
title?: string;
|
|
137
|
+
description?: string;
|
|
138
|
+
imageUrl?: string;
|
|
139
|
+
[key: string]: any;
|
|
140
|
+
}
|
|
141
|
+
export interface DeepLinkContext {
|
|
142
|
+
action: string;
|
|
143
|
+
resourceId?: string;
|
|
144
|
+
params?: {
|
|
145
|
+
[key: string]: any;
|
|
146
|
+
};
|
|
147
|
+
metadata?: DeepLinkContextMetadata;
|
|
148
|
+
campaign?: string;
|
|
149
|
+
source?: string;
|
|
150
|
+
[key: string]: any;
|
|
151
|
+
}
|
|
152
|
+
export interface FingerprintMatchResponse {
|
|
153
|
+
matched: boolean;
|
|
154
|
+
matchConfidence?: number;
|
|
155
|
+
install?: FingerprintMatchInstallInfo;
|
|
156
|
+
deepLinkContext?: DeepLinkContext;
|
|
157
|
+
[key: string]: any;
|
|
158
|
+
}
|
package/lib/types.js
ADDED
package/package.json
ADDED
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "rn-prodeeplinks",
|
|
3
|
+
"version": "0.0.1",
|
|
4
|
+
"description": "Secure deep linking package with license key validation and device fingerprinting for React Native",
|
|
5
|
+
"main": "lib/index.js",
|
|
6
|
+
"types": "lib/index.d.ts",
|
|
7
|
+
"scripts": {
|
|
8
|
+
"build": "tsc",
|
|
9
|
+
"prepublishOnly": "npm run build",
|
|
10
|
+
"test": "echo \"Error: no test specified\" && exit 1"
|
|
11
|
+
},
|
|
12
|
+
"keywords": [
|
|
13
|
+
"react-native",
|
|
14
|
+
"deeplink",
|
|
15
|
+
"deep-link",
|
|
16
|
+
"device-fingerprint",
|
|
17
|
+
"license",
|
|
18
|
+
"secure",
|
|
19
|
+
"authentication"
|
|
20
|
+
],
|
|
21
|
+
"author": "",
|
|
22
|
+
"license": "MIT",
|
|
23
|
+
"peerDependencies": {
|
|
24
|
+
"react-native": ">=0.60.0",
|
|
25
|
+
"react-native-device-info": "^10.0.0",
|
|
26
|
+
"@react-native-community/netinfo": "^9.0.0"
|
|
27
|
+
},
|
|
28
|
+
"devDependencies": {
|
|
29
|
+
"@types/react-native": "^0.72.0",
|
|
30
|
+
"typescript": "^5.0.0"
|
|
31
|
+
},
|
|
32
|
+
"files": [
|
|
33
|
+
"lib",
|
|
34
|
+
"README.md",
|
|
35
|
+
"LICENSE"
|
|
36
|
+
],
|
|
37
|
+
"repository": {
|
|
38
|
+
"type": "git",
|
|
39
|
+
"url": "https://github.com/2ndGenTech/rn-prodeeplinks.git"
|
|
40
|
+
}
|
|
41
|
+
}
|