@openfort/react-native 0.1.3 → 0.1.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.
@@ -2,6 +2,7 @@ import { Openfort as OpenfortClient } from '@openfort/openfort-js';
2
2
  import { digest } from 'expo-crypto';
3
3
  import { applicationId } from 'expo-application';
4
4
  import { SecureStorageAdapter, createNormalizedStorage } from './storage';
5
+ import { logger } from '../lib/logger';
5
6
  /**
6
7
  * Creates an instance of the Openfort client configured for Expo/React Native
7
8
  *
@@ -16,7 +17,7 @@ import { SecureStorageAdapter, createNormalizedStorage } from './storage';
16
17
  */
17
18
  export function createOpenfortClient({ baseConfiguration, overrides, shieldConfiguration, }) {
18
19
  const nativeAppId = getNativeApplicationId();
19
- console.log('Creating Openfort client with native app ID:', nativeAppId);
20
+ logger.info('Creating Openfort client with native app ID', nativeAppId);
20
21
  // appId,
21
22
  // clientId,
22
23
  // supportedChains,
@@ -1,18 +1,54 @@
1
- import React, { useState, useEffect, useCallback, useMemo, useRef } from 'react';
2
- import { OpenfortConfiguration, ShieldConfiguration, EmbeddedState } from '@openfort/openfort-js';
1
+ import React, { useState, useEffect, useCallback, useMemo } from 'react';
2
+ import { OpenfortConfiguration, ShieldConfiguration, EmbeddedState, } from '@openfort/openfort-js';
3
3
  import { OpenfortContext } from './context';
4
4
  import { createOpenfortClient, setDefaultClient } from './client';
5
5
  import { EmbeddedWalletWebView, WebViewUtils } from '../native';
6
+ import { logger, getEmbeddedStateName } from '../lib/logger';
7
+ /**
8
+ * Starts polling the embedded wallet state and calls onChange only when the
9
+ * state actually changes. Returns a cleanup function to stop polling.
10
+ */
11
+ function startEmbeddedStatePolling(client, onChange, intervalMs = 1000) {
12
+ let lastState = null;
13
+ let stopped = false;
14
+ const check = async () => {
15
+ if (stopped)
16
+ return;
17
+ try {
18
+ const state = await client.embeddedWallet.getEmbeddedState();
19
+ if (state !== lastState) {
20
+ lastState = state;
21
+ onChange(state);
22
+ }
23
+ }
24
+ catch (error) {
25
+ logger.error('Error checking embedded state with Openfort', error);
26
+ }
27
+ };
28
+ const intervalId = setInterval(check, intervalMs);
29
+ // Run once immediately so we don't wait for the first interval tick
30
+ void check();
31
+ return () => {
32
+ stopped = true;
33
+ clearInterval(intervalId);
34
+ };
35
+ }
6
36
  /**
7
37
  * Main provider component that wraps the entire application and provides
8
38
  * Openfort SDK functionality through React context
9
39
  */
10
- export const OpenfortProvider = ({ children, publishableKey, customAuth, supportedChains, walletConfig, overrides, }) => {
40
+ export const OpenfortProvider = ({ children, publishableKey, customAuth, supportedChains, walletConfig, overrides, thirdPartyAuth, verbose = false, }) => {
11
41
  // Prevent multiple OpenfortProvider instances
12
42
  const existingContext = React.useContext(OpenfortContext);
13
43
  if (existingContext) {
14
44
  throw new Error('Found multiple instances of OpenfortProvider. Ensure there is only one mounted in your application tree.');
15
45
  }
46
+ // Set logger verbose mode
47
+ useEffect(() => {
48
+ if (verbose)
49
+ logger.printVerboseWarning();
50
+ logger.setVerbose(verbose);
51
+ }, [verbose]);
16
52
  // Create or use provided client
17
53
  const client = useMemo(() => {
18
54
  const newClient = createOpenfortClient({
@@ -21,49 +57,25 @@ export const OpenfortProvider = ({ children, publishableKey, customAuth, support
21
57
  }),
22
58
  shieldConfiguration: walletConfig ? new ShieldConfiguration({
23
59
  shieldPublishableKey: walletConfig.shieldPublishableKey,
24
- shieldEncryptionKey: 'shieldEncryptionKey' in walletConfig ? walletConfig.shieldEncryptionKey : undefined,
25
60
  shieldDebug: walletConfig.debug,
26
61
  }) : undefined,
27
- overrides: {
28
- ...overrides,
29
- },
62
+ overrides,
63
+ thirdPartyAuth,
30
64
  });
31
65
  setDefaultClient(newClient);
32
66
  return newClient;
33
67
  }, [publishableKey, walletConfig, overrides]);
34
68
  // Embedded state
35
69
  const [embeddedState, setEmbeddedState] = useState(EmbeddedState.NONE);
36
- const pollingRef = useRef(null);
37
- const pollEmbeddedState = useCallback(async () => {
38
- if (!client)
39
- return;
40
- try {
41
- const state = await client.embeddedWallet.getEmbeddedState();
42
- console.log('Current embedded state:', state);
43
- setEmbeddedState(state);
44
- }
45
- catch (error) {
46
- console.error('Error checking embedded state with Openfort:', error);
47
- if (pollingRef.current)
48
- clearInterval(pollingRef.current);
49
- }
50
- }, [client]);
51
- const startPollingEmbeddedState = useCallback(() => {
52
- if (pollingRef.current)
53
- return;
54
- pollingRef.current = setInterval(pollEmbeddedState, 1000);
55
- }, [pollEmbeddedState]);
56
- const stopPollingEmbeddedState = useCallback(() => {
57
- clearInterval(pollingRef.current || undefined);
58
- pollingRef.current = null;
59
- }, []);
70
+ // Start polling embedded state: only update and log when state changes
60
71
  useEffect(() => {
61
72
  if (!client)
62
73
  return;
63
- startPollingEmbeddedState();
64
- return () => {
65
- stopPollingEmbeddedState();
66
- };
74
+ const stop = startEmbeddedStatePolling(client, (state) => {
75
+ setEmbeddedState(state);
76
+ logger.info('Current state of the embedded wallet:', getEmbeddedStateName(state));
77
+ }, 1000);
78
+ return stop;
67
79
  }, [client]);
68
80
  // Core state
69
81
  const [user, setUser] = useState(null);
@@ -77,7 +89,15 @@ export const OpenfortProvider = ({ children, publishableKey, customAuth, support
77
89
  const [recoveryFlowState, setRecoveryFlowState] = useState({ status: 'initial' });
78
90
  // User state management
79
91
  const handleUserChange = useCallback((newUser) => {
80
- console.log('User state changed:', newUser);
92
+ if (newUser === null) {
93
+ logger.info('User not authenticated. User state changed to: null');
94
+ }
95
+ else if ('id' in newUser) {
96
+ logger.info('User authenticated. User state changed to user with id:', newUser.id);
97
+ }
98
+ else {
99
+ logger.error('User state changed to user in wrong format:', newUser);
100
+ }
81
101
  setUser(newUser);
82
102
  if (newUser) {
83
103
  setError(null);
@@ -93,41 +113,22 @@ export const OpenfortProvider = ({ children, publishableKey, customAuth, support
93
113
  return await client.getAccessToken();
94
114
  }
95
115
  catch (err) {
96
- console.debug('Failed to get access token:', err);
116
+ logger.debug('Failed to get access token', err);
97
117
  return null;
98
118
  }
99
119
  }, [client]);
100
- // Initialize client and user
101
- useEffect(() => {
102
- console.log('Initializing Openfort client and user state', isUserInitialized);
103
- if (!isUserInitialized) {
104
- (async () => {
105
- console.log('Initializing Openfort client');
106
- try {
107
- // Openfort client doesn't need explicit initialization
108
- setIsClientReady(true);
109
- }
110
- catch (err) {
111
- setError(err instanceof Error ? err : new Error(String(err)));
112
- }
113
- try {
114
- console.log('Refreshing user state on initial load');
115
- await refreshUserState();
116
- }
117
- catch {
118
- // User not logged in, which is fine
119
- handleUserChange(null);
120
- }
121
- finally {
122
- setIsUserInitialized(true);
123
- }
124
- })();
125
- }
126
- }, [client, isUserInitialized, handleUserChange]);
127
120
  // Internal refresh function for auth hooks to use
128
121
  const refreshUserState = useCallback(async (user) => {
129
122
  try {
130
- console.log('Refreshing user state', user);
123
+ if (user === undefined) {
124
+ logger.info('Refreshing user state, no user provided');
125
+ }
126
+ else if ('id' in user) {
127
+ logger.info('Refreshing user state, user provided with id:', user.id);
128
+ }
129
+ else {
130
+ logger.error('Refreshing user state, user provided is in wrong format:', user);
131
+ }
131
132
  // If user is provided, use it directly instead of fetching from API
132
133
  if (user !== undefined) {
133
134
  handleUserChange(user);
@@ -135,16 +136,46 @@ export const OpenfortProvider = ({ children, publishableKey, customAuth, support
135
136
  }
136
137
  // Otherwise, fetch from API
137
138
  const currentUser = await client.user.get();
138
- console.log('Refreshed user state:', currentUser);
139
+ logger.info('Refreshed user state', currentUser);
139
140
  handleUserChange(currentUser);
140
141
  return currentUser;
141
142
  }
142
143
  catch (err) {
143
- console.log('Failed to refresh user state:', err);
144
+ logger.warn('Failed to refresh user state', err);
144
145
  handleUserChange(null);
145
146
  return null;
146
147
  }
147
148
  }, [client, handleUserChange]);
149
+ // Initialize client and user
150
+ useEffect(() => {
151
+ if (isUserInitialized) {
152
+ logger.info('Openfort client and user state already initialized. isUserInitialized:', isUserInitialized);
153
+ return;
154
+ }
155
+ let cancelled = false;
156
+ const initialize = async () => {
157
+ logger.info('Initializing Openfort client and user state');
158
+ // No explicit client initialization required
159
+ setIsClientReady(true);
160
+ try {
161
+ logger.info('Refreshing user state on initial load');
162
+ await refreshUserState();
163
+ }
164
+ catch (err) {
165
+ logger.error('Failed to initialize user state', err);
166
+ // User not logged in or fetch failed; treat as unauthenticated
167
+ handleUserChange(null);
168
+ }
169
+ finally {
170
+ if (!cancelled)
171
+ setIsUserInitialized(true);
172
+ }
173
+ };
174
+ void initialize();
175
+ return () => {
176
+ cancelled = true;
177
+ };
178
+ }, [client, isUserInitialized, handleUserChange, refreshUserState]);
148
179
  // Custom auth state management
149
180
  useEffect(() => {
150
181
  if (customAuth?.enabled && isUserInitialized && isClientReady) {
@@ -157,11 +188,11 @@ export const OpenfortProvider = ({ children, publishableKey, customAuth, support
157
188
  if (customToken) {
158
189
  // Custom auth sync implementation would go here
159
190
  // This would typically handle SIWE authentication with the custom token
160
- console.debug('Custom token available for authentication sync');
191
+ logger.debug('Custom token available for authentication sync');
161
192
  }
162
193
  }
163
194
  catch (err) {
164
- console.error('Custom auth sync failed:', err);
195
+ logger.error('Custom auth sync failed', err);
165
196
  }
166
197
  })();
167
198
  }
@@ -217,8 +248,8 @@ export const OpenfortProvider = ({ children, publishableKey, customAuth, support
217
248
  children,
218
249
  client && isReady && WebViewUtils.isSupported() && (React.createElement(EmbeddedWalletWebView, { client: client, isClientReady: isReady, onProxyStatusChange: (status) => {
219
250
  // Handle WebView status changes for debugging
220
- if (process.env.NODE_ENV === 'development') {
221
- console.debug('WebView status changed:', status);
251
+ if (verbose) {
252
+ logger.debug('WebView status changed', status);
222
253
  }
223
254
  } }))));
224
255
  };
@@ -1,6 +1,7 @@
1
1
  /* eslint-disable @typescript-eslint/no-explicit-any */
2
2
  import * as SecureStore from 'expo-secure-store';
3
3
  import { NativeStorageUtils } from '../native';
4
+ import { logger } from '../lib/logger';
4
5
  // Define the StorageKeys enum values that match the Openfort SDK
5
6
  var StorageKeys;
6
7
  (function (StorageKeys) {
@@ -29,16 +30,16 @@ export const SecureStorageAdapter = {
29
30
  }
30
31
  // Handle unexpected Promise-like objects (shouldn't happen according to docs)
31
32
  if (result && typeof result === 'object' && '_j' in result) {
32
- console.warn('WARNING: SecureStore returned a Promise-like object instead of a string');
33
+ logger.warn('WARNING: SecureStore returned a Promise-like object instead of a string');
33
34
  const actualValue = result._j;
34
35
  return typeof actualValue === 'string' ? actualValue : null;
35
36
  }
36
37
  // If we get here, something is wrong
37
- console.error('Unexpected result type from SecureStore:', result);
38
+ logger.error('Unexpected result type from SecureStore', result);
38
39
  return null;
39
40
  }
40
41
  catch (error) {
41
- console.warn('Failed to get item from secure store:', error);
42
+ logger.warn('Failed to get item from secure store', error);
42
43
  return null;
43
44
  }
44
45
  },
@@ -48,7 +49,7 @@ export const SecureStorageAdapter = {
48
49
  await SecureStore.setItemAsync(normalizedKey, value, NativeStorageUtils.getStorageOptions());
49
50
  }
50
51
  catch (error) {
51
- console.warn('Failed to set item in secure store:', error);
52
+ logger.warn('Failed to set item in secure store', error);
52
53
  throw error;
53
54
  }
54
55
  },
@@ -58,7 +59,7 @@ export const SecureStorageAdapter = {
58
59
  await SecureStore.deleteItemAsync(normalizedKey, NativeStorageUtils.getStorageOptions());
59
60
  }
60
61
  catch (error) {
61
- console.warn('Failed to delete item from secure store:', error);
62
+ logger.warn('Failed to delete item from secure store', error);
62
63
  throw error;
63
64
  }
64
65
  },
@@ -96,23 +97,23 @@ export function createNormalizedStorage(customStorage) {
96
97
  return result;
97
98
  },
98
99
  save(key, value) {
99
- console.log('storage save:', key, value);
100
+ logger.info(`Saving to storage key: ${key}, value: ${value}`);
100
101
  const storageKey = keyToStorageKeys(key);
101
102
  // Fire and forget - don't await as the SDK expects synchronous behavior
102
103
  baseStorage.save(storageKey, value).catch(error => {
103
- console.error('Failed to save to storage:', error);
104
+ logger.error('Failed to save to storage', error);
104
105
  });
105
106
  },
106
107
  remove(key) {
107
- console.log('storage remove:', key);
108
+ logger.info(`Removing from storage key: ${key}`);
108
109
  const storageKey = keyToStorageKeys(key);
109
110
  // Fire and forget - don't await as the SDK expects synchronous behavior
110
111
  baseStorage.remove(storageKey).catch(error => {
111
- console.error('Failed to remove from storage:', error);
112
+ logger.error('Failed to remove from storage', error);
112
113
  });
113
114
  },
114
115
  flush() {
115
- console.log('storage flush');
116
+ logger.info('Flushing storage');
116
117
  baseStorage.flush();
117
118
  },
118
119
  };
@@ -6,6 +6,7 @@ import { useCallback, useEffect, useMemo, useRef, useState } from 'react';
6
6
  import { useOpenfortContext } from '../../core/context';
7
7
  import { onError, onSuccess } from '../../lib/hookConsistency';
8
8
  import { OpenfortError, OpenfortErrorType } from '../../types/openfortError';
9
+ import { logger } from '../../lib/logger';
9
10
  const mapWalletStatus = (status) => {
10
11
  return {
11
12
  error: status.error,
@@ -130,7 +131,7 @@ export function useWallets(hookOptions = {}) {
130
131
  }
131
132
  else {
132
133
  if (!walletConfig?.getEncryptionSession) {
133
- throw new OpenfortError('Encryption session is required for automatic recovery', OpenfortErrorType.WALLET_ERROR);
134
+ throw new OpenfortError('Encryption session (walletConfig.getEncryptionSession) is required for automatic recovery', OpenfortErrorType.WALLET_ERROR);
134
135
  }
135
136
  recoveryParams = {
136
137
  recoveryMethod: RecoveryMethod.AUTOMATIC,
@@ -231,7 +232,7 @@ export function useWallets(hookOptions = {}) {
231
232
  },
232
233
  }))), [embeddedAccounts, activeWalletId, status.status === "connecting", client.embeddedWallet]);
233
234
  const create = useCallback(async (options) => {
234
- console.log('Creating Ethereum wallet with options:', options);
235
+ logger.info('Creating Ethereum wallet with options', options);
235
236
  try {
236
237
  setStatus({
237
238
  status: 'creating',
@@ -251,7 +252,7 @@ export function useWallets(hookOptions = {}) {
251
252
  else {
252
253
  throw new OpenfortError('No supported chains available for wallet creation', OpenfortErrorType.WALLET_ERROR);
253
254
  }
254
- console.log('Using chain ID for wallet creation:', chainId);
255
+ logger.info('Using chain ID for wallet creation', chainId);
255
256
  let recoveryParams;
256
257
  ;
257
258
  if (options?.recoveryPassword) {
@@ -262,7 +263,7 @@ export function useWallets(hookOptions = {}) {
262
263
  }
263
264
  else {
264
265
  if (!walletConfig?.getEncryptionSession) {
265
- throw new OpenfortError('Encryption session is required for automatic recovery', OpenfortErrorType.WALLET_ERROR);
266
+ throw new OpenfortError('Encryption session (walletConfig.getEncryptionSession) is required for automatic recovery', OpenfortErrorType.WALLET_ERROR);
266
267
  }
267
268
  recoveryParams = {
268
269
  recoveryMethod: RecoveryMethod.AUTOMATIC,
@@ -276,7 +277,7 @@ export function useWallets(hookOptions = {}) {
276
277
  chainType: options?.chainType || ChainTypeEnum.EVM,
277
278
  recoveryParams,
278
279
  });
279
- console.log('Embedded wallet configured with shield authentication');
280
+ logger.info('Embedded wallet configured with shield authentication');
280
281
  // Get the Ethereum provider
281
282
  const provider = await client.embeddedWallet.getEthereumProvider({
282
283
  announceProvider: false,
package/dist/index.js CHANGED
@@ -8,6 +8,8 @@
8
8
  * @author Openfort
9
9
  * @version 0.1.0
10
10
  */
11
+ // Re-export commonly used types from @openfort/openfort-js
12
+ export { OpenfortError, RecoveryMethod, Openfort as OpenfortClient, OpenfortConfiguration, ShieldConfiguration, EmbeddedState, } from '@openfort/openfort-js';
11
13
  // Re-export enums and values from @openfort/openfort-js
12
14
  export { OAuthProvider, } from '@openfort/openfort-js';
13
15
  // Re-export all types from the main types module
@@ -0,0 +1,62 @@
1
+ // Lightweight logger with standardized prefix
2
+ // Usage: logger.info('message', optionalData)
3
+ import { EmbeddedState } from '@openfort/openfort-js';
4
+ const PREFIX = '[OPENFORT_PROVIDER]';
5
+ let verboseMode = false;
6
+ function formatMessage(level, message) {
7
+ const text = typeof message === 'string' ? message : JSON.stringify(message);
8
+ return `${PREFIX} ${text}`;
9
+ }
10
+ function log(level, message, ...optionalParams) {
11
+ // Only log debug and info messages in verbose mode
12
+ if ((level === 'debug' || level === 'info') && !verboseMode) {
13
+ return;
14
+ }
15
+ const formatted = formatMessage(level, message);
16
+ switch (level) {
17
+ case 'debug':
18
+ // eslint-disable-next-line no-console
19
+ console.debug(formatted, ...optionalParams);
20
+ break;
21
+ case 'info':
22
+ // eslint-disable-next-line no-console
23
+ console.log(formatted, ...optionalParams);
24
+ break;
25
+ case 'warn':
26
+ // eslint-disable-next-line no-console
27
+ console.warn(formatted, ...optionalParams);
28
+ break;
29
+ case 'error':
30
+ // eslint-disable-next-line no-console
31
+ console.error(formatted, ...optionalParams);
32
+ break;
33
+ }
34
+ }
35
+ export const logger = {
36
+ debug: (message, ...optionalParams) => log('debug', message, ...optionalParams),
37
+ info: (message, ...optionalParams) => log('info', message, ...optionalParams),
38
+ warn: (message, ...optionalParams) => log('warn', message, ...optionalParams),
39
+ error: (message, ...optionalParams) => log('error', message, ...optionalParams),
40
+ setVerbose: (verbose) => {
41
+ verboseMode = verbose;
42
+ },
43
+ printVerboseWarning: () => {
44
+ log('warn', 'Verbose mode is enabled. Debug and info logs will be printed. To disable, set the "verbose" prop on OpenfortProvider to false.');
45
+ },
46
+ };
47
+ export const getEmbeddedStateName = (state) => {
48
+ switch (state) {
49
+ case EmbeddedState.NONE:
50
+ return 'NONE';
51
+ case EmbeddedState.UNAUTHENTICATED:
52
+ return 'UNAUTHENTICATED';
53
+ case EmbeddedState.EMBEDDED_SIGNER_NOT_CONFIGURED:
54
+ return 'EMBEDDED_SIGNER_NOT_CONFIGURED';
55
+ case EmbeddedState.CREATING_ACCOUNT:
56
+ return 'CREATING_ACCOUNT';
57
+ case EmbeddedState.READY:
58
+ return 'READY';
59
+ default:
60
+ return `STATE: ${String(state)}`;
61
+ }
62
+ };
@@ -1,6 +1,7 @@
1
1
  import { Platform } from 'react-native';
2
2
  import * as WebBrowser from 'expo-web-browser';
3
3
  import * as Linking from 'expo-linking';
4
+ import { logger } from '../lib/logger';
4
5
  import * as AppleAuthentication from 'expo-apple-authentication';
5
6
  import { OAuthProvider as OAuthProviderType } from '@openfort/openfort-js';
6
7
  /**
@@ -94,7 +95,7 @@ export async function isAppleSignInAvailable() {
94
95
  export function parseOAuthUrl(url) {
95
96
  try {
96
97
  const { queryParams } = Linking.parse(url);
97
- console.log('Parsed OAuth URL:', queryParams);
98
+ logger.info('Parsed OAuth URL', queryParams);
98
99
  return {
99
100
  access_token: queryParams?.access_token,
100
101
  refresh_token: queryParams?.refresh_token,
@@ -104,7 +105,7 @@ export function parseOAuthUrl(url) {
104
105
  };
105
106
  }
106
107
  catch (error) {
107
- console.warn('Failed to parse OAuth URL:', error);
108
+ logger.warn('Failed to parse OAuth URL', error);
108
109
  return {};
109
110
  }
110
111
  }
@@ -1,6 +1,7 @@
1
1
  /* eslint-disable @typescript-eslint/no-explicit-any */
2
2
  import * as SecureStore from 'expo-secure-store';
3
3
  import { Platform } from 'react-native';
4
+ import { logger } from '../lib/logger';
4
5
  /**
5
6
  * Checks if a message is a secure storage related message
6
7
  */
@@ -22,7 +23,7 @@ export function isSecureStorageMessage(message) {
22
23
  * Handles secure storage operations from WebView messages
23
24
  */
24
25
  export async function handleSecureStorageMessage(message) {
25
- console.log('Handling secure storage message:', message);
26
+ logger.info('Handling secure storage message', message);
26
27
  switch (message.event) {
27
28
  case 'app:secure-storage:get': {
28
29
  const { key } = message.data;
@@ -37,7 +38,7 @@ export async function handleSecureStorageMessage(message) {
37
38
  };
38
39
  }
39
40
  catch (error) {
40
- console.warn('Failed to get the value from secure store', error);
41
+ logger.warn('Failed to get the value from secure store', error);
41
42
  return {
42
43
  event: message.event,
43
44
  id: message.id,
@@ -58,7 +59,7 @@ export async function handleSecureStorageMessage(message) {
58
59
  };
59
60
  }
60
61
  catch (error) {
61
- console.warn('Failed to write the value to secure store', error);
62
+ logger.warn('Failed to write the value to secure store', error);
62
63
  return {
63
64
  event: message.event,
64
65
  id: message.id,
@@ -79,7 +80,7 @@ export async function handleSecureStorageMessage(message) {
79
80
  };
80
81
  }
81
82
  catch (error) {
82
- console.warn('Failed to remove the value from secure store', error);
83
+ logger.warn('Failed to remove the value from secure store', error);
83
84
  return {
84
85
  event: message.event,
85
86
  id: message.id,
@@ -105,11 +106,11 @@ export async function handleSecureStorageMessage(message) {
105
106
  }
106
107
  catch (error) {
107
108
  // Ignore errors for keys that don't exist
108
- console.debug(`Key ${fullKey} not found during flush:`, error);
109
+ logger.debug(`Key ${fullKey} not found during flush`, error);
109
110
  }
110
111
  });
111
112
  await Promise.all(deletePromises);
112
- console.log('Flushed secure storage for origin:', origin);
113
+ logger.info('Flushed secure storage for origin', origin);
113
114
  return {
114
115
  event: message.event,
115
116
  id: message.id,
@@ -117,7 +118,7 @@ export async function handleSecureStorageMessage(message) {
117
118
  };
118
119
  }
119
120
  catch (error) {
120
- console.warn('Failed to flush secure store', error);
121
+ logger.warn('Failed to flush secure store', error);
121
122
  return {
122
123
  event: message.event,
123
124
  id: message.id,
@@ -3,6 +3,7 @@ import React, { useRef, useCallback, useEffect } from 'react';
3
3
  import { AppState, Platform, View } from 'react-native';
4
4
  import WebView from 'react-native-webview';
5
5
  import { isSecureStorageMessage, handleSecureStorageMessage } from './storage';
6
+ import { logger } from '../lib/logger';
6
7
  /**
7
8
  * WebView component for embedded wallet integration
8
9
  * Handles secure communication between React Native and the embedded wallet WebView
@@ -23,7 +24,7 @@ export const EmbeddedWalletWebView = ({ client, isClientReady, onProxyStatusChan
23
24
  // }
24
25
  }
25
26
  catch (error) {
26
- console.warn('Failed to ping embedded wallet:', error);
27
+ logger.warn('Failed to ping embedded wallet', error);
27
28
  }
28
29
  }
29
30
  };
@@ -35,7 +36,7 @@ export const EmbeddedWalletWebView = ({ client, isClientReady, onProxyStatusChan
35
36
  onProxyStatusChange?.('loaded');
36
37
  }, [onProxyStatusChange]);
37
38
  const handleError = useCallback((error) => {
38
- console.error('WebView error:', error);
39
+ logger.error('WebView error', error);
39
40
  }, []);
40
41
  // Set up WebView reference with client immediately when both are available
41
42
  useEffect(() => {
@@ -65,7 +66,7 @@ export const EmbeddedWalletWebView = ({ client, isClientReady, onProxyStatusChan
65
66
  client.embeddedWallet.onMessage(messageData);
66
67
  }
67
68
  catch (error) {
68
- console.error('Failed to handle WebView message:', error);
69
+ logger.error('Failed to handle WebView message', error);
69
70
  // Don't crash the app on message handling errors
70
71
  }
71
72
  }, [client]);
@@ -4,5 +4,5 @@ export type { SDKOverrides } from '@openfort/openfort-js';
4
4
  export { OpenfortContext, useOpenfortContext, useOpenfortContextSafe, isOpenfortContextValue } from './context';
5
5
  export type { OpenfortContextValue } from './context';
6
6
  export { OpenfortProvider } from './provider';
7
- export type { OpenfortProviderProps, EmbeddedWalletConfiguration, CommonEmbeddedWalletConfiguration, EncryptionSession, AutomaticRecoveryEmbeddedWalletConfiguration, PasswordRecoveryEmbeddedWalletConfiguration } from './provider';
7
+ export type { OpenfortProviderProps, EmbeddedWalletConfiguration, CommonEmbeddedWalletConfiguration, EncryptionSession, } from './provider';
8
8
  export { SecureStorageAdapter, createNormalizedStorage } from './storage';
@@ -1,5 +1,5 @@
1
1
  import React from 'react';
2
- import { RecoveryMethod, SDKOverrides, AccountTypeEnum } from '@openfort/openfort-js';
2
+ import { SDKOverrides, AccountTypeEnum, ThirdPartyAuthConfiguration } from '@openfort/openfort-js';
3
3
  /**
4
4
  * Custom auth configuration
5
5
  */
@@ -13,36 +13,18 @@ export type CommonEmbeddedWalletConfiguration = {
13
13
  shieldPublishableKey: string;
14
14
  /** Policy ID (pol_...) for the embedded signer */
15
15
  ethereumProviderPolicyId?: string;
16
- debug?: boolean;
17
16
  accountType?: AccountTypeEnum;
17
+ debug?: boolean;
18
18
  };
19
19
  export type EncryptionSession = {
20
20
  /** Function to retrieve an encryption session using a session ID */
21
- getEncryptionSession: () => Promise<string>;
21
+ getEncryptionSession?: () => Promise<string>;
22
22
  createEncryptedSessionEndpoint?: never;
23
23
  } | {
24
24
  /** API endpoint for creating an encrypted session */
25
- createEncryptedSessionEndpoint: string;
25
+ createEncryptedSessionEndpoint?: string;
26
26
  getEncryptionSession?: never;
27
27
  };
28
- /**
29
- * Configuration for automatic recovery, which requires an encryption session.
30
- */
31
- export type AutomaticRecoveryEmbeddedWalletConfiguration = {
32
- /** Specifies that the recovery method is automatic */
33
- recoveryMethod: RecoveryMethod.AUTOMATIC;
34
- } & EncryptionSession;
35
- export type PasswordRecoveryEmbeddedWalletConfiguration = {
36
- /** Specifies that the recovery method is password-based */
37
- recoveryMethod: RecoveryMethod.PASSWORD;
38
- } & ((EncryptionSession & {
39
- shieldEncryptionKey?: never;
40
- }) | {
41
- /** Required shield encryption key when no encryption session is used */
42
- shieldEncryptionKey: string;
43
- createEncryptedSessionEndpoint?: never;
44
- getEncryptionSession?: never;
45
- });
46
28
  /**
47
29
  * Configuration for automatic recovery.
48
30
  * - An encryption session is required.
@@ -55,7 +37,7 @@ export type PasswordRecoveryEmbeddedWalletConfiguration = {
55
37
  * - `createEncryptedSessionEndpoint` as a string, OR
56
38
  * - `getEncryptionSession.` as a function that returns a promise.
57
39
  */
58
- export type EmbeddedWalletConfiguration = CommonEmbeddedWalletConfiguration & (AutomaticRecoveryEmbeddedWalletConfiguration | PasswordRecoveryEmbeddedWalletConfiguration);
40
+ export type EmbeddedWalletConfiguration = CommonEmbeddedWalletConfiguration & EncryptionSession;
59
41
  /**
60
42
  * These types are fully compatible with WAGMI chain types, in case
61
43
  * we need interop in the future.
@@ -118,10 +100,18 @@ export interface OpenfortProviderProps {
118
100
  * SDK overrides configuration for advanced customization
119
101
  */
120
102
  overrides?: SDKOverrides;
103
+ /**
104
+ * Third party auth configuration for integrating with external auth providers
105
+ */
106
+ thirdPartyAuth?: ThirdPartyAuthConfiguration;
107
+ /**
108
+ * Enable verbose logging for debugging purposes
109
+ */
110
+ verbose?: boolean;
121
111
  }
122
112
  /**
123
113
  * Main provider component that wraps the entire application and provides
124
114
  * Openfort SDK functionality through React context
125
115
  */
126
- export declare const OpenfortProvider: ({ children, publishableKey, customAuth, supportedChains, walletConfig, overrides, }: OpenfortProviderProps) => React.JSX.Element;
116
+ export declare const OpenfortProvider: ({ children, publishableKey, customAuth, supportedChains, walletConfig, overrides, thirdPartyAuth, verbose, }: OpenfortProviderProps) => React.JSX.Element;
127
117
  export {};
@@ -1,3 +1,4 @@
1
+ import { Storage } from '@openfort/openfort-js';
1
2
  declare enum StorageKeys {
2
3
  AUTHENTICATION = "openfort.authentication",
3
4
  SIGNER = "openfort.signer",
@@ -30,5 +31,5 @@ export declare const SecureStorageAdapter: OpenfortStorage;
30
31
  * Creates a type-safe storage adapter that bridges between the Openfort SDK's
31
32
  * expected Storage interface and our React Native implementation
32
33
  */
33
- export declare function createNormalizedStorage(customStorage?: OpenfortStorage): import('@openfort/openfort-js').Storage;
34
+ export declare function createNormalizedStorage(customStorage?: OpenfortStorage): Storage;
34
35
  export {};
@@ -8,7 +8,7 @@
8
8
  * @author Openfort
9
9
  * @version 0.1.0
10
10
  */
11
- export type { AuthPlayerResponse, OpenfortError, RecoveryMethod, Openfort as OpenfortClient, Provider, OpenfortConfiguration, ShieldConfiguration, EmbeddedState, } from '@openfort/openfort-js';
11
+ export { AuthPlayerResponse, OpenfortError, RecoveryMethod, Openfort as OpenfortClient, Provider, OpenfortConfiguration, ShieldConfiguration, EmbeddedState, } from '@openfort/openfort-js';
12
12
  export { OAuthProvider, } from '@openfort/openfort-js';
13
13
  export * from './types';
14
14
  export * from './hooks';
@@ -0,0 +1,12 @@
1
+ import { EmbeddedState } from '@openfort/openfort-js';
2
+ type LogLevel = 'debug' | 'info' | 'warn' | 'error';
3
+ export declare const logger: {
4
+ debug: (message: unknown, ...optionalParams: unknown[]) => void;
5
+ info: (message: unknown, ...optionalParams: unknown[]) => void;
6
+ warn: (message: unknown, ...optionalParams: unknown[]) => void;
7
+ error: (message: unknown, ...optionalParams: unknown[]) => void;
8
+ setVerbose: (verbose: boolean) => void;
9
+ printVerboseWarning: () => void;
10
+ };
11
+ export declare const getEmbeddedStateName: (state: EmbeddedState) => string;
12
+ export type { LogLevel };
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@openfort/react-native",
3
3
  "main": "dist/index.js",
4
- "version": "0.1.3",
4
+ "version": "0.1.5",
5
5
  "license": "MIT",
6
6
  "description": "React Native SDK for Openfort platform integration",
7
7
  "scripts": {
@@ -21,8 +21,10 @@
21
21
  "types": "./dist/types/index.d.ts"
22
22
  }
23
23
  },
24
+ "dependencies": {
25
+ "@openfort/openfort-js": "^0.10.9"
26
+ },
24
27
  "peerDependencies": {
25
- "@openfort/openfort-js": "^0.10.1",
26
28
  "expo-apple-authentication": "*",
27
29
  "expo-crypto": "*",
28
30
  "expo-linking": "*",
@@ -35,7 +37,6 @@
35
37
  },
36
38
  "devDependencies": {
37
39
  "@eslint/js": "^9.17.0",
38
- "@openfort/openfort-js": "^0.10.1",
39
40
  "@types/react": "~18.3.12",
40
41
  "@types/react-test-renderer": "^18.3.0",
41
42
  "buffer": "^5.4.3",