@turnkey/react-wallet-kit 1.0.0-beta.5 → 1.0.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/README.MD +5 -2
- package/dist/_virtual/_rollupPluginBabelHelpers.mjs +49 -1
- package/dist/_virtual/_rollupPluginBabelHelpers.mjs.map +1 -1
- package/dist/components/auth/Email.d.ts.map +1 -1
- package/dist/components/auth/Email.js +3 -0
- package/dist/components/auth/Email.js.map +1 -1
- package/dist/components/auth/Email.mjs +3 -0
- package/dist/components/auth/Email.mjs.map +1 -1
- package/dist/components/auth/OAuth.d.ts.map +1 -1
- package/dist/components/auth/OAuth.js +1 -0
- package/dist/components/auth/OAuth.js.map +1 -1
- package/dist/components/auth/OAuth.mjs +1 -0
- package/dist/components/auth/OAuth.mjs.map +1 -1
- package/dist/components/auth/OTP.d.ts +1 -0
- package/dist/components/auth/OTP.d.ts.map +1 -1
- package/dist/components/auth/OTP.js +5 -1
- package/dist/components/auth/OTP.js.map +1 -1
- package/dist/components/auth/OTP.mjs +6 -3
- package/dist/components/auth/OTP.mjs.map +1 -1
- package/dist/components/auth/Passkey.d.ts.map +1 -1
- package/dist/components/auth/Passkey.js +2 -0
- package/dist/components/auth/Passkey.js.map +1 -1
- package/dist/components/auth/Passkey.mjs +2 -0
- package/dist/components/auth/Passkey.mjs.map +1 -1
- package/dist/components/auth/Wallet.d.ts +4 -4
- package/dist/components/auth/Wallet.d.ts.map +1 -1
- package/dist/components/auth/Wallet.js +72 -50
- package/dist/components/auth/Wallet.js.map +1 -1
- package/dist/components/auth/Wallet.mjs +78 -57
- package/dist/components/auth/Wallet.mjs.map +1 -1
- package/dist/components/auth/index.d.ts +5 -1
- package/dist/components/auth/index.d.ts.map +1 -1
- package/dist/components/auth/index.js +100 -14
- package/dist/components/auth/index.js.map +1 -1
- package/dist/components/auth/index.mjs +187 -84
- package/dist/components/auth/index.mjs.map +1 -1
- package/dist/components/design/Buttons.d.ts +2 -0
- package/dist/components/design/Buttons.d.ts.map +1 -1
- package/dist/components/design/Buttons.js +8 -2
- package/dist/components/design/Buttons.js.map +1 -1
- package/dist/components/design/Buttons.mjs +9 -3
- package/dist/components/design/Buttons.mjs.map +1 -1
- package/dist/components/export/Export.d.ts +2 -1
- package/dist/components/export/Export.d.ts.map +1 -1
- package/dist/components/export/Export.js +8 -6
- package/dist/components/export/Export.js.map +1 -1
- package/dist/components/export/Export.mjs +8 -6
- package/dist/components/export/Export.mjs.map +1 -1
- package/dist/components/export/ExportWarning.d.ts +2 -1
- package/dist/components/export/ExportWarning.d.ts.map +1 -1
- package/dist/components/export/ExportWarning.js +4 -2
- package/dist/components/export/ExportWarning.js.map +1 -1
- package/dist/components/export/ExportWarning.mjs +4 -2
- package/dist/components/export/ExportWarning.mjs.map +1 -1
- package/dist/components/import/Import.d.ts +7 -3
- package/dist/components/import/Import.d.ts.map +1 -1
- package/dist/components/import/Import.js +77 -37
- package/dist/components/import/Import.js.map +1 -1
- package/dist/components/import/Import.mjs +120 -55
- package/dist/components/import/Import.mjs.map +1 -1
- package/dist/components/sign/Message.d.ts.map +1 -1
- package/dist/components/sign/Message.js +1 -0
- package/dist/components/sign/Message.js.map +1 -1
- package/dist/components/sign/Message.mjs +1 -0
- package/dist/components/sign/Message.mjs.map +1 -1
- package/dist/components/user/ConnectWallet.d.ts +8 -0
- package/dist/components/user/ConnectWallet.d.ts.map +1 -0
- package/dist/components/user/{LinkWallet.js → ConnectWallet.js} +18 -18
- package/dist/components/user/ConnectWallet.js.map +1 -0
- package/dist/components/user/{LinkWallet.mjs → ConnectWallet.mjs} +25 -25
- package/dist/components/user/ConnectWallet.mjs.map +1 -0
- package/dist/components/user/RemovePasskey.d.ts.map +1 -1
- package/dist/components/user/RemovePasskey.js +1 -0
- package/dist/components/user/RemovePasskey.js.map +1 -1
- package/dist/components/user/RemovePasskey.mjs +1 -0
- package/dist/components/user/RemovePasskey.mjs.map +1 -1
- package/dist/index.js +13 -0
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +2 -1
- package/dist/index.mjs.map +1 -1
- package/dist/providers/client/Provider.d.ts +3 -3
- package/dist/providers/client/Provider.d.ts.map +1 -1
- package/dist/providers/client/Provider.js +760 -149
- package/dist/providers/client/Provider.js.map +1 -1
- package/dist/providers/client/Provider.mjs +2474 -1624
- package/dist/providers/client/Provider.mjs.map +1 -1
- package/dist/providers/client/Types.d.ts +116 -11
- package/dist/providers/client/Types.d.ts.map +1 -1
- package/dist/providers/client/Types.js.map +1 -1
- package/dist/providers/client/Types.mjs.map +1 -1
- package/dist/providers/modal/Provider.js +1 -1
- package/dist/providers/modal/Provider.mjs +1 -1
- package/dist/styles.css +1 -1
- package/dist/tests/timers-test.d.ts +2 -0
- package/dist/tests/timers-test.d.ts.map +1 -0
- package/dist/tests/utils-test.d.ts +2 -0
- package/dist/tests/utils-test.d.ts.map +1 -0
- package/dist/types/base.d.ts +31 -3
- package/dist/types/base.d.ts.map +1 -1
- package/dist/types/base.js +23 -0
- package/dist/types/base.js.map +1 -1
- package/dist/types/base.mjs +19 -1
- package/dist/types/base.mjs.map +1 -1
- package/dist/utils/timers.d.ts +73 -0
- package/dist/utils/timers.d.ts.map +1 -0
- package/dist/utils/timers.js +133 -0
- package/dist/utils/timers.js.map +1 -0
- package/dist/utils/timers.mjs +142 -0
- package/dist/utils/timers.mjs.map +1 -0
- package/dist/{utils.d.ts → utils/utils.d.ts} +8 -3
- package/dist/utils/utils.d.ts.map +1 -0
- package/dist/{utils.js → utils/utils.js} +12 -3
- package/dist/utils/utils.js.map +1 -0
- package/dist/{utils.mjs → utils/utils.mjs} +12 -5
- package/dist/utils/utils.mjs.map +1 -0
- package/package.json +6 -5
- package/dist/components/user/LinkWallet.d.ts +0 -8
- package/dist/components/user/LinkWallet.d.ts.map +0 -1
- package/dist/components/user/LinkWallet.js.map +0 -1
- package/dist/components/user/LinkWallet.mjs.map +0 -1
- package/dist/utils.d.ts.map +0 -1
- package/dist/utils.js.map +0 -1
- package/dist/utils.mjs.map +0 -1
|
@@ -4,7 +4,8 @@
|
|
|
4
4
|
var jsxRuntime = require('react/jsx-runtime');
|
|
5
5
|
var sha2 = require('@noble/hashes/sha2');
|
|
6
6
|
var utils$1 = require('@noble/hashes/utils');
|
|
7
|
-
var utils = require('../../utils.js');
|
|
7
|
+
var utils = require('../../utils/utils.js');
|
|
8
|
+
var timers = require('../../utils/timers.js');
|
|
8
9
|
var core = require('@turnkey/core');
|
|
9
10
|
var react = require('react');
|
|
10
11
|
var sdkTypes = require('@turnkey/sdk-types');
|
|
@@ -23,7 +24,7 @@ var UpdatePhoneNumber = require('../../components/user/UpdatePhoneNumber.js');
|
|
|
23
24
|
var UpdateUserName = require('../../components/user/UpdateUserName.js');
|
|
24
25
|
var RemoveOAuthProvider = require('../../components/user/RemoveOAuthProvider.js');
|
|
25
26
|
var RemovePasskey = require('../../components/user/RemovePasskey.js');
|
|
26
|
-
var
|
|
27
|
+
var ConnectWallet = require('../../components/user/ConnectWallet.js');
|
|
27
28
|
var Types = require('./Types.js');
|
|
28
29
|
var OTP = require('../../components/auth/OTP.js');
|
|
29
30
|
var RemoveEmail = require('../../components/user/RemoveEmail.js');
|
|
@@ -32,7 +33,7 @@ var RemovePhoneNumber = require('../../components/user/RemovePhoneNumber.js');
|
|
|
32
33
|
/**
|
|
33
34
|
* Provides Turnkey client authentication, session management, wallet operations, and user profile management
|
|
34
35
|
* for the React Wallet Kit SDK. This context provider encapsulates all core authentication flows (Passkey, Wallet, OTP, OAuth),
|
|
35
|
-
* session lifecycle (creation, expiration, refresh), wallet
|
|
36
|
+
* session lifecycle (creation, expiration, refresh), wallet connecting/import/export, and user profile updates (email, phone, name).
|
|
36
37
|
*
|
|
37
38
|
* The provider automatically initializes the Turnkey client, fetches configuration (including proxy auth config if needed),
|
|
38
39
|
* and synchronizes session and authentication state. It exposes a comprehensive set of methods for authentication flows,
|
|
@@ -41,9 +42,9 @@ var RemovePhoneNumber = require('../../components/user/RemovePhoneNumber.js');
|
|
|
41
42
|
* Features:
|
|
42
43
|
* - Passkey, Wallet, OTP (Email/SMS), and OAuth (Google, Apple, Facebook) authentication and sign-up flows.
|
|
43
44
|
* - Session management: creation, expiration scheduling, refresh, and clearing.
|
|
44
|
-
* - Wallet management: fetch,
|
|
45
|
+
* - Wallet management: fetch, connect, import, export, account management.
|
|
45
46
|
* - User profile management: email, phone, name, OAuth provider, and passkey linking/removal.
|
|
46
|
-
* - Modal-driven UI flows for authentication, wallet
|
|
47
|
+
* - Modal-driven UI flows for authentication, wallet connecting, and profile updates.
|
|
47
48
|
* - Error handling and callback integration for custom error and event responses.
|
|
48
49
|
*
|
|
49
50
|
* Usage:
|
|
@@ -74,6 +75,7 @@ const ClientProvider = ({
|
|
|
74
75
|
const proxyAuthConfigRef = react.useRef(null);
|
|
75
76
|
const [allSessions, setAllSessions] = react.useState(undefined);
|
|
76
77
|
const {
|
|
78
|
+
isMobile,
|
|
77
79
|
pushPage,
|
|
78
80
|
closeModal
|
|
79
81
|
} = Hook.useModal();
|
|
@@ -92,6 +94,7 @@ const ClientProvider = ({
|
|
|
92
94
|
const flow = stateParams.get("flow");
|
|
93
95
|
const publicKey = stateParams.get("publicKey");
|
|
94
96
|
const openModal = stateParams.get("openModal");
|
|
97
|
+
const sessionKey = stateParams.get("sessionKey");
|
|
95
98
|
if (provider === "facebook" && flow === "redirect" && publicKey) {
|
|
96
99
|
// We have all the required parameters for a Facebook PKCE flow
|
|
97
100
|
const clientId = masterConfig?.auth?.oauthConfig?.facebookClientId;
|
|
@@ -116,8 +119,13 @@ const ClientProvider = ({
|
|
|
116
119
|
await completeOauth({
|
|
117
120
|
oidcToken,
|
|
118
121
|
publicKey,
|
|
119
|
-
providerName: "facebook"
|
|
122
|
+
providerName: "facebook",
|
|
123
|
+
...(sessionKey && {
|
|
124
|
+
sessionKey
|
|
125
|
+
})
|
|
120
126
|
});
|
|
127
|
+
// Clean up the URL after processing
|
|
128
|
+
window.history.replaceState(null, document.title, window.location.pathname);
|
|
121
129
|
resolve();
|
|
122
130
|
} catch (err) {
|
|
123
131
|
reject(err);
|
|
@@ -140,6 +148,116 @@ const ClientProvider = ({
|
|
|
140
148
|
});
|
|
141
149
|
}
|
|
142
150
|
}
|
|
151
|
+
if (provider === "discord" && flow === "redirect" && publicKey) {
|
|
152
|
+
const clientId = masterConfig?.auth?.oauthConfig?.discordClientId;
|
|
153
|
+
const redirectURI = masterConfig?.auth?.oauthConfig?.oauthRedirectUri;
|
|
154
|
+
const verifier = sessionStorage.getItem("discord_verifier");
|
|
155
|
+
const nonce = stateParams.get("nonce");
|
|
156
|
+
const sessionKey = stateParams.get("sessionKey");
|
|
157
|
+
if (clientId && redirectURI && verifier && nonce) {
|
|
158
|
+
await new Promise((resolve, reject) => {
|
|
159
|
+
pushPage({
|
|
160
|
+
key: `Discord OAuth`,
|
|
161
|
+
content: jsxRuntime.jsx(Action.ActionPage, {
|
|
162
|
+
title: `Authenticating with Discord...`,
|
|
163
|
+
action: async () => {
|
|
164
|
+
try {
|
|
165
|
+
const resp = await client?.httpClient.proxyOAuth2Authenticate({
|
|
166
|
+
provider: "OAUTH2_PROVIDER_DISCORD",
|
|
167
|
+
authCode: code,
|
|
168
|
+
redirectUri: redirectURI,
|
|
169
|
+
codeVerifier: verifier,
|
|
170
|
+
clientId,
|
|
171
|
+
nonce: nonce
|
|
172
|
+
});
|
|
173
|
+
sessionStorage.removeItem("discord_verifier");
|
|
174
|
+
const oidcToken = resp?.oidcToken;
|
|
175
|
+
if (!oidcToken) {
|
|
176
|
+
throw new sdkTypes.TurnkeyError("Missing OIDC token", sdkTypes.TurnkeyErrorCodes.OAUTH_LOGIN_ERROR);
|
|
177
|
+
}
|
|
178
|
+
await completeOauth({
|
|
179
|
+
oidcToken,
|
|
180
|
+
publicKey,
|
|
181
|
+
providerName: "discord",
|
|
182
|
+
...(sessionKey && {
|
|
183
|
+
sessionKey
|
|
184
|
+
})
|
|
185
|
+
});
|
|
186
|
+
// Clean up the URL after processing
|
|
187
|
+
window.history.replaceState(null, document.title, window.location.pathname);
|
|
188
|
+
resolve(null);
|
|
189
|
+
} catch (err) {
|
|
190
|
+
reject(err);
|
|
191
|
+
if (callbacks?.onError) {
|
|
192
|
+
callbacks.onError(err instanceof sdkTypes.TurnkeyError ? err : new sdkTypes.TurnkeyError("Discord authentication failed", sdkTypes.TurnkeyErrorCodes.OAUTH_SIGNUP_ERROR, err));
|
|
193
|
+
}
|
|
194
|
+
}
|
|
195
|
+
},
|
|
196
|
+
icon: jsxRuntime.jsx(reactFontawesome.FontAwesomeIcon, {
|
|
197
|
+
size: "3x",
|
|
198
|
+
icon: freeBrandsSvgIcons.faDiscord
|
|
199
|
+
})
|
|
200
|
+
}),
|
|
201
|
+
showTitle: false
|
|
202
|
+
});
|
|
203
|
+
});
|
|
204
|
+
}
|
|
205
|
+
}
|
|
206
|
+
if (provider === "twitter" && flow === "redirect" && publicKey) {
|
|
207
|
+
const clientId = masterConfig?.auth?.oauthConfig?.xClientId;
|
|
208
|
+
const redirectURI = masterConfig?.auth?.oauthConfig?.oauthRedirectUri;
|
|
209
|
+
const verifier = sessionStorage.getItem("twitter_verifier");
|
|
210
|
+
const nonce = stateParams.get("nonce");
|
|
211
|
+
const sessionKey = stateParams.get("sessionKey");
|
|
212
|
+
if (clientId && redirectURI && verifier && nonce) {
|
|
213
|
+
await new Promise((resolve, reject) => {
|
|
214
|
+
pushPage({
|
|
215
|
+
key: `Twitter OAuth`,
|
|
216
|
+
content: jsxRuntime.jsx(Action.ActionPage, {
|
|
217
|
+
title: `Authenticating with Twitter...`,
|
|
218
|
+
action: async () => {
|
|
219
|
+
try {
|
|
220
|
+
const resp = await client?.httpClient.proxyOAuth2Authenticate({
|
|
221
|
+
provider: "OAUTH2_PROVIDER_X",
|
|
222
|
+
authCode: code,
|
|
223
|
+
redirectUri: redirectURI,
|
|
224
|
+
codeVerifier: verifier,
|
|
225
|
+
clientId,
|
|
226
|
+
nonce: nonce
|
|
227
|
+
});
|
|
228
|
+
sessionStorage.removeItem("twitter_verifier");
|
|
229
|
+
const oidcToken = resp?.oidcToken;
|
|
230
|
+
if (!oidcToken) {
|
|
231
|
+
throw new sdkTypes.TurnkeyError("Missing OIDC token", sdkTypes.TurnkeyErrorCodes.OAUTH_LOGIN_ERROR);
|
|
232
|
+
}
|
|
233
|
+
await completeOauth({
|
|
234
|
+
oidcToken,
|
|
235
|
+
publicKey,
|
|
236
|
+
providerName: "twitter",
|
|
237
|
+
...(sessionKey && {
|
|
238
|
+
sessionKey
|
|
239
|
+
})
|
|
240
|
+
});
|
|
241
|
+
// Clean up the URL after processing
|
|
242
|
+
window.history.replaceState(null, document.title, window.location.pathname);
|
|
243
|
+
resolve(null);
|
|
244
|
+
} catch (err) {
|
|
245
|
+
reject(err);
|
|
246
|
+
if (callbacks?.onError) {
|
|
247
|
+
callbacks.onError(err instanceof sdkTypes.TurnkeyError ? err : new sdkTypes.TurnkeyError("Twitter authentication failed", sdkTypes.TurnkeyErrorCodes.OAUTH_SIGNUP_ERROR, err));
|
|
248
|
+
}
|
|
249
|
+
}
|
|
250
|
+
},
|
|
251
|
+
icon: jsxRuntime.jsx(reactFontawesome.FontAwesomeIcon, {
|
|
252
|
+
size: "3x",
|
|
253
|
+
icon: freeBrandsSvgIcons.faXTwitter
|
|
254
|
+
})
|
|
255
|
+
}),
|
|
256
|
+
showTitle: false
|
|
257
|
+
});
|
|
258
|
+
});
|
|
259
|
+
}
|
|
260
|
+
}
|
|
143
261
|
}
|
|
144
262
|
}
|
|
145
263
|
// Handle Google/Apple redirects (uses hash with id_token)
|
|
@@ -151,7 +269,8 @@ const ClientProvider = ({
|
|
|
151
269
|
provider,
|
|
152
270
|
flow,
|
|
153
271
|
publicKey,
|
|
154
|
-
openModal
|
|
272
|
+
openModal,
|
|
273
|
+
sessionKey
|
|
155
274
|
} = utils.parseOAuthRedirect(hash);
|
|
156
275
|
if (idToken && flow === "redirect" && publicKey) {
|
|
157
276
|
if (openModal === "true") {
|
|
@@ -183,7 +302,10 @@ const ClientProvider = ({
|
|
|
183
302
|
publicKey,
|
|
184
303
|
...(provider ? {
|
|
185
304
|
providerName: provider
|
|
186
|
-
} : {})
|
|
305
|
+
} : {}),
|
|
306
|
+
...(sessionKey && {
|
|
307
|
+
sessionKey
|
|
308
|
+
})
|
|
187
309
|
});
|
|
188
310
|
resolve(null);
|
|
189
311
|
} catch (err) {
|
|
@@ -223,11 +345,21 @@ const ClientProvider = ({
|
|
|
223
345
|
passkeyAuthEnabled: config.auth?.methods?.passkeyAuthEnabled ?? proxyAuthConfig?.enabledProviders.includes("passkey"),
|
|
224
346
|
walletAuthEnabled: config.auth?.methods?.walletAuthEnabled ?? proxyAuthConfig?.enabledProviders.includes("wallet"),
|
|
225
347
|
googleOauthEnabled: config.auth?.methods?.googleOauthEnabled ?? proxyAuthConfig?.enabledProviders.includes("google"),
|
|
348
|
+
xOauthEnabled: config.auth?.methods?.xOauthEnabled ?? proxyAuthConfig?.enabledProviders.includes("x"),
|
|
349
|
+
discordOauthEnabled: config.auth?.methods?.discordOauthEnabled ?? proxyAuthConfig?.enabledProviders.includes("discord"),
|
|
226
350
|
appleOauthEnabled: config.auth?.methods?.appleOauthEnabled ?? proxyAuthConfig?.enabledProviders.includes("apple"),
|
|
227
351
|
facebookOauthEnabled: config.auth?.methods?.facebookOauthEnabled ?? proxyAuthConfig?.enabledProviders.includes("facebook")
|
|
228
352
|
};
|
|
353
|
+
const resolvedClientIds = {
|
|
354
|
+
googleClientId: config.auth?.oauthConfig?.googleClientId ?? proxyAuthConfig?.oauthClientIds?.google,
|
|
355
|
+
appleClientId: config.auth?.oauthConfig?.appleClientId ?? proxyAuthConfig?.oauthClientIds?.apple,
|
|
356
|
+
facebookClientId: config.auth?.oauthConfig?.facebookClientId ?? proxyAuthConfig?.oauthClientIds?.facebook,
|
|
357
|
+
xClientId: config.auth?.oauthConfig?.xClientId ?? proxyAuthConfig?.oauthClientIds?.x,
|
|
358
|
+
discordClientId: config.auth?.oauthConfig?.discordClientId ?? proxyAuthConfig?.oauthClientIds?.discord
|
|
359
|
+
};
|
|
360
|
+
const redirectUrl = config.auth?.oauthConfig?.oauthRedirectUri ?? proxyAuthConfig?.oauthRedirectUrl;
|
|
229
361
|
// Set a default ordering for the oAuth methods
|
|
230
|
-
const oauthOrder = config.auth?.oauthOrder ?? ["google", "apple", "facebook"].filter(provider => resolvedMethods[`${provider}OauthEnabled`]);
|
|
362
|
+
const oauthOrder = config.auth?.oauthOrder ?? ["google", "apple", "x", "discord", "facebook"].filter(provider => resolvedMethods[`${provider}OauthEnabled`]);
|
|
231
363
|
// Set a default ordering for the overall auth methods
|
|
232
364
|
const methodOrder = config.auth?.methodOrder ?? [oauthOrder.length > 0 ? "socials" : null, resolvedMethods.emailOtpAuthEnabled ? "email" : null, resolvedMethods.smsOtpAuthEnabled ? "sms" : null, resolvedMethods.passkeyAuthEnabled ? "passkey" : null, resolvedMethods.walletAuthEnabled ? "wallet" : null].filter(Boolean);
|
|
233
365
|
return {
|
|
@@ -238,13 +370,18 @@ const ClientProvider = ({
|
|
|
238
370
|
methods: resolvedMethods,
|
|
239
371
|
oauthConfig: {
|
|
240
372
|
...config.auth?.oauthConfig,
|
|
241
|
-
|
|
373
|
+
...resolvedClientIds,
|
|
374
|
+
oauthRedirectUri: redirectUrl,
|
|
375
|
+
// on mobile we default to true since many mobile browsers
|
|
376
|
+
// (e.g. Safari) block popups
|
|
377
|
+
openOauthInPage: isMobile ? true : config.auth?.oauthConfig?.openOauthInPage
|
|
242
378
|
},
|
|
243
379
|
sessionExpirationSeconds: proxyAuthConfig?.sessionExpirationSeconds,
|
|
244
380
|
methodOrder,
|
|
245
381
|
oauthOrder,
|
|
246
382
|
autoRefreshSession: config.auth?.autoRefreshSession ?? true
|
|
247
383
|
},
|
|
384
|
+
autoRefreshManagedState: config.autoRefreshManagedState ?? true,
|
|
248
385
|
walletConfig: {
|
|
249
386
|
...config.walletConfig,
|
|
250
387
|
features: {
|
|
@@ -442,14 +579,13 @@ const ClientProvider = ({
|
|
|
442
579
|
}
|
|
443
580
|
/**
|
|
444
581
|
* @internal
|
|
445
|
-
* Schedules a session expiration and warning
|
|
582
|
+
* Schedules a session expiration and warning timer for the given session key.
|
|
446
583
|
*
|
|
447
|
-
* -
|
|
448
|
-
* -
|
|
449
|
-
* - The expiration timeout clears the session and triggers any necessary callbacks.
|
|
584
|
+
* - Sets up two timers: one for warning before expiry and one for actual expiry.
|
|
585
|
+
* - Uses capped timeouts under the hood so delays > 24.8 days are safe (see utils/timers.ts).
|
|
450
586
|
*
|
|
451
587
|
* @param params.sessionKey - The key of the session to schedule expiration for.
|
|
452
|
-
* @param params.expiry - The expiration time in seconds
|
|
588
|
+
* @param params.expiry - The expiration time in seconds since epoch.
|
|
453
589
|
* @throws {TurnkeyError} If an error occurs while scheduling the session expiration.
|
|
454
590
|
*/
|
|
455
591
|
async function scheduleSessionExpiration(params) {
|
|
@@ -458,21 +594,18 @@ const ClientProvider = ({
|
|
|
458
594
|
expiry
|
|
459
595
|
} = params;
|
|
460
596
|
try {
|
|
461
|
-
|
|
462
|
-
|
|
463
|
-
|
|
464
|
-
|
|
465
|
-
|
|
466
|
-
|
|
467
|
-
|
|
468
|
-
delete expiryTimeoutsRef.current[`${sessionKey}-warning`];
|
|
469
|
-
}
|
|
470
|
-
const timeUntilExpiry = expiry * 1000 - Date.now();
|
|
597
|
+
const warnKey = `${sessionKey}-warning`;
|
|
598
|
+
// Replace any prior timers for this session
|
|
599
|
+
timers.clearKey(expiryTimeoutsRef.current, sessionKey);
|
|
600
|
+
timers.clearKey(expiryTimeoutsRef.current, warnKey);
|
|
601
|
+
const now = Date.now();
|
|
602
|
+
const expiryMs = expiry * 1000;
|
|
603
|
+
const timeUntilExpiry = expiryMs - now;
|
|
471
604
|
const beforeExpiry = async () => {
|
|
472
605
|
const activeSession = await getSession();
|
|
473
|
-
if (!activeSession && expiryTimeoutsRef.current[
|
|
474
|
-
|
|
475
|
-
expiryTimeoutsRef.current
|
|
606
|
+
if (!activeSession && expiryTimeoutsRef.current[warnKey]) {
|
|
607
|
+
// Keep nudging until session materializes (short 10s timer is fine)
|
|
608
|
+
timers.setTimeoutInMap(expiryTimeoutsRef.current, warnKey, beforeExpiry, 10_000);
|
|
476
609
|
return;
|
|
477
610
|
}
|
|
478
611
|
const session = await getSession({
|
|
@@ -500,27 +633,36 @@ const ClientProvider = ({
|
|
|
500
633
|
if ((await getActiveSessionKey()) === sessionKey) {
|
|
501
634
|
setSession(undefined);
|
|
502
635
|
}
|
|
503
|
-
setAllSessions(
|
|
504
|
-
if (!
|
|
505
|
-
const
|
|
506
|
-
...
|
|
636
|
+
setAllSessions(prev => {
|
|
637
|
+
if (!prev) return prev;
|
|
638
|
+
const next = {
|
|
639
|
+
...prev
|
|
507
640
|
};
|
|
508
|
-
delete
|
|
509
|
-
return
|
|
641
|
+
delete next[sessionKey];
|
|
642
|
+
return next;
|
|
510
643
|
});
|
|
511
644
|
await clearSession({
|
|
512
645
|
sessionKey
|
|
513
646
|
});
|
|
514
|
-
|
|
515
|
-
|
|
647
|
+
// Remove timers for this session
|
|
648
|
+
timers.clearKey(expiryTimeoutsRef.current, sessionKey);
|
|
649
|
+
timers.clearKey(expiryTimeoutsRef.current, warnKey);
|
|
516
650
|
await logout();
|
|
517
651
|
};
|
|
518
|
-
|
|
519
|
-
|
|
652
|
+
// Already expired → expire immediately
|
|
653
|
+
if (timeUntilExpiry <= 0) {
|
|
654
|
+
await expireSession();
|
|
655
|
+
return;
|
|
656
|
+
}
|
|
657
|
+
// Warning timer (if threshold is in the future)
|
|
658
|
+
const warnAt = expiryMs - utils.SESSION_WARNING_THRESHOLD_MS;
|
|
659
|
+
if (warnAt <= now) {
|
|
660
|
+
void beforeExpiry(); // fire-and-forget is fine
|
|
520
661
|
} else {
|
|
521
|
-
expiryTimeoutsRef.current
|
|
662
|
+
timers.setCappedTimeoutInMap(expiryTimeoutsRef.current, warnKey, beforeExpiry, warnAt - now);
|
|
522
663
|
}
|
|
523
|
-
|
|
664
|
+
// Actual expiry timer (safe for long delays)
|
|
665
|
+
timers.setCappedTimeoutInMap(expiryTimeoutsRef.current, sessionKey, expireSession, timeUntilExpiry);
|
|
524
666
|
} catch (error) {
|
|
525
667
|
if (error instanceof sdkTypes.TurnkeyError || error instanceof sdkTypes.TurnkeyNetworkError) {
|
|
526
668
|
callbacks?.onError?.(error);
|
|
@@ -530,25 +672,25 @@ const ClientProvider = ({
|
|
|
530
672
|
}
|
|
531
673
|
}
|
|
532
674
|
/**
|
|
533
|
-
* Clears all scheduled session
|
|
675
|
+
* Clears all scheduled session timers (warning + expiry).
|
|
534
676
|
*
|
|
535
|
-
* -
|
|
536
|
-
* -
|
|
537
|
-
* - All timeouts stored in `expiryTimeoutsRef` are cleared and the reference is reset.
|
|
677
|
+
* - Removes all active timers managed by this client.
|
|
678
|
+
* - Useful on re-init or logout to avoid stale timers.
|
|
538
679
|
*
|
|
539
|
-
* @throws {TurnkeyError} If an error occurs while clearing the
|
|
680
|
+
* @throws {TurnkeyError} If an error occurs while clearing the timers.
|
|
540
681
|
*/
|
|
541
|
-
function clearSessionTimeouts() {
|
|
682
|
+
function clearSessionTimeouts(sessionKeys) {
|
|
542
683
|
try {
|
|
543
|
-
|
|
544
|
-
|
|
545
|
-
}
|
|
546
|
-
|
|
684
|
+
if (sessionKeys) {
|
|
685
|
+
timers.clearKeys(expiryTimeoutsRef.current, sessionKeys);
|
|
686
|
+
} else {
|
|
687
|
+
timers.clearAll(expiryTimeoutsRef.current); // clears & deletes everything
|
|
688
|
+
}
|
|
547
689
|
} catch (error) {
|
|
548
690
|
if (error instanceof sdkTypes.TurnkeyError || error instanceof sdkTypes.TurnkeyNetworkError) {
|
|
549
691
|
callbacks?.onError?.(error);
|
|
550
692
|
} else {
|
|
551
|
-
callbacks?.onError?.(new sdkTypes.TurnkeyError(
|
|
693
|
+
callbacks?.onError?.(new sdkTypes.TurnkeyError("Failed to clear session timeouts", sdkTypes.TurnkeyErrorCodes.CLEAR_SESSION_TIMEOUTS_ERROR, error));
|
|
552
694
|
}
|
|
553
695
|
}
|
|
554
696
|
}
|
|
@@ -564,7 +706,12 @@ const ClientProvider = ({
|
|
|
564
706
|
* @returns A void promise.
|
|
565
707
|
* @throws {TurnkeyError} If the client is not initialized or if there is an error during the process.
|
|
566
708
|
*/
|
|
567
|
-
const handlePostAuth = async
|
|
709
|
+
const handlePostAuth = async params => {
|
|
710
|
+
const {
|
|
711
|
+
method,
|
|
712
|
+
action,
|
|
713
|
+
identifier
|
|
714
|
+
} = params;
|
|
568
715
|
try {
|
|
569
716
|
const sessionKey = await getActiveSessionKey();
|
|
570
717
|
const session = await getSession({
|
|
@@ -581,6 +728,12 @@ const ClientProvider = ({
|
|
|
581
728
|
setAllSessions(allSessions);
|
|
582
729
|
await refreshWallets();
|
|
583
730
|
await refreshUser();
|
|
731
|
+
callbacks?.onAuthenticationSuccess?.({
|
|
732
|
+
session,
|
|
733
|
+
method,
|
|
734
|
+
action,
|
|
735
|
+
identifier
|
|
736
|
+
});
|
|
584
737
|
} catch (error) {
|
|
585
738
|
if (error instanceof sdkTypes.TurnkeyError || error instanceof sdkTypes.TurnkeyNetworkError) {
|
|
586
739
|
callbacks?.onError?.(error);
|
|
@@ -594,19 +747,29 @@ const ClientProvider = ({
|
|
|
594
747
|
* Handles the post-logout flow.
|
|
595
748
|
*
|
|
596
749
|
* - This function is called after a successful logout or session clear.
|
|
597
|
-
* - It clears all scheduled session expiration and warning timeouts to prevent memory leaks.
|
|
598
|
-
* - It resets the session state, removes
|
|
750
|
+
* - It clears all scheduled session expiration and warning timeouts associated to the session key to prevent memory leaks.
|
|
751
|
+
* - It resets the session state, removes user data from memory, the logged out session from all sessions state, and clears the wallets list.
|
|
599
752
|
* - This ensures that all sensitive information is removed from the provider state after logout.
|
|
600
753
|
* - Called internally after logout or when all sessions are cleared.
|
|
601
754
|
*
|
|
602
755
|
* @returns void
|
|
603
756
|
* @throws {TurnkeyError} If there is an error during the post-logout process.
|
|
604
757
|
*/
|
|
605
|
-
const handlePostLogout =
|
|
758
|
+
const handlePostLogout = sessionKey => {
|
|
606
759
|
try {
|
|
607
|
-
clearSessionTimeouts();
|
|
760
|
+
clearSessionTimeouts(sessionKey ? [sessionKey, `${sessionKey}-warning`] : undefined);
|
|
761
|
+
setAllSessions(prev => {
|
|
762
|
+
if (!prev) return prev;
|
|
763
|
+
if (sessionKey) {
|
|
764
|
+
const next = {
|
|
765
|
+
...prev
|
|
766
|
+
};
|
|
767
|
+
delete next[sessionKey];
|
|
768
|
+
return next;
|
|
769
|
+
}
|
|
770
|
+
return {};
|
|
771
|
+
});
|
|
608
772
|
setSession(undefined);
|
|
609
|
-
setAllSessions(undefined);
|
|
610
773
|
setUser(undefined);
|
|
611
774
|
setWallets([]);
|
|
612
775
|
} catch (error) {
|
|
@@ -625,8 +788,14 @@ const ClientProvider = ({
|
|
|
625
788
|
if (!client) {
|
|
626
789
|
throw new sdkTypes.TurnkeyError("Client is not initialized.", sdkTypes.TurnkeyErrorCodes.CLIENT_NOT_INITIALIZED);
|
|
627
790
|
}
|
|
628
|
-
await utils.withTurnkeyErrorHandling(() =>
|
|
629
|
-
|
|
791
|
+
await utils.withTurnkeyErrorHandling(async () => {
|
|
792
|
+
// If no sessionKey is provided, we try to get the active one.
|
|
793
|
+
let sessionKey = params?.sessionKey;
|
|
794
|
+
if (!sessionKey) sessionKey = await getActiveSessionKey();
|
|
795
|
+
await client.logout(params);
|
|
796
|
+
// We only handle post logout if the sessionKey is defined since that means we actually logged out of a session.
|
|
797
|
+
if (sessionKey) handlePostLogout(sessionKey);
|
|
798
|
+
}, callbacks, "Failed to logout");
|
|
630
799
|
return;
|
|
631
800
|
}, [client, callbacks]);
|
|
632
801
|
const loginWithPasskey = react.useCallback(async params => {
|
|
@@ -639,7 +808,11 @@ const ClientProvider = ({
|
|
|
639
808
|
expirationSeconds
|
|
640
809
|
}), callbacks, "Failed to login with passkey");
|
|
641
810
|
if (res) {
|
|
642
|
-
await handlePostAuth(
|
|
811
|
+
await handlePostAuth({
|
|
812
|
+
method: base.AuthMethod.Passkey,
|
|
813
|
+
action: sdkTypes.AuthAction.LOGIN,
|
|
814
|
+
identifier: res.credentialId
|
|
815
|
+
});
|
|
643
816
|
}
|
|
644
817
|
return res;
|
|
645
818
|
}, [client, callbacks]);
|
|
@@ -674,15 +847,19 @@ const ClientProvider = ({
|
|
|
674
847
|
expirationSeconds
|
|
675
848
|
}), callbacks, "Failed to sign up with passkey");
|
|
676
849
|
if (res) {
|
|
677
|
-
await handlePostAuth(
|
|
850
|
+
await handlePostAuth({
|
|
851
|
+
method: base.AuthMethod.Passkey,
|
|
852
|
+
action: sdkTypes.AuthAction.SIGNUP,
|
|
853
|
+
identifier: res.credentialId
|
|
854
|
+
});
|
|
678
855
|
}
|
|
679
856
|
return res;
|
|
680
857
|
}, [client, callbacks]);
|
|
681
|
-
const
|
|
858
|
+
const fetchWalletProviders = react.useCallback(async chain => {
|
|
682
859
|
if (!client) {
|
|
683
860
|
throw new sdkTypes.TurnkeyError("Client is not initialized.", sdkTypes.TurnkeyErrorCodes.CLIENT_NOT_INITIALIZED);
|
|
684
861
|
}
|
|
685
|
-
const newProviders = await client.
|
|
862
|
+
const newProviders = await client.fetchWalletProviders(chain);
|
|
686
863
|
// we update state with the latest providers
|
|
687
864
|
// we keep this state so that initializeWalletProviderListeners() re-runs
|
|
688
865
|
// whenever the list of connected providers changes
|
|
@@ -705,7 +882,7 @@ const ClientProvider = ({
|
|
|
705
882
|
await client.disconnectWalletAccount(walletProvider);
|
|
706
883
|
// we only refresh the wallets if:
|
|
707
884
|
// 1. there is an active session. This is needed because for WalletConnect
|
|
708
|
-
// you can
|
|
885
|
+
// you can disconnect a wallet before actually being logged in
|
|
709
886
|
//
|
|
710
887
|
// 2. it was a WalletConnect provider that we just disconnected. Since
|
|
711
888
|
// native providers emit a disconnect event which will already refresh
|
|
@@ -734,7 +911,11 @@ const ClientProvider = ({
|
|
|
734
911
|
expirationSeconds
|
|
735
912
|
}), callbacks, "Failed to login with wallet");
|
|
736
913
|
if (res) {
|
|
737
|
-
await handlePostAuth(
|
|
914
|
+
await handlePostAuth({
|
|
915
|
+
method: base.AuthMethod.Wallet,
|
|
916
|
+
action: sdkTypes.AuthAction.LOGIN,
|
|
917
|
+
identifier: res.address
|
|
918
|
+
});
|
|
738
919
|
}
|
|
739
920
|
return res;
|
|
740
921
|
}, [client, callbacks]);
|
|
@@ -759,7 +940,11 @@ const ClientProvider = ({
|
|
|
759
940
|
expirationSeconds
|
|
760
941
|
}), callbacks, "Failed to sign up with wallet");
|
|
761
942
|
if (res) {
|
|
762
|
-
await handlePostAuth(
|
|
943
|
+
await handlePostAuth({
|
|
944
|
+
method: base.AuthMethod.Wallet,
|
|
945
|
+
action: sdkTypes.AuthAction.SIGNUP,
|
|
946
|
+
identifier: res.address
|
|
947
|
+
});
|
|
763
948
|
}
|
|
764
949
|
return res;
|
|
765
950
|
}, [client, callbacks, masterConfig]);
|
|
@@ -784,7 +969,11 @@ const ClientProvider = ({
|
|
|
784
969
|
expirationSeconds
|
|
785
970
|
}), callbacks, "Failed to login or sign up with wallet");
|
|
786
971
|
if (res) {
|
|
787
|
-
await handlePostAuth(
|
|
972
|
+
await handlePostAuth({
|
|
973
|
+
method: base.AuthMethod.Wallet,
|
|
974
|
+
action: res.action,
|
|
975
|
+
identifier: res.address
|
|
976
|
+
});
|
|
788
977
|
}
|
|
789
978
|
return res;
|
|
790
979
|
}, [client, callbacks, masterConfig]);
|
|
@@ -806,7 +995,11 @@ const ClientProvider = ({
|
|
|
806
995
|
}
|
|
807
996
|
const res = await utils.withTurnkeyErrorHandling(() => client.loginWithOtp(params), callbacks, "Failed to login with OTP");
|
|
808
997
|
if (res) {
|
|
809
|
-
await handlePostAuth(
|
|
998
|
+
await handlePostAuth({
|
|
999
|
+
method: base.AuthMethod.Otp,
|
|
1000
|
+
action: sdkTypes.AuthAction.LOGIN,
|
|
1001
|
+
identifier: params.verificationToken
|
|
1002
|
+
});
|
|
810
1003
|
}
|
|
811
1004
|
return res;
|
|
812
1005
|
}, [client, callbacks]);
|
|
@@ -834,7 +1027,11 @@ const ClientProvider = ({
|
|
|
834
1027
|
};
|
|
835
1028
|
const res = await utils.withTurnkeyErrorHandling(() => client.signUpWithOtp(params), callbacks, "Failed to sign up with OTP");
|
|
836
1029
|
if (res) {
|
|
837
|
-
await handlePostAuth(
|
|
1030
|
+
await handlePostAuth({
|
|
1031
|
+
method: base.AuthMethod.Otp,
|
|
1032
|
+
action: sdkTypes.AuthAction.SIGNUP,
|
|
1033
|
+
identifier: params.verificationToken
|
|
1034
|
+
});
|
|
838
1035
|
}
|
|
839
1036
|
return res;
|
|
840
1037
|
}, [client, callbacks, masterConfig]);
|
|
@@ -862,11 +1059,29 @@ const ClientProvider = ({
|
|
|
862
1059
|
};
|
|
863
1060
|
const res = await utils.withTurnkeyErrorHandling(() => client.completeOtp(params), callbacks, "Failed to complete OTP");
|
|
864
1061
|
if (res) {
|
|
865
|
-
await handlePostAuth(
|
|
1062
|
+
await handlePostAuth({
|
|
1063
|
+
method: base.AuthMethod.Otp,
|
|
1064
|
+
action: res.action,
|
|
1065
|
+
identifier: res.verificationToken
|
|
1066
|
+
});
|
|
866
1067
|
}
|
|
867
1068
|
return res;
|
|
868
1069
|
}, [client, callbacks, masterConfig]);
|
|
869
|
-
const
|
|
1070
|
+
const loginWithOauth = react.useCallback(async params => {
|
|
1071
|
+
if (!client) {
|
|
1072
|
+
throw new sdkTypes.TurnkeyError("Client is not initialized.", sdkTypes.TurnkeyErrorCodes.CLIENT_NOT_INITIALIZED);
|
|
1073
|
+
}
|
|
1074
|
+
const res = await utils.withTurnkeyErrorHandling(() => client.loginWithOauth(params), callbacks, "Failed to login with OAuth");
|
|
1075
|
+
if (res) {
|
|
1076
|
+
await handlePostAuth({
|
|
1077
|
+
method: base.AuthMethod.Oauth,
|
|
1078
|
+
action: sdkTypes.AuthAction.LOGIN,
|
|
1079
|
+
identifier: params.oidcToken
|
|
1080
|
+
});
|
|
1081
|
+
}
|
|
1082
|
+
return res;
|
|
1083
|
+
}, [client, callbacks]);
|
|
1084
|
+
const signUpWithOauth = react.useCallback(async params => {
|
|
870
1085
|
if (!client) {
|
|
871
1086
|
throw new sdkTypes.TurnkeyError("Client is not initialized.", sdkTypes.TurnkeyErrorCodes.CLIENT_NOT_INITIALIZED);
|
|
872
1087
|
}
|
|
@@ -874,30 +1089,24 @@ const ClientProvider = ({
|
|
|
874
1089
|
throw new sdkTypes.TurnkeyError("Config is not ready yet!", sdkTypes.TurnkeyErrorCodes.INVALID_CONFIGURATION);
|
|
875
1090
|
}
|
|
876
1091
|
// If createSubOrgParams is not provided, use the default from masterConfig
|
|
877
|
-
|
|
1092
|
+
let createSubOrgParams = params.createSubOrgParams ?? masterConfig.auth?.createSuborgParams?.oauth;
|
|
878
1093
|
params = createSubOrgParams !== undefined ? {
|
|
879
1094
|
...params,
|
|
880
1095
|
createSubOrgParams
|
|
881
1096
|
} : {
|
|
882
1097
|
...params
|
|
883
1098
|
};
|
|
884
|
-
const res = await utils.withTurnkeyErrorHandling(() => client.
|
|
1099
|
+
const res = await utils.withTurnkeyErrorHandling(() => client.signUpWithOauth(params), callbacks, "Failed to sign up with OAuth");
|
|
885
1100
|
if (res) {
|
|
886
|
-
await handlePostAuth(
|
|
1101
|
+
await handlePostAuth({
|
|
1102
|
+
method: base.AuthMethod.Oauth,
|
|
1103
|
+
action: sdkTypes.AuthAction.SIGNUP,
|
|
1104
|
+
identifier: params.oidcToken
|
|
1105
|
+
});
|
|
887
1106
|
}
|
|
888
1107
|
return res;
|
|
889
1108
|
}, [client, callbacks, masterConfig]);
|
|
890
|
-
const
|
|
891
|
-
if (!client) {
|
|
892
|
-
throw new sdkTypes.TurnkeyError("Client is not initialized.", sdkTypes.TurnkeyErrorCodes.CLIENT_NOT_INITIALIZED);
|
|
893
|
-
}
|
|
894
|
-
const res = await utils.withTurnkeyErrorHandling(() => client.loginWithOauth(params), callbacks, "Failed to login with OAuth");
|
|
895
|
-
if (res) {
|
|
896
|
-
await handlePostAuth();
|
|
897
|
-
}
|
|
898
|
-
return res;
|
|
899
|
-
}, [client, callbacks]);
|
|
900
|
-
const signUpWithOauth = react.useCallback(async params => {
|
|
1109
|
+
const completeOauth = react.useCallback(async params => {
|
|
901
1110
|
if (!client) {
|
|
902
1111
|
throw new sdkTypes.TurnkeyError("Client is not initialized.", sdkTypes.TurnkeyErrorCodes.CLIENT_NOT_INITIALIZED);
|
|
903
1112
|
}
|
|
@@ -905,16 +1114,20 @@ const ClientProvider = ({
|
|
|
905
1114
|
throw new sdkTypes.TurnkeyError("Config is not ready yet!", sdkTypes.TurnkeyErrorCodes.INVALID_CONFIGURATION);
|
|
906
1115
|
}
|
|
907
1116
|
// If createSubOrgParams is not provided, use the default from masterConfig
|
|
908
|
-
|
|
1117
|
+
const createSubOrgParams = params.createSubOrgParams ?? masterConfig.auth?.createSuborgParams?.oauth;
|
|
909
1118
|
params = createSubOrgParams !== undefined ? {
|
|
910
1119
|
...params,
|
|
911
1120
|
createSubOrgParams
|
|
912
1121
|
} : {
|
|
913
1122
|
...params
|
|
914
1123
|
};
|
|
915
|
-
const res = await utils.withTurnkeyErrorHandling(() => client.
|
|
1124
|
+
const res = await utils.withTurnkeyErrorHandling(() => client.completeOauth(params), callbacks, "Failed to complete OAuth");
|
|
916
1125
|
if (res) {
|
|
917
|
-
await handlePostAuth(
|
|
1126
|
+
await handlePostAuth({
|
|
1127
|
+
method: base.AuthMethod.Oauth,
|
|
1128
|
+
action: res.action,
|
|
1129
|
+
identifier: params.oidcToken
|
|
1130
|
+
});
|
|
918
1131
|
}
|
|
919
1132
|
return res;
|
|
920
1133
|
}, [client, callbacks, masterConfig]);
|
|
@@ -930,6 +1143,12 @@ const ClientProvider = ({
|
|
|
930
1143
|
}
|
|
931
1144
|
return utils.withTurnkeyErrorHandling(() => client.fetchWalletAccounts(params), callbacks, "Failed to fetch wallet accounts");
|
|
932
1145
|
}, [client, callbacks]);
|
|
1146
|
+
const fetchPrivateKeys = react.useCallback(async params => {
|
|
1147
|
+
if (!client) {
|
|
1148
|
+
throw new sdkTypes.TurnkeyError("Client is not initialized.", sdkTypes.TurnkeyErrorCodes.CLIENT_NOT_INITIALIZED);
|
|
1149
|
+
}
|
|
1150
|
+
return utils.withTurnkeyErrorHandling(() => client.fetchPrivateKeys(params), callbacks, "Failed to fetch private keys");
|
|
1151
|
+
}, [client, callbacks]);
|
|
933
1152
|
const signMessage = react.useCallback(async params => {
|
|
934
1153
|
if (!client) throw new sdkTypes.TurnkeyError("Client is not initialized.", sdkTypes.TurnkeyErrorCodes.CLIENT_NOT_INITIALIZED);
|
|
935
1154
|
return utils.withTurnkeyErrorHandling(() => client.signMessage(params), callbacks, "Failed to sign message");
|
|
@@ -941,7 +1160,7 @@ const ClientProvider = ({
|
|
|
941
1160
|
if (!client) throw new sdkTypes.TurnkeyError("Client is not initialized.", sdkTypes.TurnkeyErrorCodes.CLIENT_NOT_INITIALIZED);
|
|
942
1161
|
return new Promise((resolve, reject) => {
|
|
943
1162
|
pushPage({
|
|
944
|
-
key: "Sign
|
|
1163
|
+
key: "Sign message",
|
|
945
1164
|
content: jsxRuntime.jsx(Message.SignMessageModal, {
|
|
946
1165
|
message: params.message,
|
|
947
1166
|
subText: params?.subText,
|
|
@@ -979,6 +1198,14 @@ const ClientProvider = ({
|
|
|
979
1198
|
if (!client) throw new sdkTypes.TurnkeyError("Client is not initialized.", sdkTypes.TurnkeyErrorCodes.CLIENT_NOT_INITIALIZED);
|
|
980
1199
|
return utils.withTurnkeyErrorHandling(() => client.fetchUser(params), callbacks, "Failed to fetch user");
|
|
981
1200
|
}, [client, callbacks]);
|
|
1201
|
+
const fetchOrCreateP256ApiKeyUser = react.useCallback(async params => {
|
|
1202
|
+
if (!client) throw new sdkTypes.TurnkeyError("Client is not initialized.", sdkTypes.TurnkeyErrorCodes.CLIENT_NOT_INITIALIZED);
|
|
1203
|
+
return utils.withTurnkeyErrorHandling(() => client.fetchOrCreateP256ApiKeyUser(params), callbacks, "Failed to fetch or create delegated access user");
|
|
1204
|
+
}, [client, callbacks]);
|
|
1205
|
+
const fetchOrCreatePolicies = react.useCallback(async params => {
|
|
1206
|
+
if (!client) throw new sdkTypes.TurnkeyError("Client is not initialized.", sdkTypes.TurnkeyErrorCodes.CLIENT_NOT_INITIALIZED);
|
|
1207
|
+
return utils.withTurnkeyErrorHandling(() => client.fetchOrCreatePolicies(params), callbacks, "Failed to fetch or create delegated access user");
|
|
1208
|
+
}, [client, callbacks]);
|
|
982
1209
|
const updateUserEmail = react.useCallback(async params => {
|
|
983
1210
|
if (!client) throw new sdkTypes.TurnkeyError("Client is not initialized.", sdkTypes.TurnkeyErrorCodes.CLIENT_NOT_INITIALIZED);
|
|
984
1211
|
const res = await utils.withTurnkeyErrorHandling(() => client.updateUserEmail(params), callbacks, "Failed to update user email");
|
|
@@ -1087,7 +1314,7 @@ const ClientProvider = ({
|
|
|
1087
1314
|
stampWith: params?.stampWith
|
|
1088
1315
|
});
|
|
1089
1316
|
return res;
|
|
1090
|
-
}, [client, callbacks]);
|
|
1317
|
+
}, [client, callbacks, masterConfig, session, user]);
|
|
1091
1318
|
const importWallet = react.useCallback(async params => {
|
|
1092
1319
|
if (!client) throw new sdkTypes.TurnkeyError("Client is not initialized.", sdkTypes.TurnkeyErrorCodes.CLIENT_NOT_INITIALIZED);
|
|
1093
1320
|
const res = await utils.withTurnkeyErrorHandling(() => client.importWallet(params), callbacks, "Failed to import wallet");
|
|
@@ -1095,16 +1322,16 @@ const ClientProvider = ({
|
|
|
1095
1322
|
stampWith: params?.stampWith
|
|
1096
1323
|
});
|
|
1097
1324
|
return res;
|
|
1098
|
-
}, [client, callbacks]);
|
|
1325
|
+
}, [client, callbacks, masterConfig, session, user]);
|
|
1099
1326
|
const importPrivateKey = react.useCallback(async params => {
|
|
1100
1327
|
if (!client) throw new sdkTypes.TurnkeyError("Client is not initialized.", sdkTypes.TurnkeyErrorCodes.CLIENT_NOT_INITIALIZED);
|
|
1101
1328
|
const res = await utils.withTurnkeyErrorHandling(() => client.importPrivateKey(params), callbacks, "Failed to import private key");
|
|
1102
1329
|
return res;
|
|
1103
|
-
}, [client, callbacks]);
|
|
1330
|
+
}, [client, callbacks, masterConfig, session, user]);
|
|
1104
1331
|
const deleteSubOrganization = react.useCallback(async params => {
|
|
1105
1332
|
if (!client) throw new sdkTypes.TurnkeyError("Client is not initialized.", sdkTypes.TurnkeyErrorCodes.CLIENT_NOT_INITIALIZED);
|
|
1106
1333
|
return utils.withTurnkeyErrorHandling(() => client.deleteSubOrganization(params), callbacks, "Failed to delete sub-organization");
|
|
1107
|
-
}, [client, callbacks]);
|
|
1334
|
+
}, [client, callbacks, masterConfig, session, user]);
|
|
1108
1335
|
const storeSession = react.useCallback(async params => {
|
|
1109
1336
|
if (!client) throw new sdkTypes.TurnkeyError("Client is not initialized.", sdkTypes.TurnkeyErrorCodes.CLIENT_NOT_INITIALIZED);
|
|
1110
1337
|
await utils.withTurnkeyErrorHandling(() => client.storeSession(params), callbacks, "Failed to store session");
|
|
@@ -1122,7 +1349,7 @@ const ClientProvider = ({
|
|
|
1122
1349
|
setSession(session);
|
|
1123
1350
|
setAllSessions(allSessions);
|
|
1124
1351
|
return;
|
|
1125
|
-
}, [client, callbacks]);
|
|
1352
|
+
}, [client, callbacks, masterConfig, session, user]);
|
|
1126
1353
|
const clearSession = react.useCallback(async params => {
|
|
1127
1354
|
if (!client) throw new sdkTypes.TurnkeyError("Client is not initialized.", sdkTypes.TurnkeyErrorCodes.CLIENT_NOT_INITIALIZED);
|
|
1128
1355
|
await utils.withTurnkeyErrorHandling(() => client.clearSession(params), callbacks, "Failed to clear session");
|
|
@@ -1131,13 +1358,13 @@ const ClientProvider = ({
|
|
|
1131
1358
|
setSession(session);
|
|
1132
1359
|
setAllSessions(allSessions);
|
|
1133
1360
|
return;
|
|
1134
|
-
}, [client, callbacks]);
|
|
1361
|
+
}, [client, callbacks, session, user, masterConfig]);
|
|
1135
1362
|
const clearAllSessions = react.useCallback(async () => {
|
|
1136
1363
|
if (!client) throw new sdkTypes.TurnkeyError("Client is not initialized.", sdkTypes.TurnkeyErrorCodes.CLIENT_NOT_INITIALIZED);
|
|
1137
1364
|
setSession(undefined);
|
|
1138
1365
|
setAllSessions(undefined);
|
|
1139
1366
|
return await utils.withTurnkeyErrorHandling(() => client.clearAllSessions(), callbacks, "Failed to clear all sessions");
|
|
1140
|
-
}, [client, callbacks]);
|
|
1367
|
+
}, [client, callbacks, session, user, masterConfig]);
|
|
1141
1368
|
const refreshSession = react.useCallback(async params => {
|
|
1142
1369
|
if (!client) {
|
|
1143
1370
|
throw new sdkTypes.TurnkeyError("Client is not initialized.", sdkTypes.TurnkeyErrorCodes.CLIENT_NOT_INITIALIZED);
|
|
@@ -1166,15 +1393,15 @@ const ClientProvider = ({
|
|
|
1166
1393
|
setSession(session);
|
|
1167
1394
|
setAllSessions(allSessions);
|
|
1168
1395
|
return res;
|
|
1169
|
-
}, [client, callbacks]);
|
|
1396
|
+
}, [client, callbacks, scheduleSessionExpiration, session, user, masterConfig]);
|
|
1170
1397
|
const getSession = react.useCallback(async params => {
|
|
1171
1398
|
if (!client) throw new sdkTypes.TurnkeyError("Client is not initialized.", sdkTypes.TurnkeyErrorCodes.CLIENT_NOT_INITIALIZED);
|
|
1172
1399
|
return utils.withTurnkeyErrorHandling(() => client.getSession(params), callbacks, "Failed to get session");
|
|
1173
|
-
}, [client, callbacks]);
|
|
1400
|
+
}, [client, callbacks, masterConfig, session, user]);
|
|
1174
1401
|
const getAllSessions = react.useCallback(async () => {
|
|
1175
1402
|
if (!client) throw new sdkTypes.TurnkeyError("Client is not initialized.", sdkTypes.TurnkeyErrorCodes.CLIENT_NOT_INITIALIZED);
|
|
1176
1403
|
return utils.withTurnkeyErrorHandling(() => client.getAllSessions(), callbacks, "Failed to get all sessions");
|
|
1177
|
-
}, [client, callbacks]);
|
|
1404
|
+
}, [client, callbacks, masterConfig, session, user]);
|
|
1178
1405
|
const setActiveSession = react.useCallback(async params => {
|
|
1179
1406
|
if (!client) throw new sdkTypes.TurnkeyError("Client is not initialized.", sdkTypes.TurnkeyErrorCodes.CLIENT_NOT_INITIALIZED);
|
|
1180
1407
|
const session = await utils.withTurnkeyErrorHandling(() => client.getSession({
|
|
@@ -1185,25 +1412,30 @@ const ClientProvider = ({
|
|
|
1185
1412
|
}
|
|
1186
1413
|
await utils.withTurnkeyErrorHandling(() => client.setActiveSession(params), callbacks, "Failed to set active session");
|
|
1187
1414
|
setSession(session);
|
|
1415
|
+
await utils.withTurnkeyErrorHandling(async () => {
|
|
1416
|
+
await refreshWallets();
|
|
1417
|
+
await refreshUser();
|
|
1418
|
+
}, callbacks, "Failed to refresh data after setting active session");
|
|
1188
1419
|
return;
|
|
1189
|
-
}, [client, callbacks]);
|
|
1420
|
+
}, [client, callbacks, session, user, masterConfig]);
|
|
1190
1421
|
const getActiveSessionKey = react.useCallback(async () => {
|
|
1191
1422
|
if (!client) throw new sdkTypes.TurnkeyError("Client is not initialized.", sdkTypes.TurnkeyErrorCodes.CLIENT_NOT_INITIALIZED);
|
|
1192
1423
|
return utils.withTurnkeyErrorHandling(() => client.getActiveSessionKey(), callbacks, "Failed to get active session key");
|
|
1193
|
-
}, [client, callbacks]);
|
|
1424
|
+
}, [client, callbacks, masterConfig, session, user]);
|
|
1194
1425
|
const clearUnusedKeyPairs = react.useCallback(async () => {
|
|
1195
1426
|
if (!client) throw new sdkTypes.TurnkeyError("Client is not initialized.", sdkTypes.TurnkeyErrorCodes.CLIENT_NOT_INITIALIZED);
|
|
1196
1427
|
return utils.withTurnkeyErrorHandling(() => client.clearUnusedKeyPairs(), callbacks, "Failed to clear unused key pairs");
|
|
1197
|
-
}, [client, callbacks]);
|
|
1428
|
+
}, [client, callbacks, masterConfig, session, user]);
|
|
1198
1429
|
const createApiKeyPair = react.useCallback(async params => {
|
|
1199
1430
|
if (!client) throw new sdkTypes.TurnkeyError("Client is not initialized.", sdkTypes.TurnkeyErrorCodes.CLIENT_NOT_INITIALIZED);
|
|
1200
1431
|
return utils.withTurnkeyErrorHandling(() => client.createApiKeyPair(params), callbacks, "Failed to create API key pair");
|
|
1201
|
-
}, [client, callbacks]);
|
|
1432
|
+
}, [client, callbacks, session, user, masterConfig]);
|
|
1202
1433
|
const getProxyAuthConfig = react.useCallback(async () => {
|
|
1203
1434
|
if (!client) throw new sdkTypes.TurnkeyError("Client is not initialized.", sdkTypes.TurnkeyErrorCodes.CLIENT_NOT_INITIALIZED);
|
|
1204
1435
|
return utils.withTurnkeyErrorHandling(() => client.getProxyAuthConfig(), callbacks, "Failed to get proxy auth config");
|
|
1205
|
-
}, [client, callbacks]);
|
|
1436
|
+
}, [client, callbacks, masterConfig, session, user]);
|
|
1206
1437
|
const refreshUser = react.useCallback(async params => {
|
|
1438
|
+
if (!masterConfig?.autoRefreshManagedState) return;
|
|
1207
1439
|
const {
|
|
1208
1440
|
stampWith
|
|
1209
1441
|
} = params || {};
|
|
@@ -1214,13 +1446,14 @@ const ClientProvider = ({
|
|
|
1214
1446
|
if (user) {
|
|
1215
1447
|
setUser(user);
|
|
1216
1448
|
}
|
|
1217
|
-
}, [client, callbacks]);
|
|
1449
|
+
}, [client, callbacks, fetchUser, masterConfig, session, user]);
|
|
1218
1450
|
const refreshWallets = react.useCallback(async params => {
|
|
1451
|
+
if (!masterConfig?.autoRefreshManagedState) return;
|
|
1219
1452
|
const {
|
|
1220
1453
|
stampWith
|
|
1221
1454
|
} = params || {};
|
|
1222
1455
|
if (!client) throw new sdkTypes.TurnkeyError("Client is not initialized.", sdkTypes.TurnkeyErrorCodes.CLIENT_NOT_INITIALIZED);
|
|
1223
|
-
const walletProviders = await utils.withTurnkeyErrorHandling(() =>
|
|
1456
|
+
const walletProviders = await utils.withTurnkeyErrorHandling(() => fetchWalletProviders(), callbacks, "Failed to refresh wallets");
|
|
1224
1457
|
const wallets = await utils.withTurnkeyErrorHandling(() => fetchWallets({
|
|
1225
1458
|
stampWith,
|
|
1226
1459
|
walletProviders
|
|
@@ -1228,7 +1461,285 @@ const ClientProvider = ({
|
|
|
1228
1461
|
if (wallets) {
|
|
1229
1462
|
setWallets(wallets);
|
|
1230
1463
|
}
|
|
1231
|
-
}, [client, callbacks,
|
|
1464
|
+
}, [client, callbacks, fetchWalletProviders, fetchWallets, masterConfig, session, user]);
|
|
1465
|
+
const handleDiscordOauth = react.useCallback(async params => {
|
|
1466
|
+
const {
|
|
1467
|
+
clientId = masterConfig?.auth?.oauthConfig?.discordClientId,
|
|
1468
|
+
openInPage = masterConfig?.auth?.oauthConfig?.openOauthInPage ?? false,
|
|
1469
|
+
additionalState: additionalParameters
|
|
1470
|
+
} = params || {};
|
|
1471
|
+
try {
|
|
1472
|
+
if (!masterConfig) {
|
|
1473
|
+
throw new sdkTypes.TurnkeyError("Config is not ready yet!", sdkTypes.TurnkeyErrorCodes.INVALID_CONFIGURATION);
|
|
1474
|
+
}
|
|
1475
|
+
if (!clientId) {
|
|
1476
|
+
throw new sdkTypes.TurnkeyError("Discord Client ID is not configured.", sdkTypes.TurnkeyErrorCodes.INVALID_CONFIGURATION);
|
|
1477
|
+
}
|
|
1478
|
+
if (!masterConfig.auth?.oauthConfig?.oauthRedirectUri) {
|
|
1479
|
+
throw new sdkTypes.TurnkeyError("OAuth Redirect URI is not configured.", sdkTypes.TurnkeyErrorCodes.INVALID_CONFIGURATION);
|
|
1480
|
+
}
|
|
1481
|
+
const flow = openInPage ? "redirect" : "popup";
|
|
1482
|
+
const redirectURI = masterConfig.auth?.oauthConfig.oauthRedirectUri;
|
|
1483
|
+
// Create key pair and generate nonce
|
|
1484
|
+
const publicKey = await createApiKeyPair();
|
|
1485
|
+
if (!publicKey) {
|
|
1486
|
+
throw new Error("Failed to create public key for OAuth.");
|
|
1487
|
+
}
|
|
1488
|
+
const nonce = utils$1.bytesToHex(sha2.sha256(publicKey));
|
|
1489
|
+
// Generate PKCE challenge pair
|
|
1490
|
+
const {
|
|
1491
|
+
verifier,
|
|
1492
|
+
codeChallenge
|
|
1493
|
+
} = await utils.generateChallengePair();
|
|
1494
|
+
sessionStorage.setItem("discord_verifier", verifier);
|
|
1495
|
+
// Construct Discord Auth URL
|
|
1496
|
+
const discordAuthUrl = new URL(utils.DISCORD_AUTH_URL);
|
|
1497
|
+
discordAuthUrl.searchParams.set("client_id", clientId);
|
|
1498
|
+
discordAuthUrl.searchParams.set("redirect_uri", redirectURI);
|
|
1499
|
+
discordAuthUrl.searchParams.set("response_type", "code");
|
|
1500
|
+
discordAuthUrl.searchParams.set("code_challenge", codeChallenge);
|
|
1501
|
+
discordAuthUrl.searchParams.set("code_challenge_method", "S256");
|
|
1502
|
+
discordAuthUrl.searchParams.set("scope", "identify email");
|
|
1503
|
+
discordAuthUrl.searchParams.set("state", `provider=discord&flow=${flow}&publicKey=${encodeURIComponent(publicKey)}&nonce=${nonce}`);
|
|
1504
|
+
if (additionalParameters) {
|
|
1505
|
+
const extra = Object.entries(additionalParameters).map(([k, v]) => `${encodeURIComponent(k)}=${encodeURIComponent(v)}`).join("&");
|
|
1506
|
+
if (extra) {
|
|
1507
|
+
discordAuthUrl.searchParams.set("state", discordAuthUrl.searchParams.get("state") + `&${extra}`);
|
|
1508
|
+
}
|
|
1509
|
+
}
|
|
1510
|
+
if (openInPage) {
|
|
1511
|
+
window.location.href = discordAuthUrl.toString();
|
|
1512
|
+
return new Promise((_, reject) => {
|
|
1513
|
+
const timeout = setTimeout(() => {
|
|
1514
|
+
reject(new Error("Authentication timed out."));
|
|
1515
|
+
}, 300000);
|
|
1516
|
+
window.addEventListener("beforeunload", () => clearTimeout(timeout));
|
|
1517
|
+
});
|
|
1518
|
+
} else {
|
|
1519
|
+
const width = utils.popupWidth;
|
|
1520
|
+
const height = utils.popupHeight;
|
|
1521
|
+
const left = window.screenX + (window.innerWidth - width) / 2;
|
|
1522
|
+
const top = window.screenY + (window.innerHeight - height) / 2;
|
|
1523
|
+
const authWindow = window.open("about:blank", "_blank", `width=${width},height=${height},top=${top},left=${left},scrollbars=yes,resizable=yes`);
|
|
1524
|
+
if (!authWindow) {
|
|
1525
|
+
throw new Error("Failed to open Discord login window.");
|
|
1526
|
+
}
|
|
1527
|
+
authWindow.location.href = discordAuthUrl.toString();
|
|
1528
|
+
return new Promise((resolve, reject) => {
|
|
1529
|
+
const interval = setInterval(() => {
|
|
1530
|
+
try {
|
|
1531
|
+
if (authWindow.closed) {
|
|
1532
|
+
clearInterval(interval);
|
|
1533
|
+
reject(new Error("Authentication window was closed."));
|
|
1534
|
+
return;
|
|
1535
|
+
}
|
|
1536
|
+
const url = authWindow.location.href || "";
|
|
1537
|
+
if (url.startsWith(window.location.origin)) {
|
|
1538
|
+
const urlParams = new URLSearchParams(new URL(url).search);
|
|
1539
|
+
const authCode = urlParams.get("code");
|
|
1540
|
+
const stateParam = urlParams.get("state");
|
|
1541
|
+
const sessionKey = stateParam?.split("&").find(param => param.startsWith("sessionKey="))?.split("=")[1];
|
|
1542
|
+
if (authCode && stateParam && stateParam.includes("provider=discord")) {
|
|
1543
|
+
authWindow.close();
|
|
1544
|
+
clearInterval(interval);
|
|
1545
|
+
const verifier = sessionStorage.getItem("discord_verifier");
|
|
1546
|
+
if (!verifier) {
|
|
1547
|
+
reject(new Error("Missing PKCE verifier"));
|
|
1548
|
+
return;
|
|
1549
|
+
}
|
|
1550
|
+
client?.httpClient.proxyOAuth2Authenticate({
|
|
1551
|
+
provider: "OAUTH2_PROVIDER_DISCORD",
|
|
1552
|
+
authCode,
|
|
1553
|
+
redirectUri: redirectURI,
|
|
1554
|
+
codeVerifier: verifier,
|
|
1555
|
+
clientId,
|
|
1556
|
+
nonce: nonce
|
|
1557
|
+
}).then(resp => {
|
|
1558
|
+
sessionStorage.removeItem("discord_verifier");
|
|
1559
|
+
const oidcToken = resp.oidcToken;
|
|
1560
|
+
if (params?.onOauthSuccess) {
|
|
1561
|
+
params.onOauthSuccess({
|
|
1562
|
+
oidcToken,
|
|
1563
|
+
providerName: "discord",
|
|
1564
|
+
...(sessionKey && {
|
|
1565
|
+
sessionKey
|
|
1566
|
+
})
|
|
1567
|
+
});
|
|
1568
|
+
} else if (callbacks?.onOauthRedirect) {
|
|
1569
|
+
callbacks.onOauthRedirect({
|
|
1570
|
+
idToken: oidcToken,
|
|
1571
|
+
publicKey,
|
|
1572
|
+
...(sessionKey && {
|
|
1573
|
+
sessionKey
|
|
1574
|
+
})
|
|
1575
|
+
});
|
|
1576
|
+
} else {
|
|
1577
|
+
completeOauth({
|
|
1578
|
+
oidcToken,
|
|
1579
|
+
publicKey,
|
|
1580
|
+
providerName: "discord",
|
|
1581
|
+
...(sessionKey && {
|
|
1582
|
+
sessionKey
|
|
1583
|
+
})
|
|
1584
|
+
}).then(() => resolve()).catch(reject);
|
|
1585
|
+
return;
|
|
1586
|
+
}
|
|
1587
|
+
resolve();
|
|
1588
|
+
}).catch(reject);
|
|
1589
|
+
}
|
|
1590
|
+
}
|
|
1591
|
+
} catch {
|
|
1592
|
+
// ignore cross-origin
|
|
1593
|
+
}
|
|
1594
|
+
}, 500);
|
|
1595
|
+
if (authWindow.closed) {
|
|
1596
|
+
clearInterval(interval);
|
|
1597
|
+
}
|
|
1598
|
+
});
|
|
1599
|
+
}
|
|
1600
|
+
} catch (error) {
|
|
1601
|
+
throw error;
|
|
1602
|
+
}
|
|
1603
|
+
}, [client, callbacks, completeOauth, createApiKeyPair, masterConfig, session, user]);
|
|
1604
|
+
const handleXOauth = react.useCallback(async params => {
|
|
1605
|
+
const {
|
|
1606
|
+
clientId = masterConfig?.auth?.oauthConfig?.xClientId,
|
|
1607
|
+
openInPage = masterConfig?.auth?.oauthConfig?.openOauthInPage ?? false,
|
|
1608
|
+
additionalState: additionalParameters
|
|
1609
|
+
} = params || {};
|
|
1610
|
+
try {
|
|
1611
|
+
if (!masterConfig) {
|
|
1612
|
+
throw new sdkTypes.TurnkeyError("Config is not ready yet!", sdkTypes.TurnkeyErrorCodes.INVALID_CONFIGURATION);
|
|
1613
|
+
}
|
|
1614
|
+
if (!clientId) {
|
|
1615
|
+
throw new sdkTypes.TurnkeyError("Twitter Client ID is not configured.", sdkTypes.TurnkeyErrorCodes.INVALID_CONFIGURATION);
|
|
1616
|
+
}
|
|
1617
|
+
if (!masterConfig.auth?.oauthConfig?.oauthRedirectUri) {
|
|
1618
|
+
throw new sdkTypes.TurnkeyError("OAuth Redirect URI is not configured.", sdkTypes.TurnkeyErrorCodes.INVALID_CONFIGURATION);
|
|
1619
|
+
}
|
|
1620
|
+
const flow = openInPage ? "redirect" : "popup";
|
|
1621
|
+
const redirectURI = masterConfig.auth?.oauthConfig.oauthRedirectUri;
|
|
1622
|
+
// Create key pair and generate nonce
|
|
1623
|
+
const publicKey = await createApiKeyPair();
|
|
1624
|
+
if (!publicKey) {
|
|
1625
|
+
throw new Error("Failed to create public key for OAuth.");
|
|
1626
|
+
}
|
|
1627
|
+
const nonce = utils$1.bytesToHex(sha2.sha256(publicKey));
|
|
1628
|
+
// Generate PKCE challenge pair
|
|
1629
|
+
const {
|
|
1630
|
+
verifier,
|
|
1631
|
+
codeChallenge
|
|
1632
|
+
} = await utils.generateChallengePair();
|
|
1633
|
+
sessionStorage.setItem("twitter_verifier", verifier);
|
|
1634
|
+
// Construct Twitter Auth URL
|
|
1635
|
+
const twitterAuthUrl = new URL(utils.X_AUTH_URL);
|
|
1636
|
+
twitterAuthUrl.searchParams.set("client_id", clientId);
|
|
1637
|
+
twitterAuthUrl.searchParams.set("redirect_uri", redirectURI);
|
|
1638
|
+
twitterAuthUrl.searchParams.set("response_type", "code");
|
|
1639
|
+
twitterAuthUrl.searchParams.set("code_challenge", codeChallenge);
|
|
1640
|
+
twitterAuthUrl.searchParams.set("code_challenge_method", "S256");
|
|
1641
|
+
twitterAuthUrl.searchParams.set("scope", "tweet.read users.read");
|
|
1642
|
+
twitterAuthUrl.searchParams.set("state", `provider=twitter&flow=${flow}&publicKey=${encodeURIComponent(publicKey)}&nonce=${nonce}`);
|
|
1643
|
+
if (additionalParameters) {
|
|
1644
|
+
const extra = Object.entries(additionalParameters).map(([k, v]) => `${encodeURIComponent(k)}=${encodeURIComponent(v)}`).join("&");
|
|
1645
|
+
if (extra) {
|
|
1646
|
+
twitterAuthUrl.searchParams.set("state", twitterAuthUrl.searchParams.get("state") + `&${extra}`);
|
|
1647
|
+
}
|
|
1648
|
+
}
|
|
1649
|
+
if (openInPage) {
|
|
1650
|
+
window.location.href = twitterAuthUrl.toString();
|
|
1651
|
+
return new Promise((_, reject) => {
|
|
1652
|
+
const timeout = setTimeout(() => {
|
|
1653
|
+
reject(new Error("Authentication timed out."));
|
|
1654
|
+
}, 300000);
|
|
1655
|
+
window.addEventListener("beforeunload", () => clearTimeout(timeout));
|
|
1656
|
+
});
|
|
1657
|
+
} else {
|
|
1658
|
+
const width = utils.popupWidth;
|
|
1659
|
+
const height = utils.popupHeight;
|
|
1660
|
+
const left = window.screenX + (window.innerWidth - width) / 2;
|
|
1661
|
+
const top = window.screenY + (window.innerHeight - height) / 2;
|
|
1662
|
+
const authWindow = window.open("about:blank", "_blank", `width=${width},height=${height},top=${top},left=${left},scrollbars=yes,resizable=yes`);
|
|
1663
|
+
if (!authWindow) {
|
|
1664
|
+
throw new Error("Failed to open Twitter login window.");
|
|
1665
|
+
}
|
|
1666
|
+
authWindow.location.href = twitterAuthUrl.toString();
|
|
1667
|
+
return new Promise((resolve, reject) => {
|
|
1668
|
+
const interval = setInterval(() => {
|
|
1669
|
+
try {
|
|
1670
|
+
if (authWindow.closed) {
|
|
1671
|
+
clearInterval(interval);
|
|
1672
|
+
reject(new Error("Authentication window was closed."));
|
|
1673
|
+
return;
|
|
1674
|
+
}
|
|
1675
|
+
const url = authWindow.location.href || "";
|
|
1676
|
+
if (url.startsWith(window.location.origin)) {
|
|
1677
|
+
const urlParams = new URLSearchParams(new URL(url).search);
|
|
1678
|
+
const authCode = urlParams.get("code");
|
|
1679
|
+
const stateParam = urlParams.get("state");
|
|
1680
|
+
const sessionKey = stateParam?.split("&").find(param => param.startsWith("sessionKey="))?.split("=")[1];
|
|
1681
|
+
if (authCode && stateParam && stateParam.includes("provider=twitter")) {
|
|
1682
|
+
authWindow.close();
|
|
1683
|
+
clearInterval(interval);
|
|
1684
|
+
const verifier = sessionStorage.getItem("twitter_verifier");
|
|
1685
|
+
if (!verifier) {
|
|
1686
|
+
reject(new Error("Missing PKCE verifier"));
|
|
1687
|
+
return;
|
|
1688
|
+
}
|
|
1689
|
+
client?.httpClient.proxyOAuth2Authenticate({
|
|
1690
|
+
provider: "OAUTH2_PROVIDER_X",
|
|
1691
|
+
authCode,
|
|
1692
|
+
redirectUri: redirectURI,
|
|
1693
|
+
codeVerifier: verifier,
|
|
1694
|
+
clientId,
|
|
1695
|
+
nonce
|
|
1696
|
+
}).then(resp => {
|
|
1697
|
+
sessionStorage.removeItem("twitter_verifier");
|
|
1698
|
+
const oidcToken = resp.oidcToken;
|
|
1699
|
+
if (params?.onOauthSuccess) {
|
|
1700
|
+
params.onOauthSuccess({
|
|
1701
|
+
oidcToken,
|
|
1702
|
+
providerName: "twitter",
|
|
1703
|
+
...(sessionKey && {
|
|
1704
|
+
sessionKey
|
|
1705
|
+
})
|
|
1706
|
+
});
|
|
1707
|
+
} else if (callbacks?.onOauthRedirect) {
|
|
1708
|
+
callbacks.onOauthRedirect({
|
|
1709
|
+
idToken: oidcToken,
|
|
1710
|
+
publicKey,
|
|
1711
|
+
...(sessionKey && {
|
|
1712
|
+
sessionKey
|
|
1713
|
+
})
|
|
1714
|
+
});
|
|
1715
|
+
} else {
|
|
1716
|
+
completeOauth({
|
|
1717
|
+
oidcToken,
|
|
1718
|
+
publicKey,
|
|
1719
|
+
providerName: "twitter",
|
|
1720
|
+
...(sessionKey && {
|
|
1721
|
+
sessionKey
|
|
1722
|
+
})
|
|
1723
|
+
}).then(() => resolve()).catch(reject);
|
|
1724
|
+
return;
|
|
1725
|
+
}
|
|
1726
|
+
resolve();
|
|
1727
|
+
}).catch(reject);
|
|
1728
|
+
}
|
|
1729
|
+
}
|
|
1730
|
+
} catch {
|
|
1731
|
+
// ignore cross-origin
|
|
1732
|
+
}
|
|
1733
|
+
}, 500);
|
|
1734
|
+
if (authWindow.closed) {
|
|
1735
|
+
clearInterval(interval);
|
|
1736
|
+
}
|
|
1737
|
+
});
|
|
1738
|
+
}
|
|
1739
|
+
} catch (error) {
|
|
1740
|
+
throw error;
|
|
1741
|
+
}
|
|
1742
|
+
}, [client, callbacks, masterConfig, session, user]);
|
|
1232
1743
|
const handleGoogleOauth = react.useCallback(async params => {
|
|
1233
1744
|
const {
|
|
1234
1745
|
clientId = masterConfig?.auth?.oauthConfig?.googleClientId,
|
|
@@ -1309,24 +1820,35 @@ const ClientProvider = ({
|
|
|
1309
1820
|
if (url.startsWith(window.location.origin)) {
|
|
1310
1821
|
const hashParams = new URLSearchParams(url.split("#")[1]);
|
|
1311
1822
|
const idToken = hashParams.get("id_token");
|
|
1823
|
+
const stateParams = hashParams.get("state");
|
|
1824
|
+
const sessionKey = stateParams?.split("&").find(param => param.startsWith("sessionKey="))?.split("=")[1];
|
|
1312
1825
|
if (idToken) {
|
|
1313
1826
|
authWindow.close();
|
|
1314
1827
|
clearInterval(interval);
|
|
1315
1828
|
if (params?.onOauthSuccess) {
|
|
1316
1829
|
params.onOauthSuccess({
|
|
1317
1830
|
oidcToken: idToken,
|
|
1318
|
-
providerName: "google"
|
|
1831
|
+
providerName: "google",
|
|
1832
|
+
...(sessionKey && {
|
|
1833
|
+
sessionKey
|
|
1834
|
+
})
|
|
1319
1835
|
});
|
|
1320
1836
|
} else if (callbacks?.onOauthRedirect) {
|
|
1321
1837
|
callbacks.onOauthRedirect({
|
|
1322
1838
|
idToken,
|
|
1323
|
-
publicKey
|
|
1839
|
+
publicKey,
|
|
1840
|
+
...(sessionKey && {
|
|
1841
|
+
sessionKey
|
|
1842
|
+
})
|
|
1324
1843
|
});
|
|
1325
1844
|
} else {
|
|
1326
1845
|
completeOauth({
|
|
1327
1846
|
oidcToken: idToken,
|
|
1328
1847
|
publicKey,
|
|
1329
|
-
providerName: "google"
|
|
1848
|
+
providerName: "google",
|
|
1849
|
+
...(sessionKey && {
|
|
1850
|
+
sessionKey
|
|
1851
|
+
})
|
|
1330
1852
|
}).then(() => resolve()).catch(reject);
|
|
1331
1853
|
return;
|
|
1332
1854
|
}
|
|
@@ -1345,7 +1867,7 @@ const ClientProvider = ({
|
|
|
1345
1867
|
} catch (error) {
|
|
1346
1868
|
throw error;
|
|
1347
1869
|
}
|
|
1348
|
-
}, [client, callbacks]);
|
|
1870
|
+
}, [client, callbacks, masterConfig, session, user]);
|
|
1349
1871
|
const handleAppleOauth = react.useCallback(async params => {
|
|
1350
1872
|
const {
|
|
1351
1873
|
clientId = masterConfig?.auth?.oauthConfig?.appleClientId,
|
|
@@ -1422,24 +1944,35 @@ const ClientProvider = ({
|
|
|
1422
1944
|
if (url.startsWith(window.location.origin)) {
|
|
1423
1945
|
const hashParams = new URLSearchParams(url.split("#")[1]);
|
|
1424
1946
|
const idToken = hashParams.get("id_token");
|
|
1947
|
+
const stateParams = hashParams.get("state");
|
|
1948
|
+
const sessionKey = stateParams?.split("&").find(param => param.startsWith("sessionKey="))?.split("=")[1];
|
|
1425
1949
|
if (idToken) {
|
|
1426
1950
|
authWindow.close();
|
|
1427
1951
|
clearInterval(interval);
|
|
1428
1952
|
if (params?.onOauthSuccess) {
|
|
1429
1953
|
params.onOauthSuccess({
|
|
1430
1954
|
oidcToken: idToken,
|
|
1431
|
-
providerName: "apple"
|
|
1955
|
+
providerName: "apple",
|
|
1956
|
+
...(sessionKey && {
|
|
1957
|
+
sessionKey
|
|
1958
|
+
})
|
|
1432
1959
|
});
|
|
1433
1960
|
} else if (callbacks?.onOauthRedirect) {
|
|
1434
1961
|
callbacks.onOauthRedirect({
|
|
1435
1962
|
idToken,
|
|
1436
|
-
publicKey
|
|
1963
|
+
publicKey,
|
|
1964
|
+
...(sessionKey && {
|
|
1965
|
+
sessionKey
|
|
1966
|
+
})
|
|
1437
1967
|
});
|
|
1438
1968
|
} else {
|
|
1439
1969
|
completeOauth({
|
|
1440
1970
|
oidcToken: idToken,
|
|
1441
1971
|
publicKey,
|
|
1442
|
-
providerName: "apple"
|
|
1972
|
+
providerName: "apple",
|
|
1973
|
+
...(sessionKey && {
|
|
1974
|
+
sessionKey
|
|
1975
|
+
})
|
|
1443
1976
|
}).then(() => resolve()).catch(reject);
|
|
1444
1977
|
return;
|
|
1445
1978
|
}
|
|
@@ -1458,7 +1991,7 @@ const ClientProvider = ({
|
|
|
1458
1991
|
} catch (error) {
|
|
1459
1992
|
throw error;
|
|
1460
1993
|
}
|
|
1461
|
-
}, [client, callbacks]);
|
|
1994
|
+
}, [client, callbacks, masterConfig, session, user]);
|
|
1462
1995
|
const handleFacebookOauth = react.useCallback(async params => {
|
|
1463
1996
|
const {
|
|
1464
1997
|
clientId = masterConfig?.auth?.oauthConfig?.facebookClientId,
|
|
@@ -1546,6 +2079,7 @@ const ClientProvider = ({
|
|
|
1546
2079
|
const authCode = urlParams.get("code");
|
|
1547
2080
|
const stateParam = urlParams.get("state");
|
|
1548
2081
|
if (authCode && stateParam && stateParam.includes("provider=facebook")) {
|
|
2082
|
+
const sessionKey = stateParam?.split("&").find(param => param.startsWith("sessionKey="))?.split("=")[1];
|
|
1549
2083
|
authWindow.close();
|
|
1550
2084
|
clearInterval(interval);
|
|
1551
2085
|
// Exchange code for token
|
|
@@ -1559,18 +2093,27 @@ const ClientProvider = ({
|
|
|
1559
2093
|
if (params?.onOauthSuccess) {
|
|
1560
2094
|
params.onOauthSuccess({
|
|
1561
2095
|
oidcToken: tokenData.id_token,
|
|
1562
|
-
providerName: "
|
|
2096
|
+
providerName: "facebook",
|
|
2097
|
+
...(sessionKey && {
|
|
2098
|
+
sessionKey
|
|
2099
|
+
})
|
|
1563
2100
|
});
|
|
1564
2101
|
} else if (callbacks?.onOauthRedirect) {
|
|
1565
2102
|
callbacks.onOauthRedirect({
|
|
1566
2103
|
idToken: tokenData.id_token,
|
|
1567
|
-
publicKey
|
|
2104
|
+
publicKey,
|
|
2105
|
+
...(sessionKey && {
|
|
2106
|
+
sessionKey
|
|
2107
|
+
})
|
|
1568
2108
|
});
|
|
1569
2109
|
} else {
|
|
1570
2110
|
completeOauth({
|
|
1571
2111
|
oidcToken: tokenData.id_token,
|
|
1572
2112
|
publicKey,
|
|
1573
|
-
providerName: "facebook"
|
|
2113
|
+
providerName: "facebook",
|
|
2114
|
+
...(sessionKey && {
|
|
2115
|
+
sessionKey
|
|
2116
|
+
})
|
|
1574
2117
|
}).then(() => resolve()).catch(reject);
|
|
1575
2118
|
return;
|
|
1576
2119
|
}
|
|
@@ -1590,13 +2133,15 @@ const ClientProvider = ({
|
|
|
1590
2133
|
} catch (error) {
|
|
1591
2134
|
throw error;
|
|
1592
2135
|
}
|
|
1593
|
-
}, [client, callbacks]);
|
|
1594
|
-
const handleLogin = react.useCallback(async
|
|
2136
|
+
}, [client, callbacks, masterConfig, client, session, user]);
|
|
2137
|
+
const handleLogin = react.useCallback(async params => {
|
|
1595
2138
|
pushPage({
|
|
1596
2139
|
key: "Log in or sign up",
|
|
1597
|
-
content: jsxRuntime.jsx(index.AuthComponent, {
|
|
2140
|
+
content: jsxRuntime.jsx(index.AuthComponent, {
|
|
2141
|
+
sessionKey: params?.sessionKey
|
|
2142
|
+
})
|
|
1598
2143
|
});
|
|
1599
|
-
}, [pushPage]);
|
|
2144
|
+
}, [pushPage, masterConfig, client, session, user]);
|
|
1600
2145
|
const handleExportWallet = react.useCallback(async params => {
|
|
1601
2146
|
const {
|
|
1602
2147
|
walletId,
|
|
@@ -1604,7 +2149,7 @@ const ClientProvider = ({
|
|
|
1604
2149
|
stampWith
|
|
1605
2150
|
} = params;
|
|
1606
2151
|
pushPage({
|
|
1607
|
-
key: "Export
|
|
2152
|
+
key: "Export wallet",
|
|
1608
2153
|
content: jsxRuntime.jsx(Export.ExportComponent, {
|
|
1609
2154
|
target: walletId,
|
|
1610
2155
|
exportType: base.ExportType.Wallet,
|
|
@@ -1616,18 +2161,22 @@ const ClientProvider = ({
|
|
|
1616
2161
|
} : {})
|
|
1617
2162
|
})
|
|
1618
2163
|
});
|
|
1619
|
-
}, [pushPage]);
|
|
2164
|
+
}, [pushPage, masterConfig, client, session, user]);
|
|
1620
2165
|
const handleExportPrivateKey = react.useCallback(async params => {
|
|
1621
2166
|
const {
|
|
1622
2167
|
privateKeyId,
|
|
1623
2168
|
targetPublicKey,
|
|
2169
|
+
keyFormat,
|
|
1624
2170
|
stampWith
|
|
1625
2171
|
} = params;
|
|
1626
2172
|
pushPage({
|
|
1627
|
-
key: "Export
|
|
2173
|
+
key: "Export private key",
|
|
1628
2174
|
content: jsxRuntime.jsx(Export.ExportComponent, {
|
|
1629
2175
|
target: privateKeyId,
|
|
1630
2176
|
exportType: base.ExportType.PrivateKey,
|
|
2177
|
+
...(keyFormat !== undefined ? {
|
|
2178
|
+
keyFormat
|
|
2179
|
+
} : {}),
|
|
1631
2180
|
...(targetPublicKey !== undefined ? {
|
|
1632
2181
|
targetPublicKey
|
|
1633
2182
|
} : {}),
|
|
@@ -1636,18 +2185,22 @@ const ClientProvider = ({
|
|
|
1636
2185
|
} : {})
|
|
1637
2186
|
})
|
|
1638
2187
|
});
|
|
1639
|
-
}, [pushPage]);
|
|
2188
|
+
}, [pushPage, masterConfig, client, session, user]);
|
|
1640
2189
|
const handleExportWalletAccount = react.useCallback(async params => {
|
|
1641
2190
|
const {
|
|
1642
2191
|
address,
|
|
1643
2192
|
targetPublicKey,
|
|
2193
|
+
keyFormat,
|
|
1644
2194
|
stampWith
|
|
1645
2195
|
} = params;
|
|
1646
2196
|
pushPage({
|
|
1647
|
-
key: "Export
|
|
2197
|
+
key: "Export wallet account",
|
|
1648
2198
|
content: jsxRuntime.jsx(Export.ExportComponent, {
|
|
1649
2199
|
target: address,
|
|
1650
2200
|
exportType: base.ExportType.WalletAccount,
|
|
2201
|
+
...(keyFormat !== undefined ? {
|
|
2202
|
+
keyFormat
|
|
2203
|
+
} : {}),
|
|
1651
2204
|
...(targetPublicKey !== undefined ? {
|
|
1652
2205
|
targetPublicKey
|
|
1653
2206
|
} : {}),
|
|
@@ -1656,7 +2209,7 @@ const ClientProvider = ({
|
|
|
1656
2209
|
} : {})
|
|
1657
2210
|
})
|
|
1658
2211
|
});
|
|
1659
|
-
}, [pushPage]);
|
|
2212
|
+
}, [pushPage, masterConfig, client, session, user]);
|
|
1660
2213
|
const handleImportWallet = react.useCallback(async params => {
|
|
1661
2214
|
const {
|
|
1662
2215
|
defaultWalletAccounts,
|
|
@@ -1665,8 +2218,9 @@ const ClientProvider = ({
|
|
|
1665
2218
|
} = params || {};
|
|
1666
2219
|
try {
|
|
1667
2220
|
return utils.withTurnkeyErrorHandling(() => new Promise((resolve, reject) => pushPage({
|
|
1668
|
-
key: "Import
|
|
2221
|
+
key: "Import wallet",
|
|
1669
2222
|
content: jsxRuntime.jsx(Import.ImportComponent, {
|
|
2223
|
+
importType: base.ImportType.Wallet,
|
|
1670
2224
|
onError: error => {
|
|
1671
2225
|
reject(error);
|
|
1672
2226
|
},
|
|
@@ -1688,7 +2242,40 @@ const ClientProvider = ({
|
|
|
1688
2242
|
}
|
|
1689
2243
|
throw new sdkTypes.TurnkeyError("Failed to import wallet.", sdkTypes.TurnkeyErrorCodes.IMPORT_WALLET_ERROR, error);
|
|
1690
2244
|
}
|
|
1691
|
-
}, [pushPage]);
|
|
2245
|
+
}, [pushPage, masterConfig, client, session, user]);
|
|
2246
|
+
const handleImportPrivateKey = react.useCallback(async params => {
|
|
2247
|
+
const {
|
|
2248
|
+
curve,
|
|
2249
|
+
addressFormats,
|
|
2250
|
+
successPageDuration = 2000,
|
|
2251
|
+
stampWith
|
|
2252
|
+
} = params || {};
|
|
2253
|
+
try {
|
|
2254
|
+
return utils.withTurnkeyErrorHandling(() => new Promise((resolve, reject) => pushPage({
|
|
2255
|
+
key: "Import private key",
|
|
2256
|
+
content: jsxRuntime.jsx(Import.ImportComponent, {
|
|
2257
|
+
importType: base.ImportType.PrivateKey,
|
|
2258
|
+
curve: curve,
|
|
2259
|
+
addressFormats: addressFormats,
|
|
2260
|
+
onError: error => {
|
|
2261
|
+
reject(error);
|
|
2262
|
+
},
|
|
2263
|
+
onSuccess: privateKeyId => resolve(privateKeyId),
|
|
2264
|
+
...(successPageDuration !== undefined && {
|
|
2265
|
+
successPageDuration
|
|
2266
|
+
}),
|
|
2267
|
+
...(stampWith !== undefined && {
|
|
2268
|
+
stampWith
|
|
2269
|
+
})
|
|
2270
|
+
})
|
|
2271
|
+
})));
|
|
2272
|
+
} catch (error) {
|
|
2273
|
+
if (error instanceof sdkTypes.TurnkeyError) {
|
|
2274
|
+
throw error;
|
|
2275
|
+
}
|
|
2276
|
+
throw new sdkTypes.TurnkeyError("Failed to import private key.", sdkTypes.TurnkeyErrorCodes.IMPORT_WALLET_ERROR, error);
|
|
2277
|
+
}
|
|
2278
|
+
}, [pushPage, masterConfig, client, session, user]);
|
|
1692
2279
|
const handleUpdateUserName = react.useCallback(async params => {
|
|
1693
2280
|
const {
|
|
1694
2281
|
successPageDuration = 2000,
|
|
@@ -1754,7 +2341,7 @@ const ClientProvider = ({
|
|
|
1754
2341
|
}
|
|
1755
2342
|
throw new sdkTypes.TurnkeyError("Failed to update user name.", sdkTypes.TurnkeyErrorCodes.UPDATE_USER_NAME_ERROR, error);
|
|
1756
2343
|
}
|
|
1757
|
-
}, [pushPage]);
|
|
2344
|
+
}, [pushPage, masterConfig, client, session, user]);
|
|
1758
2345
|
const handleUpdateUserPhoneNumber = react.useCallback(async params => {
|
|
1759
2346
|
const {
|
|
1760
2347
|
successPageDuration = 2000,
|
|
@@ -1858,7 +2445,7 @@ const ClientProvider = ({
|
|
|
1858
2445
|
}
|
|
1859
2446
|
throw new sdkTypes.TurnkeyError("Failed to initialize OTP for sms verification.", sdkTypes.TurnkeyErrorCodes.INIT_OTP_ERROR, error);
|
|
1860
2447
|
}
|
|
1861
|
-
}, [pushPage]);
|
|
2448
|
+
}, [pushPage, masterConfig, client, session, user]);
|
|
1862
2449
|
const handleUpdateUserEmail = react.useCallback(async params => {
|
|
1863
2450
|
const {
|
|
1864
2451
|
successPageDuration = 2000,
|
|
@@ -1955,14 +2542,16 @@ const ClientProvider = ({
|
|
|
1955
2542
|
}
|
|
1956
2543
|
throw new sdkTypes.TurnkeyError("Failed to initialize OTP for email verification.", sdkTypes.TurnkeyErrorCodes.INIT_OTP_ERROR, error);
|
|
1957
2544
|
}
|
|
1958
|
-
}, [pushPage]);
|
|
2545
|
+
}, [pushPage, masterConfig, client, session, user]);
|
|
1959
2546
|
const handleAddEmail = react.useCallback(async params => {
|
|
1960
2547
|
const {
|
|
1961
2548
|
successPageDuration = 2000,
|
|
1962
2549
|
subTitle,
|
|
1963
2550
|
title
|
|
1964
2551
|
} = params || {};
|
|
1965
|
-
if (!client)
|
|
2552
|
+
if (!client) {
|
|
2553
|
+
throw new sdkTypes.TurnkeyError("Client is not initialized.", sdkTypes.TurnkeyErrorCodes.CLIENT_NOT_INITIALIZED);
|
|
2554
|
+
}
|
|
1966
2555
|
if (!session) {
|
|
1967
2556
|
throw new sdkTypes.TurnkeyError("No active session found.", sdkTypes.TurnkeyErrorCodes.NO_SESSION_FOUND);
|
|
1968
2557
|
}
|
|
@@ -2052,7 +2641,7 @@ const ClientProvider = ({
|
|
|
2052
2641
|
}
|
|
2053
2642
|
throw new sdkTypes.TurnkeyError("Failed to initialize OTP for email verification.", sdkTypes.TurnkeyErrorCodes.INIT_OTP_ERROR, error);
|
|
2054
2643
|
}
|
|
2055
|
-
}, [pushPage]);
|
|
2644
|
+
}, [pushPage, client, session, user]);
|
|
2056
2645
|
const handleAddPhoneNumber = react.useCallback(async params => {
|
|
2057
2646
|
const {
|
|
2058
2647
|
successPageDuration = 2000,
|
|
@@ -2160,7 +2749,7 @@ const ClientProvider = ({
|
|
|
2160
2749
|
}
|
|
2161
2750
|
throw new sdkTypes.TurnkeyError("Failed to initialize OTP for sms verification.", sdkTypes.TurnkeyErrorCodes.INIT_OTP_ERROR, error);
|
|
2162
2751
|
}
|
|
2163
|
-
}, [pushPage]);
|
|
2752
|
+
}, [pushPage, masterConfig, client, session, user]);
|
|
2164
2753
|
const handleRemovePasskey = react.useCallback(async params => {
|
|
2165
2754
|
const {
|
|
2166
2755
|
authenticatorId,
|
|
@@ -2201,7 +2790,7 @@ const ClientProvider = ({
|
|
|
2201
2790
|
preventBack: true
|
|
2202
2791
|
});
|
|
2203
2792
|
}), callbacks, "Failed to remove passkey");
|
|
2204
|
-
}, [pushPage]);
|
|
2793
|
+
}, [pushPage, masterConfig, client, session, user]);
|
|
2205
2794
|
const handleAddPasskey = react.useCallback(async params => {
|
|
2206
2795
|
const {
|
|
2207
2796
|
name,
|
|
@@ -2246,7 +2835,7 @@ const ClientProvider = ({
|
|
|
2246
2835
|
}
|
|
2247
2836
|
throw new sdkTypes.TurnkeyError("Failed to add passkey in handler.", sdkTypes.TurnkeyErrorCodes.ADD_PASSKEY_ERROR, error);
|
|
2248
2837
|
}
|
|
2249
|
-
}, [pushPage]);
|
|
2838
|
+
}, [pushPage, masterConfig, client, session, user]);
|
|
2250
2839
|
const handleRemoveOauthProvider = react.useCallback(async params => {
|
|
2251
2840
|
const {
|
|
2252
2841
|
providerId,
|
|
@@ -2290,7 +2879,7 @@ const ClientProvider = ({
|
|
|
2290
2879
|
}
|
|
2291
2880
|
throw new sdkTypes.TurnkeyError("Failed to remove OAuth provider in handler.", sdkTypes.TurnkeyErrorCodes.REMOVE_OAUTH_PROVIDER_ERROR, error);
|
|
2292
2881
|
}
|
|
2293
|
-
}, [pushPage]);
|
|
2882
|
+
}, [pushPage, masterConfig, client, session, user]);
|
|
2294
2883
|
const handleAddOauthProvider = react.useCallback(async params => {
|
|
2295
2884
|
if (!client) throw new sdkTypes.TurnkeyError("Client is not initialized.", sdkTypes.TurnkeyErrorCodes.CLIENT_NOT_INITIALIZED);
|
|
2296
2885
|
if (!session) {
|
|
@@ -2320,6 +2909,22 @@ const ClientProvider = ({
|
|
|
2320
2909
|
});
|
|
2321
2910
|
};
|
|
2322
2911
|
switch (providerName) {
|
|
2912
|
+
case sdkTypes.OAuthProviders.DISCORD:
|
|
2913
|
+
{
|
|
2914
|
+
await handleDiscordOauth({
|
|
2915
|
+
openInPage: false,
|
|
2916
|
+
onOauthSuccess
|
|
2917
|
+
});
|
|
2918
|
+
break;
|
|
2919
|
+
}
|
|
2920
|
+
case sdkTypes.OAuthProviders.X:
|
|
2921
|
+
{
|
|
2922
|
+
await handleXOauth({
|
|
2923
|
+
openInPage: false,
|
|
2924
|
+
onOauthSuccess
|
|
2925
|
+
});
|
|
2926
|
+
break;
|
|
2927
|
+
}
|
|
2323
2928
|
case sdkTypes.OAuthProviders.GOOGLE:
|
|
2324
2929
|
{
|
|
2325
2930
|
await handleGoogleOauth({
|
|
@@ -2349,8 +2954,8 @@ const ClientProvider = ({
|
|
|
2349
2954
|
throw new sdkTypes.TurnkeyError(`Unsupported OAuth provider: ${providerName}`, sdkTypes.TurnkeyErrorCodes.NOT_FOUND);
|
|
2350
2955
|
}
|
|
2351
2956
|
}
|
|
2352
|
-
}, [pushPage]);
|
|
2353
|
-
const
|
|
2957
|
+
}, [pushPage, masterConfig, client, session, user]);
|
|
2958
|
+
const handleConnectExternalWallet = react.useCallback(async params => {
|
|
2354
2959
|
const {
|
|
2355
2960
|
successPageDuration = 2000
|
|
2356
2961
|
} = params || {};
|
|
@@ -2361,15 +2966,15 @@ const ClientProvider = ({
|
|
|
2361
2966
|
if (!masterConfig?.walletConfig?.features?.connecting) {
|
|
2362
2967
|
throw new sdkTypes.TurnkeyError("Wallet connecting is not enabled.", sdkTypes.TurnkeyErrorCodes.FEATURE_NOT_ENABLED);
|
|
2363
2968
|
}
|
|
2364
|
-
const providers = await
|
|
2969
|
+
const providers = await fetchWalletProviders();
|
|
2365
2970
|
pushPage({
|
|
2366
|
-
key: "
|
|
2367
|
-
content: jsxRuntime.jsx(
|
|
2971
|
+
key: "Connect wallet",
|
|
2972
|
+
content: jsxRuntime.jsx(ConnectWallet.ConnectWalletModal, {
|
|
2368
2973
|
providers: providers,
|
|
2369
2974
|
successPageDuration: successPageDuration
|
|
2370
2975
|
})
|
|
2371
2976
|
});
|
|
2372
|
-
}, [pushPage]);
|
|
2977
|
+
}, [pushPage, masterConfig, client, session, user]);
|
|
2373
2978
|
const handleRemoveUserEmail = react.useCallback(async params => {
|
|
2374
2979
|
const {
|
|
2375
2980
|
successPageDuration = 2000,
|
|
@@ -2408,7 +3013,7 @@ const ClientProvider = ({
|
|
|
2408
3013
|
}
|
|
2409
3014
|
throw new sdkTypes.TurnkeyError("Failed to remove user email.", sdkTypes.TurnkeyErrorCodes.UPDATE_USER_EMAIL_ERROR, error);
|
|
2410
3015
|
}
|
|
2411
|
-
}, [pushPage]);
|
|
3016
|
+
}, [pushPage, masterConfig, client, session, user]);
|
|
2412
3017
|
const handleRemoveUserPhoneNumber = react.useCallback(async params => {
|
|
2413
3018
|
const {
|
|
2414
3019
|
successPageDuration = 2000,
|
|
@@ -2447,7 +3052,7 @@ const ClientProvider = ({
|
|
|
2447
3052
|
}
|
|
2448
3053
|
throw new sdkTypes.TurnkeyError("Failed to remove user phone number.", sdkTypes.TurnkeyErrorCodes.UPDATE_USER_PHONE_NUMBER_ERROR, error);
|
|
2449
3054
|
}
|
|
2450
|
-
}, [pushPage]);
|
|
3055
|
+
}, [pushPage, masterConfig, client, session, user]);
|
|
2451
3056
|
react.useEffect(() => {
|
|
2452
3057
|
if (proxyAuthConfigRef.current) return;
|
|
2453
3058
|
// Only fetch the proxy auth config once. Use that to build the master config.
|
|
@@ -2546,7 +3151,7 @@ const ClientProvider = ({
|
|
|
2546
3151
|
logout,
|
|
2547
3152
|
loginWithPasskey,
|
|
2548
3153
|
signUpWithPasskey,
|
|
2549
|
-
|
|
3154
|
+
fetchWalletProviders,
|
|
2550
3155
|
connectWalletAccount,
|
|
2551
3156
|
disconnectWalletAccount,
|
|
2552
3157
|
switchWalletAccountChain,
|
|
@@ -2563,11 +3168,14 @@ const ClientProvider = ({
|
|
|
2563
3168
|
completeOauth,
|
|
2564
3169
|
fetchWallets,
|
|
2565
3170
|
fetchWalletAccounts,
|
|
3171
|
+
fetchPrivateKeys,
|
|
2566
3172
|
refreshWallets,
|
|
2567
3173
|
signMessage,
|
|
2568
3174
|
signTransaction,
|
|
2569
3175
|
signAndSendTransaction,
|
|
2570
3176
|
fetchUser,
|
|
3177
|
+
fetchOrCreateP256ApiKeyUser,
|
|
3178
|
+
fetchOrCreatePolicies,
|
|
2571
3179
|
refreshUser,
|
|
2572
3180
|
updateUserEmail,
|
|
2573
3181
|
removeUserEmail,
|
|
@@ -2599,12 +3207,15 @@ const ClientProvider = ({
|
|
|
2599
3207
|
getProxyAuthConfig,
|
|
2600
3208
|
handleLogin,
|
|
2601
3209
|
handleGoogleOauth,
|
|
3210
|
+
handleXOauth,
|
|
3211
|
+
handleDiscordOauth,
|
|
2602
3212
|
handleAppleOauth,
|
|
2603
3213
|
handleFacebookOauth,
|
|
2604
3214
|
handleExportWallet,
|
|
2605
3215
|
handleExportPrivateKey,
|
|
2606
3216
|
handleExportWalletAccount,
|
|
2607
3217
|
handleImportWallet,
|
|
3218
|
+
handleImportPrivateKey,
|
|
2608
3219
|
handleUpdateUserEmail,
|
|
2609
3220
|
handleUpdateUserPhoneNumber,
|
|
2610
3221
|
handleUpdateUserName,
|
|
@@ -2615,7 +3226,7 @@ const ClientProvider = ({
|
|
|
2615
3226
|
handleAddEmail,
|
|
2616
3227
|
handleAddPhoneNumber,
|
|
2617
3228
|
handleSignMessage,
|
|
2618
|
-
|
|
3229
|
+
handleConnectExternalWallet,
|
|
2619
3230
|
handleRemoveUserEmail,
|
|
2620
3231
|
handleRemoveUserPhoneNumber
|
|
2621
3232
|
},
|