@0xkey-io/react-native-wallet-kit 0.1.0
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/LICENSE +201 -0
- package/README.md +93 -0
- package/dist/hooks/use-0xkey.d.ts +3 -0
- package/dist/hooks/use-0xkey.d.ts.map +1 -0
- package/dist/hooks/use-0xkey.js +15 -0
- package/dist/hooks/use-0xkey.js.map +1 -0
- package/dist/hooks/use-0xkey.mjs +13 -0
- package/dist/hooks/use-0xkey.mjs.map +1 -0
- package/dist/index.d.ts +21 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +55 -0
- package/dist/index.js.map +1 -0
- package/dist/index.mjs +6 -0
- package/dist/index.mjs.map +1 -0
- package/dist/providers/Types.d.ts +275 -0
- package/dist/providers/Types.d.ts.map +1 -0
- package/dist/providers/Types.js +9 -0
- package/dist/providers/Types.js.map +1 -0
- package/dist/providers/Types.mjs +7 -0
- package/dist/providers/Types.mjs.map +1 -0
- package/dist/providers/ZeroXKeyProvider.d.ts +39 -0
- package/dist/providers/ZeroXKeyProvider.d.ts.map +1 -0
- package/dist/providers/ZeroXKeyProvider.js +1846 -0
- package/dist/providers/ZeroXKeyProvider.js.map +1 -0
- package/dist/providers/ZeroXKeyProvider.mjs +1844 -0
- package/dist/providers/ZeroXKeyProvider.mjs.map +1 -0
- package/dist/providers/index.d.ts +4 -0
- package/dist/providers/index.d.ts.map +1 -0
- package/dist/tests/oauth-test.d.ts +2 -0
- package/dist/tests/oauth-test.d.ts.map +1 -0
- package/dist/typedoc-entry/index.d.ts +5 -0
- package/dist/typedoc-entry/index.d.ts.map +1 -0
- package/dist/types/base.d.ts +137 -0
- package/dist/types/base.d.ts.map +1 -0
- package/dist/types/base.js +48 -0
- package/dist/types/base.js.map +1 -0
- package/dist/types/base.mjs +48 -0
- package/dist/types/base.mjs.map +1 -0
- package/dist/types/method-types.d.ts +102 -0
- package/dist/types/method-types.d.ts.map +1 -0
- package/dist/utils/index.d.ts +4 -0
- package/dist/utils/index.d.ts.map +1 -0
- package/dist/utils/oauth.d.ts +240 -0
- package/dist/utils/oauth.d.ts.map +1 -0
- package/dist/utils/oauth.js +340 -0
- package/dist/utils/oauth.js.map +1 -0
- package/dist/utils/oauth.mjs +319 -0
- package/dist/utils/oauth.mjs.map +1 -0
- package/dist/utils/timers.d.ts +73 -0
- package/dist/utils/timers.d.ts.map +1 -0
- package/dist/utils/timers.js +132 -0
- package/dist/utils/timers.js.map +1 -0
- package/dist/utils/timers.mjs +122 -0
- package/dist/utils/timers.mjs.map +1 -0
- package/dist/utils/utils.d.ts +27 -0
- package/dist/utils/utils.d.ts.map +1 -0
- package/dist/utils/utils.js +37 -0
- package/dist/utils/utils.js.map +1 -0
- package/dist/utils/utils.mjs +33 -0
- package/dist/utils/utils.mjs.map +1 -0
- package/package.json +80 -0
|
@@ -0,0 +1,1844 @@
|
|
|
1
|
+
import { jsx } from 'react/jsx-runtime';
|
|
2
|
+
import { withZeroXKeyErrorHandling, isValidSession, SESSION_WARNING_THRESHOLD_MS } from '../utils/utils.mjs';
|
|
3
|
+
import { clearKey, setTimeoutInMap, setCappedTimeoutInMap, clearKeys, clearAll } from '../utils/timers.mjs';
|
|
4
|
+
import { generateChallengePair, storePKCEVerifier, buildOAuthUrl, parseInAppBrowserResult, handlePKCEFlow, completeOAuthFlow, exchangeCodeForToken, ZEROXKEY_OAUTH_REDIRECT_URL } from '../utils/oauth.mjs';
|
|
5
|
+
import { DEFAULT_SESSION_EXPIRATION_IN_SECONDS, OtpType, getAuthProxyConfig, ZeroXKeyClient } from '@0xkey-io/core';
|
|
6
|
+
import { useState, useRef, useCallback, useEffect } from 'react';
|
|
7
|
+
import { Platform } from 'react-native';
|
|
8
|
+
import DeviceInfo from 'react-native-device-info';
|
|
9
|
+
import { InAppBrowser } from 'react-native-inappbrowser-reborn';
|
|
10
|
+
import { sha256 } from '@noble/hashes/sha2';
|
|
11
|
+
import { bytesToHex } from '@noble/hashes/utils';
|
|
12
|
+
import { ZeroXKeyError, ZeroXKeyErrorCodes, AuthAction, OAuthProviders, ZeroXKeyNetworkError } from '@0xkey-io/sdk-types';
|
|
13
|
+
import { AuthState, AuthMethod, ClientState } from '../types/base.mjs';
|
|
14
|
+
import { ClientContext } from './Types.mjs';
|
|
15
|
+
import { generateP256KeyPair, decryptExportBundle, encryptWalletToBundle, encryptPrivateKeyToBundle } from '@0xkey-io/crypto';
|
|
16
|
+
|
|
17
|
+
/**
|
|
18
|
+
* Provides ZeroXKey client authentication, session management, wallet operations, and user profile management
|
|
19
|
+
* for the React Native Wallet Kit SDK. This context provider encapsulates all core authentication flows (Passkey, OTP, OAuth),
|
|
20
|
+
* session lifecycle (creation, expiration, refresh), wallet import/export, and user profile updates (email, phone, name).
|
|
21
|
+
*
|
|
22
|
+
* The provider automatically initializes the ZeroXKey client, fetches configuration (including proxy auth config if needed),
|
|
23
|
+
* and synchronizes session and authentication state. It exposes a comprehensive set of methods for authentication flows,
|
|
24
|
+
* wallet management, and user profile operations, as well as UI handlers for modal-driven flows.
|
|
25
|
+
*
|
|
26
|
+
* Features:
|
|
27
|
+
* - Passkey, OTP (Email/SMS), and OAuth (Google, Apple, Facebook, Discord, X) authentication and sign-up flows.
|
|
28
|
+
* - React Native-specific OAuth: opens an in-app browser (Custom Tabs/Safari View Controller) and deep-links back via the configured app scheme.
|
|
29
|
+
* - Session management: creation, expiration scheduling, refresh, and clearing.
|
|
30
|
+
* - Wallet management: fetch, import, export, account management.
|
|
31
|
+
* - User profile management: email, phone, name, OAuth provider, and passkey linking/removal.
|
|
32
|
+
* - Error handling and callback integration for custom error and event responses.
|
|
33
|
+
*
|
|
34
|
+
* Usage:
|
|
35
|
+
* Wrap your application with `ZeroXKeyProvider` to enable authentication and wallet features via context.
|
|
36
|
+
*
|
|
37
|
+
* @param config - The ZeroXKey provider configuration object.
|
|
38
|
+
* @param children - React children to be rendered within the provider.
|
|
39
|
+
* @param callbacks - Optional callbacks for error handling and session events.
|
|
40
|
+
*
|
|
41
|
+
* @returns A React context provider exposing authentication, wallet, and user management methods and state.
|
|
42
|
+
*/
|
|
43
|
+
const ZeroXKeyProvider = ({ config, children, callbacks, }) => {
|
|
44
|
+
const [client, setClient] = useState(undefined);
|
|
45
|
+
const [session, setSession] = useState(undefined);
|
|
46
|
+
const [masterConfig, setMasterConfig] = useState(undefined);
|
|
47
|
+
const [wallets, setWallets] = useState([]);
|
|
48
|
+
const [user, setUser] = useState(undefined);
|
|
49
|
+
const [clientState, setClientState] = useState();
|
|
50
|
+
const [authState, setAuthState] = useState(AuthState.Unauthenticated);
|
|
51
|
+
const expiryTimeoutsRef = useRef({});
|
|
52
|
+
const proxyAuthConfigRef = useRef(null);
|
|
53
|
+
const [allSessions, setAllSessions] = useState(undefined);
|
|
54
|
+
// if there is no authProxyConfigId or if autoFetchWalletKitConfig is specifically
|
|
55
|
+
// set to false, we don't need to fetch the config
|
|
56
|
+
const shouldFetchWalletKitConfig = config.authProxyConfigId != null &&
|
|
57
|
+
config.authProxyConfigId !== "" &&
|
|
58
|
+
config.autoFetchWalletKitConfig !== false;
|
|
59
|
+
const buildConfig = (proxyAuthConfig) => {
|
|
60
|
+
// Juggle the local overrides with the values set in the dashboard (proxyAuthConfig).
|
|
61
|
+
// Normalize potentially empty string values coming from the app-level config
|
|
62
|
+
const sanitizedAuthProxyUrl = config.authProxyUrl && config.authProxyUrl.trim()
|
|
63
|
+
? config.authProxyUrl
|
|
64
|
+
: undefined;
|
|
65
|
+
// Resolve OTP enablement
|
|
66
|
+
const emailOtpEnabled = config.auth?.otp?.email ??
|
|
67
|
+
proxyAuthConfig?.enabledProviders.includes("email") ??
|
|
68
|
+
false;
|
|
69
|
+
const smsOtpEnabled = config.auth?.otp?.sms ??
|
|
70
|
+
proxyAuthConfig?.enabledProviders.includes("sms") ??
|
|
71
|
+
false;
|
|
72
|
+
// Resolve shared redirect; do NOT attach scheme here. We'll attach in handler on demand.
|
|
73
|
+
const appScheme = config.auth?.oauth?.appScheme ?? undefined;
|
|
74
|
+
const redirectUrl = config.auth?.oauth?.redirectUri ??
|
|
75
|
+
proxyAuthConfig?.oauthRedirectUrl ??
|
|
76
|
+
ZEROXKEY_OAUTH_REDIRECT_URL;
|
|
77
|
+
// Warn if they are trying to set auth proxy only settings directly
|
|
78
|
+
if (proxyAuthConfig) {
|
|
79
|
+
if (config.auth?.sessionExpirationSeconds) {
|
|
80
|
+
console.warn("ZeroXKey SDK warning. You have set sessionExpirationSeconds directly in the ZeroXKeyProvider. This setting will be ignored because you are using an auth proxy. Please configure session expiration in the ZeroXKey dashboard.");
|
|
81
|
+
}
|
|
82
|
+
if (config.auth?.otp?.alphanumeric !== undefined &&
|
|
83
|
+
shouldFetchWalletKitConfig) {
|
|
84
|
+
console.warn("ZeroXKey SDK warning. You have set otpAlphanumeric directly in the ZeroXKeyProvider. This setting will be ignored because you are using an auth proxy. Please configure OTP settings in the ZeroXKey dashboard.");
|
|
85
|
+
}
|
|
86
|
+
if (config.auth?.otp?.length && shouldFetchWalletKitConfig) {
|
|
87
|
+
console.warn("ZeroXKey SDK warning. You have set otpLength directly in the ZeroXKeyProvider. This setting will be ignored because you are using an auth proxy. Please configure OTP settings in the ZeroXKey dashboard.");
|
|
88
|
+
}
|
|
89
|
+
}
|
|
90
|
+
// These are settings that can only be set via the auth proxy config
|
|
91
|
+
const authProxyPrioSettings = {
|
|
92
|
+
sessionExpirationSeconds: proxyAuthConfig?.sessionExpirationSeconds ??
|
|
93
|
+
config.auth?.sessionExpirationSeconds,
|
|
94
|
+
otp: {
|
|
95
|
+
alphanumeric: proxyAuthConfig?.otpAlphanumeric ??
|
|
96
|
+
config.auth?.otp?.alphanumeric ??
|
|
97
|
+
true,
|
|
98
|
+
length: proxyAuthConfig?.otpLength ?? config.auth?.otp?.length ?? "6",
|
|
99
|
+
},
|
|
100
|
+
};
|
|
101
|
+
return {
|
|
102
|
+
...config,
|
|
103
|
+
// Ensure empty strings are not forwarded as URLs
|
|
104
|
+
authProxyUrl: sanitizedAuthProxyUrl,
|
|
105
|
+
// Overrides:
|
|
106
|
+
auth: {
|
|
107
|
+
...config.auth,
|
|
108
|
+
// Proxy-controlled settings
|
|
109
|
+
sessionExpirationSeconds: authProxyPrioSettings.sessionExpirationSeconds,
|
|
110
|
+
otp: {
|
|
111
|
+
...config.auth?.otp,
|
|
112
|
+
// Enablement flags
|
|
113
|
+
email: emailOtpEnabled,
|
|
114
|
+
sms: smsOtpEnabled,
|
|
115
|
+
// Proxy-only settings
|
|
116
|
+
alphanumeric: authProxyPrioSettings.otp.alphanumeric,
|
|
117
|
+
length: authProxyPrioSettings.otp.length,
|
|
118
|
+
},
|
|
119
|
+
// OAuth shared settings
|
|
120
|
+
oauth: {
|
|
121
|
+
...config.auth?.oauth,
|
|
122
|
+
...(appScheme && { appScheme }),
|
|
123
|
+
redirectUri: redirectUrl,
|
|
124
|
+
},
|
|
125
|
+
autoRefreshSession: config.auth?.autoRefreshSession ?? true,
|
|
126
|
+
},
|
|
127
|
+
autoRefreshManagedState: config.autoRefreshManagedState ?? true,
|
|
128
|
+
};
|
|
129
|
+
};
|
|
130
|
+
const getOauthProviderSettings = (provider) => {
|
|
131
|
+
const oauth = masterConfig?.auth?.oauth;
|
|
132
|
+
const providerConfig = oauth ? oauth[provider] : undefined;
|
|
133
|
+
const providerObjectConfig = providerConfig && typeof providerConfig === "object"
|
|
134
|
+
? providerConfig
|
|
135
|
+
: undefined;
|
|
136
|
+
const proxyClientIds = proxyAuthConfigRef.current?.oauthClientIds;
|
|
137
|
+
const clientId = providerObjectConfig?.clientId ??
|
|
138
|
+
(proxyClientIds ? proxyClientIds[provider] : undefined);
|
|
139
|
+
const appScheme = oauth?.appScheme;
|
|
140
|
+
// For Discord and X, default to scheme-based deep link if not explicitly provided.
|
|
141
|
+
const redirectUri = providerObjectConfig?.redirectUri ??
|
|
142
|
+
((provider === "discord" || provider === "x") && appScheme
|
|
143
|
+
? `${appScheme}://`
|
|
144
|
+
: (oauth?.redirectUri ??
|
|
145
|
+
proxyAuthConfigRef.current?.oauthRedirectUrl ??
|
|
146
|
+
ZEROXKEY_OAUTH_REDIRECT_URL));
|
|
147
|
+
return { clientId, redirectUri, appScheme };
|
|
148
|
+
};
|
|
149
|
+
/**
|
|
150
|
+
* Initializes the ZeroXKey client with the provided configuration.
|
|
151
|
+
* This function sets up the client, fetches the proxy auth config if needed,
|
|
152
|
+
* and prepares the client for use in authentication and wallet operations.
|
|
153
|
+
*
|
|
154
|
+
* @internal
|
|
155
|
+
*/
|
|
156
|
+
const initializeClient = async () => {
|
|
157
|
+
if (!masterConfig || client || clientState == ClientState.Loading)
|
|
158
|
+
return;
|
|
159
|
+
try {
|
|
160
|
+
setClientState(ClientState.Loading);
|
|
161
|
+
const zeroXKeyClient = new ZeroXKeyClient({
|
|
162
|
+
apiBaseUrl: masterConfig.apiBaseUrl,
|
|
163
|
+
authProxyUrl: masterConfig.authProxyUrl,
|
|
164
|
+
authProxyConfigId: masterConfig.authProxyConfigId,
|
|
165
|
+
organizationId: masterConfig.organizationId,
|
|
166
|
+
defaultStamperType: masterConfig.defaultStamperType,
|
|
167
|
+
// Define passkey and wallet config here. If we don't pass it into the client, Mr. Client will assume that we don't want to use passkeys/wallets and not create the stamper!
|
|
168
|
+
passkeyConfig: {
|
|
169
|
+
rpId: masterConfig.passkeyConfig?.rpId,
|
|
170
|
+
timeout: masterConfig.passkeyConfig?.timeout || 60000, // 60 seconds
|
|
171
|
+
userVerification: masterConfig.passkeyConfig?.userVerification || "preferred",
|
|
172
|
+
allowCredentials: masterConfig.passkeyConfig?.allowCredentials || [],
|
|
173
|
+
},
|
|
174
|
+
});
|
|
175
|
+
await zeroXKeyClient.init();
|
|
176
|
+
setClient(zeroXKeyClient);
|
|
177
|
+
// Don't set clientState to ready until we fetch the proxy auth config (See other fetchProxyAuthConfig useEffect)
|
|
178
|
+
}
|
|
179
|
+
catch (error) {
|
|
180
|
+
setClientState(ClientState.Error);
|
|
181
|
+
if (error instanceof ZeroXKeyError ||
|
|
182
|
+
error instanceof ZeroXKeyNetworkError) {
|
|
183
|
+
callbacks?.onError?.(error);
|
|
184
|
+
}
|
|
185
|
+
else {
|
|
186
|
+
callbacks?.onError?.(new ZeroXKeyError(`Failed to initialize ZeroXKey client`, ZeroXKeyErrorCodes.INITIALIZE_CLIENT_ERROR, error));
|
|
187
|
+
}
|
|
188
|
+
}
|
|
189
|
+
};
|
|
190
|
+
/**
|
|
191
|
+
* @internal
|
|
192
|
+
* Schedules a session expiration and warning timer for the given session key.
|
|
193
|
+
*
|
|
194
|
+
* - Sets up two timers: one for warning before expiry and one for actual expiry.
|
|
195
|
+
* - Uses capped timeouts under the hood so delays > 24.8 days are safe (see utils/timers.ts).
|
|
196
|
+
*
|
|
197
|
+
* @param params.sessionKey - The key of the session to schedule expiration for.
|
|
198
|
+
* @param params.expiry - The expiration time in seconds since epoch.
|
|
199
|
+
* @throws {ZeroXKeyError} If an error occurs while scheduling the session expiration.
|
|
200
|
+
*/
|
|
201
|
+
async function scheduleSessionExpiration(params) {
|
|
202
|
+
const { sessionKey, expiry } = params;
|
|
203
|
+
try {
|
|
204
|
+
const warnKey = `${sessionKey}-warning`;
|
|
205
|
+
// Replace any prior timers for this session
|
|
206
|
+
clearKey(expiryTimeoutsRef.current, sessionKey);
|
|
207
|
+
clearKey(expiryTimeoutsRef.current, warnKey);
|
|
208
|
+
const now = Date.now();
|
|
209
|
+
const expiryMs = expiry * 1000;
|
|
210
|
+
const timeUntilExpiry = expiryMs - now;
|
|
211
|
+
const beforeExpiry = async () => {
|
|
212
|
+
const activeSession = await getSession();
|
|
213
|
+
if (!activeSession && expiryTimeoutsRef.current[warnKey]) {
|
|
214
|
+
// Keep nudging until session materializes (short 10s timer is fine)
|
|
215
|
+
setTimeoutInMap(expiryTimeoutsRef.current, warnKey, beforeExpiry, 10_000);
|
|
216
|
+
return;
|
|
217
|
+
}
|
|
218
|
+
const session = await getSession({ sessionKey });
|
|
219
|
+
if (!session)
|
|
220
|
+
return;
|
|
221
|
+
callbacks?.beforeSessionExpiry?.({ sessionKey });
|
|
222
|
+
if (masterConfig?.auth?.autoRefreshSession) {
|
|
223
|
+
await refreshSession({
|
|
224
|
+
expirationSeconds: session.expirationSeconds,
|
|
225
|
+
sessionKey,
|
|
226
|
+
});
|
|
227
|
+
}
|
|
228
|
+
};
|
|
229
|
+
const expireSession = async () => {
|
|
230
|
+
const expiredSession = await getSession({ sessionKey });
|
|
231
|
+
if (!expiredSession)
|
|
232
|
+
return;
|
|
233
|
+
callbacks?.onSessionExpired?.({ sessionKey });
|
|
234
|
+
if ((await getActiveSessionKey()) === sessionKey) {
|
|
235
|
+
setSession(undefined);
|
|
236
|
+
}
|
|
237
|
+
setAllSessions((prev) => {
|
|
238
|
+
if (!prev)
|
|
239
|
+
return prev;
|
|
240
|
+
const next = { ...prev };
|
|
241
|
+
delete next[sessionKey];
|
|
242
|
+
return next;
|
|
243
|
+
});
|
|
244
|
+
await clearSession({ sessionKey });
|
|
245
|
+
// Remove timers for this session
|
|
246
|
+
clearKey(expiryTimeoutsRef.current, sessionKey);
|
|
247
|
+
clearKey(expiryTimeoutsRef.current, warnKey);
|
|
248
|
+
await logout();
|
|
249
|
+
};
|
|
250
|
+
// Already expired → expire immediately
|
|
251
|
+
if (timeUntilExpiry <= 0) {
|
|
252
|
+
await expireSession();
|
|
253
|
+
return;
|
|
254
|
+
}
|
|
255
|
+
// Warning timer (if threshold is in the future)
|
|
256
|
+
const warnAt = expiryMs - SESSION_WARNING_THRESHOLD_MS;
|
|
257
|
+
if (warnAt <= now) {
|
|
258
|
+
void beforeExpiry(); // fire-and-forget is fine
|
|
259
|
+
}
|
|
260
|
+
else {
|
|
261
|
+
setCappedTimeoutInMap(expiryTimeoutsRef.current, warnKey, beforeExpiry, warnAt - now);
|
|
262
|
+
}
|
|
263
|
+
// Actual expiry timer (safe for long delays)
|
|
264
|
+
setCappedTimeoutInMap(expiryTimeoutsRef.current, sessionKey, expireSession, timeUntilExpiry);
|
|
265
|
+
}
|
|
266
|
+
catch (error) {
|
|
267
|
+
if (error instanceof ZeroXKeyError ||
|
|
268
|
+
error instanceof ZeroXKeyNetworkError) {
|
|
269
|
+
callbacks?.onError?.(error);
|
|
270
|
+
}
|
|
271
|
+
else {
|
|
272
|
+
callbacks?.onError?.(new ZeroXKeyError(`Failed to schedule session expiration for ${sessionKey}`, ZeroXKeyErrorCodes.SCHEDULE_SESSION_EXPIRY_ERROR, error));
|
|
273
|
+
}
|
|
274
|
+
}
|
|
275
|
+
}
|
|
276
|
+
/**
|
|
277
|
+
* Clears all scheduled session timers (warning + expiry).
|
|
278
|
+
*
|
|
279
|
+
* - Removes all active timers managed by this client.
|
|
280
|
+
* - Useful on re-init or logout to avoid stale timers.
|
|
281
|
+
*
|
|
282
|
+
* @throws {ZeroXKeyError} If an error occurs while clearing the timers.
|
|
283
|
+
*/
|
|
284
|
+
function clearSessionTimeouts(sessionKeys) {
|
|
285
|
+
try {
|
|
286
|
+
if (sessionKeys) {
|
|
287
|
+
clearKeys(expiryTimeoutsRef.current, sessionKeys);
|
|
288
|
+
}
|
|
289
|
+
else {
|
|
290
|
+
clearAll(expiryTimeoutsRef.current); // clears & deletes everything
|
|
291
|
+
}
|
|
292
|
+
}
|
|
293
|
+
catch (error) {
|
|
294
|
+
if (error instanceof ZeroXKeyError ||
|
|
295
|
+
error instanceof ZeroXKeyNetworkError) {
|
|
296
|
+
callbacks?.onError?.(error);
|
|
297
|
+
}
|
|
298
|
+
else {
|
|
299
|
+
callbacks?.onError?.(new ZeroXKeyError("Failed to clear session timeouts", ZeroXKeyErrorCodes.CLEAR_SESSION_TIMEOUTS_ERROR, error));
|
|
300
|
+
}
|
|
301
|
+
}
|
|
302
|
+
}
|
|
303
|
+
/**
|
|
304
|
+
* Initializes the user sessions by fetching all active sessions and setting up their state.
|
|
305
|
+
* @internal
|
|
306
|
+
*/
|
|
307
|
+
const initializeSessions = async () => {
|
|
308
|
+
setSession(undefined);
|
|
309
|
+
setAllSessions(undefined);
|
|
310
|
+
try {
|
|
311
|
+
const allLocalStorageSessions = await getAllSessions();
|
|
312
|
+
if (!allLocalStorageSessions)
|
|
313
|
+
return;
|
|
314
|
+
await Promise.all(Object.keys(allLocalStorageSessions).map(async (sessionKey) => {
|
|
315
|
+
const s = allLocalStorageSessions?.[sessionKey];
|
|
316
|
+
if (!isValidSession(s)) {
|
|
317
|
+
await clearSession({ sessionKey });
|
|
318
|
+
if (sessionKey === (await getActiveSessionKey())) {
|
|
319
|
+
setSession(undefined);
|
|
320
|
+
}
|
|
321
|
+
delete allLocalStorageSessions[sessionKey];
|
|
322
|
+
return;
|
|
323
|
+
}
|
|
324
|
+
await scheduleSessionExpiration({
|
|
325
|
+
sessionKey,
|
|
326
|
+
expiry: s.expiry,
|
|
327
|
+
});
|
|
328
|
+
}));
|
|
329
|
+
setAllSessions(allLocalStorageSessions || undefined);
|
|
330
|
+
const activeSessionKey = await client?.getActiveSessionKey();
|
|
331
|
+
if (activeSessionKey) {
|
|
332
|
+
if (!allLocalStorageSessions[activeSessionKey]) {
|
|
333
|
+
return;
|
|
334
|
+
}
|
|
335
|
+
setSession(allLocalStorageSessions[activeSessionKey]);
|
|
336
|
+
await maybeRefreshUser();
|
|
337
|
+
await maybeRefreshWallets();
|
|
338
|
+
return;
|
|
339
|
+
}
|
|
340
|
+
}
|
|
341
|
+
catch (error) {
|
|
342
|
+
if (error instanceof ZeroXKeyError ||
|
|
343
|
+
error instanceof ZeroXKeyNetworkError) {
|
|
344
|
+
callbacks?.onError?.(error);
|
|
345
|
+
}
|
|
346
|
+
else {
|
|
347
|
+
callbacks?.onError?.(new ZeroXKeyError(`Failed to initialize sessions`, ZeroXKeyErrorCodes.INITIALIZE_SESSION_ERROR, error));
|
|
348
|
+
}
|
|
349
|
+
}
|
|
350
|
+
};
|
|
351
|
+
/**
|
|
352
|
+
* @internal
|
|
353
|
+
* Handles the post-authentication flow.
|
|
354
|
+
*
|
|
355
|
+
* - This function is called after a successful authentication (login or sign-up) via any supported method (Passkey, Wallet, OTP, OAuth).
|
|
356
|
+
* - It fetches the active session and all sessions, updates the session state, and schedules session expiration and warning timeouts.
|
|
357
|
+
* - It also refreshes the user's wallets and profile information to ensure the provider state is up to date.
|
|
358
|
+
* - This function is used internally after all authentication flows to synchronize state and trigger any necessary callbacks.
|
|
359
|
+
*
|
|
360
|
+
* @returns A void promise.
|
|
361
|
+
* @throws {ZeroXKeyError} If the client is not initialized or if there is an error during the process.
|
|
362
|
+
*/
|
|
363
|
+
const handlePostAuth = async (params) => {
|
|
364
|
+
const { method, action, identifier } = params;
|
|
365
|
+
try {
|
|
366
|
+
const sessionKey = await getActiveSessionKey();
|
|
367
|
+
const session = await getSession({
|
|
368
|
+
...(sessionKey && { sessionKey }),
|
|
369
|
+
});
|
|
370
|
+
if (session && sessionKey)
|
|
371
|
+
await scheduleSessionExpiration({
|
|
372
|
+
sessionKey,
|
|
373
|
+
expiry: session.expiry,
|
|
374
|
+
});
|
|
375
|
+
const allSessions = await client.getAllSessions();
|
|
376
|
+
setSession(session);
|
|
377
|
+
setAllSessions(allSessions);
|
|
378
|
+
await maybeRefreshWallets();
|
|
379
|
+
await maybeRefreshUser();
|
|
380
|
+
callbacks?.onAuthenticationSuccess?.({
|
|
381
|
+
session,
|
|
382
|
+
method,
|
|
383
|
+
action,
|
|
384
|
+
identifier,
|
|
385
|
+
});
|
|
386
|
+
}
|
|
387
|
+
catch (error) {
|
|
388
|
+
if (error instanceof ZeroXKeyError ||
|
|
389
|
+
error instanceof ZeroXKeyNetworkError) {
|
|
390
|
+
callbacks?.onError?.(error);
|
|
391
|
+
}
|
|
392
|
+
else {
|
|
393
|
+
callbacks?.onError?.(new ZeroXKeyError(`Failed to handle post-authentication`, ZeroXKeyErrorCodes.HANDLE_POST_AUTH_ERROR, error));
|
|
394
|
+
}
|
|
395
|
+
}
|
|
396
|
+
};
|
|
397
|
+
/**
|
|
398
|
+
* @internal
|
|
399
|
+
* Handles the post-logout flow.
|
|
400
|
+
*
|
|
401
|
+
* - This function is called after a successful logout or session clear.
|
|
402
|
+
* - It clears all scheduled session expiration and warning timeouts associated to the session key to prevent memory leaks.
|
|
403
|
+
* - It resets the session state, removes user data from memory, the logged out session from all sessions state, and clears the wallets list.
|
|
404
|
+
* - This ensures that all sensitive information is removed from the provider state after logout.
|
|
405
|
+
* - Called internally after logout or when all sessions are cleared.
|
|
406
|
+
*
|
|
407
|
+
* @returns void
|
|
408
|
+
* @throws {ZeroXKeyError} If there is an error during the post-logout process.
|
|
409
|
+
*/
|
|
410
|
+
const handlePostLogout = (sessionKey) => {
|
|
411
|
+
try {
|
|
412
|
+
clearSessionTimeouts(sessionKey ? [sessionKey, `${sessionKey}-warning`] : undefined);
|
|
413
|
+
setAllSessions((prev) => {
|
|
414
|
+
if (!prev)
|
|
415
|
+
return prev;
|
|
416
|
+
if (sessionKey) {
|
|
417
|
+
const next = { ...prev };
|
|
418
|
+
delete next[sessionKey];
|
|
419
|
+
return next;
|
|
420
|
+
}
|
|
421
|
+
return {};
|
|
422
|
+
});
|
|
423
|
+
setSession(undefined);
|
|
424
|
+
setUser(undefined);
|
|
425
|
+
setWallets([]);
|
|
426
|
+
}
|
|
427
|
+
catch (error) {
|
|
428
|
+
callbacks?.onError?.(new ZeroXKeyError(`Failed to initialize sessions`, ZeroXKeyErrorCodes.HANDLE_POST_LOGOUT_ERROR, error));
|
|
429
|
+
}
|
|
430
|
+
};
|
|
431
|
+
const createPasskey = useCallback(async (params) => {
|
|
432
|
+
if (!client) {
|
|
433
|
+
throw new ZeroXKeyError("Client is not initialized.", ZeroXKeyErrorCodes.CLIENT_NOT_INITIALIZED);
|
|
434
|
+
}
|
|
435
|
+
return withZeroXKeyErrorHandling(() => client.createPasskey({ ...params }), () => logout(), callbacks, "Failed to create passkey");
|
|
436
|
+
}, [client, callbacks]);
|
|
437
|
+
const createHttpClient = useCallback((params) => {
|
|
438
|
+
if (!client) {
|
|
439
|
+
throw new ZeroXKeyError("Client is not initialized.", ZeroXKeyErrorCodes.CLIENT_NOT_INITIALIZED);
|
|
440
|
+
}
|
|
441
|
+
return client.createHttpClient(params);
|
|
442
|
+
}, [client]);
|
|
443
|
+
const logout = useCallback(async (params) => {
|
|
444
|
+
if (!client) {
|
|
445
|
+
throw new ZeroXKeyError("Client is not initialized.", ZeroXKeyErrorCodes.CLIENT_NOT_INITIALIZED);
|
|
446
|
+
}
|
|
447
|
+
await withZeroXKeyErrorHandling(async () => {
|
|
448
|
+
// If no sessionKey is provided, we try to get the active one.
|
|
449
|
+
let sessionKey = params?.sessionKey;
|
|
450
|
+
if (!sessionKey)
|
|
451
|
+
sessionKey = await getActiveSessionKey();
|
|
452
|
+
await client.logout(params);
|
|
453
|
+
// We only handle post logout if the sessionKey is defined since that means we actually logged out of a session.
|
|
454
|
+
if (sessionKey)
|
|
455
|
+
handlePostLogout(sessionKey);
|
|
456
|
+
}, () => logout(), callbacks, "Failed to logout");
|
|
457
|
+
return;
|
|
458
|
+
}, [client, callbacks]);
|
|
459
|
+
const loginWithPasskey = useCallback(async (params) => {
|
|
460
|
+
if (!client) {
|
|
461
|
+
throw new ZeroXKeyError("Client is not initialized.", ZeroXKeyErrorCodes.CLIENT_NOT_INITIALIZED);
|
|
462
|
+
}
|
|
463
|
+
const expirationSeconds = params?.expirationSeconds ??
|
|
464
|
+
masterConfig?.auth?.sessionExpirationSeconds ??
|
|
465
|
+
DEFAULT_SESSION_EXPIRATION_IN_SECONDS;
|
|
466
|
+
const res = await withZeroXKeyErrorHandling(() => client.loginWithPasskey({ ...params, expirationSeconds }), () => logout(), callbacks, "Failed to login with passkey");
|
|
467
|
+
if (res) {
|
|
468
|
+
await handlePostAuth({
|
|
469
|
+
method: AuthMethod.Passkey,
|
|
470
|
+
action: AuthAction.LOGIN,
|
|
471
|
+
identifier: res.credentialId,
|
|
472
|
+
});
|
|
473
|
+
}
|
|
474
|
+
return res;
|
|
475
|
+
}, [client, callbacks]);
|
|
476
|
+
const signUpWithPasskey = useCallback(async (params) => {
|
|
477
|
+
if (!client) {
|
|
478
|
+
throw new ZeroXKeyError("Client is not initialized.", ZeroXKeyErrorCodes.CLIENT_NOT_INITIALIZED);
|
|
479
|
+
}
|
|
480
|
+
if (!masterConfig) {
|
|
481
|
+
throw new ZeroXKeyError("Config is not ready yet!", ZeroXKeyErrorCodes.INVALID_CONFIGURATION);
|
|
482
|
+
}
|
|
483
|
+
// If createSubOrgParams is not provided, use the default from masterConfig
|
|
484
|
+
let createSubOrgParams = params?.createSubOrgParams ??
|
|
485
|
+
masterConfig.auth?.createSuborgParams?.passkeyAuth;
|
|
486
|
+
params =
|
|
487
|
+
createSubOrgParams !== undefined
|
|
488
|
+
? { ...params, createSubOrgParams }
|
|
489
|
+
: { ...params };
|
|
490
|
+
const expirationSeconds = params.expirationSeconds ??
|
|
491
|
+
masterConfig?.auth?.sessionExpirationSeconds ??
|
|
492
|
+
DEFAULT_SESSION_EXPIRATION_IN_SECONDS;
|
|
493
|
+
const websiteName = Platform.OS === "web" && typeof window !== "undefined"
|
|
494
|
+
? window.location.hostname
|
|
495
|
+
: DeviceInfo.getApplicationName() ||
|
|
496
|
+
DeviceInfo.getBundleId() ||
|
|
497
|
+
"mobile-app";
|
|
498
|
+
const timestamp = new Date().toLocaleDateString() +
|
|
499
|
+
"-" +
|
|
500
|
+
new Date().toLocaleTimeString([], {
|
|
501
|
+
hour: "2-digit",
|
|
502
|
+
minute: "2-digit",
|
|
503
|
+
});
|
|
504
|
+
// We allow passkeyName to be passed in thru the provider or thru the params of this function directly.
|
|
505
|
+
// This is because signUpWithPasskey will create a new passkey using that name.
|
|
506
|
+
// Any extra authenticators will be created after the first one. (see core implementation)
|
|
507
|
+
const passkeyName = params?.passkeyDisplayName ??
|
|
508
|
+
masterConfig.auth?.createSuborgParams?.passkeyAuth?.passkeyName ??
|
|
509
|
+
`${websiteName}-${timestamp}`;
|
|
510
|
+
const res = await withZeroXKeyErrorHandling(() => client.signUpWithPasskey({
|
|
511
|
+
...params,
|
|
512
|
+
passkeyDisplayName: passkeyName,
|
|
513
|
+
expirationSeconds,
|
|
514
|
+
}), () => logout(), callbacks, "Failed to sign up with passkey");
|
|
515
|
+
if (res) {
|
|
516
|
+
await handlePostAuth({
|
|
517
|
+
method: AuthMethod.Passkey,
|
|
518
|
+
action: AuthAction.SIGNUP,
|
|
519
|
+
identifier: res.credentialId,
|
|
520
|
+
});
|
|
521
|
+
}
|
|
522
|
+
return res;
|
|
523
|
+
}, [client, callbacks]);
|
|
524
|
+
const initOtp = useCallback(async (params) => {
|
|
525
|
+
if (!client) {
|
|
526
|
+
throw new ZeroXKeyError("Client is not initialized.", ZeroXKeyErrorCodes.CLIENT_NOT_INITIALIZED);
|
|
527
|
+
}
|
|
528
|
+
return withZeroXKeyErrorHandling(() => client.initOtp(params), () => logout(), callbacks, "Failed to initialize OTP");
|
|
529
|
+
}, [client, callbacks]);
|
|
530
|
+
const verifyOtp = useCallback(async (params) => {
|
|
531
|
+
if (!client) {
|
|
532
|
+
throw new ZeroXKeyError("Client is not initialized.", ZeroXKeyErrorCodes.CLIENT_NOT_INITIALIZED);
|
|
533
|
+
}
|
|
534
|
+
return withZeroXKeyErrorHandling(() => client.verifyOtp(params), () => logout(), callbacks, "Failed to verify OTP");
|
|
535
|
+
}, [client, callbacks]);
|
|
536
|
+
const loginWithOtp = useCallback(async (params) => {
|
|
537
|
+
if (!client) {
|
|
538
|
+
throw new ZeroXKeyError("Client is not initialized.", ZeroXKeyErrorCodes.CLIENT_NOT_INITIALIZED);
|
|
539
|
+
}
|
|
540
|
+
const res = await withZeroXKeyErrorHandling(() => client.loginWithOtp(params), () => logout(), callbacks, "Failed to login with OTP");
|
|
541
|
+
if (res) {
|
|
542
|
+
await handlePostAuth({
|
|
543
|
+
method: AuthMethod.Otp,
|
|
544
|
+
action: AuthAction.LOGIN,
|
|
545
|
+
identifier: params.verificationToken,
|
|
546
|
+
});
|
|
547
|
+
}
|
|
548
|
+
return res;
|
|
549
|
+
}, [client, callbacks]);
|
|
550
|
+
const signUpWithOtp = useCallback(async (params) => {
|
|
551
|
+
if (!client) {
|
|
552
|
+
throw new ZeroXKeyError("Client is not initialized.", ZeroXKeyErrorCodes.CLIENT_NOT_INITIALIZED);
|
|
553
|
+
}
|
|
554
|
+
if (!masterConfig) {
|
|
555
|
+
throw new ZeroXKeyError("Config is not ready yet!", ZeroXKeyErrorCodes.INVALID_CONFIGURATION);
|
|
556
|
+
}
|
|
557
|
+
// If createSubOrgParams is not provided, use the default from masterConfig
|
|
558
|
+
let createSubOrgParams = params.createSubOrgParams;
|
|
559
|
+
if (!createSubOrgParams && masterConfig?.auth?.createSuborgParams) {
|
|
560
|
+
if (params.otpType === OtpType.Email) {
|
|
561
|
+
createSubOrgParams =
|
|
562
|
+
masterConfig.auth.createSuborgParams.emailOtpAuth;
|
|
563
|
+
}
|
|
564
|
+
else if (params.otpType === OtpType.Sms) {
|
|
565
|
+
createSubOrgParams = masterConfig.auth.createSuborgParams.smsOtpAuth;
|
|
566
|
+
}
|
|
567
|
+
}
|
|
568
|
+
params =
|
|
569
|
+
createSubOrgParams !== undefined
|
|
570
|
+
? { ...params, createSubOrgParams }
|
|
571
|
+
: { ...params };
|
|
572
|
+
const res = await withZeroXKeyErrorHandling(() => client.signUpWithOtp(params), () => logout(), callbacks, "Failed to sign up with OTP");
|
|
573
|
+
if (res) {
|
|
574
|
+
await handlePostAuth({
|
|
575
|
+
method: AuthMethod.Otp,
|
|
576
|
+
action: AuthAction.SIGNUP,
|
|
577
|
+
identifier: params.verificationToken,
|
|
578
|
+
});
|
|
579
|
+
}
|
|
580
|
+
return res;
|
|
581
|
+
}, [client, callbacks, masterConfig]);
|
|
582
|
+
const completeOtp = useCallback(async (params) => {
|
|
583
|
+
if (!client) {
|
|
584
|
+
throw new ZeroXKeyError("Client is not initialized.", ZeroXKeyErrorCodes.CLIENT_NOT_INITIALIZED);
|
|
585
|
+
}
|
|
586
|
+
if (!masterConfig) {
|
|
587
|
+
throw new ZeroXKeyError("Config is not ready yet!", ZeroXKeyErrorCodes.INVALID_CONFIGURATION);
|
|
588
|
+
}
|
|
589
|
+
// If createSubOrgParams is not provided, use the default from masterConfig
|
|
590
|
+
let createSubOrgParams = params.createSubOrgParams;
|
|
591
|
+
if (!createSubOrgParams && masterConfig?.auth?.createSuborgParams) {
|
|
592
|
+
if (params.otpType === OtpType.Email) {
|
|
593
|
+
createSubOrgParams =
|
|
594
|
+
masterConfig.auth.createSuborgParams.emailOtpAuth;
|
|
595
|
+
}
|
|
596
|
+
else if (params.otpType === OtpType.Sms) {
|
|
597
|
+
createSubOrgParams = masterConfig.auth.createSuborgParams.smsOtpAuth;
|
|
598
|
+
}
|
|
599
|
+
}
|
|
600
|
+
params =
|
|
601
|
+
createSubOrgParams !== undefined
|
|
602
|
+
? { ...params, createSubOrgParams }
|
|
603
|
+
: { ...params };
|
|
604
|
+
const res = await withZeroXKeyErrorHandling(() => client.completeOtp(params), () => logout(), callbacks, "Failed to complete OTP");
|
|
605
|
+
if (res) {
|
|
606
|
+
await handlePostAuth({
|
|
607
|
+
method: AuthMethod.Otp,
|
|
608
|
+
action: res.action,
|
|
609
|
+
identifier: res.verificationToken,
|
|
610
|
+
});
|
|
611
|
+
}
|
|
612
|
+
return res;
|
|
613
|
+
}, [client, callbacks, masterConfig]);
|
|
614
|
+
const loginWithOauth = useCallback(async (params) => {
|
|
615
|
+
if (!client) {
|
|
616
|
+
throw new ZeroXKeyError("Client is not initialized.", ZeroXKeyErrorCodes.CLIENT_NOT_INITIALIZED);
|
|
617
|
+
}
|
|
618
|
+
const res = await withZeroXKeyErrorHandling(() => client.loginWithOauth(params), () => logout(), callbacks, "Failed to login with OAuth");
|
|
619
|
+
if (res) {
|
|
620
|
+
await handlePostAuth({
|
|
621
|
+
method: AuthMethod.Oauth,
|
|
622
|
+
action: AuthAction.LOGIN,
|
|
623
|
+
identifier: params.oidcToken,
|
|
624
|
+
});
|
|
625
|
+
}
|
|
626
|
+
return res;
|
|
627
|
+
}, [client, callbacks]);
|
|
628
|
+
const signUpWithOauth = useCallback(async (params) => {
|
|
629
|
+
if (!client) {
|
|
630
|
+
throw new ZeroXKeyError("Client is not initialized.", ZeroXKeyErrorCodes.CLIENT_NOT_INITIALIZED);
|
|
631
|
+
}
|
|
632
|
+
if (!masterConfig) {
|
|
633
|
+
throw new ZeroXKeyError("Config is not ready yet!", ZeroXKeyErrorCodes.INVALID_CONFIGURATION);
|
|
634
|
+
}
|
|
635
|
+
// If createSubOrgParams is not provided, use the default from masterConfig
|
|
636
|
+
let createSubOrgParams = params.createSubOrgParams ??
|
|
637
|
+
masterConfig.auth?.createSuborgParams?.oauth;
|
|
638
|
+
params =
|
|
639
|
+
createSubOrgParams !== undefined
|
|
640
|
+
? { ...params, createSubOrgParams }
|
|
641
|
+
: { ...params };
|
|
642
|
+
const res = await withZeroXKeyErrorHandling(() => client.signUpWithOauth(params), () => logout(), callbacks, "Failed to sign up with OAuth");
|
|
643
|
+
if (res) {
|
|
644
|
+
await handlePostAuth({
|
|
645
|
+
method: AuthMethod.Oauth,
|
|
646
|
+
action: AuthAction.SIGNUP,
|
|
647
|
+
identifier: params.oidcToken,
|
|
648
|
+
});
|
|
649
|
+
}
|
|
650
|
+
return res;
|
|
651
|
+
}, [client, callbacks, masterConfig]);
|
|
652
|
+
const completeOauth = useCallback(async (params) => {
|
|
653
|
+
if (!client) {
|
|
654
|
+
throw new ZeroXKeyError("Client is not initialized.", ZeroXKeyErrorCodes.CLIENT_NOT_INITIALIZED);
|
|
655
|
+
}
|
|
656
|
+
if (!masterConfig) {
|
|
657
|
+
throw new ZeroXKeyError("Config is not ready yet!", ZeroXKeyErrorCodes.INVALID_CONFIGURATION);
|
|
658
|
+
}
|
|
659
|
+
// If createSubOrgParams is not provided, use the default from masterConfig
|
|
660
|
+
const createSubOrgParams = params.createSubOrgParams ??
|
|
661
|
+
masterConfig.auth?.createSuborgParams?.oauth;
|
|
662
|
+
params =
|
|
663
|
+
createSubOrgParams !== undefined
|
|
664
|
+
? { ...params, createSubOrgParams }
|
|
665
|
+
: { ...params };
|
|
666
|
+
const res = await withZeroXKeyErrorHandling(() => client.completeOauth(params), () => logout(), callbacks, "Failed to complete OAuth");
|
|
667
|
+
if (res) {
|
|
668
|
+
await handlePostAuth({
|
|
669
|
+
method: AuthMethod.Oauth,
|
|
670
|
+
action: res.action,
|
|
671
|
+
identifier: params.oidcToken,
|
|
672
|
+
});
|
|
673
|
+
}
|
|
674
|
+
return res;
|
|
675
|
+
}, [client, callbacks, masterConfig]);
|
|
676
|
+
const fetchWallets = useCallback(async (params) => {
|
|
677
|
+
if (!client) {
|
|
678
|
+
throw new ZeroXKeyError("Client is not initialized.", ZeroXKeyErrorCodes.CLIENT_NOT_INITIALIZED);
|
|
679
|
+
}
|
|
680
|
+
return withZeroXKeyErrorHandling(() => client.fetchWallets(params), () => logout(), callbacks, "Failed to fetch wallets");
|
|
681
|
+
}, [client, callbacks]);
|
|
682
|
+
const fetchWalletAccounts = useCallback(async (params) => {
|
|
683
|
+
if (!client) {
|
|
684
|
+
throw new ZeroXKeyError("Client is not initialized.", ZeroXKeyErrorCodes.CLIENT_NOT_INITIALIZED);
|
|
685
|
+
}
|
|
686
|
+
return withZeroXKeyErrorHandling(() => client.fetchWalletAccounts(params), () => logout(), callbacks, "Failed to fetch wallet accounts");
|
|
687
|
+
}, [client, callbacks]);
|
|
688
|
+
const fetchPrivateKeys = useCallback(async (params) => {
|
|
689
|
+
if (!client) {
|
|
690
|
+
throw new ZeroXKeyError("Client is not initialized.", ZeroXKeyErrorCodes.CLIENT_NOT_INITIALIZED);
|
|
691
|
+
}
|
|
692
|
+
return withZeroXKeyErrorHandling(() => client.fetchPrivateKeys(params), () => logout(), callbacks, "Failed to fetch private keys");
|
|
693
|
+
}, [client, callbacks]);
|
|
694
|
+
const fetchBootProofForAppProof = useCallback(async (params) => {
|
|
695
|
+
if (!client)
|
|
696
|
+
throw new ZeroXKeyError("Client is not initialized.", ZeroXKeyErrorCodes.CLIENT_NOT_INITIALIZED);
|
|
697
|
+
return withZeroXKeyErrorHandling(() => client.fetchBootProofForAppProof(params), () => logout(), callbacks, "Failed to fetch or create delegated access user");
|
|
698
|
+
}, [client, callbacks]);
|
|
699
|
+
const signMessage = useCallback(async (params) => {
|
|
700
|
+
if (!client)
|
|
701
|
+
throw new ZeroXKeyError("Client is not initialized.", ZeroXKeyErrorCodes.CLIENT_NOT_INITIALIZED);
|
|
702
|
+
return withZeroXKeyErrorHandling(() => client.signMessage(params), () => logout(), callbacks, "Failed to sign message");
|
|
703
|
+
}, [client, callbacks]);
|
|
704
|
+
const signTransaction = useCallback(async (params) => {
|
|
705
|
+
if (!client)
|
|
706
|
+
throw new ZeroXKeyError("Client is not initialized.", ZeroXKeyErrorCodes.CLIENT_NOT_INITIALIZED);
|
|
707
|
+
return withZeroXKeyErrorHandling(() => client.signTransaction(params), () => logout(), callbacks, "Failed to sign transaction");
|
|
708
|
+
}, [client, callbacks]);
|
|
709
|
+
const solSendTransaction = useCallback(async (params) => {
|
|
710
|
+
if (!client)
|
|
711
|
+
throw new ZeroXKeyError("Client is not initialized.", ZeroXKeyErrorCodes.CLIENT_NOT_INITIALIZED);
|
|
712
|
+
return withZeroXKeyErrorHandling(() => client.solSendTransaction(params), () => logout(), callbacks, "Failed to send sol transaction");
|
|
713
|
+
}, [client, callbacks]);
|
|
714
|
+
const ethSendTransaction = useCallback(async (params) => {
|
|
715
|
+
if (!client)
|
|
716
|
+
throw new ZeroXKeyError("Client is not initialized.", ZeroXKeyErrorCodes.CLIENT_NOT_INITIALIZED);
|
|
717
|
+
return withZeroXKeyErrorHandling(() => client.ethSendTransaction(params), () => logout(), callbacks, "Failed to send eth transaction");
|
|
718
|
+
}, [client, callbacks]);
|
|
719
|
+
const ethSendErc20Transfer = useCallback(async (params) => {
|
|
720
|
+
if (!client)
|
|
721
|
+
throw new ZeroXKeyError("Client is not initialized.", ZeroXKeyErrorCodes.CLIENT_NOT_INITIALIZED);
|
|
722
|
+
return withZeroXKeyErrorHandling(() => client.ethSendErc20Transfer(params), () => logout(), callbacks, "Failed to send ERC20 transfer");
|
|
723
|
+
}, [client, callbacks]);
|
|
724
|
+
const signAndSendTransaction = useCallback(async (params) => {
|
|
725
|
+
if (!client)
|
|
726
|
+
throw new ZeroXKeyError("Client is not initialized.", ZeroXKeyErrorCodes.CLIENT_NOT_INITIALIZED);
|
|
727
|
+
return withZeroXKeyErrorHandling(() => client.signAndSendTransaction(params), () => logout(), callbacks, "Failed to sign and send raw transaction");
|
|
728
|
+
}, [client, callbacks, logout]);
|
|
729
|
+
const pollTransactionStatus = useCallback(async (params) => {
|
|
730
|
+
if (!client)
|
|
731
|
+
throw new ZeroXKeyError("Client is not initialized.", ZeroXKeyErrorCodes.CLIENT_NOT_INITIALIZED);
|
|
732
|
+
return withZeroXKeyErrorHandling(() => client.pollTransactionStatus(params), () => logout(), callbacks, "Failed to poll transaction status");
|
|
733
|
+
}, [client, callbacks]);
|
|
734
|
+
const fetchUser = useCallback(async (params) => {
|
|
735
|
+
if (!client)
|
|
736
|
+
throw new ZeroXKeyError("Client is not initialized.", ZeroXKeyErrorCodes.CLIENT_NOT_INITIALIZED);
|
|
737
|
+
return withZeroXKeyErrorHandling(() => client.fetchUser(params), () => logout(), callbacks, "Failed to fetch user");
|
|
738
|
+
}, [client, callbacks]);
|
|
739
|
+
const fetchOrCreateP256ApiKeyUser = useCallback(async (params) => {
|
|
740
|
+
if (!client)
|
|
741
|
+
throw new ZeroXKeyError("Client is not initialized.", ZeroXKeyErrorCodes.CLIENT_NOT_INITIALIZED);
|
|
742
|
+
return withZeroXKeyErrorHandling(() => client.fetchOrCreateP256ApiKeyUser(params), () => logout(), callbacks, "Failed to fetch or create delegated access user");
|
|
743
|
+
}, [client, callbacks]);
|
|
744
|
+
const fetchOrCreatePolicies = useCallback(async (params) => {
|
|
745
|
+
if (!client)
|
|
746
|
+
throw new ZeroXKeyError("Client is not initialized.", ZeroXKeyErrorCodes.CLIENT_NOT_INITIALIZED);
|
|
747
|
+
return withZeroXKeyErrorHandling(() => client.fetchOrCreatePolicies(params), () => logout(), callbacks, "Failed to fetch or create delegated access user");
|
|
748
|
+
}, [client, callbacks]);
|
|
749
|
+
const updateUserEmail = useCallback(async (params) => {
|
|
750
|
+
if (!client)
|
|
751
|
+
throw new ZeroXKeyError("Client is not initialized.", ZeroXKeyErrorCodes.CLIENT_NOT_INITIALIZED);
|
|
752
|
+
const res = await withZeroXKeyErrorHandling(() => client.updateUserEmail(params), () => logout(), callbacks, "Failed to update user email");
|
|
753
|
+
if (res)
|
|
754
|
+
await maybeRefreshUser({
|
|
755
|
+
stampWith: params?.stampWith,
|
|
756
|
+
...(params?.organizationId && {
|
|
757
|
+
organizationId: params.organizationId,
|
|
758
|
+
}),
|
|
759
|
+
...(params?.userId && { userId: params.userId }),
|
|
760
|
+
});
|
|
761
|
+
return res;
|
|
762
|
+
}, [client, callbacks]);
|
|
763
|
+
const removeUserEmail = useCallback(async (params) => {
|
|
764
|
+
if (!client)
|
|
765
|
+
throw new ZeroXKeyError("Client is not initialized.", ZeroXKeyErrorCodes.CLIENT_NOT_INITIALIZED);
|
|
766
|
+
const res = await withZeroXKeyErrorHandling(() => client.removeUserEmail(params), () => logout(), callbacks, "Failed to remove user email");
|
|
767
|
+
if (res)
|
|
768
|
+
await maybeRefreshUser({
|
|
769
|
+
stampWith: params?.stampWith,
|
|
770
|
+
...(params?.organizationId && {
|
|
771
|
+
organizationId: params.organizationId,
|
|
772
|
+
}),
|
|
773
|
+
...(params?.userId && { userId: params.userId }),
|
|
774
|
+
});
|
|
775
|
+
return res;
|
|
776
|
+
}, [client, callbacks]);
|
|
777
|
+
const updateUserPhoneNumber = useCallback(async (params) => {
|
|
778
|
+
if (!client)
|
|
779
|
+
throw new ZeroXKeyError("Client is not initialized.", ZeroXKeyErrorCodes.CLIENT_NOT_INITIALIZED);
|
|
780
|
+
const res = await withZeroXKeyErrorHandling(() => client.updateUserPhoneNumber(params), () => logout(), callbacks, "Failed to update user phone number");
|
|
781
|
+
if (res)
|
|
782
|
+
await maybeRefreshUser({
|
|
783
|
+
stampWith: params?.stampWith,
|
|
784
|
+
...(params?.organizationId && {
|
|
785
|
+
organizationId: params.organizationId,
|
|
786
|
+
}),
|
|
787
|
+
...(params?.userId && { userId: params.userId }),
|
|
788
|
+
});
|
|
789
|
+
return res;
|
|
790
|
+
}, [client, callbacks]);
|
|
791
|
+
const removeUserPhoneNumber = useCallback(async (params) => {
|
|
792
|
+
if (!client)
|
|
793
|
+
throw new ZeroXKeyError("Client is not initialized.", ZeroXKeyErrorCodes.CLIENT_NOT_INITIALIZED);
|
|
794
|
+
const res = await withZeroXKeyErrorHandling(() => client.removeUserPhoneNumber(params), () => logout(), callbacks, "Failed to remove user phone number");
|
|
795
|
+
if (res)
|
|
796
|
+
await maybeRefreshUser({
|
|
797
|
+
stampWith: params?.stampWith,
|
|
798
|
+
...(params?.organizationId && {
|
|
799
|
+
organizationId: params.organizationId,
|
|
800
|
+
}),
|
|
801
|
+
...(params?.userId && { userId: params.userId }),
|
|
802
|
+
});
|
|
803
|
+
return res;
|
|
804
|
+
}, [client, callbacks]);
|
|
805
|
+
const updateUserName = useCallback(async (params) => {
|
|
806
|
+
if (!client)
|
|
807
|
+
throw new ZeroXKeyError("Client is not initialized.", ZeroXKeyErrorCodes.CLIENT_NOT_INITIALIZED);
|
|
808
|
+
const res = await withZeroXKeyErrorHandling(() => client.updateUserName(params), () => logout(), callbacks, "Failed to update user name");
|
|
809
|
+
if (res)
|
|
810
|
+
await maybeRefreshUser({
|
|
811
|
+
stampWith: params?.stampWith,
|
|
812
|
+
...(params?.organizationId && {
|
|
813
|
+
organizationId: params.organizationId,
|
|
814
|
+
}),
|
|
815
|
+
...(params?.userId && { userId: params.userId }),
|
|
816
|
+
});
|
|
817
|
+
return res;
|
|
818
|
+
}, [client, callbacks]);
|
|
819
|
+
const addOauthProvider = useCallback(async (params) => {
|
|
820
|
+
if (!client)
|
|
821
|
+
throw new ZeroXKeyError("Client is not initialized.", ZeroXKeyErrorCodes.CLIENT_NOT_INITIALIZED);
|
|
822
|
+
const res = await withZeroXKeyErrorHandling(() => client.addOauthProvider(params), () => logout(), callbacks, "Failed to add OAuth provider");
|
|
823
|
+
if (res)
|
|
824
|
+
await maybeRefreshUser({
|
|
825
|
+
stampWith: params?.stampWith,
|
|
826
|
+
...(params?.organizationId && {
|
|
827
|
+
organizationId: params.organizationId,
|
|
828
|
+
}),
|
|
829
|
+
...(params?.userId && { userId: params.userId }),
|
|
830
|
+
});
|
|
831
|
+
return res;
|
|
832
|
+
}, [client, callbacks]);
|
|
833
|
+
const removeOauthProviders = useCallback(async (params) => {
|
|
834
|
+
if (!client)
|
|
835
|
+
throw new ZeroXKeyError("Client is not initialized.", ZeroXKeyErrorCodes.CLIENT_NOT_INITIALIZED);
|
|
836
|
+
const res = await withZeroXKeyErrorHandling(() => client.removeOauthProviders(params), () => logout(), callbacks, "Failed to remove OAuth providers");
|
|
837
|
+
if (res)
|
|
838
|
+
await maybeRefreshUser({
|
|
839
|
+
stampWith: params?.stampWith,
|
|
840
|
+
...(params?.organizationId && {
|
|
841
|
+
organizationId: params.organizationId,
|
|
842
|
+
}),
|
|
843
|
+
...(params?.userId && { userId: params.userId }),
|
|
844
|
+
});
|
|
845
|
+
return res;
|
|
846
|
+
}, [client, callbacks]);
|
|
847
|
+
const addPasskey = useCallback(async (params) => {
|
|
848
|
+
if (!client)
|
|
849
|
+
throw new ZeroXKeyError("Client is not initialized.", ZeroXKeyErrorCodes.CLIENT_NOT_INITIALIZED);
|
|
850
|
+
const res = await withZeroXKeyErrorHandling(() => client.addPasskey(params), () => logout(), callbacks, "Failed to add passkey");
|
|
851
|
+
if (res)
|
|
852
|
+
await maybeRefreshUser({
|
|
853
|
+
stampWith: params?.stampWith,
|
|
854
|
+
...(params?.organizationId && {
|
|
855
|
+
organizationId: params.organizationId,
|
|
856
|
+
}),
|
|
857
|
+
...(params?.userId && { userId: params.userId }),
|
|
858
|
+
});
|
|
859
|
+
return res;
|
|
860
|
+
}, [client, callbacks]);
|
|
861
|
+
const removePasskeys = useCallback(async (params) => {
|
|
862
|
+
if (!client)
|
|
863
|
+
throw new ZeroXKeyError("Client is not initialized.", ZeroXKeyErrorCodes.CLIENT_NOT_INITIALIZED);
|
|
864
|
+
const res = await withZeroXKeyErrorHandling(() => client.removePasskeys(params), () => logout(), callbacks, "Failed to remove passkeys");
|
|
865
|
+
if (res)
|
|
866
|
+
await maybeRefreshUser({
|
|
867
|
+
stampWith: params?.stampWith,
|
|
868
|
+
...(params?.organizationId && {
|
|
869
|
+
organizationId: params.organizationId,
|
|
870
|
+
}),
|
|
871
|
+
...(params?.userId && { userId: params.userId }),
|
|
872
|
+
});
|
|
873
|
+
return res;
|
|
874
|
+
}, [client, callbacks]);
|
|
875
|
+
const createWallet = useCallback(async (params) => {
|
|
876
|
+
if (!client)
|
|
877
|
+
throw new ZeroXKeyError("Client is not initialized.", ZeroXKeyErrorCodes.CLIENT_NOT_INITIALIZED);
|
|
878
|
+
const res = await withZeroXKeyErrorHandling(() => client.createWallet(params), () => logout(), callbacks, "Failed to create wallet");
|
|
879
|
+
const s = await getSession();
|
|
880
|
+
if (res && s)
|
|
881
|
+
await maybeRefreshWallets({
|
|
882
|
+
stampWith: params?.stampWith,
|
|
883
|
+
...(params?.organizationId && {
|
|
884
|
+
organizationId: params.organizationId,
|
|
885
|
+
}),
|
|
886
|
+
});
|
|
887
|
+
return res;
|
|
888
|
+
}, [client, session, callbacks]);
|
|
889
|
+
const createWalletAccounts = useCallback(async (params) => {
|
|
890
|
+
if (!client)
|
|
891
|
+
throw new ZeroXKeyError("Client is not initialized.", ZeroXKeyErrorCodes.CLIENT_NOT_INITIALIZED);
|
|
892
|
+
const res = await withZeroXKeyErrorHandling(() => client.createWalletAccounts(params), () => logout(), callbacks, "Failed to create wallet accounts");
|
|
893
|
+
const s = await getSession();
|
|
894
|
+
if (res && s)
|
|
895
|
+
await maybeRefreshWallets({
|
|
896
|
+
stampWith: params?.stampWith,
|
|
897
|
+
...(params?.organizationId && {
|
|
898
|
+
organizationId: params.organizationId,
|
|
899
|
+
}),
|
|
900
|
+
});
|
|
901
|
+
return res;
|
|
902
|
+
}, [client, session, callbacks]);
|
|
903
|
+
const exportWallet = useCallback(async (params) => {
|
|
904
|
+
if (!client)
|
|
905
|
+
throw new ZeroXKeyError("Client is not initialized.", ZeroXKeyErrorCodes.CLIENT_NOT_INITIALIZED);
|
|
906
|
+
// Default: decrypt unless explicitly disabled
|
|
907
|
+
const shouldDecrypt = params?.decrypt !== false;
|
|
908
|
+
if (!shouldDecrypt) {
|
|
909
|
+
const res = await withZeroXKeyErrorHandling(() => client.exportWallet({
|
|
910
|
+
walletId: params.walletId,
|
|
911
|
+
targetPublicKey: params.targetPublicKey,
|
|
912
|
+
...(params.organizationId && {
|
|
913
|
+
organizationId: params.organizationId,
|
|
914
|
+
}),
|
|
915
|
+
...(params.stampWith && { stampWith: params.stampWith }),
|
|
916
|
+
}), () => logout(), callbacks, "Failed to export wallet");
|
|
917
|
+
const s = await getSession();
|
|
918
|
+
if (res && s)
|
|
919
|
+
await maybeRefreshWallets({
|
|
920
|
+
stampWith: params?.stampWith,
|
|
921
|
+
...(params?.organizationId && {
|
|
922
|
+
organizationId: params.organizationId,
|
|
923
|
+
}),
|
|
924
|
+
});
|
|
925
|
+
return res;
|
|
926
|
+
}
|
|
927
|
+
// Decrypting path: generate P-256 keypair, export, then decrypt to mnemonic
|
|
928
|
+
try {
|
|
929
|
+
const { privateKey, publicKeyUncompressed } = generateP256KeyPair();
|
|
930
|
+
const targetPublicKey = publicKeyUncompressed;
|
|
931
|
+
const exportParams = {
|
|
932
|
+
walletId: params.walletId,
|
|
933
|
+
targetPublicKey,
|
|
934
|
+
...(params.organizationId && {
|
|
935
|
+
organizationId: params.organizationId,
|
|
936
|
+
}),
|
|
937
|
+
...(params.stampWith && { stampWith: params.stampWith }),
|
|
938
|
+
};
|
|
939
|
+
const bundle = await withZeroXKeyErrorHandling(() => client.exportWallet(exportParams), () => logout(), callbacks, "Failed to export wallet");
|
|
940
|
+
const session = await getSession();
|
|
941
|
+
const orgId = session?.organizationId;
|
|
942
|
+
if (!orgId) {
|
|
943
|
+
throw new ZeroXKeyError("Missing organizationId in session for decryption", ZeroXKeyErrorCodes.INVALID_REQUEST);
|
|
944
|
+
}
|
|
945
|
+
const mnemonic = await decryptExportBundle({
|
|
946
|
+
exportBundle: bundle,
|
|
947
|
+
embeddedKey: privateKey,
|
|
948
|
+
organizationId: orgId,
|
|
949
|
+
returnMnemonic: true,
|
|
950
|
+
keyFormat: "HEXADECIMAL",
|
|
951
|
+
});
|
|
952
|
+
return mnemonic;
|
|
953
|
+
}
|
|
954
|
+
catch (error) {
|
|
955
|
+
throw error;
|
|
956
|
+
}
|
|
957
|
+
}, [client, session, callbacks]);
|
|
958
|
+
const exportPrivateKey = useCallback(async (params) => {
|
|
959
|
+
if (!client)
|
|
960
|
+
throw new ZeroXKeyError("Client is not initialized.", ZeroXKeyErrorCodes.CLIENT_NOT_INITIALIZED);
|
|
961
|
+
const shouldDecrypt = params?.decrypt !== false;
|
|
962
|
+
if (!shouldDecrypt) {
|
|
963
|
+
const res = await withZeroXKeyErrorHandling(() => client.exportPrivateKey({
|
|
964
|
+
privateKeyId: params.privateKeyId,
|
|
965
|
+
targetPublicKey: params.targetPublicKey,
|
|
966
|
+
...(params.organizationId && {
|
|
967
|
+
organizationId: params.organizationId,
|
|
968
|
+
}),
|
|
969
|
+
...(params.stampWith && { stampWith: params.stampWith }),
|
|
970
|
+
}), () => logout(), callbacks, "Failed to export private key");
|
|
971
|
+
return res;
|
|
972
|
+
}
|
|
973
|
+
try {
|
|
974
|
+
const { privateKey, publicKeyUncompressed } = generateP256KeyPair();
|
|
975
|
+
const targetPublicKey = publicKeyUncompressed;
|
|
976
|
+
const exportParams = {
|
|
977
|
+
privateKeyId: params.privateKeyId,
|
|
978
|
+
targetPublicKey,
|
|
979
|
+
...(params.organizationId && {
|
|
980
|
+
organizationId: params.organizationId,
|
|
981
|
+
}),
|
|
982
|
+
...(params.stampWith && { stampWith: params.stampWith }),
|
|
983
|
+
};
|
|
984
|
+
const bundle = await withZeroXKeyErrorHandling(() => client.exportPrivateKey(exportParams), () => logout(), callbacks, "Failed to export private key");
|
|
985
|
+
const session = await getSession();
|
|
986
|
+
const orgId = session?.organizationId;
|
|
987
|
+
if (!orgId) {
|
|
988
|
+
throw new ZeroXKeyError("Missing organizationId in session for decryption", ZeroXKeyErrorCodes.INVALID_REQUEST);
|
|
989
|
+
}
|
|
990
|
+
const rawPrivateKey = await decryptExportBundle({
|
|
991
|
+
exportBundle: bundle,
|
|
992
|
+
embeddedKey: privateKey,
|
|
993
|
+
organizationId: orgId,
|
|
994
|
+
returnMnemonic: false,
|
|
995
|
+
keyFormat: "HEXADECIMAL",
|
|
996
|
+
});
|
|
997
|
+
return rawPrivateKey;
|
|
998
|
+
}
|
|
999
|
+
catch (error) {
|
|
1000
|
+
throw error;
|
|
1001
|
+
}
|
|
1002
|
+
}, [client, callbacks]);
|
|
1003
|
+
const exportWalletAccount = useCallback(async (params) => {
|
|
1004
|
+
if (!client)
|
|
1005
|
+
throw new ZeroXKeyError("Client is not initialized.", ZeroXKeyErrorCodes.CLIENT_NOT_INITIALIZED);
|
|
1006
|
+
const shouldDecrypt = params?.decrypt !== false;
|
|
1007
|
+
if (!shouldDecrypt) {
|
|
1008
|
+
const res = await withZeroXKeyErrorHandling(() => client.exportWalletAccount({
|
|
1009
|
+
address: params.address,
|
|
1010
|
+
targetPublicKey: params.targetPublicKey,
|
|
1011
|
+
...(params.organizationId && {
|
|
1012
|
+
organizationId: params.organizationId,
|
|
1013
|
+
}),
|
|
1014
|
+
...(params.stampWith && { stampWith: params.stampWith }),
|
|
1015
|
+
}), () => logout(), callbacks, "Failed to export wallet accounts");
|
|
1016
|
+
return res;
|
|
1017
|
+
}
|
|
1018
|
+
try {
|
|
1019
|
+
const { privateKey, publicKeyUncompressed } = generateP256KeyPair();
|
|
1020
|
+
const targetPublicKey = publicKeyUncompressed;
|
|
1021
|
+
const exportParams = {
|
|
1022
|
+
address: params.address,
|
|
1023
|
+
targetPublicKey,
|
|
1024
|
+
...(params.organizationId && {
|
|
1025
|
+
organizationId: params.organizationId,
|
|
1026
|
+
}),
|
|
1027
|
+
...(params.stampWith && { stampWith: params.stampWith }),
|
|
1028
|
+
};
|
|
1029
|
+
const bundle = await withZeroXKeyErrorHandling(() => client.exportWalletAccount(exportParams), () => logout(), callbacks, "Failed to export wallet accounts");
|
|
1030
|
+
const session = await getSession();
|
|
1031
|
+
const orgId = session?.organizationId;
|
|
1032
|
+
if (!orgId) {
|
|
1033
|
+
throw new ZeroXKeyError("Missing organizationId in session for decryption", ZeroXKeyErrorCodes.INVALID_REQUEST);
|
|
1034
|
+
}
|
|
1035
|
+
const decryptedKey = await decryptExportBundle({
|
|
1036
|
+
exportBundle: bundle,
|
|
1037
|
+
embeddedKey: privateKey,
|
|
1038
|
+
organizationId: orgId,
|
|
1039
|
+
returnMnemonic: false,
|
|
1040
|
+
keyFormat: "HEXADECIMAL",
|
|
1041
|
+
});
|
|
1042
|
+
return decryptedKey;
|
|
1043
|
+
}
|
|
1044
|
+
catch (error) {
|
|
1045
|
+
throw error;
|
|
1046
|
+
}
|
|
1047
|
+
}, [client, callbacks, masterConfig, session, user]);
|
|
1048
|
+
const importWallet = useCallback(async (params) => {
|
|
1049
|
+
if (!client)
|
|
1050
|
+
throw new ZeroXKeyError("Client is not initialized.", ZeroXKeyErrorCodes.CLIENT_NOT_INITIALIZED);
|
|
1051
|
+
const { mnemonic, walletName, accounts, organizationId, userId, stampWith, } = params;
|
|
1052
|
+
// Resolve org/user from params or current session
|
|
1053
|
+
const currentSession = await getSession();
|
|
1054
|
+
const effectiveOrgId = organizationId ?? currentSession?.organizationId;
|
|
1055
|
+
const effectiveUserId = userId ?? currentSession?.userId;
|
|
1056
|
+
if (!effectiveOrgId || !effectiveUserId) {
|
|
1057
|
+
throw new ZeroXKeyError("Missing organizationId or userId for wallet import", ZeroXKeyErrorCodes.INVALID_REQUEST);
|
|
1058
|
+
}
|
|
1059
|
+
// Step 1: init import to obtain importBundle
|
|
1060
|
+
const initRes = await withZeroXKeyErrorHandling(() => client.httpClient?.initImportWallet({
|
|
1061
|
+
organizationId: effectiveOrgId,
|
|
1062
|
+
userId: effectiveUserId,
|
|
1063
|
+
}, stampWith), () => logout(), callbacks, "Failed to init wallet import");
|
|
1064
|
+
const importBundle = initRes?.importBundle;
|
|
1065
|
+
if (!importBundle) {
|
|
1066
|
+
throw new ZeroXKeyError("Failed to retrieve import bundle", ZeroXKeyErrorCodes.IMPORT_WALLET_ERROR);
|
|
1067
|
+
}
|
|
1068
|
+
// Step 2: encrypt mnemonic to encryptedBundle
|
|
1069
|
+
const encryptedBundle = await encryptWalletToBundle({
|
|
1070
|
+
mnemonic,
|
|
1071
|
+
importBundle,
|
|
1072
|
+
userId: effectiveUserId,
|
|
1073
|
+
organizationId: effectiveOrgId,
|
|
1074
|
+
});
|
|
1075
|
+
// Step 3: call importWallet with encrypted bundle
|
|
1076
|
+
const res = await withZeroXKeyErrorHandling(() => client.importWallet({
|
|
1077
|
+
encryptedBundle,
|
|
1078
|
+
walletName,
|
|
1079
|
+
...(accounts && { accounts }),
|
|
1080
|
+
organizationId: effectiveOrgId,
|
|
1081
|
+
userId: effectiveUserId,
|
|
1082
|
+
...(stampWith && { stampWith }),
|
|
1083
|
+
}), () => logout(), callbacks, "Failed to import wallet");
|
|
1084
|
+
// Refresh state after import
|
|
1085
|
+
if (res)
|
|
1086
|
+
await maybeRefreshWallets({
|
|
1087
|
+
...(stampWith && { stampWith }),
|
|
1088
|
+
organizationId: effectiveOrgId,
|
|
1089
|
+
userId: effectiveUserId,
|
|
1090
|
+
});
|
|
1091
|
+
return res;
|
|
1092
|
+
}, [client, callbacks, masterConfig, session, user]);
|
|
1093
|
+
const importPrivateKey = useCallback(async (params) => {
|
|
1094
|
+
if (!client)
|
|
1095
|
+
throw new ZeroXKeyError("Client is not initialized.", ZeroXKeyErrorCodes.CLIENT_NOT_INITIALIZED);
|
|
1096
|
+
const { privateKey, privateKeyName, addressFormats, curve, keyFormat = "HEXADECIMAL", organizationId, userId, stampWith, } = params;
|
|
1097
|
+
// Resolve org/user
|
|
1098
|
+
const currentSession = await getSession();
|
|
1099
|
+
const effectiveOrgId = organizationId ?? currentSession?.organizationId;
|
|
1100
|
+
const effectiveUserId = userId ?? currentSession?.userId;
|
|
1101
|
+
if (!effectiveOrgId || !effectiveUserId) {
|
|
1102
|
+
throw new ZeroXKeyError("Missing organizationId or userId for private key import", ZeroXKeyErrorCodes.INVALID_REQUEST);
|
|
1103
|
+
}
|
|
1104
|
+
// Init import to get bundle
|
|
1105
|
+
const initRes = await withZeroXKeyErrorHandling(() => client.httpClient?.initImportPrivateKey({
|
|
1106
|
+
organizationId: effectiveOrgId,
|
|
1107
|
+
userId: effectiveUserId,
|
|
1108
|
+
}, stampWith), () => logout(), callbacks, "Failed to init private key import");
|
|
1109
|
+
const importBundle = initRes?.importBundle;
|
|
1110
|
+
if (!importBundle) {
|
|
1111
|
+
throw new ZeroXKeyError("Failed to retrieve import bundle", ZeroXKeyErrorCodes.IMPORT_WALLET_ERROR);
|
|
1112
|
+
}
|
|
1113
|
+
// Encrypt provided private key to bundle
|
|
1114
|
+
const encryptedBundle = await encryptPrivateKeyToBundle({
|
|
1115
|
+
privateKey,
|
|
1116
|
+
keyFormat,
|
|
1117
|
+
importBundle,
|
|
1118
|
+
userId: effectiveUserId,
|
|
1119
|
+
organizationId: effectiveOrgId,
|
|
1120
|
+
});
|
|
1121
|
+
// Import
|
|
1122
|
+
const res = await withZeroXKeyErrorHandling(() => client.importPrivateKey({
|
|
1123
|
+
encryptedBundle,
|
|
1124
|
+
privateKeyName,
|
|
1125
|
+
addressFormats,
|
|
1126
|
+
curve: curve ?? "CURVE_SECP256K1",
|
|
1127
|
+
organizationId: effectiveOrgId,
|
|
1128
|
+
userId: effectiveUserId,
|
|
1129
|
+
...(stampWith && { stampWith }),
|
|
1130
|
+
}), () => logout(), callbacks, "Failed to import private key");
|
|
1131
|
+
return res;
|
|
1132
|
+
}, [client, callbacks, masterConfig, session, user]);
|
|
1133
|
+
const deleteSubOrganization = useCallback(async (params) => {
|
|
1134
|
+
if (!client)
|
|
1135
|
+
throw new ZeroXKeyError("Client is not initialized.", ZeroXKeyErrorCodes.CLIENT_NOT_INITIALIZED);
|
|
1136
|
+
return withZeroXKeyErrorHandling(() => client.deleteSubOrganization(params), () => logout(), callbacks, "Failed to delete sub-organization");
|
|
1137
|
+
}, [client, callbacks, masterConfig, session, user]);
|
|
1138
|
+
const storeSession = useCallback(async (params) => {
|
|
1139
|
+
if (!client)
|
|
1140
|
+
throw new ZeroXKeyError("Client is not initialized.", ZeroXKeyErrorCodes.CLIENT_NOT_INITIALIZED);
|
|
1141
|
+
await withZeroXKeyErrorHandling(() => client.storeSession(params), () => logout(), callbacks, "Failed to store session");
|
|
1142
|
+
const sessionKey = await getActiveSessionKey();
|
|
1143
|
+
const session = await getSession({
|
|
1144
|
+
...(sessionKey && { sessionKey }),
|
|
1145
|
+
});
|
|
1146
|
+
if (session && sessionKey)
|
|
1147
|
+
await scheduleSessionExpiration({ sessionKey, expiry: session.expiry });
|
|
1148
|
+
const allSessions = await getAllSessions();
|
|
1149
|
+
setSession(session);
|
|
1150
|
+
setAllSessions(allSessions);
|
|
1151
|
+
await maybeRefreshWallets();
|
|
1152
|
+
await maybeRefreshUser();
|
|
1153
|
+
}, [client, callbacks, masterConfig, session, user]);
|
|
1154
|
+
const clearSession = useCallback(async (params) => {
|
|
1155
|
+
if (!client)
|
|
1156
|
+
throw new ZeroXKeyError("Client is not initialized.", ZeroXKeyErrorCodes.CLIENT_NOT_INITIALIZED);
|
|
1157
|
+
await withZeroXKeyErrorHandling(async () => client.clearSession(params), () => logout(), callbacks, "Failed to clear session");
|
|
1158
|
+
const sessionKey = params?.sessionKey ?? (await getActiveSessionKey());
|
|
1159
|
+
if (!sessionKey)
|
|
1160
|
+
return;
|
|
1161
|
+
if (!params?.sessionKey) {
|
|
1162
|
+
setSession(undefined);
|
|
1163
|
+
}
|
|
1164
|
+
clearSessionTimeouts([sessionKey]);
|
|
1165
|
+
// clear only the cleared session from allSessions
|
|
1166
|
+
const newAllSessions = { ...allSessions };
|
|
1167
|
+
if (newAllSessions) {
|
|
1168
|
+
delete newAllSessions[sessionKey];
|
|
1169
|
+
}
|
|
1170
|
+
setAllSessions(newAllSessions);
|
|
1171
|
+
return;
|
|
1172
|
+
}, [client, callbacks, session, user, masterConfig]);
|
|
1173
|
+
const clearAllSessions = useCallback(async () => {
|
|
1174
|
+
if (!client)
|
|
1175
|
+
throw new ZeroXKeyError("Client is not initialized.", ZeroXKeyErrorCodes.CLIENT_NOT_INITIALIZED);
|
|
1176
|
+
setSession(undefined);
|
|
1177
|
+
setAllSessions(undefined);
|
|
1178
|
+
clearSessionTimeouts();
|
|
1179
|
+
return await withZeroXKeyErrorHandling(() => client.clearAllSessions(), () => logout(), callbacks, "Failed to clear all sessions");
|
|
1180
|
+
}, [client, callbacks, session, user, masterConfig]);
|
|
1181
|
+
const refreshSession = useCallback(async (params) => {
|
|
1182
|
+
if (!client) {
|
|
1183
|
+
throw new ZeroXKeyError("Client is not initialized.", ZeroXKeyErrorCodes.CLIENT_NOT_INITIALIZED);
|
|
1184
|
+
}
|
|
1185
|
+
const activeSessionKey = await client.getActiveSessionKey();
|
|
1186
|
+
if (!activeSessionKey) {
|
|
1187
|
+
throw new ZeroXKeyError("No active session found.", ZeroXKeyErrorCodes.NO_SESSION_FOUND);
|
|
1188
|
+
}
|
|
1189
|
+
const sessionKey = params?.sessionKey ?? activeSessionKey;
|
|
1190
|
+
const res = await withZeroXKeyErrorHandling(() => client.refreshSession({ ...params }), () => logout(), callbacks, "Failed to refresh session");
|
|
1191
|
+
const session = await getSession({ sessionKey });
|
|
1192
|
+
if (session && sessionKey) {
|
|
1193
|
+
await scheduleSessionExpiration({
|
|
1194
|
+
sessionKey,
|
|
1195
|
+
expiry: session.expiry,
|
|
1196
|
+
...(params?.expirationSeconds && {
|
|
1197
|
+
expirationSeconds: params?.expirationSeconds,
|
|
1198
|
+
}),
|
|
1199
|
+
});
|
|
1200
|
+
}
|
|
1201
|
+
const allSessions = await getAllSessions();
|
|
1202
|
+
setSession(session);
|
|
1203
|
+
setAllSessions(allSessions);
|
|
1204
|
+
return res;
|
|
1205
|
+
}, [client, callbacks, scheduleSessionExpiration, session, user, masterConfig]);
|
|
1206
|
+
const getSession = useCallback(async (params) => {
|
|
1207
|
+
if (!client)
|
|
1208
|
+
throw new ZeroXKeyError("Client is not initialized.", ZeroXKeyErrorCodes.CLIENT_NOT_INITIALIZED);
|
|
1209
|
+
return withZeroXKeyErrorHandling(() => client.getSession(params), () => logout(), callbacks, "Failed to get session");
|
|
1210
|
+
}, [client, callbacks, masterConfig, session, user]);
|
|
1211
|
+
const getAllSessions = useCallback(async () => {
|
|
1212
|
+
if (!client)
|
|
1213
|
+
throw new ZeroXKeyError("Client is not initialized.", ZeroXKeyErrorCodes.CLIENT_NOT_INITIALIZED);
|
|
1214
|
+
return withZeroXKeyErrorHandling(() => client.getAllSessions(), () => logout(), callbacks, "Failed to get all sessions");
|
|
1215
|
+
}, [client, callbacks, masterConfig, session, user]);
|
|
1216
|
+
const setActiveSession = useCallback(async (params) => {
|
|
1217
|
+
if (!client)
|
|
1218
|
+
throw new ZeroXKeyError("Client is not initialized.", ZeroXKeyErrorCodes.CLIENT_NOT_INITIALIZED);
|
|
1219
|
+
const session = await withZeroXKeyErrorHandling(() => client.getSession({ sessionKey: params.sessionKey }), () => logout(), callbacks, "Failed to get session");
|
|
1220
|
+
const s = await getSession();
|
|
1221
|
+
if (!s) {
|
|
1222
|
+
throw new ZeroXKeyError("Session not found.", ZeroXKeyErrorCodes.NOT_FOUND);
|
|
1223
|
+
}
|
|
1224
|
+
await withZeroXKeyErrorHandling(() => client.setActiveSession(params), () => logout(), callbacks, "Failed to set active session");
|
|
1225
|
+
setSession(session);
|
|
1226
|
+
await withZeroXKeyErrorHandling(async () => {
|
|
1227
|
+
await maybeRefreshWallets();
|
|
1228
|
+
await maybeRefreshUser();
|
|
1229
|
+
}, () => logout(), callbacks, "Failed to refresh data after setting active session");
|
|
1230
|
+
return;
|
|
1231
|
+
}, [client, callbacks, session, user, masterConfig]);
|
|
1232
|
+
const getActiveSessionKey = useCallback(async () => {
|
|
1233
|
+
if (!client)
|
|
1234
|
+
throw new ZeroXKeyError("Client is not initialized.", ZeroXKeyErrorCodes.CLIENT_NOT_INITIALIZED);
|
|
1235
|
+
return withZeroXKeyErrorHandling(() => client.getActiveSessionKey(), () => logout(), callbacks, "Failed to get active session key");
|
|
1236
|
+
}, [client, callbacks, masterConfig, session, user]);
|
|
1237
|
+
const clearUnusedKeyPairs = useCallback(async () => {
|
|
1238
|
+
if (!client)
|
|
1239
|
+
throw new ZeroXKeyError("Client is not initialized.", ZeroXKeyErrorCodes.CLIENT_NOT_INITIALIZED);
|
|
1240
|
+
return withZeroXKeyErrorHandling(() => client.clearUnusedKeyPairs(), () => logout(), callbacks, "Failed to clear unused key pairs");
|
|
1241
|
+
}, [client, callbacks, masterConfig, session, user]);
|
|
1242
|
+
const createApiKeyPair = useCallback(async (params) => {
|
|
1243
|
+
if (!client)
|
|
1244
|
+
throw new ZeroXKeyError("Client is not initialized.", ZeroXKeyErrorCodes.CLIENT_NOT_INITIALIZED);
|
|
1245
|
+
return withZeroXKeyErrorHandling(() => client.createApiKeyPair(params), () => logout(), callbacks, "Failed to create API key pair");
|
|
1246
|
+
}, [client, callbacks, session, user, masterConfig]);
|
|
1247
|
+
const getProxyAuthConfig = useCallback(async () => {
|
|
1248
|
+
if (!client)
|
|
1249
|
+
throw new ZeroXKeyError("Client is not initialized.", ZeroXKeyErrorCodes.CLIENT_NOT_INITIALIZED);
|
|
1250
|
+
return withZeroXKeyErrorHandling(() => client.getProxyAuthConfig(), () => logout(), callbacks, "Failed to get proxy auth config");
|
|
1251
|
+
}, [client, callbacks, masterConfig, session, user]);
|
|
1252
|
+
const verifyAppProofs = useCallback(async (params) => {
|
|
1253
|
+
if (!client)
|
|
1254
|
+
throw new ZeroXKeyError("Client is not initialized.", ZeroXKeyErrorCodes.CLIENT_NOT_INITIALIZED);
|
|
1255
|
+
return withZeroXKeyErrorHandling(() => client.verifyAppProofs(params), () => logout(), callbacks, "Failed to verify app proofs");
|
|
1256
|
+
}, [client, callbacks]);
|
|
1257
|
+
const refreshUser = useCallback(async (params) => {
|
|
1258
|
+
const { stampWith, organizationId, userId } = params || {};
|
|
1259
|
+
if (!client)
|
|
1260
|
+
throw new ZeroXKeyError("Client is not initialized.", ZeroXKeyErrorCodes.CLIENT_NOT_INITIALIZED);
|
|
1261
|
+
const user = await withZeroXKeyErrorHandling(() => fetchUser({
|
|
1262
|
+
stampWith,
|
|
1263
|
+
...(organizationId && { organizationId }),
|
|
1264
|
+
...(userId && { userId }),
|
|
1265
|
+
}), () => logout(), callbacks, "Failed to refresh user");
|
|
1266
|
+
if (user) {
|
|
1267
|
+
setUser(user);
|
|
1268
|
+
}
|
|
1269
|
+
}, [client, callbacks, fetchUser, session, user]);
|
|
1270
|
+
/**
|
|
1271
|
+
* @internal
|
|
1272
|
+
* Auto-refresh user only if enabled in config. This is only used internally.
|
|
1273
|
+
*
|
|
1274
|
+
* @param params.organizationId - organization ID to specify the sub-organization (defaults to the current session's organizationId).
|
|
1275
|
+
* @param params.userId - user ID to fetch specific user details (defaults to the current session's userId).
|
|
1276
|
+
* @param params.stampWith - parameter to stamp the request with a specific stamper (StamperType.Passkey, StamperType.ApiKey, or StamperType.Wallet).
|
|
1277
|
+
* @returns A promise that resolves when the user is refreshed, or does nothing if auto-refresh is disabled
|
|
1278
|
+
*/
|
|
1279
|
+
const maybeRefreshUser = useCallback(async (params) => {
|
|
1280
|
+
if (!masterConfig?.autoRefreshManagedState)
|
|
1281
|
+
return;
|
|
1282
|
+
return refreshUser(params);
|
|
1283
|
+
}, [masterConfig, refreshUser]);
|
|
1284
|
+
const refreshWallets = useCallback(async (params) => {
|
|
1285
|
+
const { stampWith, organizationId, userId } = params || {};
|
|
1286
|
+
if (!client)
|
|
1287
|
+
throw new ZeroXKeyError("Client is not initialized.", ZeroXKeyErrorCodes.CLIENT_NOT_INITIALIZED);
|
|
1288
|
+
const wallets = await withZeroXKeyErrorHandling(() => fetchWallets({
|
|
1289
|
+
stampWith,
|
|
1290
|
+
...(organizationId && { organizationId }),
|
|
1291
|
+
...(userId && { userId }),
|
|
1292
|
+
}), () => logout(), callbacks, "Failed to refresh wallets");
|
|
1293
|
+
if (wallets) {
|
|
1294
|
+
setWallets(wallets);
|
|
1295
|
+
}
|
|
1296
|
+
return wallets;
|
|
1297
|
+
}, [client, callbacks, fetchWallets, session, user]);
|
|
1298
|
+
/**
|
|
1299
|
+
* @internal
|
|
1300
|
+
* Auto-refresh wallets only if enabled in config. This is only used internally.
|
|
1301
|
+
*
|
|
1302
|
+
* @param params.organizationId - organization ID to specify the sub-organization (defaults to the current session's organizationId).
|
|
1303
|
+
* @param params.userId - user ID to fetch specific user details (defaults to the current session's userId).
|
|
1304
|
+
* @param params.stampWith - parameter to stamp the request with a specific stamper (StamperType.Passkey, StamperType.ApiKey, or StamperType.Wallet).
|
|
1305
|
+
* @returns A promise that resolves to an array of wallets, or an empty array if auto-refresh is disabled
|
|
1306
|
+
*/
|
|
1307
|
+
const maybeRefreshWallets = useCallback(async (params) => {
|
|
1308
|
+
if (!masterConfig?.autoRefreshManagedState)
|
|
1309
|
+
return [];
|
|
1310
|
+
return refreshWallets(params);
|
|
1311
|
+
}, [masterConfig, refreshWallets]);
|
|
1312
|
+
const handleDiscordOauth = useCallback(async (params) => {
|
|
1313
|
+
const { additionalState: additionalParameters } = params || {};
|
|
1314
|
+
const { clientId, redirectUri, appScheme: scheme, } = getOauthProviderSettings(OAuthProviders.DISCORD);
|
|
1315
|
+
try {
|
|
1316
|
+
if (!masterConfig) {
|
|
1317
|
+
throw new ZeroXKeyError("Config is not ready yet!", ZeroXKeyErrorCodes.INVALID_CONFIGURATION);
|
|
1318
|
+
}
|
|
1319
|
+
if (!clientId) {
|
|
1320
|
+
throw new ZeroXKeyError("Discord Client ID is not configured.", ZeroXKeyErrorCodes.INVALID_CONFIGURATION);
|
|
1321
|
+
}
|
|
1322
|
+
if (!redirectUri) {
|
|
1323
|
+
throw new ZeroXKeyError("OAuth Redirect URI is not configured.", ZeroXKeyErrorCodes.INVALID_CONFIGURATION);
|
|
1324
|
+
}
|
|
1325
|
+
if (!scheme) {
|
|
1326
|
+
throw new ZeroXKeyError("Missing appScheme. Please set auth.oauth.appScheme.", ZeroXKeyErrorCodes.INVALID_CONFIGURATION);
|
|
1327
|
+
}
|
|
1328
|
+
// Create key pair and generate nonce
|
|
1329
|
+
const publicKey = await createApiKeyPair();
|
|
1330
|
+
if (!publicKey) {
|
|
1331
|
+
throw new ZeroXKeyError("Failed to create public key for OAuth.", ZeroXKeyErrorCodes.OAUTH_SIGNUP_ERROR);
|
|
1332
|
+
}
|
|
1333
|
+
const nonce = bytesToHex(sha256(publicKey));
|
|
1334
|
+
// Generate PKCE challenge pair and store verifier
|
|
1335
|
+
const { verifier, codeChallenge } = await generateChallengePair();
|
|
1336
|
+
await storePKCEVerifier(OAuthProviders.DISCORD, verifier);
|
|
1337
|
+
// Build OAuth URL (direct Discord URL, not proxy)
|
|
1338
|
+
const discordAuthUrl = buildOAuthUrl({
|
|
1339
|
+
provider: OAuthProviders.DISCORD,
|
|
1340
|
+
clientId,
|
|
1341
|
+
redirectUri,
|
|
1342
|
+
publicKey,
|
|
1343
|
+
nonce,
|
|
1344
|
+
codeChallenge,
|
|
1345
|
+
additionalState: additionalParameters,
|
|
1346
|
+
useOauthProxyOrigin: false,
|
|
1347
|
+
});
|
|
1348
|
+
if (!(await InAppBrowser.isAvailable())) {
|
|
1349
|
+
throw new ZeroXKeyError("InAppBrowser is not available", ZeroXKeyErrorCodes.INVALID_CONFIGURATION);
|
|
1350
|
+
}
|
|
1351
|
+
const result = await InAppBrowser.openAuth(discordAuthUrl, scheme, {
|
|
1352
|
+
dismissButtonStyle: "cancel",
|
|
1353
|
+
animated: true,
|
|
1354
|
+
modalPresentationStyle: "fullScreen",
|
|
1355
|
+
modalTransitionStyle: "coverVertical",
|
|
1356
|
+
modalEnabled: true,
|
|
1357
|
+
enableBarCollapsing: false,
|
|
1358
|
+
showTitle: true,
|
|
1359
|
+
enableUrlBarHiding: true,
|
|
1360
|
+
enableDefaultShare: true,
|
|
1361
|
+
});
|
|
1362
|
+
if (!result || result.type !== "success" || !result.url) {
|
|
1363
|
+
throw new ZeroXKeyError("OAuth flow did not complete successfully", ZeroXKeyErrorCodes.OAUTH_SIGNUP_ERROR);
|
|
1364
|
+
}
|
|
1365
|
+
// Parse the deep link result
|
|
1366
|
+
const parsed = parseInAppBrowserResult(result.url);
|
|
1367
|
+
if (!parsed.authCode) {
|
|
1368
|
+
throw new ZeroXKeyError("Missing authorization code from Discord OAuth", ZeroXKeyErrorCodes.OAUTH_SIGNUP_ERROR);
|
|
1369
|
+
}
|
|
1370
|
+
// Handle PKCE flow: exchange code for token and complete
|
|
1371
|
+
await handlePKCEFlow({
|
|
1372
|
+
provider: OAuthProviders.DISCORD,
|
|
1373
|
+
publicKey,
|
|
1374
|
+
authCode: parsed.authCode,
|
|
1375
|
+
...(parsed.sessionKey && { sessionKey: parsed.sessionKey }),
|
|
1376
|
+
...(callbacks && { callbacks }),
|
|
1377
|
+
completeOauth,
|
|
1378
|
+
exchangeCodeForToken: async (codeVerifier) => {
|
|
1379
|
+
const resp = await client?.httpClient?.proxyOAuth2Authenticate({
|
|
1380
|
+
provider: "OAUTH2_PROVIDER_DISCORD",
|
|
1381
|
+
authCode: parsed.authCode,
|
|
1382
|
+
redirectUri,
|
|
1383
|
+
codeVerifier,
|
|
1384
|
+
clientId,
|
|
1385
|
+
nonce,
|
|
1386
|
+
});
|
|
1387
|
+
const oidcToken = resp?.oidcToken;
|
|
1388
|
+
if (!oidcToken) {
|
|
1389
|
+
throw new ZeroXKeyError("Missing oidcToken from OAuth exchange", ZeroXKeyErrorCodes.OAUTH_SIGNUP_ERROR);
|
|
1390
|
+
}
|
|
1391
|
+
return oidcToken;
|
|
1392
|
+
},
|
|
1393
|
+
});
|
|
1394
|
+
return;
|
|
1395
|
+
}
|
|
1396
|
+
catch (error) {
|
|
1397
|
+
throw error;
|
|
1398
|
+
}
|
|
1399
|
+
}, [client, callbacks, masterConfig, session, user]);
|
|
1400
|
+
const handleXOauth = useCallback(async (params) => {
|
|
1401
|
+
const { additionalState: additionalParameters } = params || {};
|
|
1402
|
+
const { clientId, redirectUri, appScheme: scheme, } = getOauthProviderSettings(OAuthProviders.X);
|
|
1403
|
+
try {
|
|
1404
|
+
if (!masterConfig) {
|
|
1405
|
+
throw new ZeroXKeyError("Config is not ready yet!", ZeroXKeyErrorCodes.INVALID_CONFIGURATION);
|
|
1406
|
+
}
|
|
1407
|
+
if (!clientId) {
|
|
1408
|
+
throw new ZeroXKeyError("Twitter Client ID is not configured.", ZeroXKeyErrorCodes.INVALID_CONFIGURATION);
|
|
1409
|
+
}
|
|
1410
|
+
if (!redirectUri) {
|
|
1411
|
+
throw new ZeroXKeyError("OAuth Redirect URI is not configured.", ZeroXKeyErrorCodes.INVALID_CONFIGURATION);
|
|
1412
|
+
}
|
|
1413
|
+
if (!scheme) {
|
|
1414
|
+
throw new ZeroXKeyError("Missing appScheme. Please set auth.oauth.appScheme.", ZeroXKeyErrorCodes.INVALID_CONFIGURATION);
|
|
1415
|
+
}
|
|
1416
|
+
const publicKey = await createApiKeyPair();
|
|
1417
|
+
if (!publicKey) {
|
|
1418
|
+
throw new ZeroXKeyError("Failed to create public key for OAuth.", ZeroXKeyErrorCodes.OAUTH_SIGNUP_ERROR);
|
|
1419
|
+
}
|
|
1420
|
+
const nonce = bytesToHex(sha256(publicKey));
|
|
1421
|
+
// Generate PKCE challenge pair and store verifier
|
|
1422
|
+
const { verifier, codeChallenge } = await generateChallengePair();
|
|
1423
|
+
await storePKCEVerifier(OAuthProviders.X, verifier);
|
|
1424
|
+
// Build OAuth URL (direct X/Twitter URL, not proxy)
|
|
1425
|
+
const twitterAuthUrl = buildOAuthUrl({
|
|
1426
|
+
provider: OAuthProviders.X,
|
|
1427
|
+
clientId,
|
|
1428
|
+
redirectUri,
|
|
1429
|
+
publicKey,
|
|
1430
|
+
nonce,
|
|
1431
|
+
codeChallenge,
|
|
1432
|
+
additionalState: additionalParameters,
|
|
1433
|
+
useOauthProxyOrigin: false,
|
|
1434
|
+
});
|
|
1435
|
+
if (!(await InAppBrowser.isAvailable())) {
|
|
1436
|
+
throw new ZeroXKeyError("InAppBrowser is not available", ZeroXKeyErrorCodes.INVALID_CONFIGURATION);
|
|
1437
|
+
}
|
|
1438
|
+
const result = await InAppBrowser.openAuth(twitterAuthUrl, scheme, {
|
|
1439
|
+
dismissButtonStyle: "cancel",
|
|
1440
|
+
animated: true,
|
|
1441
|
+
modalPresentationStyle: "fullScreen",
|
|
1442
|
+
modalTransitionStyle: "coverVertical",
|
|
1443
|
+
modalEnabled: true,
|
|
1444
|
+
enableBarCollapsing: false,
|
|
1445
|
+
showTitle: true,
|
|
1446
|
+
enableUrlBarHiding: true,
|
|
1447
|
+
enableDefaultShare: true,
|
|
1448
|
+
});
|
|
1449
|
+
if (!result || result.type !== "success" || !result.url) {
|
|
1450
|
+
throw new ZeroXKeyError("OAuth flow did not complete successfully", ZeroXKeyErrorCodes.OAUTH_SIGNUP_ERROR);
|
|
1451
|
+
}
|
|
1452
|
+
// Parse the deep link result
|
|
1453
|
+
const parsed = parseInAppBrowserResult(result.url);
|
|
1454
|
+
if (!parsed.authCode) {
|
|
1455
|
+
throw new ZeroXKeyError("Missing authorization code from Twitter OAuth", ZeroXKeyErrorCodes.OAUTH_SIGNUP_ERROR);
|
|
1456
|
+
}
|
|
1457
|
+
// Handle PKCE flow: exchange code for token and complete
|
|
1458
|
+
await handlePKCEFlow({
|
|
1459
|
+
provider: OAuthProviders.X,
|
|
1460
|
+
publicKey,
|
|
1461
|
+
authCode: parsed.authCode,
|
|
1462
|
+
...(parsed.sessionKey && { sessionKey: parsed.sessionKey }),
|
|
1463
|
+
...(callbacks && { callbacks }),
|
|
1464
|
+
completeOauth,
|
|
1465
|
+
exchangeCodeForToken: async (codeVerifier) => {
|
|
1466
|
+
const resp = await client?.httpClient?.proxyOAuth2Authenticate({
|
|
1467
|
+
provider: "OAUTH2_PROVIDER_X",
|
|
1468
|
+
authCode: parsed.authCode,
|
|
1469
|
+
redirectUri,
|
|
1470
|
+
codeVerifier,
|
|
1471
|
+
clientId,
|
|
1472
|
+
nonce,
|
|
1473
|
+
});
|
|
1474
|
+
const oidcToken = resp?.oidcToken;
|
|
1475
|
+
if (!oidcToken) {
|
|
1476
|
+
throw new ZeroXKeyError("Missing oidcToken from OAuth exchange", ZeroXKeyErrorCodes.OAUTH_SIGNUP_ERROR);
|
|
1477
|
+
}
|
|
1478
|
+
return oidcToken;
|
|
1479
|
+
},
|
|
1480
|
+
});
|
|
1481
|
+
return;
|
|
1482
|
+
}
|
|
1483
|
+
catch (error) {
|
|
1484
|
+
throw error;
|
|
1485
|
+
}
|
|
1486
|
+
}, [client, callbacks, masterConfig, session, user]);
|
|
1487
|
+
const handleGoogleOauth = useCallback(async (params) => {
|
|
1488
|
+
const { clientId, redirectUri, appScheme: scheme, } = getOauthProviderSettings(OAuthProviders.GOOGLE);
|
|
1489
|
+
try {
|
|
1490
|
+
if (!masterConfig) {
|
|
1491
|
+
throw new ZeroXKeyError("Config is not ready yet!", ZeroXKeyErrorCodes.INVALID_CONFIGURATION);
|
|
1492
|
+
}
|
|
1493
|
+
if (!clientId) {
|
|
1494
|
+
throw new ZeroXKeyError("Google Client ID is not configured.", ZeroXKeyErrorCodes.INVALID_CONFIGURATION);
|
|
1495
|
+
}
|
|
1496
|
+
if (!redirectUri) {
|
|
1497
|
+
throw new ZeroXKeyError("OAuth Redirect URI is not configured.", ZeroXKeyErrorCodes.INVALID_CONFIGURATION);
|
|
1498
|
+
}
|
|
1499
|
+
if (!scheme) {
|
|
1500
|
+
throw new ZeroXKeyError("Missing appScheme. Please set auth.oauth.appScheme.", ZeroXKeyErrorCodes.INVALID_CONFIGURATION);
|
|
1501
|
+
}
|
|
1502
|
+
const finalRedirectUri = `${redirectUri}?scheme=${encodeURIComponent(scheme)}`;
|
|
1503
|
+
// Create key pair and generate nonce
|
|
1504
|
+
const publicKey = await createApiKeyPair();
|
|
1505
|
+
if (!publicKey) {
|
|
1506
|
+
throw new ZeroXKeyError("Failed to create public key for OAuth.", ZeroXKeyErrorCodes.OAUTH_SIGNUP_ERROR);
|
|
1507
|
+
}
|
|
1508
|
+
const nonce = bytesToHex(sha256(publicKey));
|
|
1509
|
+
// Build OAuth URL using ZeroXKey OAuth proxy
|
|
1510
|
+
const oauthUrl = buildOAuthUrl({
|
|
1511
|
+
provider: OAuthProviders.GOOGLE,
|
|
1512
|
+
clientId,
|
|
1513
|
+
redirectUri: finalRedirectUri,
|
|
1514
|
+
publicKey,
|
|
1515
|
+
nonce,
|
|
1516
|
+
useOauthProxyOrigin: true,
|
|
1517
|
+
});
|
|
1518
|
+
if (!(await InAppBrowser.isAvailable())) {
|
|
1519
|
+
throw new ZeroXKeyError("InAppBrowser is not available", ZeroXKeyErrorCodes.INVALID_CONFIGURATION);
|
|
1520
|
+
}
|
|
1521
|
+
const result = await InAppBrowser.openAuth(oauthUrl, scheme, {
|
|
1522
|
+
dismissButtonStyle: "cancel",
|
|
1523
|
+
animated: true,
|
|
1524
|
+
modalPresentationStyle: "fullScreen",
|
|
1525
|
+
modalTransitionStyle: "coverVertical",
|
|
1526
|
+
modalEnabled: true,
|
|
1527
|
+
enableBarCollapsing: false,
|
|
1528
|
+
showTitle: true,
|
|
1529
|
+
enableUrlBarHiding: true,
|
|
1530
|
+
enableDefaultShare: true,
|
|
1531
|
+
});
|
|
1532
|
+
if (!result || result.type !== "success" || !result.url) {
|
|
1533
|
+
throw new ZeroXKeyError("OAuth flow did not complete successfully", ZeroXKeyErrorCodes.OAUTH_SIGNUP_ERROR);
|
|
1534
|
+
}
|
|
1535
|
+
// Parse the deep link result
|
|
1536
|
+
const parsed = parseInAppBrowserResult(result.url);
|
|
1537
|
+
if (!parsed.idToken) {
|
|
1538
|
+
throw new ZeroXKeyError("oidcToken not found in the response", ZeroXKeyErrorCodes.OAUTH_SIGNUP_ERROR);
|
|
1539
|
+
}
|
|
1540
|
+
// Complete OAuth flow
|
|
1541
|
+
await completeOAuthFlow({
|
|
1542
|
+
provider: OAuthProviders.GOOGLE,
|
|
1543
|
+
publicKey,
|
|
1544
|
+
oidcToken: parsed.idToken,
|
|
1545
|
+
...(parsed.sessionKey && { sessionKey: parsed.sessionKey }),
|
|
1546
|
+
...(callbacks && { callbacks }),
|
|
1547
|
+
completeOauth,
|
|
1548
|
+
});
|
|
1549
|
+
return;
|
|
1550
|
+
}
|
|
1551
|
+
catch (error) {
|
|
1552
|
+
throw error;
|
|
1553
|
+
}
|
|
1554
|
+
}, [client, callbacks, masterConfig, session, user]);
|
|
1555
|
+
const handleAppleOauth = useCallback(async (params) => {
|
|
1556
|
+
const { additionalState: additionalParameters } = params || {};
|
|
1557
|
+
const { clientId, redirectUri, appScheme: scheme, } = getOauthProviderSettings(OAuthProviders.APPLE);
|
|
1558
|
+
try {
|
|
1559
|
+
if (!masterConfig) {
|
|
1560
|
+
throw new ZeroXKeyError("Config is not ready yet!", ZeroXKeyErrorCodes.INVALID_CONFIGURATION);
|
|
1561
|
+
}
|
|
1562
|
+
if (!clientId) {
|
|
1563
|
+
throw new ZeroXKeyError("Apple Client ID is not configured.", ZeroXKeyErrorCodes.INVALID_CONFIGURATION);
|
|
1564
|
+
}
|
|
1565
|
+
if (!redirectUri) {
|
|
1566
|
+
throw new ZeroXKeyError("OAuth Redirect URI is not configured.", ZeroXKeyErrorCodes.INVALID_CONFIGURATION);
|
|
1567
|
+
}
|
|
1568
|
+
if (!scheme) {
|
|
1569
|
+
throw new ZeroXKeyError("Missing appScheme. Please set auth.oauth.appScheme.", ZeroXKeyErrorCodes.INVALID_CONFIGURATION);
|
|
1570
|
+
}
|
|
1571
|
+
const finalRedirectUri = `${redirectUri}?scheme=${encodeURIComponent(scheme)}`;
|
|
1572
|
+
// Create key pair and generate nonce
|
|
1573
|
+
const publicKey = await createApiKeyPair();
|
|
1574
|
+
if (!publicKey) {
|
|
1575
|
+
throw new ZeroXKeyError("Failed to create public key for OAuth.", ZeroXKeyErrorCodes.OAUTH_SIGNUP_ERROR);
|
|
1576
|
+
}
|
|
1577
|
+
const nonce = bytesToHex(sha256(publicKey));
|
|
1578
|
+
// Build OAuth URL using ZeroXKey OAuth proxy
|
|
1579
|
+
const oauthUrl = buildOAuthUrl({
|
|
1580
|
+
provider: OAuthProviders.APPLE,
|
|
1581
|
+
clientId,
|
|
1582
|
+
redirectUri: finalRedirectUri,
|
|
1583
|
+
publicKey,
|
|
1584
|
+
nonce,
|
|
1585
|
+
additionalState: additionalParameters,
|
|
1586
|
+
useOauthProxyOrigin: true,
|
|
1587
|
+
});
|
|
1588
|
+
if (!(await InAppBrowser.isAvailable())) {
|
|
1589
|
+
throw new ZeroXKeyError("InAppBrowser is not available", ZeroXKeyErrorCodes.INVALID_CONFIGURATION);
|
|
1590
|
+
}
|
|
1591
|
+
const result = await InAppBrowser.openAuth(oauthUrl, scheme, {
|
|
1592
|
+
dismissButtonStyle: "cancel",
|
|
1593
|
+
animated: true,
|
|
1594
|
+
modalPresentationStyle: "fullScreen",
|
|
1595
|
+
modalTransitionStyle: "coverVertical",
|
|
1596
|
+
modalEnabled: true,
|
|
1597
|
+
enableBarCollapsing: false,
|
|
1598
|
+
showTitle: true,
|
|
1599
|
+
enableUrlBarHiding: true,
|
|
1600
|
+
enableDefaultShare: true,
|
|
1601
|
+
});
|
|
1602
|
+
if (!result || result.type !== "success" || !result.url) {
|
|
1603
|
+
throw new ZeroXKeyError("OAuth flow did not complete successfully", ZeroXKeyErrorCodes.OAUTH_SIGNUP_ERROR);
|
|
1604
|
+
}
|
|
1605
|
+
// Parse the deep link result
|
|
1606
|
+
const parsed = parseInAppBrowserResult(result.url);
|
|
1607
|
+
if (!parsed.idToken) {
|
|
1608
|
+
throw new ZeroXKeyError("oidcToken not found in the response", ZeroXKeyErrorCodes.OAUTH_SIGNUP_ERROR);
|
|
1609
|
+
}
|
|
1610
|
+
// Complete OAuth flow
|
|
1611
|
+
await completeOAuthFlow({
|
|
1612
|
+
provider: OAuthProviders.APPLE,
|
|
1613
|
+
publicKey,
|
|
1614
|
+
oidcToken: parsed.idToken,
|
|
1615
|
+
...(parsed.sessionKey && { sessionKey: parsed.sessionKey }),
|
|
1616
|
+
...(callbacks && { callbacks }),
|
|
1617
|
+
completeOauth,
|
|
1618
|
+
});
|
|
1619
|
+
return;
|
|
1620
|
+
}
|
|
1621
|
+
catch (error) {
|
|
1622
|
+
throw error;
|
|
1623
|
+
}
|
|
1624
|
+
}, [client, callbacks, masterConfig, session, user]);
|
|
1625
|
+
const handleFacebookOauth = useCallback(async (params) => {
|
|
1626
|
+
const { additionalState: additionalParameters } = params || {};
|
|
1627
|
+
const { clientId, redirectUri, appScheme: scheme, } = getOauthProviderSettings(OAuthProviders.FACEBOOK);
|
|
1628
|
+
try {
|
|
1629
|
+
if (!masterConfig) {
|
|
1630
|
+
throw new ZeroXKeyError("Config is not ready yet!", ZeroXKeyErrorCodes.INVALID_CONFIGURATION);
|
|
1631
|
+
}
|
|
1632
|
+
if (!clientId) {
|
|
1633
|
+
throw new ZeroXKeyError("Facebook Client ID is not configured.", ZeroXKeyErrorCodes.INVALID_CONFIGURATION);
|
|
1634
|
+
}
|
|
1635
|
+
if (!redirectUri) {
|
|
1636
|
+
throw new ZeroXKeyError("OAuth Redirect URI is not configured.", ZeroXKeyErrorCodes.INVALID_CONFIGURATION);
|
|
1637
|
+
}
|
|
1638
|
+
if (!scheme) {
|
|
1639
|
+
throw new ZeroXKeyError("Missing appScheme. Please set auth.oauth.appScheme.", ZeroXKeyErrorCodes.INVALID_CONFIGURATION);
|
|
1640
|
+
}
|
|
1641
|
+
const finalRedirectUri = `${redirectUri}?scheme=${encodeURIComponent(scheme)}`;
|
|
1642
|
+
// Create key pair and generate nonce
|
|
1643
|
+
const publicKey = await createApiKeyPair();
|
|
1644
|
+
if (!publicKey) {
|
|
1645
|
+
throw new ZeroXKeyError("Failed to create public key for OAuth.", ZeroXKeyErrorCodes.OAUTH_SIGNUP_ERROR);
|
|
1646
|
+
}
|
|
1647
|
+
const nonce = bytesToHex(sha256(publicKey));
|
|
1648
|
+
// Generate PKCE challenge pair and store verifier
|
|
1649
|
+
const { verifier, codeChallenge } = await generateChallengePair();
|
|
1650
|
+
await storePKCEVerifier(OAuthProviders.FACEBOOK, verifier);
|
|
1651
|
+
// Build OAuth URL using ZeroXKey OAuth proxy
|
|
1652
|
+
const oauthUrl = buildOAuthUrl({
|
|
1653
|
+
provider: OAuthProviders.FACEBOOK,
|
|
1654
|
+
clientId,
|
|
1655
|
+
redirectUri: finalRedirectUri,
|
|
1656
|
+
publicKey,
|
|
1657
|
+
nonce,
|
|
1658
|
+
codeChallenge,
|
|
1659
|
+
additionalState: additionalParameters,
|
|
1660
|
+
useOauthProxyOrigin: true,
|
|
1661
|
+
});
|
|
1662
|
+
if (!(await InAppBrowser.isAvailable())) {
|
|
1663
|
+
throw new ZeroXKeyError("InAppBrowser is not available", ZeroXKeyErrorCodes.INVALID_CONFIGURATION);
|
|
1664
|
+
}
|
|
1665
|
+
const result = await InAppBrowser.openAuth(oauthUrl, scheme, {
|
|
1666
|
+
dismissButtonStyle: "cancel",
|
|
1667
|
+
animated: true,
|
|
1668
|
+
modalPresentationStyle: "fullScreen",
|
|
1669
|
+
modalTransitionStyle: "coverVertical",
|
|
1670
|
+
modalEnabled: true,
|
|
1671
|
+
enableBarCollapsing: false,
|
|
1672
|
+
showTitle: true,
|
|
1673
|
+
enableUrlBarHiding: true,
|
|
1674
|
+
enableDefaultShare: true,
|
|
1675
|
+
});
|
|
1676
|
+
if (!result || result.type !== "success" || !result.url) {
|
|
1677
|
+
throw new ZeroXKeyError("OAuth flow did not complete successfully", ZeroXKeyErrorCodes.OAUTH_SIGNUP_ERROR);
|
|
1678
|
+
}
|
|
1679
|
+
// Parse the deep link result
|
|
1680
|
+
const parsed = parseInAppBrowserResult(result.url);
|
|
1681
|
+
if (!parsed.authCode) {
|
|
1682
|
+
throw new ZeroXKeyError("Missing authorization code from Facebook OAuth", ZeroXKeyErrorCodes.OAUTH_SIGNUP_ERROR);
|
|
1683
|
+
}
|
|
1684
|
+
// Handle PKCE flow: exchange code for token and complete
|
|
1685
|
+
await handlePKCEFlow({
|
|
1686
|
+
provider: OAuthProviders.FACEBOOK,
|
|
1687
|
+
publicKey,
|
|
1688
|
+
authCode: parsed.authCode,
|
|
1689
|
+
...(parsed.sessionKey && { sessionKey: parsed.sessionKey }),
|
|
1690
|
+
...(callbacks && { callbacks }),
|
|
1691
|
+
completeOauth,
|
|
1692
|
+
exchangeCodeForToken: async (codeVerifier) => {
|
|
1693
|
+
const tokenData = await exchangeCodeForToken(clientId, finalRedirectUri, parsed.authCode, codeVerifier);
|
|
1694
|
+
const idToken = tokenData?.id_token;
|
|
1695
|
+
if (!idToken) {
|
|
1696
|
+
throw new ZeroXKeyError("Missing oidcToken from OAuth exchange", ZeroXKeyErrorCodes.OAUTH_SIGNUP_ERROR);
|
|
1697
|
+
}
|
|
1698
|
+
return idToken;
|
|
1699
|
+
},
|
|
1700
|
+
});
|
|
1701
|
+
return;
|
|
1702
|
+
}
|
|
1703
|
+
catch (error) {
|
|
1704
|
+
throw error;
|
|
1705
|
+
}
|
|
1706
|
+
}, [client, callbacks, masterConfig, session, user]);
|
|
1707
|
+
useEffect(() => {
|
|
1708
|
+
if (proxyAuthConfigRef.current)
|
|
1709
|
+
return;
|
|
1710
|
+
// Only fetch the proxy auth config once. Use that to build the master config.
|
|
1711
|
+
const fetchProxyAuthConfig = async () => {
|
|
1712
|
+
try {
|
|
1713
|
+
let proxyAuthConfig;
|
|
1714
|
+
if (shouldFetchWalletKitConfig) {
|
|
1715
|
+
// Only fetch the proxy auth config if we have an authProxyId and the autoFetchWalletKitConfig param is enabled or not passed in.
|
|
1716
|
+
const sanitizedAuthProxyUrl = config.authProxyUrl && config.authProxyUrl.trim()
|
|
1717
|
+
? config.authProxyUrl
|
|
1718
|
+
: undefined;
|
|
1719
|
+
proxyAuthConfig = await getAuthProxyConfig(config.authProxyConfigId, // Can assert safely. See shouldFetchWalletKitConfig definition.
|
|
1720
|
+
sanitizedAuthProxyUrl);
|
|
1721
|
+
proxyAuthConfigRef.current = proxyAuthConfig;
|
|
1722
|
+
}
|
|
1723
|
+
setMasterConfig(buildConfig(proxyAuthConfig));
|
|
1724
|
+
}
|
|
1725
|
+
catch {
|
|
1726
|
+
setClientState(ClientState.Error);
|
|
1727
|
+
}
|
|
1728
|
+
};
|
|
1729
|
+
fetchProxyAuthConfig();
|
|
1730
|
+
}, []);
|
|
1731
|
+
useEffect(() => {
|
|
1732
|
+
// Start the client initialization process once we have the master config.
|
|
1733
|
+
if (!masterConfig)
|
|
1734
|
+
return;
|
|
1735
|
+
initializeClient();
|
|
1736
|
+
}, [masterConfig]);
|
|
1737
|
+
useEffect(() => {
|
|
1738
|
+
// Handle changes to the passed in config prop -- update the master config
|
|
1739
|
+
// Rebuild the master config with the updated config and stored proxyAuthConfig
|
|
1740
|
+
// If we don't have a stored proxyAuthConfig and we need to fetch it, we wait until that fetch is done in the other useEffect.
|
|
1741
|
+
// If shouldFetchWalletKitConfig is false, we'll never have a proxyAuthConfig to build the master config with, so this useEffect should always run.
|
|
1742
|
+
if (!proxyAuthConfigRef.current && shouldFetchWalletKitConfig)
|
|
1743
|
+
return;
|
|
1744
|
+
setMasterConfig(buildConfig(proxyAuthConfigRef.current ?? undefined));
|
|
1745
|
+
}, [config, proxyAuthConfigRef.current]);
|
|
1746
|
+
useEffect(() => {
|
|
1747
|
+
// authState must be consistent with session state. We found during testing that there are cases where the session and authState can be out of sync in very rare edge cases.
|
|
1748
|
+
// This will ensure that they are always in sync and remove the need to setAuthState manually in other places.
|
|
1749
|
+
if (session && isValidSession(session)) {
|
|
1750
|
+
setAuthState(AuthState.Authenticated);
|
|
1751
|
+
}
|
|
1752
|
+
else {
|
|
1753
|
+
setAuthState(AuthState.Unauthenticated);
|
|
1754
|
+
}
|
|
1755
|
+
}, [session]);
|
|
1756
|
+
useEffect(() => {
|
|
1757
|
+
// After client and config are ready, initialize sessions then mark client ready.
|
|
1758
|
+
if (!client || !masterConfig)
|
|
1759
|
+
return;
|
|
1760
|
+
clearSessionTimeouts();
|
|
1761
|
+
initializeSessions().finally(() => {
|
|
1762
|
+
setClientState(ClientState.Ready);
|
|
1763
|
+
});
|
|
1764
|
+
return () => {
|
|
1765
|
+
clearSessionTimeouts();
|
|
1766
|
+
};
|
|
1767
|
+
}, [client]);
|
|
1768
|
+
return (jsx(ClientContext.Provider, { value: {
|
|
1769
|
+
session,
|
|
1770
|
+
allSessions,
|
|
1771
|
+
clientState,
|
|
1772
|
+
authState,
|
|
1773
|
+
user,
|
|
1774
|
+
wallets,
|
|
1775
|
+
config: masterConfig,
|
|
1776
|
+
httpClient: client?.httpClient,
|
|
1777
|
+
createHttpClient,
|
|
1778
|
+
createPasskey,
|
|
1779
|
+
logout,
|
|
1780
|
+
loginWithPasskey,
|
|
1781
|
+
signUpWithPasskey,
|
|
1782
|
+
initOtp,
|
|
1783
|
+
verifyOtp,
|
|
1784
|
+
loginWithOtp,
|
|
1785
|
+
signUpWithOtp,
|
|
1786
|
+
completeOtp,
|
|
1787
|
+
loginWithOauth,
|
|
1788
|
+
signUpWithOauth,
|
|
1789
|
+
completeOauth,
|
|
1790
|
+
fetchWallets,
|
|
1791
|
+
fetchWalletAccounts,
|
|
1792
|
+
fetchPrivateKeys,
|
|
1793
|
+
verifyAppProofs,
|
|
1794
|
+
refreshWallets,
|
|
1795
|
+
signMessage,
|
|
1796
|
+
signTransaction,
|
|
1797
|
+
signAndSendTransaction,
|
|
1798
|
+
ethSendTransaction,
|
|
1799
|
+
ethSendErc20Transfer,
|
|
1800
|
+
solSendTransaction,
|
|
1801
|
+
pollTransactionStatus,
|
|
1802
|
+
fetchUser,
|
|
1803
|
+
fetchOrCreateP256ApiKeyUser,
|
|
1804
|
+
fetchOrCreatePolicies,
|
|
1805
|
+
refreshUser,
|
|
1806
|
+
updateUserEmail,
|
|
1807
|
+
removeUserEmail,
|
|
1808
|
+
updateUserPhoneNumber,
|
|
1809
|
+
removeUserPhoneNumber,
|
|
1810
|
+
updateUserName,
|
|
1811
|
+
addOauthProvider,
|
|
1812
|
+
removeOauthProviders,
|
|
1813
|
+
addPasskey,
|
|
1814
|
+
removePasskeys,
|
|
1815
|
+
createWallet,
|
|
1816
|
+
createWalletAccounts,
|
|
1817
|
+
exportWallet,
|
|
1818
|
+
exportPrivateKey,
|
|
1819
|
+
exportWalletAccount,
|
|
1820
|
+
importWallet,
|
|
1821
|
+
importPrivateKey,
|
|
1822
|
+
deleteSubOrganization,
|
|
1823
|
+
storeSession,
|
|
1824
|
+
clearSession,
|
|
1825
|
+
clearAllSessions,
|
|
1826
|
+
refreshSession,
|
|
1827
|
+
getSession,
|
|
1828
|
+
getAllSessions,
|
|
1829
|
+
setActiveSession,
|
|
1830
|
+
clearUnusedKeyPairs,
|
|
1831
|
+
getActiveSessionKey,
|
|
1832
|
+
createApiKeyPair,
|
|
1833
|
+
getProxyAuthConfig,
|
|
1834
|
+
handleGoogleOauth,
|
|
1835
|
+
handleXOauth,
|
|
1836
|
+
handleDiscordOauth,
|
|
1837
|
+
handleAppleOauth,
|
|
1838
|
+
handleFacebookOauth,
|
|
1839
|
+
fetchBootProofForAppProof,
|
|
1840
|
+
}, children: children }));
|
|
1841
|
+
};
|
|
1842
|
+
|
|
1843
|
+
export { ZeroXKeyProvider };
|
|
1844
|
+
//# sourceMappingURL=ZeroXKeyProvider.mjs.map
|