@explorins/pers-sdk-react-native 1.5.18 → 1.5.21
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/useAnalytics.d.ts +6 -2
- package/dist/hooks/useAnalytics.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 +9 -10
- package/dist/hooks/useWeb3.d.ts +8 -2
- package/dist/hooks/useWeb3.d.ts.map +1 -1
- package/dist/index.d.ts +211 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +21061 -18475
- 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 +24 -36
- package/dist/providers/react-native-auth-provider.d.ts.map +1 -1
- package/dist/providers/react-native-auth-provider.js +35 -146
- package/dist/providers/react-native-http-client.d.ts +15 -0
- package/dist/providers/react-native-http-client.d.ts.map +1 -1
- 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/useAnalytics.ts +6 -2
- 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 +12 -11
- package/src/hooks/useWeb3.ts +8 -1
- package/src/index.ts +243 -7
- package/src/providers/PersSDKProvider.tsx +21 -40
- package/src/providers/react-native-auth-provider.ts +58 -176
- package/src/providers/react-native-http-client.ts +15 -0
- package/src/storage/async-storage-token-storage.ts +133 -0
package/src/index.ts
CHANGED
|
@@ -1,13 +1,123 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @fileoverview PERS SDK for React Native - Tourism Loyalty System
|
|
3
|
+
*
|
|
4
|
+
* A comprehensive React Native SDK for integrating with the PERS (Phygital Experience Rewards System)
|
|
5
|
+
* platform. Provides complete functionality for tourism loyalty applications including user management,
|
|
6
|
+
* token operations, business integrations, campaign management, and blockchain transaction signing.
|
|
7
|
+
*
|
|
8
|
+
* **Key Features:**
|
|
9
|
+
* - Secure authentication with React Native Keychain integration
|
|
10
|
+
* - Token management (earn, redeem, transfer, balance checking)
|
|
11
|
+
* - Business and campaign management
|
|
12
|
+
* - Blockchain transaction signing with WebAuthn
|
|
13
|
+
* - React Native optimized with automatic polyfills
|
|
14
|
+
* - Type-safe interfaces with comprehensive TypeScript support
|
|
15
|
+
* - Analytics and reporting capabilities
|
|
16
|
+
* - Donation and charitable giving features
|
|
17
|
+
*
|
|
18
|
+
* @example
|
|
19
|
+
* **Quick Start:**
|
|
20
|
+
* ```typescript
|
|
21
|
+
* import { PersSDKProvider, usePersSDK, useTransactionSigner } from '@explorins/pers-sdk-react-native';
|
|
22
|
+
*
|
|
23
|
+
* // 1. Wrap your app with the provider
|
|
24
|
+
* function App() {
|
|
25
|
+
* return (
|
|
26
|
+
* <PersSDKProvider config={{ apiUrl: 'https://api.pers.ninja' }}>
|
|
27
|
+
* <YourApp />
|
|
28
|
+
* </PersSDKProvider>
|
|
29
|
+
* );
|
|
30
|
+
* }
|
|
31
|
+
*
|
|
32
|
+
* // 2. Use hooks in your components
|
|
33
|
+
* function RewardScreen() {
|
|
34
|
+
* const { user, isAuthenticated, earnTokens } = usePersSDK();
|
|
35
|
+
* const { signAndSubmitTransactionWithJWT } = useTransactionSigner();
|
|
36
|
+
*
|
|
37
|
+
* // Your reward logic here...
|
|
38
|
+
* }
|
|
39
|
+
* ```
|
|
40
|
+
*
|
|
41
|
+
* @version 1.5.19
|
|
42
|
+
* @author eXplorins
|
|
43
|
+
* @license MIT
|
|
44
|
+
*/
|
|
45
|
+
|
|
1
46
|
// Initialize React Native polyfills automatically
|
|
2
47
|
import './polyfills';
|
|
3
48
|
|
|
4
|
-
//
|
|
49
|
+
// ==============================================================================
|
|
50
|
+
// AUTHENTICATION PROVIDERS
|
|
51
|
+
// ==============================================================================
|
|
52
|
+
|
|
53
|
+
/**
|
|
54
|
+
* React Native-specific authentication provider with secure keychain integration
|
|
55
|
+
*
|
|
56
|
+
* Provides secure token storage using React Native Keychain, biometric authentication,
|
|
57
|
+
* and automatic token refresh capabilities.
|
|
58
|
+
*
|
|
59
|
+
* @see {@link createReactNativeAuthProvider} - Factory function for auth provider
|
|
60
|
+
* @see {@link ReactNativeAuthConfig} - Configuration interface
|
|
61
|
+
*/
|
|
5
62
|
export {
|
|
6
|
-
|
|
63
|
+
createReactNativeAuthProvider,
|
|
7
64
|
type ReactNativeAuthConfig
|
|
8
65
|
} from './providers/react-native-auth-provider';
|
|
9
66
|
|
|
10
|
-
//
|
|
67
|
+
// ==============================================================================
|
|
68
|
+
// SECURE STORAGE
|
|
69
|
+
// ==============================================================================
|
|
70
|
+
|
|
71
|
+
/**
|
|
72
|
+
* Secure token storage using React Native AsyncStorage
|
|
73
|
+
*
|
|
74
|
+
* Provides encrypted token storage with automatic cleanup and secure key management.
|
|
75
|
+
* Integrates with React Native Keychain for enhanced security on supported devices.
|
|
76
|
+
*
|
|
77
|
+
* @see {@link AsyncStorageTokenStorage} - Secure storage implementation
|
|
78
|
+
*/
|
|
79
|
+
export {
|
|
80
|
+
AsyncStorageTokenStorage,
|
|
81
|
+
} from './storage/async-storage-token-storage';
|
|
82
|
+
|
|
83
|
+
// ==============================================================================
|
|
84
|
+
// CORE PROVIDER & CONTEXT
|
|
85
|
+
// ==============================================================================
|
|
86
|
+
|
|
87
|
+
/**
|
|
88
|
+
* Main PERS SDK provider and context for React Native applications
|
|
89
|
+
*
|
|
90
|
+
* The PersSDKProvider should wrap your entire app to provide PERS functionality
|
|
91
|
+
* throughout your component tree. Use usePersSDK hook to access SDK features.
|
|
92
|
+
*
|
|
93
|
+
* @example
|
|
94
|
+
* ```typescript
|
|
95
|
+
* import { PersSDKProvider, usePersSDK } from '@explorins/pers-sdk-react-native';
|
|
96
|
+
*
|
|
97
|
+
* function App() {
|
|
98
|
+
* return (
|
|
99
|
+
* <PersSDKProvider config={{
|
|
100
|
+
* apiUrl: 'https://api.pers.ninja',
|
|
101
|
+
* tenantId: 'your-tenant-id'
|
|
102
|
+
* }}>
|
|
103
|
+
* <NavigationContainer>
|
|
104
|
+
* <YourAppContent />
|
|
105
|
+
* </NavigationContainer>
|
|
106
|
+
* </PersSDKProvider>
|
|
107
|
+
* );
|
|
108
|
+
* }
|
|
109
|
+
*
|
|
110
|
+
* function YourComponent() {
|
|
111
|
+
* const { user, isAuthenticated, earnTokens } = usePersSDK();
|
|
112
|
+
* // Use PERS functionality here...
|
|
113
|
+
* }
|
|
114
|
+
* ```
|
|
115
|
+
*
|
|
116
|
+
* @see {@link PersSDKProvider} - Main provider component
|
|
117
|
+
* @see {@link usePersSDK} - Hook to access SDK functionality
|
|
118
|
+
* @see {@link PersConfig} - Provider configuration interface
|
|
119
|
+
* @see {@link PersSDKContext} - Context type definition
|
|
120
|
+
*/
|
|
11
121
|
export {
|
|
12
122
|
PersSDKProvider,
|
|
13
123
|
usePersSDK,
|
|
@@ -15,7 +125,80 @@ export {
|
|
|
15
125
|
type PersSDKContext
|
|
16
126
|
} from './providers/PersSDKProvider';
|
|
17
127
|
|
|
18
|
-
//
|
|
128
|
+
// ==============================================================================
|
|
129
|
+
// REACT HOOKS (Primary Interface)
|
|
130
|
+
// ==============================================================================
|
|
131
|
+
|
|
132
|
+
/**
|
|
133
|
+
* Comprehensive React hooks for PERS platform integration
|
|
134
|
+
*
|
|
135
|
+
* These hooks provide the primary interface for interacting with the PERS platform
|
|
136
|
+
* in React Native applications. Each hook is optimized for specific functionality
|
|
137
|
+
* and includes automatic error handling, loading states, and real-time updates.
|
|
138
|
+
*
|
|
139
|
+
* **Authentication & User Management:**
|
|
140
|
+
* - `useAuth` - User authentication, login, logout, registration
|
|
141
|
+
* - `useUsers` - User profile management and data operations
|
|
142
|
+
* - `useUserStatus` - Real-time user status and activity monitoring
|
|
143
|
+
*
|
|
144
|
+
* **Token & Financial Operations:**
|
|
145
|
+
* - `useTokens` - Token balance, earning, and management
|
|
146
|
+
* - `useTransactions` - Transaction history and monitoring
|
|
147
|
+
* - `useTransactionSigner` - **⭐ Blockchain transaction signing**
|
|
148
|
+
* - `usePurchases` - Purchase history and payment processing
|
|
149
|
+
* - `useDonations` - Charitable giving and donation management
|
|
150
|
+
*
|
|
151
|
+
* **Business & Campaign Management:**
|
|
152
|
+
* - `useBusiness` - Business profile and operations
|
|
153
|
+
* - `useCampaigns` - Marketing campaigns and promotions
|
|
154
|
+
* - `useRedemptions` - Reward redemption and fulfillment
|
|
155
|
+
*
|
|
156
|
+
* **Platform & Analytics:**
|
|
157
|
+
* - `useTenants` - Multi-tenant configuration and management
|
|
158
|
+
* - `useAnalytics` - Usage analytics and reporting
|
|
159
|
+
* - `useFiles` - File upload and management
|
|
160
|
+
* - `useWeb3` - Blockchain integration and wallet operations
|
|
161
|
+
*
|
|
162
|
+
* @example
|
|
163
|
+
* **Token Operations:**
|
|
164
|
+
* ```typescript
|
|
165
|
+
* import { useTokens, useTransactionSigner } from '@explorins/pers-sdk-react-native';
|
|
166
|
+
*
|
|
167
|
+
* function TokenScreen() {
|
|
168
|
+
* const { balance, earnTokens, redeemTokens } = useTokens();
|
|
169
|
+
* const { signAndSubmitTransactionWithJWT } = useTransactionSigner();
|
|
170
|
+
*
|
|
171
|
+
* const handleEarn = async (amount: number) => {
|
|
172
|
+
* const result = await earnTokens({ amount, source: 'reward' });
|
|
173
|
+
* console.log('Earned tokens:', result);
|
|
174
|
+
* };
|
|
175
|
+
*
|
|
176
|
+
* const handleRedeem = async (amount: number) => {
|
|
177
|
+
* const redemption = await redeemTokens({ amount });
|
|
178
|
+
* const txResult = await signAndSubmitTransactionWithJWT(redemption.jwtToken);
|
|
179
|
+
* console.log('Redemption completed:', txResult.transactionHash);
|
|
180
|
+
* };
|
|
181
|
+
* }
|
|
182
|
+
* ```
|
|
183
|
+
*
|
|
184
|
+
* @example
|
|
185
|
+
* **Campaign Integration:**
|
|
186
|
+
* ```typescript
|
|
187
|
+
* import { useCampaigns, useAuth } from '@explorins/pers-sdk-react-native';
|
|
188
|
+
*
|
|
189
|
+
* function CampaignScreen() {
|
|
190
|
+
* const { activeCampaigns, participateInCampaign } = useCampaigns();
|
|
191
|
+
* const { user } = useAuth();
|
|
192
|
+
*
|
|
193
|
+
* const handleParticipate = async (campaignId: string) => {
|
|
194
|
+
* const result = await participateInCampaign(campaignId, {
|
|
195
|
+
* userId: user?.id,
|
|
196
|
+
* participationData: { source: 'mobile_app' }
|
|
197
|
+
* });
|
|
198
|
+
* };
|
|
199
|
+
* }
|
|
200
|
+
* ```
|
|
201
|
+
*/
|
|
19
202
|
export {
|
|
20
203
|
useAuth,
|
|
21
204
|
useTokens,
|
|
@@ -34,19 +217,72 @@ export {
|
|
|
34
217
|
useDonations
|
|
35
218
|
} from './hooks';
|
|
36
219
|
|
|
220
|
+
// ==============================================================================
|
|
221
|
+
// PLATFORM ADAPTERS
|
|
222
|
+
// ==============================================================================
|
|
223
|
+
|
|
224
|
+
/**
|
|
225
|
+
* React Native-optimized HTTP client with automatic request/response handling
|
|
226
|
+
*
|
|
227
|
+
* Provides platform-specific networking with proper error handling, timeout management,
|
|
228
|
+
* and React Native compatibility. Automatically handles headers, authentication tokens,
|
|
229
|
+
* and response parsing.
|
|
230
|
+
*/
|
|
37
231
|
export {
|
|
38
232
|
ReactNativeHttpClient
|
|
39
233
|
} from './providers/react-native-http-client';
|
|
40
234
|
|
|
41
|
-
//
|
|
235
|
+
// ==============================================================================
|
|
236
|
+
// POLYFILLS & COMPATIBILITY
|
|
237
|
+
// ==============================================================================
|
|
238
|
+
|
|
239
|
+
/**
|
|
240
|
+
* React Native polyfill utilities for web compatibility
|
|
241
|
+
*
|
|
242
|
+
* Automatically initializes required polyfills for crypto, URL, and other web APIs
|
|
243
|
+
* that may not be available in React Native environments. These are typically
|
|
244
|
+
* loaded automatically, but manual initialization is available for advanced use cases.
|
|
245
|
+
*
|
|
246
|
+
* @see {@link initializeReactNativePolyfills} - Manual polyfill initialization
|
|
247
|
+
*/
|
|
42
248
|
export {
|
|
43
249
|
initializeReactNativePolyfills
|
|
44
250
|
} from './polyfills';
|
|
45
251
|
|
|
46
|
-
//
|
|
252
|
+
// ==============================================================================
|
|
253
|
+
// TYPE DEFINITIONS & SHARED UTILITIES
|
|
254
|
+
// ==============================================================================
|
|
255
|
+
|
|
256
|
+
/**
|
|
257
|
+
* Re-export all types and utilities from the shared PERS library
|
|
258
|
+
*
|
|
259
|
+
* This includes all core types, DTOs, enums, and utility functions used across
|
|
260
|
+
* the PERS platform. These types ensure consistency between different SDK versions
|
|
261
|
+
* and platform implementations.
|
|
262
|
+
*
|
|
263
|
+
* **Included Types:**
|
|
264
|
+
* - User and authentication types (UserDTO, AuthenticationResult, etc.)
|
|
265
|
+
* - Token and transaction types (TokenDTO, TransactionDTO, etc.)
|
|
266
|
+
* - Business and campaign types (BusinessDTO, CampaignDTO, etc.)
|
|
267
|
+
* - API request/response types for all endpoints
|
|
268
|
+
* - Error types and status enums
|
|
269
|
+
*
|
|
270
|
+
* @see {@link https://github.com/eXplorins/pers-shared} - Shared library documentation
|
|
271
|
+
*/
|
|
47
272
|
export * from '@explorins/pers-shared';
|
|
48
273
|
|
|
49
|
-
|
|
274
|
+
/**
|
|
275
|
+
* Re-export Web3 and blockchain-related types from base SDK
|
|
276
|
+
*
|
|
277
|
+
* Provides TypeScript definitions for Web3 operations, token management,
|
|
278
|
+
* and blockchain interactions. These types are used by the transaction
|
|
279
|
+
* signing hooks and Web3 integration features.
|
|
280
|
+
*
|
|
281
|
+
* @see {@link TokenBalanceRequest} - Request structure for token balance queries
|
|
282
|
+
* @see {@link TokenBalance} - Token balance response data
|
|
283
|
+
* @see {@link TokenMetadata} - Token metadata and details
|
|
284
|
+
* @see {@link TokenCollection} - Collection of tokens for batch operations
|
|
285
|
+
*/
|
|
50
286
|
export type {
|
|
51
287
|
TokenBalanceRequest,
|
|
52
288
|
TokenBalance,
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import React, { createContext, useContext, useState, ReactNode, useCallback, useRef } from 'react';
|
|
2
|
-
import { PersSDK, PersConfig,
|
|
2
|
+
import { PersSDK, PersConfig, DefaultAuthProvider } from '@explorins/pers-sdk/core';
|
|
3
3
|
import { ReactNativeHttpClient } from './react-native-http-client';
|
|
4
|
-
import {
|
|
4
|
+
import { createReactNativeAuthProvider } from './react-native-auth-provider';
|
|
5
5
|
import { UserDTO, AdminDTO } from '@explorins/pers-shared';
|
|
6
6
|
|
|
7
7
|
// Import manager types for TypeScript
|
|
@@ -42,8 +42,8 @@ export interface PersSDKContext {
|
|
|
42
42
|
// Legacy support (deprecated but kept for backward compatibility)
|
|
43
43
|
business: BusinessManager | null;
|
|
44
44
|
|
|
45
|
-
// Platform-specific providers
|
|
46
|
-
authProvider:
|
|
45
|
+
// Platform-specific providers - now uses unified auth provider
|
|
46
|
+
authProvider: DefaultAuthProvider | null;
|
|
47
47
|
|
|
48
48
|
// State
|
|
49
49
|
isInitialized: boolean;
|
|
@@ -60,34 +60,13 @@ export interface PersSDKContext {
|
|
|
60
60
|
// Create the context
|
|
61
61
|
const SDKContext = createContext<PersSDKContext | null>(null);
|
|
62
62
|
|
|
63
|
-
// Simple wrapper for SDK integration
|
|
64
|
-
class ReactNativeSDKAuthProvider extends ReactNativeAuthProvider {
|
|
65
|
-
constructor(projectKey: string) {
|
|
66
|
-
super(projectKey, { debug: true });
|
|
67
|
-
}
|
|
68
|
-
|
|
69
|
-
// Override setAccessToken to provide backward compatibility
|
|
70
|
-
async setToken(token: string | null): Promise<void> {
|
|
71
|
-
if (token) {
|
|
72
|
-
await this.setAccessToken(token);
|
|
73
|
-
} else {
|
|
74
|
-
await this.clearTokens();
|
|
75
|
-
}
|
|
76
|
-
}
|
|
77
|
-
|
|
78
|
-
// Override getToken for backward compatibility
|
|
79
|
-
async getToken(): Promise<string | null> {
|
|
80
|
-
return await super.getToken();
|
|
81
|
-
}
|
|
82
|
-
}
|
|
83
|
-
|
|
84
63
|
// Provider component
|
|
85
64
|
export const PersSDKProvider: React.FC<{
|
|
86
65
|
children: ReactNode;
|
|
87
66
|
}> = ({ children }) => {
|
|
88
67
|
const initializingRef = useRef(false);
|
|
89
68
|
const [sdk, setSdk] = useState<PersSDK | null>(null);
|
|
90
|
-
const [authProvider, setAuthProvider] = useState<
|
|
69
|
+
const [authProvider, setAuthProvider] = useState<DefaultAuthProvider | null>(null);
|
|
91
70
|
|
|
92
71
|
const [isInitialized, setIsInitialized] = useState(false);
|
|
93
72
|
const [isAuthenticated, setIsAuthenticated] = useState(false);
|
|
@@ -97,34 +76,38 @@ export const PersSDKProvider: React.FC<{
|
|
|
97
76
|
const initialize = useCallback(async (config: PersConfig) => {
|
|
98
77
|
// Prevent multiple initializations
|
|
99
78
|
if (isInitialized || initializingRef.current) {
|
|
100
|
-
console.log('SDK already initialized or initializing, skipping...');
|
|
101
79
|
return;
|
|
102
80
|
}
|
|
103
81
|
|
|
104
82
|
initializingRef.current = true;
|
|
105
83
|
|
|
106
84
|
try {
|
|
107
|
-
console.log('Initializing PERS SDK with config:', config);
|
|
108
|
-
|
|
109
|
-
// Create React Native auth provider
|
|
110
|
-
const auth = new ReactNativeSDKAuthProvider(config.apiProjectKey || 'default-project');
|
|
111
|
-
setAuthProvider(auth);
|
|
112
|
-
|
|
113
85
|
// Create HTTP client
|
|
114
86
|
const httpClient = new ReactNativeHttpClient();
|
|
115
87
|
|
|
116
|
-
// Create
|
|
88
|
+
// Create platform-aware auth provider if not provided
|
|
89
|
+
let authProvider: DefaultAuthProvider;
|
|
90
|
+
if (config.authProvider) {
|
|
91
|
+
authProvider = config.authProvider as DefaultAuthProvider;
|
|
92
|
+
} else {
|
|
93
|
+
// Use our platform-aware auth provider that automatically selects LocalStorage (web) or AsyncStorage (mobile)
|
|
94
|
+
authProvider = createReactNativeAuthProvider(config.apiProjectKey || 'default-project', {
|
|
95
|
+
debug: false
|
|
96
|
+
});
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
// Enhanced config with platform-appropriate auth provider
|
|
117
100
|
const sdkConfig: PersConfig = {
|
|
118
101
|
...config,
|
|
119
|
-
authProvider
|
|
102
|
+
authProvider
|
|
120
103
|
};
|
|
121
104
|
|
|
122
|
-
// Initialize PersSDK with
|
|
105
|
+
// Initialize PersSDK with platform-aware auth provider
|
|
123
106
|
const sdkInstance = new PersSDK(httpClient, sdkConfig);
|
|
107
|
+
|
|
108
|
+
setAuthProvider(authProvider);
|
|
124
109
|
setSdk(sdkInstance);
|
|
125
110
|
setIsInitialized(true);
|
|
126
|
-
|
|
127
|
-
console.log('PERS SDK initialized successfully');
|
|
128
111
|
} catch (error) {
|
|
129
112
|
console.error('Failed to initialize PERS SDK:', error);
|
|
130
113
|
initializingRef.current = false;
|
|
@@ -146,10 +129,8 @@ export const PersSDKProvider: React.FC<{
|
|
|
146
129
|
}
|
|
147
130
|
|
|
148
131
|
try {
|
|
149
|
-
console.log('Refreshing user data from remote server...');
|
|
150
132
|
const freshUserData = await sdk.users.getCurrentUser();
|
|
151
133
|
setUser(freshUserData);
|
|
152
|
-
console.log('User data refreshed successfully:', freshUserData);
|
|
153
134
|
} catch (error) {
|
|
154
135
|
console.error('Failed to refresh user data:', error);
|
|
155
136
|
throw error;
|
|
@@ -1,189 +1,71 @@
|
|
|
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
|
-
* - Automatic fallback to AsyncStorage if Keychain is unavailable
|
|
23
|
-
* - Cross-platform compatibility (iOS/Android/Expo)
|
|
38
|
+
* @param projectKey - PERS project key
|
|
39
|
+
* @param config - Configuration options
|
|
40
|
+
* @returns DefaultAuthProvider configured for the current platform
|
|
24
41
|
*/
|
|
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
|
-
}
|
|
42
|
+
export function createReactNativeAuthProvider(
|
|
43
|
+
projectKey: string,
|
|
44
|
+
config: ReactNativeAuthConfig = {}
|
|
45
|
+
): DefaultAuthProvider {
|
|
46
|
+
if (!projectKey || typeof projectKey !== 'string') {
|
|
47
|
+
throw new Error('createReactNativeAuthProvider: projectKey is required and must be a string');
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
const {
|
|
51
|
+
keyPrefix = `pers_${projectKey.slice(0, 8)}_`,
|
|
52
|
+
debug = false,
|
|
53
|
+
customStorage,
|
|
54
|
+
authType = 'user'
|
|
55
|
+
} = config;
|
|
56
|
+
|
|
57
|
+
// Platform-specific storage selection
|
|
58
|
+
const tokenStorage = customStorage || (
|
|
59
|
+
isWebPlatform
|
|
60
|
+
? new LocalStorageTokenStorage()
|
|
61
|
+
: new AsyncStorageTokenStorage(keyPrefix)
|
|
62
|
+
);
|
|
63
|
+
|
|
64
|
+
// Return DefaultAuthProvider configured with platform-appropriate storage
|
|
65
|
+
return new DefaultAuthProvider({
|
|
66
|
+
authType,
|
|
67
|
+
projectKey,
|
|
68
|
+
storage: tokenStorage
|
|
69
|
+
});
|
|
70
|
+
}
|
|
184
71
|
|
|
185
|
-
private async removeFromKeychain(key: string): Promise<void> {
|
|
186
|
-
const Keychain = require('react-native-keychain');
|
|
187
|
-
await Keychain.resetInternetCredentials(key);
|
|
188
|
-
}
|
|
189
|
-
}
|
|
@@ -5,6 +5,15 @@
|
|
|
5
5
|
* and uses fetch API which is available in React Native.
|
|
6
6
|
*/
|
|
7
7
|
|
|
8
|
+
/**
|
|
9
|
+
* Request options for HTTP client operations
|
|
10
|
+
*
|
|
11
|
+
* @interface RequestOptions
|
|
12
|
+
* @property {Record<string, string>} [headers] - HTTP headers to include
|
|
13
|
+
* @property {Record<string, string>} [params] - URL parameters
|
|
14
|
+
* @property {number} [timeout] - Request timeout in milliseconds
|
|
15
|
+
* @property {'json' | 'blob' | 'text' | 'arraybuffer'} [responseType] - Expected response type
|
|
16
|
+
*/
|
|
8
17
|
export interface RequestOptions {
|
|
9
18
|
headers?: Record<string, string>;
|
|
10
19
|
params?: Record<string, string>;
|
|
@@ -12,6 +21,12 @@ export interface RequestOptions {
|
|
|
12
21
|
responseType?: 'json' | 'blob' | 'text' | 'arraybuffer';
|
|
13
22
|
}
|
|
14
23
|
|
|
24
|
+
/**
|
|
25
|
+
* HTTP Client interface for React Native
|
|
26
|
+
*
|
|
27
|
+
* @interface HttpClient
|
|
28
|
+
* @template T - Response type
|
|
29
|
+
*/
|
|
15
30
|
export interface HttpClient {
|
|
16
31
|
get<T>(url: string, options?: RequestOptions): Promise<T>;
|
|
17
32
|
post<T>(url: string, body: any, options?: RequestOptions): Promise<T>;
|