@explorins/pers-sdk-react-native 2.0.4 → 2.0.5
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/dist/index.js +124 -9
- package/dist/index.js.map +1 -1
- package/dist/providers/PersSDKProvider.d.ts.map +1 -1
- package/dist/providers/PersSDKProvider.js +65 -1
- package/dist/storage/async-storage-token-storage.d.ts.map +1 -1
- package/dist/storage/async-storage-token-storage.js +15 -5
- package/package.json +2 -2
- package/src/providers/PersSDKProvider.tsx +74 -1
- package/src/storage/async-storage-token-storage.ts +14 -5
package/dist/index.js
CHANGED
|
@@ -27823,12 +27823,20 @@ class PersApiClient {
|
|
|
27823
27823
|
/**
|
|
27824
27824
|
* Ensures valid authentication token before making requests
|
|
27825
27825
|
*
|
|
27826
|
-
*
|
|
27827
|
-
*
|
|
27828
|
-
*
|
|
27826
|
+
* Validates the current token and automatically refreshes if expired or near expiration.
|
|
27827
|
+
* Uses a 120-second margin - tokens are refreshed if they expire within 2 minutes.
|
|
27828
|
+
*
|
|
27829
|
+
* This method is called automatically before each request but can also be called
|
|
27830
|
+
* manually when needed (e.g., app resume from background).
|
|
27829
27831
|
*
|
|
27830
|
-
* @private
|
|
27831
27832
|
* @returns Promise that resolves when token validation is complete
|
|
27833
|
+
* @throws Error if token refresh fails
|
|
27834
|
+
*
|
|
27835
|
+
* @example
|
|
27836
|
+
* ```typescript
|
|
27837
|
+
* // Validate tokens when app becomes active
|
|
27838
|
+
* await apiClient.ensureValidToken();
|
|
27839
|
+
* ```
|
|
27832
27840
|
*/
|
|
27833
27841
|
async ensureValidToken() {
|
|
27834
27842
|
if (!this.mergedConfig.authProvider) {
|
|
@@ -28572,6 +28580,39 @@ class AuthManager {
|
|
|
28572
28580
|
const authService = this.apiClient.getAuthService();
|
|
28573
28581
|
await authService.clearTokens();
|
|
28574
28582
|
}
|
|
28583
|
+
/**
|
|
28584
|
+
* Ensure authentication token is valid
|
|
28585
|
+
*
|
|
28586
|
+
* Checks if the current token is expired or about to expire and automatically
|
|
28587
|
+
* refreshes it if needed. This is useful for ensuring valid authentication
|
|
28588
|
+
* before performing critical operations or when app resumes from background.
|
|
28589
|
+
*
|
|
28590
|
+
* Uses a 120-second margin - tokens are refreshed if they expire within 2 minutes.
|
|
28591
|
+
*
|
|
28592
|
+
* @returns Promise that resolves when token is validated/refreshed
|
|
28593
|
+
*
|
|
28594
|
+
* @example App Resume (React Native)
|
|
28595
|
+
* ```typescript
|
|
28596
|
+
* AppState.addEventListener('change', async (state) => {
|
|
28597
|
+
* if (state === 'active') {
|
|
28598
|
+
* // Validate tokens when app returns from background
|
|
28599
|
+
* await sdk.auth.ensureValidToken().catch(console.error);
|
|
28600
|
+
* }
|
|
28601
|
+
* });
|
|
28602
|
+
* ```
|
|
28603
|
+
*
|
|
28604
|
+
* @example Before Critical Operation
|
|
28605
|
+
* ```typescript
|
|
28606
|
+
* async function processPayment() {
|
|
28607
|
+
* // Ensure token is valid before payment
|
|
28608
|
+
* await sdk.auth.ensureValidToken();
|
|
28609
|
+
* const result = await sdk.purchases.createPurchase(paymentData);
|
|
28610
|
+
* }
|
|
28611
|
+
* ```
|
|
28612
|
+
*/
|
|
28613
|
+
async ensureValidToken() {
|
|
28614
|
+
return this.apiClient.ensureValidToken();
|
|
28615
|
+
}
|
|
28575
28616
|
/**
|
|
28576
28617
|
* Check if SDK has valid authentication
|
|
28577
28618
|
*
|
|
@@ -34118,19 +34159,24 @@ class AsyncStorageTokenStorage {
|
|
|
34118
34159
|
}
|
|
34119
34160
|
async set(key, value) {
|
|
34120
34161
|
try {
|
|
34121
|
-
|
|
34162
|
+
const fullKey = `${this.keyPrefix}${key}`;
|
|
34163
|
+
await this.asyncStorage.setItem(fullKey, value);
|
|
34164
|
+
console.log(`[AsyncStorage] Token stored: ${key}`);
|
|
34122
34165
|
}
|
|
34123
34166
|
catch (error) {
|
|
34124
|
-
console.error(`Failed to store token ${key}:`, error);
|
|
34167
|
+
console.error(`[AsyncStorage] Failed to store token ${key}:`, error);
|
|
34125
34168
|
throw new Error(`Token storage failed: ${error}`);
|
|
34126
34169
|
}
|
|
34127
34170
|
}
|
|
34128
34171
|
async get(key) {
|
|
34129
34172
|
try {
|
|
34130
|
-
|
|
34173
|
+
const fullKey = `${this.keyPrefix}${key}`;
|
|
34174
|
+
const value = await this.asyncStorage.getItem(fullKey);
|
|
34175
|
+
console.log(`[AsyncStorage] Token retrieved: ${key} - ${value ? 'exists' : 'null'}`);
|
|
34176
|
+
return value;
|
|
34131
34177
|
}
|
|
34132
34178
|
catch (error) {
|
|
34133
|
-
console.error(`Failed to retrieve token ${key}:`, error);
|
|
34179
|
+
console.error(`[AsyncStorage] Failed to retrieve token ${key}:`, error);
|
|
34134
34180
|
return null;
|
|
34135
34181
|
}
|
|
34136
34182
|
}
|
|
@@ -34147,11 +34193,16 @@ class AsyncStorageTokenStorage {
|
|
|
34147
34193
|
const allKeys = await this.asyncStorage.getAllKeys();
|
|
34148
34194
|
const ourKeys = allKeys.filter(key => key.startsWith(this.keyPrefix));
|
|
34149
34195
|
if (ourKeys.length > 0) {
|
|
34196
|
+
console.log(`[AsyncStorage] Clearing ${ourKeys.length} token(s):`, ourKeys);
|
|
34150
34197
|
await this.asyncStorage.multiRemove(ourKeys);
|
|
34198
|
+
console.log('[AsyncStorage] All tokens cleared successfully');
|
|
34199
|
+
}
|
|
34200
|
+
else {
|
|
34201
|
+
console.log('[AsyncStorage] No tokens to clear');
|
|
34151
34202
|
}
|
|
34152
34203
|
}
|
|
34153
34204
|
catch (error) {
|
|
34154
|
-
console.error('Failed to clear token storage:', error);
|
|
34205
|
+
console.error('[AsyncStorage] Failed to clear token storage:', error);
|
|
34155
34206
|
}
|
|
34156
34207
|
}
|
|
34157
34208
|
}
|
|
@@ -34649,6 +34700,70 @@ const PersSDKProvider = ({ children, config }) => {
|
|
|
34649
34700
|
throw error;
|
|
34650
34701
|
}
|
|
34651
34702
|
}, [sdk, isAuthenticated, isInitialized]);
|
|
34703
|
+
// Listen for authentication status changes and refresh user data when tokens are renewed
|
|
34704
|
+
react.useEffect(() => {
|
|
34705
|
+
if (!authProvider || !isInitialized)
|
|
34706
|
+
return;
|
|
34707
|
+
// Access the config object with proper type safety
|
|
34708
|
+
const providerConfig = authProvider.config;
|
|
34709
|
+
if (!providerConfig)
|
|
34710
|
+
return;
|
|
34711
|
+
// Set up auth status change handler
|
|
34712
|
+
const originalHandler = providerConfig.onAuthStatusChange;
|
|
34713
|
+
const authStatusHandler = async (status) => {
|
|
34714
|
+
console.log('[PersSDK] Auth status changed:', status);
|
|
34715
|
+
// Call original handler first if it exists
|
|
34716
|
+
if (originalHandler) {
|
|
34717
|
+
await originalHandler(status);
|
|
34718
|
+
}
|
|
34719
|
+
// If token was refreshed successfully and user is authenticated, reload user data
|
|
34720
|
+
if (status === 'authenticated' && isAuthenticated && sdk) {
|
|
34721
|
+
try {
|
|
34722
|
+
console.log('[PersSDK] Token refreshed, reloading user data...');
|
|
34723
|
+
await refreshUserData();
|
|
34724
|
+
}
|
|
34725
|
+
catch (error) {
|
|
34726
|
+
console.error('[PersSDK] Failed to refresh user data after token renewal:', error);
|
|
34727
|
+
}
|
|
34728
|
+
}
|
|
34729
|
+
// If authentication failed, clear state
|
|
34730
|
+
if (status === 'auth_failed') {
|
|
34731
|
+
console.log('[PersSDK] Authentication failed, clearing state');
|
|
34732
|
+
setAuthenticationState(null, false);
|
|
34733
|
+
}
|
|
34734
|
+
};
|
|
34735
|
+
// Inject our handler into the auth provider config
|
|
34736
|
+
providerConfig.onAuthStatusChange = authStatusHandler;
|
|
34737
|
+
// Cleanup
|
|
34738
|
+
return () => {
|
|
34739
|
+
if (originalHandler) {
|
|
34740
|
+
providerConfig.onAuthStatusChange = originalHandler;
|
|
34741
|
+
}
|
|
34742
|
+
};
|
|
34743
|
+
}, [authProvider, isInitialized, isAuthenticated, sdk, refreshUserData, setAuthenticationState]);
|
|
34744
|
+
// iOS/Android: Monitor app state and validate tokens when app becomes active
|
|
34745
|
+
react.useEffect(() => {
|
|
34746
|
+
if (!sdk || reactNative.Platform.OS === 'web') {
|
|
34747
|
+
return;
|
|
34748
|
+
}
|
|
34749
|
+
const handleAppStateChange = async (nextAppState) => {
|
|
34750
|
+
if (nextAppState === 'active' && isAuthenticated) {
|
|
34751
|
+
console.log('[PersSDK] App became active - validating tokens');
|
|
34752
|
+
try {
|
|
34753
|
+
// Trigger token validation when app resumes from background
|
|
34754
|
+
// This ensures tokens are checked after extended inactivity
|
|
34755
|
+
await sdk.auth.ensureValidToken();
|
|
34756
|
+
}
|
|
34757
|
+
catch (error) {
|
|
34758
|
+
console.warn('[PersSDK] Token validation failed on app resume:', error);
|
|
34759
|
+
}
|
|
34760
|
+
}
|
|
34761
|
+
};
|
|
34762
|
+
const subscription = reactNative.AppState.addEventListener('change', handleAppStateChange);
|
|
34763
|
+
return () => {
|
|
34764
|
+
subscription?.remove();
|
|
34765
|
+
};
|
|
34766
|
+
}, [sdk, isAuthenticated]);
|
|
34652
34767
|
const contextValue = react.useMemo(() => ({
|
|
34653
34768
|
// Main SDK instance
|
|
34654
34769
|
sdk,
|