@explorins/pers-sdk-react-native 2.1.2 → 2.1.3

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,21 +1,9 @@
1
1
  import React, { ReactNode } from 'react';
2
2
  import { PersSDK, PersConfig, DefaultAuthProvider } from '@explorins/pers-sdk/core';
3
3
  import { UserDTO, AdminDTO } from '@explorins/pers-shared';
4
- import type { AuthManager, UserManager, TokenManager, BusinessManager, CampaignManager, RedemptionManager, TransactionManager, PurchaseManager, TenantManager, AnalyticsManager, DonationManager } from '@explorins/pers-sdk/core';
5
4
  export type { PersConfig } from '@explorins/pers-sdk/core';
6
5
  export interface PersSDKContext {
7
6
  sdk: PersSDK | null;
8
- auth: AuthManager | null;
9
- users: UserManager | null;
10
- tokens: TokenManager | null;
11
- businesses: BusinessManager | null;
12
- campaigns: CampaignManager | null;
13
- redemptions: RedemptionManager | null;
14
- transactions: TransactionManager | null;
15
- purchases: PurchaseManager | null;
16
- tenants: TenantManager | null;
17
- analytics: AnalyticsManager | null;
18
- donations: DonationManager | null;
19
7
  authProvider: DefaultAuthProvider | null;
20
8
  isInitialized: boolean;
21
9
  isAuthenticated: boolean;
@@ -23,6 +11,7 @@ export interface PersSDKContext {
23
11
  initialize: (config: PersConfig) => Promise<void>;
24
12
  setAuthenticationState: (user: UserDTO | AdminDTO | null, isAuthenticated: boolean) => void;
25
13
  refreshUserData: () => Promise<void>;
14
+ restoreSession: () => Promise<UserDTO | null>;
26
15
  }
27
16
  export declare const PersSDKProvider: React.FC<{
28
17
  children: ReactNode;
@@ -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,CAyMA,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;AAkB3D,YAAY,EAAE,UAAU,EAAE,MAAM,0BAA0B,CAAC;AAE3D,MAAM,WAAW,cAAc;IAE7B,GAAG,EAAE,OAAO,GAAG,IAAI,CAAC;IAGpB,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;IACrC,cAAc,EAAE,MAAM,OAAO,CAAC,OAAO,GAAG,IAAI,CAAC,CAAC;CAC/C;AAMD,eAAO,MAAM,eAAe,EAAE,KAAK,CAAC,EAAE,CAAC;IACrC,QAAQ,EAAE,SAAS,CAAC;IACpB,MAAM,CAAC,EAAE,UAAU,CAAC;CACrB,CAwOA,CAAC;AAGF,eAAO,MAAM,UAAU,QAAO,cAQ7B,CAAC"}
@@ -10,11 +10,19 @@ const SDKContext = createContext(null);
10
10
  // Provider component
11
11
  export const PersSDKProvider = ({ children, config }) => {
12
12
  const initializingRef = useRef(false);
13
+ // State refs for stable functions to read current values
14
+ const sdkRef = useRef(null);
15
+ const isInitializedRef = useRef(false);
16
+ const isAuthenticatedRef = useRef(false);
13
17
  const [sdk, setSdk] = useState(null);
14
18
  const [authProvider, setAuthProvider] = useState(null);
15
19
  const [isInitialized, setIsInitialized] = useState(false);
16
20
  const [isAuthenticated, setIsAuthenticated] = useState(false);
17
21
  const [user, setUser] = useState(null);
22
+ // Keep state refs in sync immediately (not in useEffect to avoid race conditions)
23
+ sdkRef.current = sdk;
24
+ isInitializedRef.current = isInitialized;
25
+ isAuthenticatedRef.current = isAuthenticated;
18
26
  const initialize = useCallback(async (config) => {
19
27
  // Prevent multiple initializations
20
28
  if (isInitialized || initializingRef.current) {
@@ -81,18 +89,40 @@ export const PersSDKProvider = ({ children, config }) => {
81
89
  }
82
90
  }, [config, isInitialized, initialize]);
83
91
  const refreshUserData = useCallback(async () => {
84
- if (!sdk || !isAuthenticated || !isInitialized) {
85
- throw new Error('SDK not initialized or not authenticated. Cannot refresh user data.');
92
+ // Read from refs to get current values
93
+ const currentSdk = sdkRef.current;
94
+ const currentIsInitialized = isInitializedRef.current;
95
+ if (!currentSdk || !currentIsInitialized) {
96
+ throw new Error('SDK not initialized. Cannot refresh user data.');
86
97
  }
87
98
  try {
88
- const freshUserData = await sdk.users.getCurrentUser();
99
+ const freshUserData = await currentSdk.users.getCurrentUser();
89
100
  setUser(freshUserData);
90
101
  }
91
102
  catch (error) {
92
103
  console.error('Failed to refresh user data:', error);
93
104
  throw error;
94
105
  }
95
- }, [sdk, isAuthenticated, isInitialized]);
106
+ }, []); // No dependencies - reads from refs
107
+ const restoreSession = useCallback(async () => {
108
+ // Read from refs to get current values
109
+ const currentSdk = sdkRef.current;
110
+ const currentIsInitialized = isInitializedRef.current;
111
+ if (!currentSdk || !currentIsInitialized) {
112
+ throw new Error('SDK not initialized. Call initialize() first.');
113
+ }
114
+ try {
115
+ const userData = await currentSdk.restoreSession();
116
+ if (userData) {
117
+ setAuthenticationState(userData, true);
118
+ }
119
+ return userData;
120
+ }
121
+ catch (error) {
122
+ console.error('[PersSDK] Failed to restore session:', error);
123
+ throw error;
124
+ }
125
+ }, [setAuthenticationState]); // Depends on setAuthenticationState
96
126
  // Listen for authentication events from core SDK
97
127
  // Set up immediately when SDK is created (don't wait for isInitialized)
98
128
  // to catch session_restored events that fire during SDK initialization
@@ -105,13 +135,18 @@ export const PersSDKProvider = ({ children, config }) => {
105
135
  // Session restored successfully - sync React state
106
136
  if (event.type === 'session_restored') {
107
137
  console.log('[PersSDK] Session restoration event received, syncing state...');
108
- sdk.users.getCurrentUser()
109
- .then(userData => {
110
- setAuthenticationState(userData, true);
111
- })
112
- .catch(error => {
113
- console.error('[PersSDK] Failed to sync restored session:', error);
114
- });
138
+ // Read user from event details if available, otherwise fetch
139
+ const userId = event.details?.userId;
140
+ if (userId) {
141
+ // User ID available, fetch user data
142
+ sdk.users.getCurrentUser()
143
+ .then(userData => {
144
+ setAuthenticationState(userData, true);
145
+ })
146
+ .catch(error => {
147
+ console.error('[PersSDK] Failed to sync restored session:', error);
148
+ });
149
+ }
115
150
  }
116
151
  // Session restoration failed or auth error - clear React state
117
152
  if (event.type === 'session_restoration_failed' || event.code === 'AUTH_FAILED') {
@@ -149,28 +184,17 @@ export const PersSDKProvider = ({ children, config }) => {
149
184
  const contextValue = useMemo(() => ({
150
185
  // Main SDK instance
151
186
  sdk,
152
- // Manager shortcuts for convenience
153
- auth: sdk?.auth || null,
154
- users: sdk?.users || null,
155
- tokens: sdk?.tokens || null,
156
- businesses: sdk?.businesses || null,
157
- campaigns: sdk?.campaigns || null,
158
- redemptions: sdk?.redemptions || null,
159
- transactions: sdk?.transactions || null,
160
- purchases: sdk?.purchases || null,
161
- tenants: sdk?.tenants || null,
162
- analytics: sdk?.analytics || null,
163
- donations: sdk?.donations || null,
164
187
  // Platform-specific providers
165
188
  authProvider,
166
189
  // State
167
190
  isInitialized,
168
191
  isAuthenticated,
169
192
  user,
170
- // Methods
193
+ // Methods - expose functions directly, not through refs
171
194
  initialize,
172
195
  setAuthenticationState,
173
196
  refreshUserData,
197
+ restoreSession,
174
198
  }), [
175
199
  sdk,
176
200
  authProvider,
@@ -179,7 +203,8 @@ export const PersSDKProvider = ({ children, config }) => {
179
203
  user,
180
204
  initialize,
181
205
  setAuthenticationState,
182
- refreshUserData
206
+ refreshUserData,
207
+ restoreSession
183
208
  ]);
184
209
  return (_jsx(SDKContext.Provider, { value: contextValue, children: children }));
185
210
  };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@explorins/pers-sdk-react-native",
3
- "version": "2.1.2",
3
+ "version": "2.1.3",
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.1.2",
40
+ "@explorins/pers-sdk": "^2.1.3",
41
41
  "@explorins/pers-signer": "^1.0.33",
42
42
  "buffer": "^6.0.3",
43
43
  "ethers": "^6.15.0",
@@ -151,7 +151,7 @@ export function useTokenBalances(options: UseTokenBalancesOptions): UseTokenBala
151
151
  refreshInterval = 0
152
152
  } = options;
153
153
 
154
- const { isAuthenticated } = usePersSDK();
154
+ const { isAuthenticated, sdk } = usePersSDK();
155
155
  const web3 = useWeb3();
156
156
 
157
157
  const [tokenBalances, setTokenBalances] = useState<TokenBalanceWithToken[]>([]);
@@ -268,16 +268,30 @@ export function useTokenBalances(options: UseTokenBalancesOptions): UseTokenBala
268
268
  }
269
269
  }, [autoLoad, isAvailable, availableTokens.length, loadBalances]);
270
270
 
271
- // Optional auto-refresh interval
271
+ // Event-driven refresh: listen for transaction events instead of polling
272
272
  useEffect(() => {
273
- if (refreshInterval > 0 && isAvailable && availableTokens.length > 0) {
274
- const intervalId = setInterval(() => {
273
+ if (!sdk || refreshInterval <= 0 || !isAvailable) return;
274
+
275
+ // Subscribe to transaction domain events
276
+ const unsubscribe = sdk.events.subscribe((event) => {
277
+ if (event.domain === 'transaction' && event.type === 'transaction_completed') {
278
+ console.log('[useTokenBalances] Transaction completed, refreshing balances...');
275
279
  loadBalances();
276
- }, refreshInterval);
277
-
278
- return () => clearInterval(intervalId);
279
- }
280
- }, [refreshInterval, isAvailable, availableTokens.length, loadBalances]);
280
+ }
281
+ }, { domains: ['transaction'] });
282
+
283
+ // Also set up a fallback polling interval (much longer than before)
284
+ // This handles cases where events might be missed
285
+ const fallbackInterval = Math.max(refreshInterval, 60000); // Minimum 1 minute
286
+ const intervalId = setInterval(() => {
287
+ loadBalances();
288
+ }, fallbackInterval);
289
+
290
+ return () => {
291
+ unsubscribe();
292
+ clearInterval(intervalId);
293
+ };
294
+ }, [sdk, refreshInterval, isAvailable, loadBalances]);
281
295
 
282
296
  return {
283
297
  tokenBalances,
@@ -28,19 +28,6 @@ export interface PersSDKContext {
28
28
  // Main SDK instance
29
29
  sdk: PersSDK | null;
30
30
 
31
- // Manager shortcuts for convenience
32
- auth: AuthManager | null;
33
- users: UserManager | null;
34
- tokens: TokenManager | null;
35
- businesses: BusinessManager | null;
36
- campaigns: CampaignManager | null;
37
- redemptions: RedemptionManager | null;
38
- transactions: TransactionManager | null;
39
- purchases: PurchaseManager | null;
40
- tenants: TenantManager | null;
41
- analytics: AnalyticsManager | null;
42
- donations: DonationManager | null;
43
-
44
31
  // Platform-specific providers
45
32
  authProvider: DefaultAuthProvider | null;
46
33
 
@@ -53,6 +40,7 @@ export interface PersSDKContext {
53
40
  initialize: (config: PersConfig) => Promise<void>;
54
41
  setAuthenticationState: (user: UserDTO | AdminDTO | null, isAuthenticated: boolean) => void;
55
42
  refreshUserData: () => Promise<void>;
43
+ restoreSession: () => Promise<UserDTO | null>;
56
44
  }
57
45
 
58
46
  // Create the context
@@ -64,6 +52,12 @@ export const PersSDKProvider: React.FC<{
64
52
  config?: PersConfig;
65
53
  }> = ({ children, config }) => {
66
54
  const initializingRef = useRef(false);
55
+
56
+ // State refs for stable functions to read current values
57
+ const sdkRef = useRef<PersSDK | null>(null);
58
+ const isInitializedRef = useRef(false);
59
+ const isAuthenticatedRef = useRef(false);
60
+
67
61
  const [sdk, setSdk] = useState<PersSDK | null>(null);
68
62
  const [authProvider, setAuthProvider] = useState<DefaultAuthProvider | null>(null);
69
63
 
@@ -71,6 +65,11 @@ export const PersSDKProvider: React.FC<{
71
65
  const [isAuthenticated, setIsAuthenticated] = useState(false);
72
66
  const [user, setUser] = useState<UserDTO | AdminDTO | null>(null);
73
67
 
68
+ // Keep state refs in sync immediately (not in useEffect to avoid race conditions)
69
+ sdkRef.current = sdk;
70
+ isInitializedRef.current = isInitialized;
71
+ isAuthenticatedRef.current = isAuthenticated;
72
+
74
73
  const initialize = useCallback(async (config: PersConfig) => {
75
74
  // Prevent multiple initializations
76
75
  if (isInitialized || initializingRef.current) {
@@ -147,18 +146,44 @@ export const PersSDKProvider: React.FC<{
147
146
  }, [config, isInitialized, initialize]);
148
147
 
149
148
  const refreshUserData = useCallback(async (): Promise<void> => {
150
- if (!sdk || !isAuthenticated || !isInitialized) {
151
- throw new Error('SDK not initialized or not authenticated. Cannot refresh user data.');
149
+ // Read from refs to get current values
150
+ const currentSdk = sdkRef.current;
151
+ const currentIsInitialized = isInitializedRef.current;
152
+
153
+ if (!currentSdk || !currentIsInitialized) {
154
+ throw new Error('SDK not initialized. Cannot refresh user data.');
152
155
  }
153
156
 
154
157
  try {
155
- const freshUserData = await sdk.users.getCurrentUser();
158
+ const freshUserData = await currentSdk.users.getCurrentUser();
156
159
  setUser(freshUserData);
157
160
  } catch (error) {
158
161
  console.error('Failed to refresh user data:', error);
159
162
  throw error;
160
163
  }
161
- }, [sdk, isAuthenticated, isInitialized]);
164
+ }, []); // No dependencies - reads from refs
165
+
166
+ const restoreSession = useCallback(async (): Promise<UserDTO | null> => {
167
+ // Read from refs to get current values
168
+ const currentSdk = sdkRef.current;
169
+ const currentIsInitialized = isInitializedRef.current;
170
+
171
+ if (!currentSdk || !currentIsInitialized) {
172
+ throw new Error('SDK not initialized. Call initialize() first.');
173
+ }
174
+
175
+ try {
176
+ const userData = await currentSdk.restoreSession();
177
+ if (userData) {
178
+ setAuthenticationState(userData, true);
179
+ }
180
+ return userData;
181
+ } catch (error) {
182
+ console.error('[PersSDK] Failed to restore session:', error);
183
+ throw error;
184
+ }
185
+ }, [setAuthenticationState]); // Depends on setAuthenticationState
186
+
162
187
  // Listen for authentication events from core SDK
163
188
  // Set up immediately when SDK is created (don't wait for isInitialized)
164
189
  // to catch session_restored events that fire during SDK initialization
@@ -171,13 +196,18 @@ export const PersSDKProvider: React.FC<{
171
196
  // Session restored successfully - sync React state
172
197
  if (event.type === 'session_restored') {
173
198
  console.log('[PersSDK] Session restoration event received, syncing state...');
174
- sdk.users.getCurrentUser()
175
- .then(userData => {
176
- setAuthenticationState(userData, true);
177
- })
178
- .catch(error => {
179
- console.error('[PersSDK] Failed to sync restored session:', error);
180
- });
199
+ // Read user from event details if available, otherwise fetch
200
+ const userId = event.details?.userId;
201
+ if (userId) {
202
+ // User ID available, fetch user data
203
+ sdk.users.getCurrentUser()
204
+ .then(userData => {
205
+ setAuthenticationState(userData, true);
206
+ })
207
+ .catch(error => {
208
+ console.error('[PersSDK] Failed to sync restored session:', error);
209
+ });
210
+ }
181
211
  }
182
212
 
183
213
  // Session restoration failed or auth error - clear React state
@@ -222,19 +252,6 @@ export const PersSDKProvider: React.FC<{
222
252
  // Main SDK instance
223
253
  sdk,
224
254
 
225
- // Manager shortcuts for convenience
226
- auth: sdk?.auth || null,
227
- users: sdk?.users || null,
228
- tokens: sdk?.tokens || null,
229
- businesses: sdk?.businesses || null,
230
- campaigns: sdk?.campaigns || null,
231
- redemptions: sdk?.redemptions || null,
232
- transactions: sdk?.transactions || null,
233
- purchases: sdk?.purchases || null,
234
- tenants: sdk?.tenants || null,
235
- analytics: sdk?.analytics || null,
236
- donations: sdk?.donations || null,
237
-
238
255
  // Platform-specific providers
239
256
  authProvider,
240
257
 
@@ -243,10 +260,11 @@ export const PersSDKProvider: React.FC<{
243
260
  isAuthenticated,
244
261
  user,
245
262
 
246
- // Methods
263
+ // Methods - expose functions directly, not through refs
247
264
  initialize,
248
265
  setAuthenticationState,
249
266
  refreshUserData,
267
+ restoreSession,
250
268
  }), [
251
269
  sdk,
252
270
  authProvider,
@@ -255,7 +273,8 @@ export const PersSDKProvider: React.FC<{
255
273
  user,
256
274
  initialize,
257
275
  setAuthenticationState,
258
- refreshUserData
276
+ refreshUserData,
277
+ restoreSession
259
278
  ]);
260
279
 
261
280
  return (