@explorins/pers-sdk-react-native 1.5.17 → 1.5.20
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 +336 -234
- package/dist/hooks/index.d.ts +1 -1
- package/dist/hooks/index.d.ts.map +1 -1
- package/dist/hooks/useAuth.d.ts +1 -1
- package/dist/hooks/useAuth.d.ts.map +1 -1
- package/dist/hooks/useAuth.js +7 -7
- package/dist/hooks/useRedemptions.d.ts.map +1 -1
- package/dist/hooks/useRedemptions.js +4 -4
- package/dist/hooks/useTenants.d.ts.map +1 -1
- package/dist/hooks/useTenants.js +0 -1
- package/dist/hooks/useTransactionSigner.d.ts +186 -53
- package/dist/hooks/useTransactionSigner.d.ts.map +1 -1
- package/dist/hooks/useTransactionSigner.js +285 -102
- package/dist/hooks/useTransactions.d.ts +2 -2
- package/dist/hooks/useTransactions.d.ts.map +1 -1
- package/dist/hooks/useTransactions.js +38 -9
- package/dist/index.d.ts +211 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +21154 -18543
- package/dist/index.js.map +1 -1
- package/dist/providers/PersSDKProvider.d.ts +2 -8
- package/dist/providers/PersSDKProvider.d.ts.map +1 -1
- package/dist/providers/PersSDKProvider.js +16 -31
- package/dist/providers/react-native-auth-provider.d.ts +25 -36
- package/dist/providers/react-native-auth-provider.d.ts.map +1 -1
- package/dist/providers/react-native-auth-provider.js +36 -146
- package/dist/storage/async-storage-token-storage.d.ts +22 -0
- package/dist/storage/async-storage-token-storage.d.ts.map +1 -0
- package/dist/storage/async-storage-token-storage.js +113 -0
- package/package.json +16 -11
- package/src/hooks/index.ts +1 -1
- package/src/hooks/useAuth.ts +7 -7
- package/src/hooks/useRedemptions.ts +5 -7
- package/src/hooks/useTenants.ts +0 -1
- package/src/hooks/useTransactionSigner.ts +322 -166
- package/src/hooks/useTransactions.ts +44 -11
- package/src/index.ts +243 -7
- package/src/providers/PersSDKProvider.tsx +21 -40
- package/src/providers/react-native-auth-provider.ts +59 -176
- package/src/storage/async-storage-token-storage.ts +133 -0
|
@@ -1,189 +1,72 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
1
|
+
/**
|
|
2
|
+
* React Native Unified Auth Provider
|
|
3
|
+
*
|
|
4
|
+
* Creates a platform-specific auth provider that automatically selects the appropriate storage:
|
|
5
|
+
* - Web: Uses LocalStorageTokenStorage from core SDK
|
|
6
|
+
* - Mobile: Uses AsyncStorage-based storage
|
|
7
|
+
*/
|
|
8
|
+
|
|
9
|
+
import { Platform } from 'react-native';
|
|
10
|
+
import { DefaultAuthProvider, AuthApi, AuthType, LocalStorageTokenStorage } from '@explorins/pers-sdk/core';
|
|
11
|
+
import { AsyncStorageTokenStorage } from '../storage/async-storage-token-storage';
|
|
12
|
+
import type { TokenStorage } from '@explorins/pers-sdk/core';
|
|
13
|
+
|
|
14
|
+
// Use React Native's built-in platform detection
|
|
15
|
+
const isWebPlatform = Platform.OS === 'web';
|
|
3
16
|
|
|
4
17
|
/**
|
|
5
|
-
* Configuration
|
|
18
|
+
* Configuration for React Native Auth Provider
|
|
6
19
|
*/
|
|
7
20
|
export interface ReactNativeAuthConfig {
|
|
8
|
-
/**
|
|
9
|
-
useSecureStorage?: boolean;
|
|
10
|
-
/** Custom key prefix for storage */
|
|
21
|
+
/** Custom storage key prefix */
|
|
11
22
|
keyPrefix?: string;
|
|
12
23
|
/** Enable debug logging */
|
|
13
24
|
debug?: boolean;
|
|
25
|
+
/** Custom token storage implementation */
|
|
26
|
+
customStorage?: TokenStorage;
|
|
27
|
+
/** Authentication type (default: 'user') */
|
|
28
|
+
authType?: AuthType;
|
|
14
29
|
}
|
|
15
30
|
|
|
16
31
|
/**
|
|
17
|
-
* React Native
|
|
32
|
+
* Create a React Native auth provider with platform-appropriate storage
|
|
33
|
+
*
|
|
34
|
+
* Automatically selects storage implementation:
|
|
35
|
+
* - Web: Uses LocalStorageTokenStorage (from core SDK)
|
|
36
|
+
* - Mobile: Uses AsyncStorageTokenStorage (React Native specific)
|
|
18
37
|
*
|
|
19
|
-
*
|
|
20
|
-
* -
|
|
21
|
-
*
|
|
22
|
-
*
|
|
23
|
-
* - Cross-platform compatibility (iOS/Android/Expo)
|
|
38
|
+
* @param projectKey - PERS project key
|
|
39
|
+
* @param authApi - Optional auth API instance
|
|
40
|
+
* @param config - Configuration options
|
|
41
|
+
* @returns DefaultAuthProvider configured for the current platform
|
|
24
42
|
*/
|
|
25
|
-
export
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
// Create storage keys
|
|
55
|
-
this.ACCESS_TOKEN_KEY = `${this.config.keyPrefix}_access_token`;
|
|
56
|
-
this.REFRESH_TOKEN_KEY = `${this.config.keyPrefix}_refresh_token`;
|
|
57
|
-
|
|
58
|
-
if (this.config.debug) {
|
|
59
|
-
console.log('ReactNativeAuthProvider initialized:', {
|
|
60
|
-
projectKey: projectKey.slice(0, 8) + '...',
|
|
61
|
-
useSecureStorage: this.config.useSecureStorage
|
|
62
|
-
});
|
|
63
|
-
}
|
|
64
|
-
}
|
|
65
|
-
|
|
66
|
-
async getProjectKey(): Promise<string | null> {
|
|
67
|
-
return this.projectKey;
|
|
68
|
-
}
|
|
69
|
-
|
|
70
|
-
async getToken(): Promise<string | null> {
|
|
71
|
-
return this.getStoredValue(this.ACCESS_TOKEN_KEY);
|
|
72
|
-
}
|
|
73
|
-
|
|
74
|
-
async setAccessToken(token: string): Promise<void> {
|
|
75
|
-
await this.storeValue(this.ACCESS_TOKEN_KEY, token);
|
|
76
|
-
if (this.config.debug) {
|
|
77
|
-
console.log('Access token stored securely');
|
|
78
|
-
}
|
|
79
|
-
}
|
|
80
|
-
|
|
81
|
-
async setRefreshToken(token: string): Promise<void> {
|
|
82
|
-
await this.storeValue(this.REFRESH_TOKEN_KEY, token);
|
|
83
|
-
if (this.config.debug) {
|
|
84
|
-
console.log('Refresh token stored securely');
|
|
85
|
-
}
|
|
86
|
-
}
|
|
87
|
-
|
|
88
|
-
async getRefreshToken(): Promise<string | null> {
|
|
89
|
-
return this.getStoredValue(this.REFRESH_TOKEN_KEY);
|
|
90
|
-
}
|
|
91
|
-
|
|
92
|
-
async clearTokens(): Promise<void> {
|
|
93
|
-
await Promise.all([
|
|
94
|
-
this.removeStoredValue(this.ACCESS_TOKEN_KEY),
|
|
95
|
-
this.removeStoredValue(this.REFRESH_TOKEN_KEY)
|
|
96
|
-
]);
|
|
97
|
-
|
|
98
|
-
if (this.config.debug) {
|
|
99
|
-
console.log('All tokens cleared from storage');
|
|
100
|
-
}
|
|
101
|
-
}
|
|
102
|
-
|
|
103
|
-
async onTokenExpired(): Promise<void> {
|
|
104
|
-
if (this.config.debug) {
|
|
105
|
-
console.warn('ReactNativeAuthProvider: Token expired - implement refresh logic in your app');
|
|
106
|
-
}
|
|
107
|
-
// Clear expired tokens
|
|
108
|
-
await this.clearTokens();
|
|
109
|
-
}
|
|
110
|
-
|
|
111
|
-
// Token validation methods
|
|
112
|
-
hasValidToken(): boolean {
|
|
113
|
-
return true; // Actual validation happens in getToken()
|
|
114
|
-
}
|
|
115
|
-
|
|
116
|
-
hasRefreshToken(): boolean {
|
|
117
|
-
return true; // Actual validation happens in getRefreshToken()
|
|
118
|
-
}
|
|
119
|
-
|
|
120
|
-
// Storage implementation methods
|
|
121
|
-
private async storeValue(key: string, value: string): Promise<void> {
|
|
122
|
-
try {
|
|
123
|
-
if (this.config.useSecureStorage && await this.isKeychainAvailable()) {
|
|
124
|
-
await this.storeInKeychain(key, value);
|
|
125
|
-
} else {
|
|
126
|
-
await AsyncStorage.setItem(key, value);
|
|
127
|
-
}
|
|
128
|
-
} catch (error) {
|
|
129
|
-
console.error(`Failed to store value for key ${key}:`, error);
|
|
130
|
-
// Fallback to memory storage
|
|
131
|
-
this.memoryStorage.set(key, value);
|
|
132
|
-
}
|
|
133
|
-
}
|
|
134
|
-
|
|
135
|
-
private async getStoredValue(key: string): Promise<string | null> {
|
|
136
|
-
try {
|
|
137
|
-
if (this.config.useSecureStorage && await this.isKeychainAvailable()) {
|
|
138
|
-
return await this.getFromKeychain(key);
|
|
139
|
-
} else {
|
|
140
|
-
return await AsyncStorage.getItem(key);
|
|
141
|
-
}
|
|
142
|
-
} catch (error) {
|
|
143
|
-
console.warn(`Failed to get value for key ${key}:`, error);
|
|
144
|
-
// Fallback to memory storage
|
|
145
|
-
return this.memoryStorage.get(key) || null;
|
|
146
|
-
}
|
|
147
|
-
}
|
|
148
|
-
|
|
149
|
-
private async removeStoredValue(key: string): Promise<void> {
|
|
150
|
-
try {
|
|
151
|
-
if (this.config.useSecureStorage && await this.isKeychainAvailable()) {
|
|
152
|
-
await this.removeFromKeychain(key);
|
|
153
|
-
} else {
|
|
154
|
-
await AsyncStorage.removeItem(key);
|
|
155
|
-
}
|
|
156
|
-
} catch (error) {
|
|
157
|
-
console.error(`Failed to remove value for key ${key}:`, error);
|
|
158
|
-
}
|
|
159
|
-
|
|
160
|
-
// Ensure memory fallback is also cleared
|
|
161
|
-
this.memoryStorage.delete(key);
|
|
162
|
-
}
|
|
163
|
-
|
|
164
|
-
// Keychain helper methods
|
|
165
|
-
private async isKeychainAvailable(): Promise<boolean> {
|
|
166
|
-
try {
|
|
167
|
-
const Keychain = require('react-native-keychain');
|
|
168
|
-
return !!Keychain && typeof Keychain.setInternetCredentials === 'function';
|
|
169
|
-
} catch {
|
|
170
|
-
return false;
|
|
171
|
-
}
|
|
172
|
-
}
|
|
173
|
-
|
|
174
|
-
private async storeInKeychain(key: string, value: string): Promise<void> {
|
|
175
|
-
const Keychain = require('react-native-keychain');
|
|
176
|
-
await Keychain.setInternetCredentials(key, 'pers-token', value);
|
|
177
|
-
}
|
|
178
|
-
|
|
179
|
-
private async getFromKeychain(key: string): Promise<string | null> {
|
|
180
|
-
const Keychain = require('react-native-keychain');
|
|
181
|
-
const credentials = await Keychain.getInternetCredentials(key);
|
|
182
|
-
return credentials ? credentials.password : null;
|
|
183
|
-
}
|
|
43
|
+
export function createReactNativeAuthProvider(
|
|
44
|
+
projectKey: string,
|
|
45
|
+
config: ReactNativeAuthConfig = {}
|
|
46
|
+
): DefaultAuthProvider {
|
|
47
|
+
if (!projectKey || typeof projectKey !== 'string') {
|
|
48
|
+
throw new Error('createReactNativeAuthProvider: projectKey is required and must be a string');
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
const {
|
|
52
|
+
keyPrefix = `pers_${projectKey.slice(0, 8)}_`,
|
|
53
|
+
debug = false,
|
|
54
|
+
customStorage,
|
|
55
|
+
authType = 'user'
|
|
56
|
+
} = config;
|
|
57
|
+
|
|
58
|
+
// Platform-specific storage selection
|
|
59
|
+
const tokenStorage = customStorage || (
|
|
60
|
+
isWebPlatform
|
|
61
|
+
? new LocalStorageTokenStorage()
|
|
62
|
+
: new AsyncStorageTokenStorage(keyPrefix)
|
|
63
|
+
);
|
|
64
|
+
|
|
65
|
+
// Return DefaultAuthProvider configured with platform-appropriate storage
|
|
66
|
+
return new DefaultAuthProvider({
|
|
67
|
+
authType,
|
|
68
|
+
projectKey,
|
|
69
|
+
storage: tokenStorage
|
|
70
|
+
});
|
|
71
|
+
}
|
|
184
72
|
|
|
185
|
-
private async removeFromKeychain(key: string): Promise<void> {
|
|
186
|
-
const Keychain = require('react-native-keychain');
|
|
187
|
-
await Keychain.resetInternetCredentials(key);
|
|
188
|
-
}
|
|
189
|
-
}
|
|
@@ -0,0 +1,133 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* AsyncStorage Token Storage for React Native Mobile Platforms
|
|
3
|
+
*
|
|
4
|
+
* Bundler-agnostic AsyncStorage implementation for mobile platforms
|
|
5
|
+
*/
|
|
6
|
+
|
|
7
|
+
import AsyncStorage from '@react-native-async-storage/async-storage';
|
|
8
|
+
import type { TokenStorage } from '@explorins/pers-sdk/core';
|
|
9
|
+
|
|
10
|
+
/**
|
|
11
|
+
* Bundler-agnostic AsyncStorage wrapper
|
|
12
|
+
* Handles different module resolution patterns across bundlers (Metro, Webpack, Rollup, etc.)
|
|
13
|
+
*/
|
|
14
|
+
class BundlerAgnosticAsyncStorage {
|
|
15
|
+
private storage: any;
|
|
16
|
+
|
|
17
|
+
constructor(asyncStorageModule: any) {
|
|
18
|
+
// Try different import patterns to handle various bundlers
|
|
19
|
+
if (asyncStorageModule?.default?.getItem) {
|
|
20
|
+
// Metro/Webpack pattern: { default: { getItem, setItem, ... } }
|
|
21
|
+
this.storage = asyncStorageModule.default;
|
|
22
|
+
} else if (asyncStorageModule?.getItem) {
|
|
23
|
+
// Direct export pattern: { getItem, setItem, ... }
|
|
24
|
+
this.storage = asyncStorageModule;
|
|
25
|
+
} else if (typeof asyncStorageModule === 'function') {
|
|
26
|
+
// Function export pattern (some bundlers)
|
|
27
|
+
this.storage = asyncStorageModule();
|
|
28
|
+
} else {
|
|
29
|
+
// Log the structure for debugging
|
|
30
|
+
console.error('[BundlerAgnosticAsyncStorage] Unknown AsyncStorage structure:', asyncStorageModule);
|
|
31
|
+
throw new Error(
|
|
32
|
+
'AsyncStorage methods not found. Expected structure with getItem/setItem methods. ' +
|
|
33
|
+
'Make sure @react-native-async-storage/async-storage is properly installed.'
|
|
34
|
+
);
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
// Validate that we have the required methods
|
|
38
|
+
const requiredMethods = ['getItem', 'setItem', 'removeItem', 'getAllKeys', 'multiRemove'];
|
|
39
|
+
const missingMethods = requiredMethods.filter(method => typeof this.storage[method] !== 'function');
|
|
40
|
+
|
|
41
|
+
if (missingMethods.length > 0) {
|
|
42
|
+
throw new Error(
|
|
43
|
+
`AsyncStorage missing required methods: ${missingMethods.join(', ')}. ` +
|
|
44
|
+
'Ensure @react-native-async-storage/async-storage is properly installed and compatible.'
|
|
45
|
+
);
|
|
46
|
+
}
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
async getItem(key: string): Promise<string | null> {
|
|
50
|
+
return this.storage.getItem(key);
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
async setItem(key: string, value: string): Promise<void> {
|
|
54
|
+
return this.storage.setItem(key, value);
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
async removeItem(key: string): Promise<void> {
|
|
58
|
+
return this.storage.removeItem(key);
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
async getAllKeys(): Promise<readonly string[]> {
|
|
62
|
+
return this.storage.getAllKeys();
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
async multiRemove(keys: string[]): Promise<void> {
|
|
66
|
+
return this.storage.multiRemove(keys);
|
|
67
|
+
}
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
/**
|
|
71
|
+
* AsyncStorage implementation for mobile platforms
|
|
72
|
+
*
|
|
73
|
+
* This class is only used on mobile platforms (iOS/Android).
|
|
74
|
+
* Web platforms use LocalStorageTokenStorage from core SDK.
|
|
75
|
+
*/
|
|
76
|
+
export class AsyncStorageTokenStorage implements TokenStorage {
|
|
77
|
+
private keyPrefix: string;
|
|
78
|
+
private asyncStorage: BundlerAgnosticAsyncStorage;
|
|
79
|
+
|
|
80
|
+
constructor(keyPrefix: string = 'pers_tokens_') {
|
|
81
|
+
this.keyPrefix = keyPrefix;
|
|
82
|
+
|
|
83
|
+
try {
|
|
84
|
+
// Initialize bundler-agnostic AsyncStorage wrapper
|
|
85
|
+
this.asyncStorage = new BundlerAgnosticAsyncStorage(AsyncStorage);
|
|
86
|
+
} catch (error) {
|
|
87
|
+
console.error('[AsyncStorageTokenStorage] Failed to initialize:', error);
|
|
88
|
+
throw new Error(
|
|
89
|
+
'Failed to initialize AsyncStorage. Make sure @react-native-async-storage/async-storage is installed and ' +
|
|
90
|
+
'this code is running on a React Native mobile platform (not web).'
|
|
91
|
+
);
|
|
92
|
+
}
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
async set(key: string, value: string): Promise<void> {
|
|
96
|
+
try {
|
|
97
|
+
await this.asyncStorage.setItem(`${this.keyPrefix}${key}`, value);
|
|
98
|
+
} catch (error) {
|
|
99
|
+
console.error(`Failed to store token ${key}:`, error);
|
|
100
|
+
throw new Error(`Token storage failed: ${error}`);
|
|
101
|
+
}
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
async get(key: string): Promise<string | null> {
|
|
105
|
+
try {
|
|
106
|
+
return await this.asyncStorage.getItem(`${this.keyPrefix}${key}`);
|
|
107
|
+
} catch (error) {
|
|
108
|
+
console.error(`Failed to retrieve token ${key}:`, error);
|
|
109
|
+
return null;
|
|
110
|
+
}
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
async remove(key: string): Promise<void> {
|
|
114
|
+
try {
|
|
115
|
+
await this.asyncStorage.removeItem(`${this.keyPrefix}${key}`);
|
|
116
|
+
} catch (error) {
|
|
117
|
+
console.error(`Failed to remove token ${key}:`, error);
|
|
118
|
+
}
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
async clear(): Promise<void> {
|
|
122
|
+
try {
|
|
123
|
+
const allKeys = await this.asyncStorage.getAllKeys();
|
|
124
|
+
const ourKeys = allKeys.filter(key => key.startsWith(this.keyPrefix));
|
|
125
|
+
|
|
126
|
+
if (ourKeys.length > 0) {
|
|
127
|
+
await this.asyncStorage.multiRemove(ourKeys);
|
|
128
|
+
}
|
|
129
|
+
} catch (error) {
|
|
130
|
+
console.error('Failed to clear token storage:', error);
|
|
131
|
+
}
|
|
132
|
+
}
|
|
133
|
+
}
|