@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.
@@ -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?: 'user' | 'admin') => Promise<SessionAuthContextResponseDTO>;
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,MAAM,GAAG,OAAO,KAAY,QAAQ,6BAA6B,CAAC;oCAuCtE,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"}
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"}
@@ -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 ('user' | 'admin'), defaults to '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, 'user');
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 = 'user') => {
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, 'admin', jwt);
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, 'user', jwt);
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, 'business', jwt);
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, 'user');
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 || 'user';
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 || 'user',
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
- * Delegates to TokenRefreshManager for centralized token logic.
27827
- * Called without await for optimal performance - requests proceed immediately
27828
- * while token validation/refresh happens in background.
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 = 'user') {
28385
+ async loginWithToken(jwtToken, userType = exports.AccountOwnerType.USER) {
28378
28386
  const authService = this.apiClient.getAuthService();
28379
- const result = userType === 'admin'
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
- await this.asyncStorage.setItem(`${this.keyPrefix}${key}`, value);
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
- return await this.asyncStorage.getItem(`${this.keyPrefix}${key}`);
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 = 'user', dpop } = config;
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 ('user' | 'admin'), defaults to '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, 'user');
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 = 'user') => {
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
  }