@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.
- package/dist/core/client.js +2 -1
- package/dist/core/provider.js +102 -71
- package/dist/core/storage.js +11 -10
- package/dist/hooks/wallet/useWallets.js +6 -5
- package/dist/index.js +2 -0
- 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 +14 -24
- package/dist/types/core/storage.d.ts +2 -1
- package/dist/types/index.d.ts +1 -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, }) => {
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
64
|
-
|
|
65
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
139
|
+
logger.info('Refreshed user state', currentUser);
|
|
139
140
|
handleUserChange(currentUser);
|
|
140
141
|
return currentUser;
|
|
141
142
|
}
|
|
142
143
|
catch (err) {
|
|
143
|
-
|
|
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
|
-
|
|
191
|
+
logger.debug('Custom token available for authentication sync');
|
|
161
192
|
}
|
|
162
193
|
}
|
|
163
194
|
catch (err) {
|
|
164
|
-
|
|
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 (
|
|
221
|
-
|
|
251
|
+
if (verbose) {
|
|
252
|
+
logger.debug('WebView status changed', status);
|
|
222
253
|
}
|
|
223
254
|
} }))));
|
|
224
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,
|
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
|
+
};
|
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.
|
|
@@ -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):
|
|
34
|
+
export declare function createNormalizedStorage(customStorage?: OpenfortStorage): Storage;
|
|
34
35
|
export {};
|
package/dist/types/index.d.ts
CHANGED
|
@@ -8,7 +8,7 @@
|
|
|
8
8
|
* @author Openfort
|
|
9
9
|
* @version 0.1.0
|
|
10
10
|
*/
|
|
11
|
-
export
|
|
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.
|
|
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",
|