@explorins/pers-sdk-react-native 2.3.7 → 2.3.8
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 +21 -0
- package/README.md +1266 -1244
- package/dist/__tests__/PersSDKProvider.test.js +33 -0
- package/dist/hooks/useBusiness.d.ts +2 -2
- package/dist/hooks/useBusiness.d.ts.map +1 -1
- package/dist/hooks/useBusiness.js +2 -2
- package/dist/hooks/useIPFSUrl.d.ts +3 -3
- package/dist/hooks/useIPFSUrl.d.ts.map +1 -1
- package/dist/hooks/useIPFSUrl.js +7 -7
- package/dist/hooks/useWeb3.js +4 -4
- package/dist/index.js +2400 -487
- package/dist/index.js.map +1 -1
- package/dist/providers/PersSDKProvider.d.ts +4 -0
- package/dist/providers/PersSDKProvider.d.ts.map +1 -1
- package/dist/providers/PersSDKProvider.js +14 -0
- package/dist/providers/react-native-http-client.d.ts +2 -0
- package/dist/providers/react-native-http-client.d.ts.map +1 -1
- package/dist/providers/react-native-http-client.js +5 -2
- package/dist/storage/rn-secure-storage.d.ts.map +1 -1
- package/dist/storage/rn-secure-storage.js +21 -8
- package/package.json +3 -3
- package/src/__tests__/PersSDKProvider.test.tsx +484 -420
- package/src/__tests__/setup.ts +40 -40
- package/src/hooks/index.ts +60 -60
- package/src/hooks/useAnalytics.ts +327 -327
- package/src/hooks/useAuth.ts +265 -265
- package/src/hooks/useBookings.ts +191 -191
- package/src/hooks/useBusiness.ts +251 -251
- package/src/hooks/useCampaigns.ts +500 -500
- package/src/hooks/useDonations.ts +66 -66
- package/src/hooks/useEvents.ts +372 -372
- package/src/hooks/useFiles.ts +155 -155
- package/src/hooks/useIPFSUrl.ts +192 -192
- package/src/hooks/usePurchases.ts +65 -65
- package/src/hooks/useRedemptions.ts +467 -467
- package/src/hooks/useTenants.ts +72 -72
- package/src/hooks/useTokenBalances.ts +385 -385
- package/src/hooks/useTokens.ts +313 -313
- package/src/hooks/useTransactionSigner.ts +611 -611
- package/src/hooks/useTransactions.ts +299 -299
- package/src/hooks/useTriggerSources.ts +301 -301
- package/src/hooks/useUserStatus.ts +61 -61
- package/src/hooks/useUsers.ts +167 -167
- package/src/hooks/useWeb3.ts +355 -355
- package/src/index.ts +777 -777
- package/src/polyfills/index.ts +160 -160
- package/src/polyfills/web3-polyfills.ts +97 -97
- package/src/providers/PersSDKProvider.tsx +393 -374
- package/src/providers/react-native-auth-provider.ts +110 -110
- package/src/providers/react-native-http-client.ts +150 -145
- package/src/providers/rn-dpop-provider.ts +190 -190
- package/src/storage/async-storage-token-storage.ts +185 -185
- package/src/storage/rn-secure-storage.ts +182 -170
- package/src/types/react-native-globals.d.ts +45 -45
- package/src/utils/index.ts +8 -8
- package/src/utils/platform-detection.ts +86 -86
- package/dist/index-CzLxqePZ.js +0 -7717
- package/dist/index-CzLxqePZ.js.map +0 -1
|
@@ -1,170 +1,182 @@
|
|
|
1
|
-
import { Platform } from 'react-native';
|
|
2
|
-
import {
|
|
3
|
-
TokenStorage,
|
|
4
|
-
DPOP_STORAGE_KEYS,
|
|
5
|
-
AUTH_STORAGE_KEYS
|
|
6
|
-
} from '@explorins/pers-sdk/core';
|
|
7
|
-
import { AsyncStorageTokenStorage } from './async-storage-token-storage';
|
|
8
|
-
|
|
9
|
-
// Conditionally require Keychain to avoid Web bundler errors
|
|
10
|
-
let Keychain: any;
|
|
11
|
-
if (Platform.OS !== 'web') {
|
|
12
|
-
try {
|
|
13
|
-
Keychain = require('react-native-keychain');
|
|
14
|
-
} catch (e) {
|
|
15
|
-
console.warn('ReactNativeSecureStorage: Failed to load react-native-keychain', e);
|
|
16
|
-
}
|
|
17
|
-
}
|
|
18
|
-
|
|
19
|
-
/**
|
|
20
|
-
* Secure Storage implementation for React Native
|
|
21
|
-
* Uses Keychain/Keystore for sensitive data and AsyncStorage for non-sensitive data.
|
|
22
|
-
*/
|
|
23
|
-
export class ReactNativeSecureStorage implements TokenStorage {
|
|
24
|
-
// Set to false because Keychain stores strings, so we need extractable (serializable) keys
|
|
25
|
-
readonly supportsObjects = false;
|
|
26
|
-
|
|
27
|
-
// Define which keys MUST go to secure hardware storage
|
|
28
|
-
private readonly SECURE_KEYS = new Set([
|
|
29
|
-
DPOP_STORAGE_KEYS.PRIVATE,
|
|
30
|
-
AUTH_STORAGE_KEYS.ACCESS_TOKEN,
|
|
31
|
-
AUTH_STORAGE_KEYS.REFRESH_TOKEN,
|
|
32
|
-
AUTH_STORAGE_KEYS.PROVIDER_TOKEN
|
|
33
|
-
]);
|
|
34
|
-
|
|
35
|
-
private fallbackStorage: AsyncStorageTokenStorage;
|
|
36
|
-
|
|
37
|
-
constructor(private keyPrefix: string = 'pers_tokens_') {
|
|
38
|
-
this.fallbackStorage = new AsyncStorageTokenStorage(keyPrefix);
|
|
39
|
-
}
|
|
40
|
-
|
|
41
|
-
async set(key: string, value: unknown): Promise<void> {
|
|
42
|
-
const prefixedKey = this.getKeyName(key);
|
|
43
|
-
const stringValue = typeof value === 'string' ? value : JSON.stringify(value);
|
|
44
|
-
|
|
45
|
-
// Cast key to any to bypass strict literal type checking of the Set.has method
|
|
46
|
-
// In runtime, 'key' is just a string, so this is safe.
|
|
47
|
-
if (this.SECURE_KEYS.has(key as any)) {
|
|
48
|
-
// Store in Keychain/Keystore
|
|
49
|
-
try {
|
|
50
|
-
if (Keychain) {
|
|
51
|
-
// Service name acts as the key identifier in simple usage
|
|
52
|
-
await Keychain.setGenericPassword(prefixedKey, stringValue, { service: prefixedKey });
|
|
53
|
-
} else {
|
|
54
|
-
throw new Error('RN Keychain not available');
|
|
55
|
-
}
|
|
56
|
-
} catch (e) {
|
|
57
|
-
console.warn(`[ReactNativeSecureStorage] Keychain set failed for ${key}, falling back to AsyncStorage`, e);
|
|
58
|
-
// Fallback to AsyncStorage if Keychain fails
|
|
59
|
-
await this.fallbackStorage.set(key, stringValue);
|
|
60
|
-
}
|
|
61
|
-
} else {
|
|
62
|
-
// Store standard config/metadata in AsyncStorage
|
|
63
|
-
await this.fallbackStorage.set(key, stringValue);
|
|
64
|
-
}
|
|
65
|
-
}
|
|
66
|
-
|
|
67
|
-
async get(key: string): Promise<unknown | null> {
|
|
68
|
-
const prefixedKey = this.getKeyName(key);
|
|
69
|
-
|
|
70
|
-
if (this.SECURE_KEYS.has(key as any)) {
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
}
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
}
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
//
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
1
|
+
import { Platform } from 'react-native';
|
|
2
|
+
import {
|
|
3
|
+
TokenStorage,
|
|
4
|
+
DPOP_STORAGE_KEYS,
|
|
5
|
+
AUTH_STORAGE_KEYS
|
|
6
|
+
} from '@explorins/pers-sdk/core';
|
|
7
|
+
import { AsyncStorageTokenStorage } from './async-storage-token-storage';
|
|
8
|
+
|
|
9
|
+
// Conditionally require Keychain to avoid Web bundler errors
|
|
10
|
+
let Keychain: any;
|
|
11
|
+
if (Platform.OS !== 'web') {
|
|
12
|
+
try {
|
|
13
|
+
Keychain = require('react-native-keychain');
|
|
14
|
+
} catch (e) {
|
|
15
|
+
console.warn('ReactNativeSecureStorage: Failed to load react-native-keychain', e);
|
|
16
|
+
}
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
/**
|
|
20
|
+
* Secure Storage implementation for React Native
|
|
21
|
+
* Uses Keychain/Keystore for sensitive data and AsyncStorage for non-sensitive data.
|
|
22
|
+
*/
|
|
23
|
+
export class ReactNativeSecureStorage implements TokenStorage {
|
|
24
|
+
// Set to false because Keychain stores strings, so we need extractable (serializable) keys
|
|
25
|
+
readonly supportsObjects = false;
|
|
26
|
+
|
|
27
|
+
// Define which keys MUST go to secure hardware storage
|
|
28
|
+
private readonly SECURE_KEYS = new Set([
|
|
29
|
+
DPOP_STORAGE_KEYS.PRIVATE,
|
|
30
|
+
AUTH_STORAGE_KEYS.ACCESS_TOKEN,
|
|
31
|
+
AUTH_STORAGE_KEYS.REFRESH_TOKEN,
|
|
32
|
+
AUTH_STORAGE_KEYS.PROVIDER_TOKEN
|
|
33
|
+
]);
|
|
34
|
+
|
|
35
|
+
private fallbackStorage: AsyncStorageTokenStorage;
|
|
36
|
+
|
|
37
|
+
constructor(private keyPrefix: string = 'pers_tokens_') {
|
|
38
|
+
this.fallbackStorage = new AsyncStorageTokenStorage(keyPrefix);
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
async set(key: string, value: unknown): Promise<void> {
|
|
42
|
+
const prefixedKey = this.getKeyName(key);
|
|
43
|
+
const stringValue = typeof value === 'string' ? value : JSON.stringify(value);
|
|
44
|
+
|
|
45
|
+
// Cast key to any to bypass strict literal type checking of the Set.has method
|
|
46
|
+
// In runtime, 'key' is just a string, so this is safe.
|
|
47
|
+
if (this.SECURE_KEYS.has(key as any)) {
|
|
48
|
+
// Store in Keychain/Keystore
|
|
49
|
+
try {
|
|
50
|
+
if (Keychain) {
|
|
51
|
+
// Service name acts as the key identifier in simple usage
|
|
52
|
+
await Keychain.setGenericPassword(prefixedKey, stringValue, { service: prefixedKey });
|
|
53
|
+
} else {
|
|
54
|
+
throw new Error('RN Keychain not available');
|
|
55
|
+
}
|
|
56
|
+
} catch (e) {
|
|
57
|
+
console.warn(`[ReactNativeSecureStorage] Keychain set failed for ${key}, falling back to AsyncStorage`, e);
|
|
58
|
+
// Fallback to AsyncStorage if Keychain fails
|
|
59
|
+
await this.fallbackStorage.set(key, stringValue);
|
|
60
|
+
}
|
|
61
|
+
} else {
|
|
62
|
+
// Store standard config/metadata in AsyncStorage
|
|
63
|
+
await this.fallbackStorage.set(key, stringValue);
|
|
64
|
+
}
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
async get(key: string): Promise<unknown | null> {
|
|
68
|
+
const prefixedKey = this.getKeyName(key);
|
|
69
|
+
|
|
70
|
+
if (this.SECURE_KEYS.has(key as any)) {
|
|
71
|
+
// The iOS Keychain can be briefly unreadable (device locked, background launch), so retry before giving up
|
|
72
|
+
let keychainError: unknown;
|
|
73
|
+
if (Keychain) {
|
|
74
|
+
for (let attempt = 0; attempt < 3; attempt++) {
|
|
75
|
+
try {
|
|
76
|
+
const credentials = await Keychain.getGenericPassword({ service: prefixedKey });
|
|
77
|
+
if (credentials) {
|
|
78
|
+
return this.tryParse(credentials.password);
|
|
79
|
+
}
|
|
80
|
+
keychainError = undefined;
|
|
81
|
+
break;
|
|
82
|
+
} catch (e) {
|
|
83
|
+
keychainError = e;
|
|
84
|
+
if (attempt < 2) await new Promise(resolve => setTimeout(resolve, 150 * (attempt + 1)));
|
|
85
|
+
}
|
|
86
|
+
}
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
if (keychainError) {
|
|
90
|
+
console.warn(`[ReactNativeSecureStorage] Failed to access keychain for ${key}`, keychainError);
|
|
91
|
+
// Returning "missing" here would make the DPoP manager regenerate the key pair and log the user out
|
|
92
|
+
if (key === DPOP_STORAGE_KEYS.PRIVATE) throw keychainError;
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
// Fallback: Check AsyncStorage if not found in Keychain or Keychain failed
|
|
96
|
+
try {
|
|
97
|
+
const val = await this.fallbackStorage.get(key);
|
|
98
|
+
return val ? this.tryParse(val) : null;
|
|
99
|
+
} catch (e) {
|
|
100
|
+
return null;
|
|
101
|
+
}
|
|
102
|
+
} else {
|
|
103
|
+
try {
|
|
104
|
+
const val = await this.fallbackStorage.get(key);
|
|
105
|
+
return val ? this.tryParse(val) : null;
|
|
106
|
+
} catch (e) {
|
|
107
|
+
console.warn(`[ReactNativeSecureStorage] Failed to access AsyncStorage for ${key}`, e);
|
|
108
|
+
return null;
|
|
109
|
+
}
|
|
110
|
+
}
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
async remove(key: string): Promise<void> {
|
|
114
|
+
const prefixedKey = this.getKeyName(key);
|
|
115
|
+
|
|
116
|
+
if (this.SECURE_KEYS.has(key as any)) {
|
|
117
|
+
try {
|
|
118
|
+
if (Keychain) {
|
|
119
|
+
await Keychain.resetGenericPassword({ service: prefixedKey });
|
|
120
|
+
}
|
|
121
|
+
} catch (e) {
|
|
122
|
+
console.warn(`[ReactNativeSecureStorage] Failed to reset keychain for ${key}`, e);
|
|
123
|
+
}
|
|
124
|
+
// Always remove from fallback storage too, just in case
|
|
125
|
+
await this.fallbackStorage.remove(key);
|
|
126
|
+
} else {
|
|
127
|
+
await this.fallbackStorage.remove(key);
|
|
128
|
+
}
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
async clear(): Promise<void> {
|
|
132
|
+
const clearPromises: Promise<void>[] = [];
|
|
133
|
+
|
|
134
|
+
// Clear all known secure keys with retry logic
|
|
135
|
+
for (const key of this.SECURE_KEYS) {
|
|
136
|
+
clearPromises.push(
|
|
137
|
+
(async () => {
|
|
138
|
+
try {
|
|
139
|
+
if (Keychain) {
|
|
140
|
+
await Keychain.resetGenericPassword({ service: this.getKeyName(key) });
|
|
141
|
+
}
|
|
142
|
+
} catch (e) {
|
|
143
|
+
console.warn(`[ReactNativeSecureStorage] Retry clearing ${key}`);
|
|
144
|
+
// Retry once
|
|
145
|
+
try {
|
|
146
|
+
if (Keychain) {
|
|
147
|
+
await Keychain.resetGenericPassword({ service: this.getKeyName(key) });
|
|
148
|
+
}
|
|
149
|
+
} catch (retryError) {
|
|
150
|
+
console.error(`[ReactNativeSecureStorage] Failed to clear ${key} after retry:`, retryError);
|
|
151
|
+
}
|
|
152
|
+
}
|
|
153
|
+
})()
|
|
154
|
+
);
|
|
155
|
+
}
|
|
156
|
+
|
|
157
|
+
// Wait for all Keychain clearing to complete (or fail)
|
|
158
|
+
await Promise.allSettled(clearPromises);
|
|
159
|
+
|
|
160
|
+
// Always clear AsyncStorage fallback
|
|
161
|
+
try {
|
|
162
|
+
await this.fallbackStorage.clear();
|
|
163
|
+
} catch (e) {
|
|
164
|
+
console.error('[ReactNativeSecureStorage] Failed to clear AsyncStorage:', e);
|
|
165
|
+
}
|
|
166
|
+
}
|
|
167
|
+
|
|
168
|
+
private getKeyName(key: string): string {
|
|
169
|
+
// For Keychain, we might want to avoid prefixes if we want to share across apps,
|
|
170
|
+
// but for simple isolation, prefix is fine to avoid collisions if multiple instances exist.
|
|
171
|
+
// However, Keychain services are global to the app bundle ID usually.
|
|
172
|
+
return `${this.keyPrefix}${key}`;
|
|
173
|
+
}
|
|
174
|
+
|
|
175
|
+
private tryParse(val: string): unknown {
|
|
176
|
+
try {
|
|
177
|
+
return JSON.parse(val);
|
|
178
|
+
} catch {
|
|
179
|
+
return val;
|
|
180
|
+
}
|
|
181
|
+
}
|
|
182
|
+
}
|
|
@@ -1,46 +1,46 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* React Native Global Type Declarations
|
|
3
|
-
*
|
|
4
|
-
* This file declares global types that are available in React Native
|
|
5
|
-
* but might not be available in TypeScript compilation.
|
|
6
|
-
*/
|
|
7
|
-
|
|
8
|
-
// React Native global type declarations
|
|
9
|
-
declare global {
|
|
10
|
-
interface Navigator {
|
|
11
|
-
product?: string;
|
|
12
|
-
}
|
|
13
|
-
|
|
14
|
-
var navigator: Navigator | undefined;
|
|
15
|
-
var localStorage: Storage | undefined;
|
|
16
|
-
|
|
17
|
-
interface Storage {
|
|
18
|
-
getItem(key: string): string | null;
|
|
19
|
-
setItem(key: string, value: string): void;
|
|
20
|
-
removeItem(key: string): void;
|
|
21
|
-
}
|
|
22
|
-
|
|
23
|
-
// Global object - React Native environment
|
|
24
|
-
var global: typeof globalThis & {
|
|
25
|
-
global: typeof globalThis;
|
|
26
|
-
Buffer: typeof Buffer;
|
|
27
|
-
process: NodeJS.Process;
|
|
28
|
-
};
|
|
29
|
-
|
|
30
|
-
// Process object for Node.js compatibility
|
|
31
|
-
namespace NodeJS {
|
|
32
|
-
interface Process {
|
|
33
|
-
env: Record<string, string | undefined>;
|
|
34
|
-
}
|
|
35
|
-
}
|
|
36
|
-
|
|
37
|
-
var process: NodeJS.Process;
|
|
38
|
-
|
|
39
|
-
// Buffer for Node.js compatibility
|
|
40
|
-
var Buffer: {
|
|
41
|
-
from(data: any, encoding?: string): any;
|
|
42
|
-
alloc(size: number): any;
|
|
43
|
-
};
|
|
44
|
-
}
|
|
45
|
-
|
|
1
|
+
/**
|
|
2
|
+
* React Native Global Type Declarations
|
|
3
|
+
*
|
|
4
|
+
* This file declares global types that are available in React Native
|
|
5
|
+
* but might not be available in TypeScript compilation.
|
|
6
|
+
*/
|
|
7
|
+
|
|
8
|
+
// React Native global type declarations
|
|
9
|
+
declare global {
|
|
10
|
+
interface Navigator {
|
|
11
|
+
product?: string;
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
var navigator: Navigator | undefined;
|
|
15
|
+
var localStorage: Storage | undefined;
|
|
16
|
+
|
|
17
|
+
interface Storage {
|
|
18
|
+
getItem(key: string): string | null;
|
|
19
|
+
setItem(key: string, value: string): void;
|
|
20
|
+
removeItem(key: string): void;
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
// Global object - React Native environment
|
|
24
|
+
var global: typeof globalThis & {
|
|
25
|
+
global: typeof globalThis;
|
|
26
|
+
Buffer: typeof Buffer;
|
|
27
|
+
process: NodeJS.Process;
|
|
28
|
+
};
|
|
29
|
+
|
|
30
|
+
// Process object for Node.js compatibility
|
|
31
|
+
namespace NodeJS {
|
|
32
|
+
interface Process {
|
|
33
|
+
env: Record<string, string | undefined>;
|
|
34
|
+
}
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
var process: NodeJS.Process;
|
|
38
|
+
|
|
39
|
+
// Buffer for Node.js compatibility
|
|
40
|
+
var Buffer: {
|
|
41
|
+
from(data: any, encoding?: string): any;
|
|
42
|
+
alloc(size: number): any;
|
|
43
|
+
};
|
|
44
|
+
}
|
|
45
|
+
|
|
46
46
|
export {};
|
package/src/utils/index.ts
CHANGED
|
@@ -1,8 +1,8 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Utility exports for React Native SDK
|
|
3
|
-
*/
|
|
4
|
-
|
|
5
|
-
export {
|
|
6
|
-
detectReactNativePlatform,
|
|
7
|
-
detectReactNativePlatformSync
|
|
8
|
-
} from './platform-detection';
|
|
1
|
+
/**
|
|
2
|
+
* Utility exports for React Native SDK
|
|
3
|
+
*/
|
|
4
|
+
|
|
5
|
+
export {
|
|
6
|
+
detectReactNativePlatform,
|
|
7
|
+
detectReactNativePlatformSync
|
|
8
|
+
} from './platform-detection';
|
|
@@ -1,86 +1,86 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* React Native Platform Detection Utilities
|
|
3
|
-
*
|
|
4
|
-
* Provides automatic platform info detection for React Native apps.
|
|
5
|
-
*
|
|
6
|
-
* @module @explorins/pers-sdk-react-native/utils
|
|
7
|
-
*/
|
|
8
|
-
|
|
9
|
-
import { Platform as RNPlatform } from 'react-native';
|
|
10
|
-
import type { Platform } from '@explorins/pers-sdk/core';
|
|
11
|
-
|
|
12
|
-
// DeviceInfo is optional - dynamically loaded if available
|
|
13
|
-
let DeviceInfo: any = null;
|
|
14
|
-
try {
|
|
15
|
-
// eslint-disable-next-line @typescript-eslint/no-require-imports
|
|
16
|
-
DeviceInfo = require('react-native-device-info').default;
|
|
17
|
-
} catch {
|
|
18
|
-
// react-native-device-info not installed - will use basic detection
|
|
19
|
-
}
|
|
20
|
-
|
|
21
|
-
/**
|
|
22
|
-
* Detect platform info for React Native apps
|
|
23
|
-
*
|
|
24
|
-
* Automatically gathers OS, version, app info, and device type.
|
|
25
|
-
* Uses react-native-device-info for enhanced detection if installed.
|
|
26
|
-
*
|
|
27
|
-
* @example
|
|
28
|
-
* ```typescript
|
|
29
|
-
* import { detectReactNativePlatform } from '@explorins/pers-sdk-react-native';
|
|
30
|
-
*
|
|
31
|
-
* // Get platform info
|
|
32
|
-
* const platform = await detectReactNativePlatform();
|
|
33
|
-
* // { os: 'iOS', osVersion: '17.4', app: 'MyApp', appVersion: '2.3.1', deviceType: 'phone' }
|
|
34
|
-
*
|
|
35
|
-
* // Set in SDK
|
|
36
|
-
* sdk.setPlatform(platform);
|
|
37
|
-
* ```
|
|
38
|
-
*/
|
|
39
|
-
export async function detectReactNativePlatform(): Promise<Platform> {
|
|
40
|
-
const platform: Platform = {
|
|
41
|
-
os: RNPlatform.OS === 'ios' ? 'iOS' : RNPlatform.OS === 'android' ? 'Android' : RNPlatform.OS,
|
|
42
|
-
osVersion: RNPlatform.Version?.toString(),
|
|
43
|
-
deviceType: 'phone', // Default fallback
|
|
44
|
-
};
|
|
45
|
-
|
|
46
|
-
if (DeviceInfo) {
|
|
47
|
-
try {
|
|
48
|
-
// App info
|
|
49
|
-
platform.app = await DeviceInfo.getApplicationName();
|
|
50
|
-
platform.appVersion = DeviceInfo.getVersion();
|
|
51
|
-
|
|
52
|
-
// Device type detection
|
|
53
|
-
const isTablet = await DeviceInfo.isTablet();
|
|
54
|
-
platform.deviceType = isTablet ? 'tablet' : 'phone';
|
|
55
|
-
} catch (error) {
|
|
56
|
-
console.debug('[Platform] DeviceInfo error, using basic detection');
|
|
57
|
-
}
|
|
58
|
-
}
|
|
59
|
-
|
|
60
|
-
return platform;
|
|
61
|
-
}
|
|
62
|
-
|
|
63
|
-
/**
|
|
64
|
-
* Synchronous version for immediate use (limited info)
|
|
65
|
-
*
|
|
66
|
-
* Use when you need platform info immediately without async.
|
|
67
|
-
* For full info including device type, use detectReactNativePlatform().
|
|
68
|
-
*/
|
|
69
|
-
export function detectReactNativePlatformSync(): Platform {
|
|
70
|
-
const platform: Platform = {
|
|
71
|
-
os: RNPlatform.OS === 'ios' ? 'iOS' : RNPlatform.OS === 'android' ? 'Android' : RNPlatform.OS,
|
|
72
|
-
osVersion: RNPlatform.Version?.toString(),
|
|
73
|
-
deviceType: 'phone', // Default, can't detect tablet sync without DeviceInfo
|
|
74
|
-
};
|
|
75
|
-
|
|
76
|
-
if (DeviceInfo) {
|
|
77
|
-
try {
|
|
78
|
-
platform.app = DeviceInfo.getApplicationNameSync?.();
|
|
79
|
-
platform.appVersion = DeviceInfo.getVersion?.();
|
|
80
|
-
} catch {
|
|
81
|
-
// Ignore if DeviceInfo methods fail
|
|
82
|
-
}
|
|
83
|
-
}
|
|
84
|
-
|
|
85
|
-
return platform;
|
|
86
|
-
}
|
|
1
|
+
/**
|
|
2
|
+
* React Native Platform Detection Utilities
|
|
3
|
+
*
|
|
4
|
+
* Provides automatic platform info detection for React Native apps.
|
|
5
|
+
*
|
|
6
|
+
* @module @explorins/pers-sdk-react-native/utils
|
|
7
|
+
*/
|
|
8
|
+
|
|
9
|
+
import { Platform as RNPlatform } from 'react-native';
|
|
10
|
+
import type { Platform } from '@explorins/pers-sdk/core';
|
|
11
|
+
|
|
12
|
+
// DeviceInfo is optional - dynamically loaded if available
|
|
13
|
+
let DeviceInfo: any = null;
|
|
14
|
+
try {
|
|
15
|
+
// eslint-disable-next-line @typescript-eslint/no-require-imports
|
|
16
|
+
DeviceInfo = require('react-native-device-info').default;
|
|
17
|
+
} catch {
|
|
18
|
+
// react-native-device-info not installed - will use basic detection
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
/**
|
|
22
|
+
* Detect platform info for React Native apps
|
|
23
|
+
*
|
|
24
|
+
* Automatically gathers OS, version, app info, and device type.
|
|
25
|
+
* Uses react-native-device-info for enhanced detection if installed.
|
|
26
|
+
*
|
|
27
|
+
* @example
|
|
28
|
+
* ```typescript
|
|
29
|
+
* import { detectReactNativePlatform } from '@explorins/pers-sdk-react-native';
|
|
30
|
+
*
|
|
31
|
+
* // Get platform info
|
|
32
|
+
* const platform = await detectReactNativePlatform();
|
|
33
|
+
* // { os: 'iOS', osVersion: '17.4', app: 'MyApp', appVersion: '2.3.1', deviceType: 'phone' }
|
|
34
|
+
*
|
|
35
|
+
* // Set in SDK
|
|
36
|
+
* sdk.setPlatform(platform);
|
|
37
|
+
* ```
|
|
38
|
+
*/
|
|
39
|
+
export async function detectReactNativePlatform(): Promise<Platform> {
|
|
40
|
+
const platform: Platform = {
|
|
41
|
+
os: RNPlatform.OS === 'ios' ? 'iOS' : RNPlatform.OS === 'android' ? 'Android' : RNPlatform.OS,
|
|
42
|
+
osVersion: RNPlatform.Version?.toString(),
|
|
43
|
+
deviceType: 'phone', // Default fallback
|
|
44
|
+
};
|
|
45
|
+
|
|
46
|
+
if (DeviceInfo) {
|
|
47
|
+
try {
|
|
48
|
+
// App info
|
|
49
|
+
platform.app = await DeviceInfo.getApplicationName();
|
|
50
|
+
platform.appVersion = DeviceInfo.getVersion();
|
|
51
|
+
|
|
52
|
+
// Device type detection
|
|
53
|
+
const isTablet = await DeviceInfo.isTablet();
|
|
54
|
+
platform.deviceType = isTablet ? 'tablet' : 'phone';
|
|
55
|
+
} catch (error) {
|
|
56
|
+
console.debug('[Platform] DeviceInfo error, using basic detection');
|
|
57
|
+
}
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
return platform;
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
/**
|
|
64
|
+
* Synchronous version for immediate use (limited info)
|
|
65
|
+
*
|
|
66
|
+
* Use when you need platform info immediately without async.
|
|
67
|
+
* For full info including device type, use detectReactNativePlatform().
|
|
68
|
+
*/
|
|
69
|
+
export function detectReactNativePlatformSync(): Platform {
|
|
70
|
+
const platform: Platform = {
|
|
71
|
+
os: RNPlatform.OS === 'ios' ? 'iOS' : RNPlatform.OS === 'android' ? 'Android' : RNPlatform.OS,
|
|
72
|
+
osVersion: RNPlatform.Version?.toString(),
|
|
73
|
+
deviceType: 'phone', // Default, can't detect tablet sync without DeviceInfo
|
|
74
|
+
};
|
|
75
|
+
|
|
76
|
+
if (DeviceInfo) {
|
|
77
|
+
try {
|
|
78
|
+
platform.app = DeviceInfo.getApplicationNameSync?.();
|
|
79
|
+
platform.appVersion = DeviceInfo.getVersion?.();
|
|
80
|
+
} catch {
|
|
81
|
+
// Ignore if DeviceInfo methods fail
|
|
82
|
+
}
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
return platform;
|
|
86
|
+
}
|