@openfort/react-native 0.1.4 → 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.
- package/dist/core/client.js +2 -1
- package/dist/core/provider.js +100 -68
- package/dist/core/storage.js +11 -10
- package/dist/hooks/wallet/useWallets.js +6 -5
- package/dist/lib/logger.js +62 -0
- package/dist/native/oauth.js +3 -2
- package/dist/native/storage.js +8 -7
- package/dist/native/webview.js +4 -3
- package/dist/types/core/index.d.ts +1 -1
- package/dist/types/core/provider.d.ts +10 -24
- package/dist/types/core/storage.d.ts +2 -1
- package/dist/types/lib/logger.d.ts +12 -0
- package/package.json +4 -3
package/dist/core/client.js
CHANGED
|
@@ -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
|
-
|
|
20
|
+
logger.info('Creating Openfort client with native app ID', nativeAppId);
|
|
20
21
|
// appId,
|
|
21
22
|
// clientId,
|
|
22
23
|
// supportedChains,
|
package/dist/core/provider.js
CHANGED
|
@@ -1,18 +1,54 @@
|
|
|
1
|
-
import React, { useState, useEffect, useCallback, useMemo
|
|
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, thirdPartyAuth, }) => {
|
|
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,7 +57,6 @@ 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
62
|
overrides,
|
|
@@ -32,37 +67,15 @@ export const OpenfortProvider = ({ children, publishableKey, customAuth, support
|
|
|
32
67
|
}, [publishableKey, walletConfig, overrides]);
|
|
33
68
|
// Embedded state
|
|
34
69
|
const [embeddedState, setEmbeddedState] = useState(EmbeddedState.NONE);
|
|
35
|
-
|
|
36
|
-
const pollEmbeddedState = useCallback(async () => {
|
|
37
|
-
if (!client)
|
|
38
|
-
return;
|
|
39
|
-
try {
|
|
40
|
-
const state = await client.embeddedWallet.getEmbeddedState();
|
|
41
|
-
console.log('Current embedded state:', state);
|
|
42
|
-
setEmbeddedState(state);
|
|
43
|
-
}
|
|
44
|
-
catch (error) {
|
|
45
|
-
console.error('Error checking embedded state with Openfort:', error);
|
|
46
|
-
if (pollingRef.current)
|
|
47
|
-
clearInterval(pollingRef.current);
|
|
48
|
-
}
|
|
49
|
-
}, [client]);
|
|
50
|
-
const startPollingEmbeddedState = useCallback(() => {
|
|
51
|
-
if (pollingRef.current)
|
|
52
|
-
return;
|
|
53
|
-
pollingRef.current = setInterval(pollEmbeddedState, 1000);
|
|
54
|
-
}, [pollEmbeddedState]);
|
|
55
|
-
const stopPollingEmbeddedState = useCallback(() => {
|
|
56
|
-
clearInterval(pollingRef.current || undefined);
|
|
57
|
-
pollingRef.current = null;
|
|
58
|
-
}, []);
|
|
70
|
+
// Start polling embedded state: only update and log when state changes
|
|
59
71
|
useEffect(() => {
|
|
60
72
|
if (!client)
|
|
61
73
|
return;
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
};
|
|
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;
|
|
66
79
|
}, [client]);
|
|
67
80
|
// Core state
|
|
68
81
|
const [user, setUser] = useState(null);
|
|
@@ -76,7 +89,15 @@ export const OpenfortProvider = ({ children, publishableKey, customAuth, support
|
|
|
76
89
|
const [recoveryFlowState, setRecoveryFlowState] = useState({ status: 'initial' });
|
|
77
90
|
// User state management
|
|
78
91
|
const handleUserChange = useCallback((newUser) => {
|
|
79
|
-
|
|
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
|
+
}
|
|
80
101
|
setUser(newUser);
|
|
81
102
|
if (newUser) {
|
|
82
103
|
setError(null);
|
|
@@ -92,41 +113,22 @@ export const OpenfortProvider = ({ children, publishableKey, customAuth, support
|
|
|
92
113
|
return await client.getAccessToken();
|
|
93
114
|
}
|
|
94
115
|
catch (err) {
|
|
95
|
-
|
|
116
|
+
logger.debug('Failed to get access token', err);
|
|
96
117
|
return null;
|
|
97
118
|
}
|
|
98
119
|
}, [client]);
|
|
99
|
-
// Initialize client and user
|
|
100
|
-
useEffect(() => {
|
|
101
|
-
console.log('Initializing Openfort client and user state', isUserInitialized);
|
|
102
|
-
if (!isUserInitialized) {
|
|
103
|
-
(async () => {
|
|
104
|
-
console.log('Initializing Openfort client');
|
|
105
|
-
try {
|
|
106
|
-
// Openfort client doesn't need explicit initialization
|
|
107
|
-
setIsClientReady(true);
|
|
108
|
-
}
|
|
109
|
-
catch (err) {
|
|
110
|
-
setError(err instanceof Error ? err : new Error(String(err)));
|
|
111
|
-
}
|
|
112
|
-
try {
|
|
113
|
-
console.log('Refreshing user state on initial load');
|
|
114
|
-
await refreshUserState();
|
|
115
|
-
}
|
|
116
|
-
catch {
|
|
117
|
-
// User not logged in, which is fine
|
|
118
|
-
handleUserChange(null);
|
|
119
|
-
}
|
|
120
|
-
finally {
|
|
121
|
-
setIsUserInitialized(true);
|
|
122
|
-
}
|
|
123
|
-
})();
|
|
124
|
-
}
|
|
125
|
-
}, [client, isUserInitialized, handleUserChange]);
|
|
126
120
|
// Internal refresh function for auth hooks to use
|
|
127
121
|
const refreshUserState = useCallback(async (user) => {
|
|
128
122
|
try {
|
|
129
|
-
|
|
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
|
+
}
|
|
130
132
|
// If user is provided, use it directly instead of fetching from API
|
|
131
133
|
if (user !== undefined) {
|
|
132
134
|
handleUserChange(user);
|
|
@@ -134,16 +136,46 @@ export const OpenfortProvider = ({ children, publishableKey, customAuth, support
|
|
|
134
136
|
}
|
|
135
137
|
// Otherwise, fetch from API
|
|
136
138
|
const currentUser = await client.user.get();
|
|
137
|
-
|
|
139
|
+
logger.info('Refreshed user state', currentUser);
|
|
138
140
|
handleUserChange(currentUser);
|
|
139
141
|
return currentUser;
|
|
140
142
|
}
|
|
141
143
|
catch (err) {
|
|
142
|
-
|
|
144
|
+
logger.warn('Failed to refresh user state', err);
|
|
143
145
|
handleUserChange(null);
|
|
144
146
|
return null;
|
|
145
147
|
}
|
|
146
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]);
|
|
147
179
|
// Custom auth state management
|
|
148
180
|
useEffect(() => {
|
|
149
181
|
if (customAuth?.enabled && isUserInitialized && isClientReady) {
|
|
@@ -156,11 +188,11 @@ export const OpenfortProvider = ({ children, publishableKey, customAuth, support
|
|
|
156
188
|
if (customToken) {
|
|
157
189
|
// Custom auth sync implementation would go here
|
|
158
190
|
// This would typically handle SIWE authentication with the custom token
|
|
159
|
-
|
|
191
|
+
logger.debug('Custom token available for authentication sync');
|
|
160
192
|
}
|
|
161
193
|
}
|
|
162
194
|
catch (err) {
|
|
163
|
-
|
|
195
|
+
logger.error('Custom auth sync failed', err);
|
|
164
196
|
}
|
|
165
197
|
})();
|
|
166
198
|
}
|
|
@@ -216,8 +248,8 @@ export const OpenfortProvider = ({ children, publishableKey, customAuth, support
|
|
|
216
248
|
children,
|
|
217
249
|
client && isReady && WebViewUtils.isSupported() && (React.createElement(EmbeddedWalletWebView, { client: client, isClientReady: isReady, onProxyStatusChange: (status) => {
|
|
218
250
|
// Handle WebView status changes for debugging
|
|
219
|
-
if (
|
|
220
|
-
|
|
251
|
+
if (verbose) {
|
|
252
|
+
logger.debug('WebView status changed', status);
|
|
221
253
|
}
|
|
222
254
|
} }))));
|
|
223
255
|
};
|
package/dist/core/storage.js
CHANGED
|
@@ -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
|
-
|
|
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
|
-
|
|
38
|
+
logger.error('Unexpected result type from SecureStore', result);
|
|
38
39
|
return null;
|
|
39
40
|
}
|
|
40
41
|
catch (error) {
|
|
41
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
104
|
+
logger.error('Failed to save to storage', error);
|
|
104
105
|
});
|
|
105
106
|
},
|
|
106
107
|
remove(key) {
|
|
107
|
-
|
|
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
|
-
|
|
112
|
+
logger.error('Failed to remove from storage', error);
|
|
112
113
|
});
|
|
113
114
|
},
|
|
114
115
|
flush() {
|
|
115
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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,
|
|
@@ -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
|
+
};
|
package/dist/native/oauth.js
CHANGED
|
@@ -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
|
-
|
|
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
|
-
|
|
108
|
+
logger.warn('Failed to parse OAuth URL', error);
|
|
108
109
|
return {};
|
|
109
110
|
}
|
|
110
111
|
}
|
package/dist/native/storage.js
CHANGED
|
@@ -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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
109
|
+
logger.debug(`Key ${fullKey} not found during flush`, error);
|
|
109
110
|
}
|
|
110
111
|
});
|
|
111
112
|
await Promise.all(deletePromises);
|
|
112
|
-
|
|
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
|
-
|
|
121
|
+
logger.warn('Failed to flush secure store', error);
|
|
121
122
|
return {
|
|
122
123
|
event: message.event,
|
|
123
124
|
id: message.id,
|
package/dist/native/webview.js
CHANGED
|
@@ -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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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,
|
|
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 {
|
|
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
|
|
21
|
+
getEncryptionSession?: () => Promise<string>;
|
|
22
22
|
createEncryptedSessionEndpoint?: never;
|
|
23
23
|
} | {
|
|
24
24
|
/** API endpoint for creating an encrypted session */
|
|
25
|
-
createEncryptedSessionEndpoint
|
|
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 &
|
|
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.
|
|
@@ -122,10 +104,14 @@ export interface OpenfortProviderProps {
|
|
|
122
104
|
* Third party auth configuration for integrating with external auth providers
|
|
123
105
|
*/
|
|
124
106
|
thirdPartyAuth?: ThirdPartyAuthConfiguration;
|
|
107
|
+
/**
|
|
108
|
+
* Enable verbose logging for debugging purposes
|
|
109
|
+
*/
|
|
110
|
+
verbose?: boolean;
|
|
125
111
|
}
|
|
126
112
|
/**
|
|
127
113
|
* Main provider component that wraps the entire application and provides
|
|
128
114
|
* Openfort SDK functionality through React context
|
|
129
115
|
*/
|
|
130
|
-
export declare const OpenfortProvider: ({ children, publishableKey, customAuth, supportedChains, walletConfig, overrides, thirdPartyAuth, }: OpenfortProviderProps) => React.JSX.Element;
|
|
116
|
+
export declare const OpenfortProvider: ({ children, publishableKey, customAuth, supportedChains, walletConfig, overrides, thirdPartyAuth, verbose, }: OpenfortProviderProps) => React.JSX.Element;
|
|
131
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):
|
|
34
|
+
export declare function createNormalizedStorage(customStorage?: OpenfortStorage): Storage;
|
|
34
35
|
export {};
|
|
@@ -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.
|
|
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.4",
|
|
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.4",
|
|
39
40
|
"@types/react": "~18.3.12",
|
|
40
41
|
"@types/react-test-renderer": "^18.3.0",
|
|
41
42
|
"buffer": "^5.4.3",
|