@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 +1 @@
1
- {"version":3,"file":"PersSDKProvider.d.ts","sourceRoot":"","sources":["../../src/providers/PersSDKProvider.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,EAAuC,SAAS,EAA2C,MAAM,OAAO,CAAC;AAEvH,OAAO,EAAE,OAAO,EAAE,UAAU,EAAE,mBAAmB,EAAE,MAAM,0BAA0B,CAAC;AAIpF,OAAO,EAAE,OAAO,EAAE,QAAQ,EAAE,MAAM,wBAAwB,CAAC;AAG3D,OAAO,KAAK,EACV,WAAW,EACX,WAAW,EACX,YAAY,EACZ,eAAe,EACf,eAAe,EACf,iBAAiB,EACjB,kBAAkB,EAClB,eAAe,EACf,aAAa,EACb,gBAAgB,EAChB,eAAe,EAChB,MAAM,0BAA0B,CAAC;AAGlC,YAAY,EAAE,UAAU,EAAE,MAAM,0BAA0B,CAAC;AAE3D,MAAM,WAAW,cAAc;IAE7B,GAAG,EAAE,OAAO,GAAG,IAAI,CAAC;IAGpB,IAAI,EAAE,WAAW,GAAG,IAAI,CAAC;IACzB,KAAK,EAAE,WAAW,GAAG,IAAI,CAAC;IAC1B,MAAM,EAAE,YAAY,GAAG,IAAI,CAAC;IAC5B,UAAU,EAAE,eAAe,GAAG,IAAI,CAAC;IACnC,SAAS,EAAE,eAAe,GAAG,IAAI,CAAC;IAClC,WAAW,EAAE,iBAAiB,GAAG,IAAI,CAAC;IACtC,YAAY,EAAE,kBAAkB,GAAG,IAAI,CAAC;IACxC,SAAS,EAAE,eAAe,GAAG,IAAI,CAAC;IAClC,OAAO,EAAE,aAAa,GAAG,IAAI,CAAC;IAC9B,SAAS,EAAE,gBAAgB,GAAG,IAAI,CAAC;IACnC,SAAS,EAAE,eAAe,GAAG,IAAI,CAAC;IAGlC,YAAY,EAAE,mBAAmB,GAAG,IAAI,CAAC;IAGzC,aAAa,EAAE,OAAO,CAAC;IACvB,eAAe,EAAE,OAAO,CAAC;IACzB,IAAI,EAAE,OAAO,GAAG,QAAQ,GAAG,IAAI,CAAC;IAGhC,UAAU,EAAE,CAAC,MAAM,EAAE,UAAU,KAAK,OAAO,CAAC,IAAI,CAAC,CAAC;IAClD,sBAAsB,EAAE,CAAC,IAAI,EAAE,OAAO,GAAG,QAAQ,GAAG,IAAI,EAAE,eAAe,EAAE,OAAO,KAAK,IAAI,CAAC;IAC5F,eAAe,EAAE,MAAM,OAAO,CAAC,IAAI,CAAC,CAAC;CACtC;AAMD,eAAO,MAAM,eAAe,EAAE,KAAK,CAAC,EAAE,CAAC;IACrC,QAAQ,EAAE,SAAS,CAAC;IACpB,MAAM,CAAC,EAAE,UAAU,CAAC;CACrB,CA+IA,CAAC;AAGF,eAAO,MAAM,UAAU,QAAO,cAQ7B,CAAC"}
1
+ {"version":3,"file":"PersSDKProvider.d.ts","sourceRoot":"","sources":["../../src/providers/PersSDKProvider.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,EAAuC,SAAS,EAA2C,MAAM,OAAO,CAAC;AAEvH,OAAO,EAAE,OAAO,EAAE,UAAU,EAAE,mBAAmB,EAAE,MAAM,0BAA0B,CAAC;AAIpF,OAAO,EAAE,OAAO,EAAE,QAAQ,EAAE,MAAM,wBAAwB,CAAC;AAG3D,OAAO,KAAK,EACV,WAAW,EACX,WAAW,EACX,YAAY,EACZ,eAAe,EACf,eAAe,EACf,iBAAiB,EACjB,kBAAkB,EAClB,eAAe,EACf,aAAa,EACb,gBAAgB,EAChB,eAAe,EAChB,MAAM,0BAA0B,CAAC;AAGlC,YAAY,EAAE,UAAU,EAAE,MAAM,0BAA0B,CAAC;AAE3D,MAAM,WAAW,cAAc;IAE7B,GAAG,EAAE,OAAO,GAAG,IAAI,CAAC;IAGpB,IAAI,EAAE,WAAW,GAAG,IAAI,CAAC;IACzB,KAAK,EAAE,WAAW,GAAG,IAAI,CAAC;IAC1B,MAAM,EAAE,YAAY,GAAG,IAAI,CAAC;IAC5B,UAAU,EAAE,eAAe,GAAG,IAAI,CAAC;IACnC,SAAS,EAAE,eAAe,GAAG,IAAI,CAAC;IAClC,WAAW,EAAE,iBAAiB,GAAG,IAAI,CAAC;IACtC,YAAY,EAAE,kBAAkB,GAAG,IAAI,CAAC;IACxC,SAAS,EAAE,eAAe,GAAG,IAAI,CAAC;IAClC,OAAO,EAAE,aAAa,GAAG,IAAI,CAAC;IAC9B,SAAS,EAAE,gBAAgB,GAAG,IAAI,CAAC;IACnC,SAAS,EAAE,eAAe,GAAG,IAAI,CAAC;IAGlC,YAAY,EAAE,mBAAmB,GAAG,IAAI,CAAC;IAGzC,aAAa,EAAE,OAAO,CAAC;IACvB,eAAe,EAAE,OAAO,CAAC;IACzB,IAAI,EAAE,OAAO,GAAG,QAAQ,GAAG,IAAI,CAAC;IAGhC,UAAU,EAAE,CAAC,MAAM,EAAE,UAAU,KAAK,OAAO,CAAC,IAAI,CAAC,CAAC;IAClD,sBAAsB,EAAE,CAAC,IAAI,EAAE,OAAO,GAAG,QAAQ,GAAG,IAAI,EAAE,eAAe,EAAE,OAAO,KAAK,IAAI,CAAC;IAC5F,eAAe,EAAE,MAAM,OAAO,CAAC,IAAI,CAAC,CAAC;CACtC;AAMD,eAAO,MAAM,eAAe,EAAE,KAAK,CAAC,EAAE,CAAC;IACrC,QAAQ,EAAE,SAAS,CAAC;IACpB,MAAM,CAAC,EAAE,UAAU,CAAC;CACrB,CAwNA,CAAC;AAGF,eAAO,MAAM,UAAU,QAAO,cAQ7B,CAAC"}
@@ -1,6 +1,6 @@
1
1
  import { jsx as _jsx } from "react/jsx-runtime";
2
2
  import { createContext, useContext, useState, useCallback, useRef, useEffect, useMemo } from 'react';
3
- import { Platform } from 'react-native';
3
+ import { Platform, AppState } from 'react-native';
4
4
  import { PersSDK } from '@explorins/pers-sdk/core';
5
5
  import { ReactNativeHttpClient } from './react-native-http-client';
6
6
  import { createReactNativeAuthProvider } from './react-native-auth-provider';
@@ -93,6 +93,70 @@ export const PersSDKProvider = ({ children, config }) => {
93
93
  throw error;
94
94
  }
95
95
  }, [sdk, isAuthenticated, isInitialized]);
96
+ // Listen for authentication status changes and refresh user data when tokens are renewed
97
+ useEffect(() => {
98
+ if (!authProvider || !isInitialized)
99
+ return;
100
+ // Access the config object with proper type safety
101
+ const providerConfig = authProvider.config;
102
+ if (!providerConfig)
103
+ return;
104
+ // Set up auth status change handler
105
+ const originalHandler = providerConfig.onAuthStatusChange;
106
+ const authStatusHandler = async (status) => {
107
+ console.log('[PersSDK] Auth status changed:', status);
108
+ // Call original handler first if it exists
109
+ if (originalHandler) {
110
+ await originalHandler(status);
111
+ }
112
+ // If token was refreshed successfully and user is authenticated, reload user data
113
+ if (status === 'authenticated' && isAuthenticated && sdk) {
114
+ try {
115
+ console.log('[PersSDK] Token refreshed, reloading user data...');
116
+ await refreshUserData();
117
+ }
118
+ catch (error) {
119
+ console.error('[PersSDK] Failed to refresh user data after token renewal:', error);
120
+ }
121
+ }
122
+ // If authentication failed, clear state
123
+ if (status === 'auth_failed') {
124
+ console.log('[PersSDK] Authentication failed, clearing state');
125
+ setAuthenticationState(null, false);
126
+ }
127
+ };
128
+ // Inject our handler into the auth provider config
129
+ providerConfig.onAuthStatusChange = authStatusHandler;
130
+ // Cleanup
131
+ return () => {
132
+ if (originalHandler) {
133
+ providerConfig.onAuthStatusChange = originalHandler;
134
+ }
135
+ };
136
+ }, [authProvider, isInitialized, isAuthenticated, sdk, refreshUserData, setAuthenticationState]);
137
+ // iOS/Android: Monitor app state and validate tokens when app becomes active
138
+ useEffect(() => {
139
+ if (!sdk || Platform.OS === 'web') {
140
+ return;
141
+ }
142
+ const handleAppStateChange = async (nextAppState) => {
143
+ if (nextAppState === 'active' && isAuthenticated) {
144
+ console.log('[PersSDK] App became active - validating tokens');
145
+ try {
146
+ // Trigger token validation when app resumes from background
147
+ // This ensures tokens are checked after extended inactivity
148
+ await sdk.auth.ensureValidToken();
149
+ }
150
+ catch (error) {
151
+ console.warn('[PersSDK] Token validation failed on app resume:', error);
152
+ }
153
+ }
154
+ };
155
+ const subscription = AppState.addEventListener('change', handleAppStateChange);
156
+ return () => {
157
+ subscription?.remove();
158
+ };
159
+ }, [sdk, isAuthenticated]);
96
160
  const contextValue = useMemo(() => ({
97
161
  // Main SDK instance
98
162
  sdk,
@@ -5,7 +5,7 @@
5
5
  * - Web: Uses LocalStorageTokenStorage from core SDK
6
6
  * - Mobile: Uses AsyncStorage-based storage
7
7
  */
8
- import { DefaultAuthProvider, AuthType } from '@explorins/pers-sdk/core';
8
+ import { DefaultAuthProvider, AccountOwnerType } from '@explorins/pers-sdk/core';
9
9
  import type { TokenStorage } from '@explorins/pers-sdk/core';
10
10
  /**
11
11
  * Configuration for React Native Auth Provider
@@ -17,8 +17,8 @@ export interface ReactNativeAuthConfig {
17
17
  debug?: boolean;
18
18
  /** Custom token storage implementation */
19
19
  customStorage?: TokenStorage;
20
- /** Authentication type (default: 'user') */
21
- authType?: AuthType;
20
+ /** Authentication type (default: AccountOwnerType.USER) */
21
+ authType?: AccountOwnerType;
22
22
  /** DPoP Configuration (optional) */
23
23
  dpop?: {
24
24
  enabled?: boolean;
@@ -1 +1 @@
1
- {"version":3,"file":"react-native-auth-provider.d.ts","sourceRoot":"","sources":["../../src/providers/react-native-auth-provider.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAGH,OAAO,EAAE,mBAAmB,EAAW,QAAQ,EAA4B,MAAM,0BAA0B,CAAC;AAG5G,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,0BAA0B,CAAC;AAK7D;;GAEG;AACH,MAAM,WAAW,qBAAqB;IACpC,gCAAgC;IAChC,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,2BAA2B;IAC3B,KAAK,CAAC,EAAE,OAAO,CAAC;IAChB,0CAA0C;IAC1C,aAAa,CAAC,EAAE,YAAY,CAAC;IAC7B,4CAA4C;IAC5C,QAAQ,CAAC,EAAE,QAAQ,CAAC;IACpB,oCAAoC;IACpC,IAAI,CAAC,EAAE;QACL,OAAO,CAAC,EAAE,OAAO,CAAC;QAClB,cAAc,CAAC,EAAE,OAAO,0BAA0B,EAAE,kBAAkB,CAAC;KACxE,CAAC;CACH;AAED;;;;;;;;;;GAUG;AACH,wBAAgB,6BAA6B,CAC3C,UAAU,EAAE,MAAM,EAClB,MAAM,GAAE,qBAA0B,GACjC,mBAAmB,CAsCrB"}
1
+ {"version":3,"file":"react-native-auth-provider.d.ts","sourceRoot":"","sources":["../../src/providers/react-native-auth-provider.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAGH,OAAO,EAAE,mBAAmB,EAAW,gBAAgB,EAA4B,MAAM,0BAA0B,CAAC;AAGpH,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,0BAA0B,CAAC;AAK7D;;GAEG;AACH,MAAM,WAAW,qBAAqB;IACpC,gCAAgC;IAChC,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,2BAA2B;IAC3B,KAAK,CAAC,EAAE,OAAO,CAAC;IAChB,0CAA0C;IAC1C,aAAa,CAAC,EAAE,YAAY,CAAC;IAC7B,2DAA2D;IAC3D,QAAQ,CAAC,EAAE,gBAAgB,CAAC;IAC5B,oCAAoC;IACpC,IAAI,CAAC,EAAE;QACL,OAAO,CAAC,EAAE,OAAO,CAAC;QAClB,cAAc,CAAC,EAAE,OAAO,0BAA0B,EAAE,kBAAkB,CAAC;KACxE,CAAC;CACH;AAED;;;;;;;;;;GAUG;AACH,wBAAgB,6BAA6B,CAC3C,UAAU,EAAE,MAAM,EAClB,MAAM,GAAE,qBAA0B,GACjC,mBAAmB,CAsCrB"}
@@ -6,7 +6,7 @@
6
6
  * - Mobile: Uses AsyncStorage-based storage
7
7
  */
8
8
  import { Platform } from 'react-native';
9
- import { DefaultAuthProvider, LocalStorageTokenStorage } from '@explorins/pers-sdk/core';
9
+ import { DefaultAuthProvider, AccountOwnerType, LocalStorageTokenStorage } from '@explorins/pers-sdk/core';
10
10
  import { ReactNativeSecureStorage } from '../storage/rn-secure-storage';
11
11
  // Use React Native's built-in platform detection
12
12
  const isWebPlatform = Platform.OS === 'web';
@@ -25,7 +25,7 @@ export function createReactNativeAuthProvider(projectKey, config = {}) {
25
25
  if (!projectKey || typeof projectKey !== 'string') {
26
26
  throw new Error('createReactNativeAuthProvider: projectKey is required and must be a string');
27
27
  }
28
- const { keyPrefix = `pers_${projectKey.slice(0, 8)}_`, debug = false, customStorage, authType = 'user', dpop } = config;
28
+ const { keyPrefix = `pers_${projectKey.slice(0, 8)}_`, debug = false, customStorage, authType = AccountOwnerType.USER, dpop } = config;
29
29
  // Platform-specific storage selection
30
30
  const tokenStorage = customStorage || (isWebPlatform
31
31
  ? new LocalStorageTokenStorage()
@@ -1 +1 @@
1
- {"version":3,"file":"async-storage-token-storage.d.ts","sourceRoot":"","sources":["../../src/storage/async-storage-token-storage.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAGH,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,0BAA0B,CAAC;AA8D7D;;;;;GAKG;AACH,qBAAa,wBAAyB,YAAW,YAAY;IAC3D,OAAO,CAAC,SAAS,CAAS;IAC1B,OAAO,CAAC,YAAY,CAA8B;gBAEtC,SAAS,GAAE,MAAuB;IAexC,GAAG,CAAC,GAAG,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;IAS9C,GAAG,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,GAAG,IAAI,CAAC;IASxC,MAAM,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;IAQlC,KAAK,IAAI,OAAO,CAAC,IAAI,CAAC;CAY7B"}
1
+ {"version":3,"file":"async-storage-token-storage.d.ts","sourceRoot":"","sources":["../../src/storage/async-storage-token-storage.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAGH,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,0BAA0B,CAAC;AA8D7D;;;;;GAKG;AACH,qBAAa,wBAAyB,YAAW,YAAY;IAC3D,OAAO,CAAC,SAAS,CAAS;IAC1B,OAAO,CAAC,YAAY,CAA8B;gBAEtC,SAAS,GAAE,MAAuB;IAexC,GAAG,CAAC,GAAG,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;IAW9C,GAAG,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,GAAG,IAAI,CAAC;IAYxC,MAAM,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;IAQlC,KAAK,IAAI,OAAO,CAAC,IAAI,CAAC;CAgB7B"}
@@ -74,19 +74,24 @@ export class AsyncStorageTokenStorage {
74
74
  }
75
75
  async set(key, value) {
76
76
  try {
77
- await this.asyncStorage.setItem(`${this.keyPrefix}${key}`, value);
77
+ const fullKey = `${this.keyPrefix}${key}`;
78
+ await this.asyncStorage.setItem(fullKey, value);
79
+ console.log(`[AsyncStorage] Token stored: ${key}`);
78
80
  }
79
81
  catch (error) {
80
- console.error(`Failed to store token ${key}:`, error);
82
+ console.error(`[AsyncStorage] Failed to store token ${key}:`, error);
81
83
  throw new Error(`Token storage failed: ${error}`);
82
84
  }
83
85
  }
84
86
  async get(key) {
85
87
  try {
86
- return await this.asyncStorage.getItem(`${this.keyPrefix}${key}`);
88
+ const fullKey = `${this.keyPrefix}${key}`;
89
+ const value = await this.asyncStorage.getItem(fullKey);
90
+ console.log(`[AsyncStorage] Token retrieved: ${key} - ${value ? 'exists' : 'null'}`);
91
+ return value;
87
92
  }
88
93
  catch (error) {
89
- console.error(`Failed to retrieve token ${key}:`, error);
94
+ console.error(`[AsyncStorage] Failed to retrieve token ${key}:`, error);
90
95
  return null;
91
96
  }
92
97
  }
@@ -103,11 +108,16 @@ export class AsyncStorageTokenStorage {
103
108
  const allKeys = await this.asyncStorage.getAllKeys();
104
109
  const ourKeys = allKeys.filter(key => key.startsWith(this.keyPrefix));
105
110
  if (ourKeys.length > 0) {
111
+ console.log(`[AsyncStorage] Clearing ${ourKeys.length} token(s):`, ourKeys);
106
112
  await this.asyncStorage.multiRemove(ourKeys);
113
+ console.log('[AsyncStorage] All tokens cleared successfully');
114
+ }
115
+ else {
116
+ console.log('[AsyncStorage] No tokens to clear');
107
117
  }
108
118
  }
109
119
  catch (error) {
110
- console.error('Failed to clear token storage:', error);
120
+ console.error('[AsyncStorage] Failed to clear token storage:', error);
111
121
  }
112
122
  }
113
123
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@explorins/pers-sdk-react-native",
3
- "version": "2.0.3",
3
+ "version": "2.0.5",
4
4
  "description": "React Native SDK for PERS Platform - Tourism Loyalty System with Blockchain Transaction Signing and WebAuthn Authentication",
5
5
  "main": "dist/index.js",
6
6
  "types": "dist/index.d.ts",
@@ -37,7 +37,7 @@
37
37
  "author": "eXplorins",
38
38
  "license": "MIT",
39
39
  "dependencies": {
40
- "@explorins/pers-sdk": "^2.0.4",
40
+ "@explorins/pers-sdk": "^2.0.6",
41
41
  "@explorins/pers-shared": "^2.1.64",
42
42
  "@explorins/pers-signer": "^1.0.33",
43
43
  "@explorins/web3-ts": "^0.3.77",
@@ -1,6 +1,7 @@
1
1
  import { useCallback } from 'react';
2
2
  import { usePersSDK } from '../providers/PersSDKProvider';
3
3
  import type { RawUserData } from '@explorins/pers-sdk/core';
4
+ import { AccountOwnerType } from '@explorins/pers-sdk/core';
4
5
  import type { UserDTO, AdminDTO, SessionAuthContextResponseDTO } from '@explorins/pers-shared';
5
6
 
6
7
  // Re-export RawUserData for convenience
@@ -58,18 +59,18 @@ export const useAuth = () => {
58
59
  * Authenticates a user with a JWT token
59
60
  *
60
61
  * @param jwtToken - The JWT token to authenticate with
61
- * @param userType - The type of user ('user' | 'admin'), defaults to 'user'
62
+ * @param userType - The type of user (AccountOwnerType), defaults to USER
62
63
  * @returns Promise resolving to session auth context with user data
63
64
  * @throws Error if SDK is not initialized or authentication fails
64
65
  *
65
66
  * @example
66
67
  * ```typescript
67
68
  * const { login } = useAuth();
68
- * const result = await login(jwtToken, 'user');
69
+ * const result = await login(jwtToken, AccountOwnerType.USER);
69
70
  * console.log('Logged in user:', result.user);
70
71
  * ```
71
72
  */
72
- const login = useCallback(async (jwtToken: string, userType: 'user' | 'admin' = 'user'): Promise<SessionAuthContextResponseDTO> => {
73
+ const login = useCallback(async (jwtToken: string, userType: AccountOwnerType = AccountOwnerType.USER): Promise<SessionAuthContextResponseDTO> => {
73
74
  if (!sdk || !authProvider) {
74
75
  throw new Error('SDK not initialized. Call initialize() first.');
75
76
  }
@@ -1,5 +1,5 @@
1
1
  import React, { createContext, useContext, useState, ReactNode, useCallback, useRef, useEffect, useMemo } from 'react';
2
- import { Platform } from 'react-native';
2
+ import { Platform, AppState, AppStateStatus } from 'react-native';
3
3
  import { PersSDK, PersConfig, DefaultAuthProvider } from '@explorins/pers-sdk/core';
4
4
  import { ReactNativeHttpClient } from './react-native-http-client';
5
5
  import { createReactNativeAuthProvider } from './react-native-auth-provider';
@@ -160,6 +160,79 @@ export const PersSDKProvider: React.FC<{
160
160
  }
161
161
  }, [sdk, isAuthenticated, isInitialized]);
162
162
 
163
+ // Listen for authentication status changes and refresh user data when tokens are renewed
164
+ useEffect(() => {
165
+ if (!authProvider || !isInitialized) return;
166
+
167
+ // Access the config object with proper type safety
168
+ const providerConfig = (authProvider as any).config;
169
+ if (!providerConfig) return;
170
+
171
+ // Set up auth status change handler
172
+ const originalHandler = providerConfig.onAuthStatusChange;
173
+
174
+ const authStatusHandler = async (status: string) => {
175
+ console.log('[PersSDK] Auth status changed:', status);
176
+
177
+ // Call original handler first if it exists
178
+ if (originalHandler) {
179
+ await originalHandler(status);
180
+ }
181
+
182
+ // If token was refreshed successfully and user is authenticated, reload user data
183
+ if (status === 'authenticated' && isAuthenticated && sdk) {
184
+ try {
185
+ console.log('[PersSDK] Token refreshed, reloading user data...');
186
+ await refreshUserData();
187
+ } catch (error) {
188
+ console.error('[PersSDK] Failed to refresh user data after token renewal:', error);
189
+ }
190
+ }
191
+
192
+ // If authentication failed, clear state
193
+ if (status === 'auth_failed') {
194
+ console.log('[PersSDK] Authentication failed, clearing state');
195
+ setAuthenticationState(null, false);
196
+ }
197
+ };
198
+
199
+ // Inject our handler into the auth provider config
200
+ providerConfig.onAuthStatusChange = authStatusHandler;
201
+
202
+ // Cleanup
203
+ return () => {
204
+ if (originalHandler) {
205
+ providerConfig.onAuthStatusChange = originalHandler;
206
+ }
207
+ };
208
+ }, [authProvider, isInitialized, isAuthenticated, sdk, refreshUserData, setAuthenticationState]);
209
+
210
+ // iOS/Android: Monitor app state and validate tokens when app becomes active
211
+ useEffect(() => {
212
+ if (!sdk || Platform.OS === 'web') {
213
+ return;
214
+ }
215
+
216
+ const handleAppStateChange = async (nextAppState: AppStateStatus) => {
217
+ if (nextAppState === 'active' && isAuthenticated) {
218
+ console.log('[PersSDK] App became active - validating tokens');
219
+ try {
220
+ // Trigger token validation when app resumes from background
221
+ // This ensures tokens are checked after extended inactivity
222
+ await sdk.auth.ensureValidToken();
223
+ } catch (error) {
224
+ console.warn('[PersSDK] Token validation failed on app resume:', error);
225
+ }
226
+ }
227
+ };
228
+
229
+ const subscription = AppState.addEventListener('change', handleAppStateChange);
230
+
231
+ return () => {
232
+ subscription?.remove();
233
+ };
234
+ }, [sdk, isAuthenticated]);
235
+
163
236
  const contextValue: PersSDKContext = useMemo(() => ({
164
237
  // Main SDK instance
165
238
  sdk,
@@ -7,7 +7,7 @@
7
7
  */
8
8
 
9
9
  import { Platform } from 'react-native';
10
- import { DefaultAuthProvider, AuthApi, AuthType, LocalStorageTokenStorage } from '@explorins/pers-sdk/core';
10
+ import { DefaultAuthProvider, AuthApi, AccountOwnerType, LocalStorageTokenStorage } from '@explorins/pers-sdk/core';
11
11
  import { AsyncStorageTokenStorage } from '../storage/async-storage-token-storage';
12
12
  import { ReactNativeSecureStorage } from '../storage/rn-secure-storage';
13
13
  import type { TokenStorage } from '@explorins/pers-sdk/core';
@@ -25,8 +25,8 @@ export interface ReactNativeAuthConfig {
25
25
  debug?: boolean;
26
26
  /** Custom token storage implementation */
27
27
  customStorage?: TokenStorage;
28
- /** Authentication type (default: 'user') */
29
- authType?: AuthType;
28
+ /** Authentication type (default: AccountOwnerType.USER) */
29
+ authType?: AccountOwnerType;
30
30
  /** DPoP Configuration (optional) */
31
31
  dpop?: {
32
32
  enabled?: boolean;
@@ -57,7 +57,7 @@ export function createReactNativeAuthProvider(
57
57
  keyPrefix = `pers_${projectKey.slice(0, 8)}_`,
58
58
  debug = false,
59
59
  customStorage,
60
- authType = 'user',
60
+ authType = AccountOwnerType.USER,
61
61
  dpop
62
62
  } = config;
63
63
 
@@ -94,18 +94,23 @@ export class AsyncStorageTokenStorage implements TokenStorage {
94
94
 
95
95
  async set(key: string, value: string): Promise<void> {
96
96
  try {
97
- await this.asyncStorage.setItem(`${this.keyPrefix}${key}`, value);
97
+ const fullKey = `${this.keyPrefix}${key}`;
98
+ await this.asyncStorage.setItem(fullKey, value);
99
+ console.log(`[AsyncStorage] Token stored: ${key}`);
98
100
  } catch (error) {
99
- console.error(`Failed to store token ${key}:`, error);
101
+ console.error(`[AsyncStorage] Failed to store token ${key}:`, error);
100
102
  throw new Error(`Token storage failed: ${error}`);
101
103
  }
102
104
  }
103
105
 
104
106
  async get(key: string): Promise<string | null> {
105
107
  try {
106
- return await this.asyncStorage.getItem(`${this.keyPrefix}${key}`);
108
+ const fullKey = `${this.keyPrefix}${key}`;
109
+ const value = await this.asyncStorage.getItem(fullKey);
110
+ console.log(`[AsyncStorage] Token retrieved: ${key} - ${value ? 'exists' : 'null'}`);
111
+ return value;
107
112
  } catch (error) {
108
- console.error(`Failed to retrieve token ${key}:`, error);
113
+ console.error(`[AsyncStorage] Failed to retrieve token ${key}:`, error);
109
114
  return null;
110
115
  }
111
116
  }
@@ -124,10 +129,14 @@ export class AsyncStorageTokenStorage implements TokenStorage {
124
129
  const ourKeys = allKeys.filter(key => key.startsWith(this.keyPrefix));
125
130
 
126
131
  if (ourKeys.length > 0) {
132
+ console.log(`[AsyncStorage] Clearing ${ourKeys.length} token(s):`, ourKeys);
127
133
  await this.asyncStorage.multiRemove(ourKeys);
134
+ console.log('[AsyncStorage] All tokens cleared successfully');
135
+ } else {
136
+ console.log('[AsyncStorage] No tokens to clear');
128
137
  }
129
138
  } catch (error) {
130
- console.error('Failed to clear token storage:', error);
139
+ console.error('[AsyncStorage] Failed to clear token storage:', error);
131
140
  }
132
141
  }
133
142
  }