@explorins/pers-sdk-react-native 2.0.3 → 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/hooks/useAuth.d.ts +2 -1
- package/dist/hooks/useAuth.d.ts.map +1 -1
- package/dist/hooks/useAuth.js +4 -3
- package/dist/index.js +136 -21
- 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/providers/react-native-auth-provider.d.ts +3 -3
- package/dist/providers/react-native-auth-provider.d.ts.map +1 -1
- package/dist/providers/react-native-auth-provider.js +2 -2
- 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/hooks/useAuth.ts +4 -3
- package/src/providers/PersSDKProvider.tsx +74 -1
- package/src/providers/react-native-auth-provider.ts +4 -4
- package/src/storage/async-storage-token-storage.ts +14 -5
package/dist/hooks/useAuth.d.ts
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import type { RawUserData } from '@explorins/pers-sdk/core';
|
|
2
|
+
import { AccountOwnerType } from '@explorins/pers-sdk/core';
|
|
2
3
|
import type { UserDTO, AdminDTO, SessionAuthContextResponseDTO } from '@explorins/pers-shared';
|
|
3
4
|
export type { RawUserData };
|
|
4
5
|
/**
|
|
@@ -42,7 +43,7 @@ export declare const useAuth: () => {
|
|
|
42
43
|
isInitialized: boolean;
|
|
43
44
|
isAuthenticated: boolean;
|
|
44
45
|
user: UserDTO | AdminDTO | null;
|
|
45
|
-
login: (jwtToken: string, userType?:
|
|
46
|
+
login: (jwtToken: string, userType?: AccountOwnerType) => Promise<SessionAuthContextResponseDTO>;
|
|
46
47
|
loginWithRawData: (rawUserData: RawUserData) => Promise<void>;
|
|
47
48
|
logout: () => Promise<void>;
|
|
48
49
|
refreshUserData: () => Promise<void>;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"useAuth.d.ts","sourceRoot":"","sources":["../../src/hooks/useAuth.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,0BAA0B,CAAC;AAC5D,OAAO,KAAK,EAAE,OAAO,EAAE,QAAQ,EAAE,6BAA6B,EAAE,MAAM,wBAAwB,CAAC;AAG/F,YAAY,EAAE,WAAW,EAAE,CAAC;AAE5B;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAoCG;AACH,eAAO,MAAM,OAAO;;;;sBA0ByB,MAAM,aAAY,
|
|
1
|
+
{"version":3,"file":"useAuth.d.ts","sourceRoot":"","sources":["../../src/hooks/useAuth.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,0BAA0B,CAAC;AAC5D,OAAO,EAAE,gBAAgB,EAAE,MAAM,0BAA0B,CAAC;AAC5D,OAAO,KAAK,EAAE,OAAO,EAAE,QAAQ,EAAE,6BAA6B,EAAE,MAAM,wBAAwB,CAAC;AAG/F,YAAY,EAAE,WAAW,EAAE,CAAC;AAE5B;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAoCG;AACH,eAAO,MAAM,OAAO;;;;sBA0ByB,MAAM,aAAY,gBAAgB,KAA2B,QAAQ,6BAA6B,CAAC;oCAuCrF,WAAW,KAAG,QAAQ,IAAI,CAAC;kBAuC/C,QAAQ,IAAI,CAAC;;0BA0BL,QAAQ,OAAO,CAAC;gCAmBV,QAAQ,OAAO,CAAC;mCAqBX,MAAM;qBAmBtB,QAAQ,IAAI,CAAC;wBAoBV,QAAQ,OAAO,CAAC;CAwB5D,CAAC;AAEF,MAAM,MAAM,QAAQ,GAAG,UAAU,CAAC,OAAO,OAAO,CAAC,CAAC"}
|
package/dist/hooks/useAuth.js
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { useCallback } from 'react';
|
|
2
2
|
import { usePersSDK } from '../providers/PersSDKProvider';
|
|
3
|
+
import { AccountOwnerType } from '@explorins/pers-sdk/core';
|
|
3
4
|
/**
|
|
4
5
|
* React hook for authentication operations in the PERS SDK
|
|
5
6
|
*
|
|
@@ -43,18 +44,18 @@ export const useAuth = () => {
|
|
|
43
44
|
* Authenticates a user with a JWT token
|
|
44
45
|
*
|
|
45
46
|
* @param jwtToken - The JWT token to authenticate with
|
|
46
|
-
* @param userType - The type of user (
|
|
47
|
+
* @param userType - The type of user (AccountOwnerType), defaults to USER
|
|
47
48
|
* @returns Promise resolving to session auth context with user data
|
|
48
49
|
* @throws Error if SDK is not initialized or authentication fails
|
|
49
50
|
*
|
|
50
51
|
* @example
|
|
51
52
|
* ```typescript
|
|
52
53
|
* const { login } = useAuth();
|
|
53
|
-
* const result = await login(jwtToken,
|
|
54
|
+
* const result = await login(jwtToken, AccountOwnerType.USER);
|
|
54
55
|
* console.log('Logged in user:', result.user);
|
|
55
56
|
* ```
|
|
56
57
|
*/
|
|
57
|
-
const login = useCallback(async (jwtToken, userType =
|
|
58
|
+
const login = useCallback(async (jwtToken, userType = AccountOwnerType.USER) => {
|
|
58
59
|
if (!sdk || !authProvider) {
|
|
59
60
|
throw new Error('SDK not initialized. Call initialize() first.');
|
|
60
61
|
}
|
package/dist/index.js
CHANGED
|
@@ -27127,7 +27127,7 @@ class AuthService {
|
|
|
27127
27127
|
async loginTenantAdmin(jwt) {
|
|
27128
27128
|
const response = await this.authApi.loginTenantAdmin(jwt);
|
|
27129
27129
|
if (this.authProvider && response.accessToken) {
|
|
27130
|
-
await this.storeTokens(response.accessToken, response.refreshToken,
|
|
27130
|
+
await this.storeTokens(response.accessToken, response.refreshToken, exports.AccountOwnerType.TENANT, jwt);
|
|
27131
27131
|
}
|
|
27132
27132
|
return response;
|
|
27133
27133
|
}
|
|
@@ -27137,7 +27137,7 @@ class AuthService {
|
|
|
27137
27137
|
async loginUser(jwt) {
|
|
27138
27138
|
const response = await this.authApi.loginUser(jwt);
|
|
27139
27139
|
if (this.authProvider && response.accessToken) {
|
|
27140
|
-
await this.storeTokens(response.accessToken, response.refreshToken,
|
|
27140
|
+
await this.storeTokens(response.accessToken, response.refreshToken, exports.AccountOwnerType.USER, jwt);
|
|
27141
27141
|
}
|
|
27142
27142
|
return response;
|
|
27143
27143
|
}
|
|
@@ -27168,7 +27168,7 @@ class AuthService {
|
|
|
27168
27168
|
async loginBusiness(jwt, options) {
|
|
27169
27169
|
const response = await this.authApi.loginBusiness(jwt, options);
|
|
27170
27170
|
if (this.authProvider && response.accessToken) {
|
|
27171
|
-
await this.storeTokens(response.accessToken, response.refreshToken,
|
|
27171
|
+
await this.storeTokens(response.accessToken, response.refreshToken, exports.AccountOwnerType.BUSINESS, jwt);
|
|
27172
27172
|
}
|
|
27173
27173
|
return response;
|
|
27174
27174
|
}
|
|
@@ -27178,7 +27178,7 @@ class AuthService {
|
|
|
27178
27178
|
async loginUserWithRawData(rawLoginData) {
|
|
27179
27179
|
const response = await this.authApi.loginUnAuthenticated(rawLoginData);
|
|
27180
27180
|
if (this.authProvider && response.accessToken) {
|
|
27181
|
-
await this.storeTokens(response.accessToken, response.refreshToken,
|
|
27181
|
+
await this.storeTokens(response.accessToken, response.refreshToken, exports.AccountOwnerType.USER);
|
|
27182
27182
|
}
|
|
27183
27183
|
return response;
|
|
27184
27184
|
}
|
|
@@ -27660,7 +27660,7 @@ class DPoPManager {
|
|
|
27660
27660
|
class DefaultAuthProvider {
|
|
27661
27661
|
constructor(config = {}) {
|
|
27662
27662
|
this.config = config;
|
|
27663
|
-
this.authType = config.authType ||
|
|
27663
|
+
this.authType = config.authType || exports.AccountOwnerType.USER;
|
|
27664
27664
|
const storage = config.storage || this.createStorage();
|
|
27665
27665
|
this.tokenManager = new AuthTokenManager(storage);
|
|
27666
27666
|
if (config.dpop?.enabled) {
|
|
@@ -27793,7 +27793,7 @@ class PersApiClient {
|
|
|
27793
27793
|
// Auto-create auth provider if none provided
|
|
27794
27794
|
if (!this.mergedConfig.authProvider) {
|
|
27795
27795
|
this.mergedConfig.authProvider = new DefaultAuthProvider({
|
|
27796
|
-
authType: this.mergedConfig.authType ||
|
|
27796
|
+
authType: this.mergedConfig.authType || exports.AccountOwnerType.USER,
|
|
27797
27797
|
projectKey: this.mergedConfig.apiProjectKey,
|
|
27798
27798
|
storage: this.mergedConfig.authStorage, // Support custom storage
|
|
27799
27799
|
dpop: {
|
|
@@ -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) {
|
|
@@ -28374,9 +28382,9 @@ class AuthManager {
|
|
|
28374
28382
|
* console.log('Admin authenticated:', authResult.admin.email);
|
|
28375
28383
|
* ```
|
|
28376
28384
|
*/
|
|
28377
|
-
async loginWithToken(jwtToken, userType =
|
|
28385
|
+
async loginWithToken(jwtToken, userType = exports.AccountOwnerType.USER) {
|
|
28378
28386
|
const authService = this.apiClient.getAuthService();
|
|
28379
|
-
const result = userType ===
|
|
28387
|
+
const result = userType === exports.AccountOwnerType.TENANT
|
|
28380
28388
|
? await authService.loginTenantAdmin(jwtToken)
|
|
28381
28389
|
: await authService.loginUser(jwtToken);
|
|
28382
28390
|
this.events?.emitSuccess({
|
|
@@ -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
|
}
|
|
@@ -34324,7 +34375,7 @@ function createReactNativeAuthProvider(projectKey, config = {}) {
|
|
|
34324
34375
|
if (!projectKey || typeof projectKey !== 'string') {
|
|
34325
34376
|
throw new Error('createReactNativeAuthProvider: projectKey is required and must be a string');
|
|
34326
34377
|
}
|
|
34327
|
-
const { keyPrefix = `pers_${projectKey.slice(0, 8)}_`, debug = false, customStorage, authType =
|
|
34378
|
+
const { keyPrefix = `pers_${projectKey.slice(0, 8)}_`, debug = false, customStorage, authType = exports.AccountOwnerType.USER, dpop } = config;
|
|
34328
34379
|
// Platform-specific storage selection
|
|
34329
34380
|
const tokenStorage = customStorage || (isWebPlatform
|
|
34330
34381
|
? new LocalStorageTokenStorage()
|
|
@@ -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,
|
|
@@ -34738,18 +34853,18 @@ const useAuth = () => {
|
|
|
34738
34853
|
* Authenticates a user with a JWT token
|
|
34739
34854
|
*
|
|
34740
34855
|
* @param jwtToken - The JWT token to authenticate with
|
|
34741
|
-
* @param userType - The type of user (
|
|
34856
|
+
* @param userType - The type of user (AccountOwnerType), defaults to USER
|
|
34742
34857
|
* @returns Promise resolving to session auth context with user data
|
|
34743
34858
|
* @throws Error if SDK is not initialized or authentication fails
|
|
34744
34859
|
*
|
|
34745
34860
|
* @example
|
|
34746
34861
|
* ```typescript
|
|
34747
34862
|
* const { login } = useAuth();
|
|
34748
|
-
* const result = await login(jwtToken,
|
|
34863
|
+
* const result = await login(jwtToken, AccountOwnerType.USER);
|
|
34749
34864
|
* console.log('Logged in user:', result.user);
|
|
34750
34865
|
* ```
|
|
34751
34866
|
*/
|
|
34752
|
-
const login = react.useCallback(async (jwtToken, userType =
|
|
34867
|
+
const login = react.useCallback(async (jwtToken, userType = exports.AccountOwnerType.USER) => {
|
|
34753
34868
|
if (!sdk || !authProvider) {
|
|
34754
34869
|
throw new Error('SDK not initialized. Call initialize() first.');
|
|
34755
34870
|
}
|