@turnkey/react-wallet-kit
Version:
The easiest and most powerful way to integrate Turnkey's Embedded Wallets into your React applications.
795 lines (793 loc) • 233 kB
JavaScript
'use client';
import { slicedToArray as _slicedToArray, asyncToGenerator as _asyncToGenerator, regeneratorRuntime as _regeneratorRuntime, objectSpread2 as _objectSpread2 } from '../../_virtual/_rollupPluginBabelHelpers.mjs';
import { jsx } from 'react/jsx-runtime';
import { sha256 } from '@noble/hashes/sha2';
import { bytesToHex } from '@noble/hashes/utils';
import { useWalletProviderState, useDebouncedCallback, isValidSession, withTurnkeyErrorHandling, GOOGLE_AUTH_URL, popupWidth, popupHeight, APPLE_AUTH_URL, exchangeCodeForToken, FACEBOOK_AUTH_URL, generateChallengePair, parseOAuthRedirect, handleFacebookPKCEFlow, SESSION_WARNING_THRESHOLD_MS } from '../../utils.mjs';
import { DEFAULT_SESSION_EXPIRATION_IN_SECONDS, WalletInterfaceType, OtpType, TurnkeyClient, Chain, getAuthProxyConfig } from '@turnkey/core';
import { useState, useRef, useCallback, useEffect } from 'react';
import { TurnkeyError, TurnkeyErrorCodes, OAuthProviders, TurnkeyNetworkError } from '@turnkey/sdk-types';
import { useModal } from '../modal/Hook.mjs';
import { AuthState, ClientState, ExportType } from '../../types/base.mjs';
import { AuthComponent } from '../../components/auth/index.mjs';
import { FontAwesomeIcon } from '@fortawesome/react-fontawesome';
import { faApple, faGoogle, faFacebook } from '@fortawesome/free-brands-svg-icons';
import { ActionPage } from '../../components/auth/Action.mjs';
import { SignMessageModal } from '../../components/sign/Message.mjs';
import { ExportComponent } from '../../components/export/Export.mjs';
import { ImportComponent } from '../../components/import/Import.mjs';
import { SuccessPage } from '../../components/design/Success.mjs';
import { UpdateEmail } from '../../components/user/UpdateEmail.mjs';
import { UpdatePhoneNumber } from '../../components/user/UpdatePhoneNumber.mjs';
import { UpdateUserName } from '../../components/user/UpdateUserName.mjs';
import { RemoveOAuthProvider } from '../../components/user/RemoveOAuthProvider.mjs';
import { RemovePasskey } from '../../components/user/RemovePasskey.mjs';
import { LinkWalletModal } from '../../components/user/LinkWallet.mjs';
import { ClientContext } from './Types.mjs';
import { OtpVerification } from '../../components/auth/OTP.mjs';
import { RemoveEmail } from '../../components/user/RemoveEmail.mjs';
import { RemovePhoneNumber } from '../../components/user/RemovePhoneNumber.mjs';
/**
* Provides Turnkey client authentication, session management, wallet operations, and user profile management
* for the React Wallet Kit SDK. This context provider encapsulates all core authentication flows (Passkey, Wallet, OTP, OAuth),
* session lifecycle (creation, expiration, refresh), wallet linking/import/export, and user profile updates (email, phone, name).
*
* The provider automatically initializes the Turnkey client, fetches configuration (including proxy auth config if needed),
* and synchronizes session and authentication state. It exposes a comprehensive set of methods for authentication flows,
* wallet management, and user profile operations, as well as UI handlers for modal-driven flows.
*
* Features:
* - Passkey, Wallet, OTP (Email/SMS), and OAuth (Google, Apple, Facebook) authentication and sign-up flows.
* - Session management: creation, expiration scheduling, refresh, and clearing.
* - Wallet management: fetch, link, import, export, account management.
* - User profile management: email, phone, name, OAuth provider, and passkey linking/removal.
* - Modal-driven UI flows for authentication, wallet linking, and profile updates.
* - Error handling and callback integration for custom error and event responses.
*
* Usage:
* Wrap your application with `TurnkeyProvider` to enable authentication and wallet features via context.
*
* @param config - The Turnkey provider configuration object.
* @param children - React children to be rendered within the provider.
* @param callbacks - Optional callbacks for error handling and session events.
*
* @returns A React context provider exposing authentication, wallet, and user management methods and state.
*/
var ClientProvider = function ClientProvider(_ref) {
var config = _ref.config,
children = _ref.children,
callbacks = _ref.callbacks;
var _useState = useState(undefined),
_useState2 = _slicedToArray(_useState, 2),
client = _useState2[0],
setClient = _useState2[1];
var _useState3 = useState(undefined),
_useState4 = _slicedToArray(_useState3, 2),
session = _useState4[0],
setSession = _useState4[1];
var _useState5 = useState(undefined),
_useState6 = _slicedToArray(_useState5, 2),
masterConfig = _useState6[0],
setMasterConfig = _useState6[1];
var _useState7 = useState([]),
_useState8 = _slicedToArray(_useState7, 2),
wallets = _useState8[0],
setWallets = _useState8[1];
var _useState9 = useState(undefined),
_useState0 = _slicedToArray(_useState9, 2),
user = _useState0[0],
setUser = _useState0[1];
var _useState1 = useState(),
_useState10 = _slicedToArray(_useState1, 2),
clientState = _useState10[0],
setClientState = _useState10[1];
var _useState11 = useState(AuthState.Unauthenticated),
_useState12 = _slicedToArray(_useState11, 2),
authState = _useState12[0],
setAuthState = _useState12[1];
// we use this custom hook to only update the state if the value is different
// this is so our useEffect that calls `initializeWalletProviderListeners()` only runs when it needs to
var _useWalletProviderSta = useWalletProviderState(),
_useWalletProviderSta2 = _slicedToArray(_useWalletProviderSta, 2),
walletProviders = _useWalletProviderSta2[0],
setWalletProviders = _useWalletProviderSta2[1];
var expiryTimeoutsRef = useRef({});
var proxyAuthConfigRef = useRef(null);
var _useState13 = useState(undefined),
_useState14 = _slicedToArray(_useState13, 2),
allSessions = _useState14[0],
setAllSessions = _useState14[1];
var _useModal = useModal(),
pushPage = _useModal.pushPage,
closeModal = _useModal.closeModal;
var completeRedirectOauth = /*#__PURE__*/function () {
var _ref2 = _asyncToGenerator(/*#__PURE__*/_regeneratorRuntime().mark(function _callee3() {
var searchParams, code, state, stateParams, provider, flow, publicKey, openModal, _masterConfig$auth, _masterConfig$auth$oa, _masterConfig$auth2, _masterConfig$auth2$o, clientId, redirectURI, hash, _parseOAuthRedirect, idToken, _provider, _flow, _publicKey, _openModal, providerName, icon;
return _regeneratorRuntime().wrap(function _callee3$(_context3) {
while (1) switch (_context3.prev = _context3.next) {
case 0:
if (!(window.location.hash || window.location.search)) {
_context3.next = 32;
break;
}
if (!(window.location.search && window.location.search.includes("code=") && window.location.search.includes("state="))) {
_context3.next = 19;
break;
}
searchParams = new URLSearchParams(window.location.search.substring(1));
code = searchParams.get("code");
state = searchParams.get("state"); // Parse state parameter
if (!(state && code)) {
_context3.next = 17;
break;
}
stateParams = new URLSearchParams(state);
provider = stateParams.get("provider");
flow = stateParams.get("flow");
publicKey = stateParams.get("publicKey");
openModal = stateParams.get("openModal");
if (!(provider === "facebook" && flow === "redirect" && publicKey)) {
_context3.next = 17;
break;
}
// We have all the required parameters for a Facebook PKCE flow
clientId = masterConfig === null || masterConfig === void 0 ? void 0 : (_masterConfig$auth = masterConfig.auth) === null || _masterConfig$auth === void 0 ? void 0 : (_masterConfig$auth$oa = _masterConfig$auth.oauthConfig) === null || _masterConfig$auth$oa === void 0 ? void 0 : _masterConfig$auth$oa.facebookClientId;
redirectURI = masterConfig === null || masterConfig === void 0 ? void 0 : (_masterConfig$auth2 = masterConfig.auth) === null || _masterConfig$auth2 === void 0 ? void 0 : (_masterConfig$auth2$o = _masterConfig$auth2.oauthConfig) === null || _masterConfig$auth2$o === void 0 ? void 0 : _masterConfig$auth2$o.oauthRedirectUri;
if (!(clientId && redirectURI)) {
_context3.next = 17;
break;
}
_context3.next = 17;
return handleFacebookPKCEFlow({
code: code,
publicKey: publicKey,
openModal: openModal,
clientId: clientId,
redirectURI: redirectURI,
callbacks: callbacks,
completeOauth: completeOauth,
onPushPage: function onPushPage(oidcToken) {
return new Promise(function (resolve, reject) {
pushPage({
key: "Facebook OAuth",
content: jsx(ActionPage, {
title: "Authenticating with Facebook...",
action: function () {
var _action = _asyncToGenerator(/*#__PURE__*/_regeneratorRuntime().mark(function _callee() {
return _regeneratorRuntime().wrap(function _callee$(_context) {
while (1) switch (_context.prev = _context.next) {
case 0:
_context.prev = 0;
_context.next = 3;
return completeOauth({
oidcToken: oidcToken,
publicKey: publicKey,
providerName: "facebook"
});
case 3:
resolve();
_context.next = 9;
break;
case 6:
_context.prev = 6;
_context.t0 = _context["catch"](0);
reject(_context.t0);
case 9:
case "end":
return _context.stop();
}
}, _callee, null, [[0, 6]]);
}));
function action() {
return _action.apply(this, arguments);
}
return action;
}(),
icon: jsx(FontAwesomeIcon, {
size: "3x",
icon: faFacebook
})
}),
showTitle: false
});
});
}
})["catch"](function (error) {
// Handle errors
if (callbacks !== null && callbacks !== void 0 && callbacks.onError) {
callbacks.onError(error instanceof TurnkeyError ? error : new TurnkeyError("Facebook authentication failed", TurnkeyErrorCodes.OAUTH_SIGNUP_ERROR, error));
}
});
case 17:
_context3.next = 32;
break;
case 19:
if (!window.location.hash) {
_context3.next = 32;
break;
}
hash = window.location.hash.substring(1); // Parse the hash using our helper functions
_parseOAuthRedirect = parseOAuthRedirect(hash), idToken = _parseOAuthRedirect.idToken, _provider = _parseOAuthRedirect.provider, _flow = _parseOAuthRedirect.flow, _publicKey = _parseOAuthRedirect.publicKey, _openModal = _parseOAuthRedirect.openModal;
if (!(idToken && _flow === "redirect" && _publicKey)) {
_context3.next = 32;
break;
}
if (!(_openModal === "true")) {
_context3.next = 30;
break;
}
providerName = _provider ? _provider.charAt(0).toUpperCase() + _provider.slice(1) : "Provider"; // Determine which icon to show based on the provider
if (_provider === "apple") {
icon = jsx(FontAwesomeIcon, {
size: "3x",
icon: faApple
});
} else {
// Default to Google icon
icon = jsx(FontAwesomeIcon, {
size: "3x",
icon: faGoogle
});
}
// This state is set when the OAuth flow comes from the AuthComponent
_context3.next = 28;
return new Promise(function (resolve, reject) {
pushPage({
key: "".concat(providerName, " OAuth"),
content: jsx(ActionPage, {
title: "Authenticating with ".concat(providerName, "..."),
action: function () {
var _action2 = _asyncToGenerator(/*#__PURE__*/_regeneratorRuntime().mark(function _callee2() {
return _regeneratorRuntime().wrap(function _callee2$(_context2) {
while (1) switch (_context2.prev = _context2.next) {
case 0:
_context2.prev = 0;
_context2.next = 3;
return completeOauth(_objectSpread2({
oidcToken: idToken,
publicKey: _publicKey
}, _provider ? {
providerName: _provider
} : {}));
case 3:
resolve(null);
_context2.next = 9;
break;
case 6:
_context2.prev = 6;
_context2.t0 = _context2["catch"](0);
reject(_context2.t0);
case 9:
case "end":
return _context2.stop();
}
}, _callee2, null, [[0, 6]]);
}));
function action() {
return _action2.apply(this, arguments);
}
return action;
}(),
icon: icon
}),
showTitle: false
});
});
case 28:
_context3.next = 31;
break;
case 30:
if (callbacks !== null && callbacks !== void 0 && callbacks.onOauthRedirect) {
callbacks.onOauthRedirect({
idToken: idToken,
publicKey: _publicKey
});
} else {
completeOauth(_objectSpread2({
oidcToken: idToken,
publicKey: _publicKey
}, _provider ? {
providerName: _provider
} : {}));
}
case 31:
// Clean up the URL after processing
window.history.replaceState(null, document.title, window.location.pathname + window.location.search);
case 32:
case "end":
return _context3.stop();
}
}, _callee3);
}));
return function completeRedirectOauth() {
return _ref2.apply(this, arguments);
};
}();
var buildConfig = function buildConfig(proxyAuthConfig) {
var _config$auth$methods$, _config$auth, _config$auth$methods, _config$auth$methods$2, _config$auth2, _config$auth2$methods, _config$auth$methods$3, _config$auth3, _config$auth3$methods, _config$auth$methods$4, _config$auth4, _config$auth4$methods, _config$auth$methods$5, _config$auth5, _config$auth5$methods, _config$auth$methods$6, _config$auth6, _config$auth6$methods, _config$auth$methods$7, _config$auth7, _config$auth7$methods, _config$auth$oauthOrd, _config$auth8, _config$auth$methodOr, _config$auth9, _config$auth0, _config$auth1, _config$auth1$oauthCo, _config$auth$autoRefr, _config$auth10, _config$walletConfig, _ref3, _resolvedMethods$wall, _config$walletConfig2, _config$walletConfig3, _config$walletConfig$, _config$walletConfig4, _config$walletConfig5, _config$walletConfig6, _config$walletConfig7, _config$walletConfig8, _config$walletConfig$2, _config$walletConfig9, _config$walletConfig0, _config$walletConfig1, _config$walletConfig10, _config$walletConfig11, _config$walletConfig$3, _config$walletConfig12, _config$walletConfig13, _config$walletConfig14, _config$importIframeU, _config$exportIframeU;
// Juggle the local overrides with the values set in the dashboard (proxyAuthConfig).
var resolvedMethods = {
emailOtpAuthEnabled: (_config$auth$methods$ = (_config$auth = config.auth) === null || _config$auth === void 0 ? void 0 : (_config$auth$methods = _config$auth.methods) === null || _config$auth$methods === void 0 ? void 0 : _config$auth$methods.emailOtpAuthEnabled) !== null && _config$auth$methods$ !== void 0 ? _config$auth$methods$ : proxyAuthConfig === null || proxyAuthConfig === void 0 ? void 0 : proxyAuthConfig.enabledProviders.includes("email"),
smsOtpAuthEnabled: (_config$auth$methods$2 = (_config$auth2 = config.auth) === null || _config$auth2 === void 0 ? void 0 : (_config$auth2$methods = _config$auth2.methods) === null || _config$auth2$methods === void 0 ? void 0 : _config$auth2$methods.smsOtpAuthEnabled) !== null && _config$auth$methods$2 !== void 0 ? _config$auth$methods$2 : proxyAuthConfig === null || proxyAuthConfig === void 0 ? void 0 : proxyAuthConfig.enabledProviders.includes("sms"),
passkeyAuthEnabled: (_config$auth$methods$3 = (_config$auth3 = config.auth) === null || _config$auth3 === void 0 ? void 0 : (_config$auth3$methods = _config$auth3.methods) === null || _config$auth3$methods === void 0 ? void 0 : _config$auth3$methods.passkeyAuthEnabled) !== null && _config$auth$methods$3 !== void 0 ? _config$auth$methods$3 : proxyAuthConfig === null || proxyAuthConfig === void 0 ? void 0 : proxyAuthConfig.enabledProviders.includes("passkey"),
walletAuthEnabled: (_config$auth$methods$4 = (_config$auth4 = config.auth) === null || _config$auth4 === void 0 ? void 0 : (_config$auth4$methods = _config$auth4.methods) === null || _config$auth4$methods === void 0 ? void 0 : _config$auth4$methods.walletAuthEnabled) !== null && _config$auth$methods$4 !== void 0 ? _config$auth$methods$4 : proxyAuthConfig === null || proxyAuthConfig === void 0 ? void 0 : proxyAuthConfig.enabledProviders.includes("wallet"),
googleOauthEnabled: (_config$auth$methods$5 = (_config$auth5 = config.auth) === null || _config$auth5 === void 0 ? void 0 : (_config$auth5$methods = _config$auth5.methods) === null || _config$auth5$methods === void 0 ? void 0 : _config$auth5$methods.googleOauthEnabled) !== null && _config$auth$methods$5 !== void 0 ? _config$auth$methods$5 : proxyAuthConfig === null || proxyAuthConfig === void 0 ? void 0 : proxyAuthConfig.enabledProviders.includes("google"),
appleOauthEnabled: (_config$auth$methods$6 = (_config$auth6 = config.auth) === null || _config$auth6 === void 0 ? void 0 : (_config$auth6$methods = _config$auth6.methods) === null || _config$auth6$methods === void 0 ? void 0 : _config$auth6$methods.appleOauthEnabled) !== null && _config$auth$methods$6 !== void 0 ? _config$auth$methods$6 : proxyAuthConfig === null || proxyAuthConfig === void 0 ? void 0 : proxyAuthConfig.enabledProviders.includes("apple"),
facebookOauthEnabled: (_config$auth$methods$7 = (_config$auth7 = config.auth) === null || _config$auth7 === void 0 ? void 0 : (_config$auth7$methods = _config$auth7.methods) === null || _config$auth7$methods === void 0 ? void 0 : _config$auth7$methods.facebookOauthEnabled) !== null && _config$auth$methods$7 !== void 0 ? _config$auth$methods$7 : proxyAuthConfig === null || proxyAuthConfig === void 0 ? void 0 : proxyAuthConfig.enabledProviders.includes("facebook")
};
// Set a default ordering for the oAuth methods
var oauthOrder = (_config$auth$oauthOrd = (_config$auth8 = config.auth) === null || _config$auth8 === void 0 ? void 0 : _config$auth8.oauthOrder) !== null && _config$auth$oauthOrd !== void 0 ? _config$auth$oauthOrd : ["google", "apple", "facebook"].filter(function (provider) {
return resolvedMethods["".concat(provider, "OauthEnabled")];
});
// Set a default ordering for the overall auth methods
var methodOrder = (_config$auth$methodOr = (_config$auth9 = config.auth) === null || _config$auth9 === void 0 ? void 0 : _config$auth9.methodOrder) !== null && _config$auth$methodOr !== void 0 ? _config$auth$methodOr : [oauthOrder.length > 0 ? "socials" : null, resolvedMethods.emailOtpAuthEnabled ? "email" : null, resolvedMethods.smsOtpAuthEnabled ? "sms" : null, resolvedMethods.passkeyAuthEnabled ? "passkey" : null, resolvedMethods.walletAuthEnabled ? "wallet" : null].filter(Boolean);
return _objectSpread2(_objectSpread2({}, config), {}, {
// Overrides:
auth: _objectSpread2(_objectSpread2({}, config.auth), {}, {
methods: resolvedMethods,
oauthConfig: _objectSpread2(_objectSpread2({}, (_config$auth0 = config.auth) === null || _config$auth0 === void 0 ? void 0 : _config$auth0.oauthConfig), {}, {
openOauthInPage: (_config$auth1 = config.auth) === null || _config$auth1 === void 0 ? void 0 : (_config$auth1$oauthCo = _config$auth1.oauthConfig) === null || _config$auth1$oauthCo === void 0 ? void 0 : _config$auth1$oauthCo.openOauthInPage
}),
sessionExpirationSeconds: proxyAuthConfig === null || proxyAuthConfig === void 0 ? void 0 : proxyAuthConfig.sessionExpirationSeconds,
methodOrder: methodOrder,
oauthOrder: oauthOrder,
autoRefreshSession: (_config$auth$autoRefr = (_config$auth10 = config.auth) === null || _config$auth10 === void 0 ? void 0 : _config$auth10.autoRefreshSession) !== null && _config$auth$autoRefr !== void 0 ? _config$auth$autoRefr : true
}),
walletConfig: _objectSpread2(_objectSpread2({}, config.walletConfig), {}, {
features: _objectSpread2(_objectSpread2({}, (_config$walletConfig = config.walletConfig) === null || _config$walletConfig === void 0 ? void 0 : _config$walletConfig.features), {}, {
auth: // If walletAuthEnabled is not set, default to true. Wallet auth can be enabled/disabled in the dashboard or by explicitly changing the walletAuthEnabled / walletConfig auth feature.
(_ref3 = (_resolvedMethods$wall = resolvedMethods.walletAuthEnabled) !== null && _resolvedMethods$wall !== void 0 ? _resolvedMethods$wall : (_config$walletConfig2 = config.walletConfig) === null || _config$walletConfig2 === void 0 ? void 0 : (_config$walletConfig3 = _config$walletConfig2.features) === null || _config$walletConfig3 === void 0 ? void 0 : _config$walletConfig3.auth) !== null && _ref3 !== void 0 ? _ref3 : true,
connecting: (_config$walletConfig$ = (_config$walletConfig4 = config.walletConfig) === null || _config$walletConfig4 === void 0 ? void 0 : (_config$walletConfig5 = _config$walletConfig4.features) === null || _config$walletConfig5 === void 0 ? void 0 : _config$walletConfig5.connecting) !== null && _config$walletConfig$ !== void 0 ? _config$walletConfig$ : true // Default connecting to true if not set. We don't care about auth settings here.
}),
chains: _objectSpread2(_objectSpread2({}, (_config$walletConfig6 = config.walletConfig) === null || _config$walletConfig6 === void 0 ? void 0 : _config$walletConfig6.chains), {}, {
ethereum: _objectSpread2(_objectSpread2({}, (_config$walletConfig7 = config.walletConfig) === null || _config$walletConfig7 === void 0 ? void 0 : (_config$walletConfig8 = _config$walletConfig7.chains) === null || _config$walletConfig8 === void 0 ? void 0 : _config$walletConfig8.ethereum), {}, {
// keep user's value if provided; default only when undefined
"native": (_config$walletConfig$2 = (_config$walletConfig9 = config.walletConfig) === null || _config$walletConfig9 === void 0 ? void 0 : (_config$walletConfig0 = _config$walletConfig9.chains) === null || _config$walletConfig0 === void 0 ? void 0 : (_config$walletConfig1 = _config$walletConfig0.ethereum) === null || _config$walletConfig1 === void 0 ? void 0 : _config$walletConfig1["native"]) !== null && _config$walletConfig$2 !== void 0 ? _config$walletConfig$2 : true
}),
solana: _objectSpread2(_objectSpread2({}, (_config$walletConfig10 = config.walletConfig) === null || _config$walletConfig10 === void 0 ? void 0 : (_config$walletConfig11 = _config$walletConfig10.chains) === null || _config$walletConfig11 === void 0 ? void 0 : _config$walletConfig11.solana), {}, {
// keep user's value if provided; default only when undefined
"native": (_config$walletConfig$3 = (_config$walletConfig12 = config.walletConfig) === null || _config$walletConfig12 === void 0 ? void 0 : (_config$walletConfig13 = _config$walletConfig12.chains) === null || _config$walletConfig13 === void 0 ? void 0 : (_config$walletConfig14 = _config$walletConfig13.solana) === null || _config$walletConfig14 === void 0 ? void 0 : _config$walletConfig14["native"]) !== null && _config$walletConfig$3 !== void 0 ? _config$walletConfig$3 : true
})
})
}),
importIframeUrl: (_config$importIframeU = config.importIframeUrl) !== null && _config$importIframeU !== void 0 ? _config$importIframeU : "https://import.turnkey.com",
exportIframeUrl: (_config$exportIframeU = config.exportIframeUrl) !== null && _config$exportIframeU !== void 0 ? _config$exportIframeU : "https://export.turnkey.com"
});
};
/**
* Initializes the Turnkey client with the provided configuration.
* This function sets up the client, fetches the proxy auth config if needed,
* and prepares the client for use in authentication and wallet operations.
*
* @internal
*/
var initializeClient = /*#__PURE__*/function () {
var _ref4 = _asyncToGenerator(/*#__PURE__*/_regeneratorRuntime().mark(function _callee4() {
var _masterConfig$passkey, _masterConfig$passkey2, _masterConfig$passkey3, _masterConfig$passkey4, _masterConfig$walletC, _masterConfig$walletC2, _masterConfig$walletC3, turnkeyClient, _callbacks$onError, _callbacks$onError2;
return _regeneratorRuntime().wrap(function _callee4$(_context4) {
while (1) switch (_context4.prev = _context4.next) {
case 0:
if (!(!masterConfig || client || clientState == ClientState.Loading)) {
_context4.next = 2;
break;
}
return _context4.abrupt("return");
case 2:
_context4.prev = 2;
setClientState(ClientState.Loading);
turnkeyClient = new TurnkeyClient({
apiBaseUrl: masterConfig.apiBaseUrl,
authProxyUrl: masterConfig.authProxyUrl,
authProxyConfigId: masterConfig.authProxyConfigId,
organizationId: masterConfig.organizationId,
// 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!
passkeyConfig: {
rpId: (_masterConfig$passkey = masterConfig.passkeyConfig) === null || _masterConfig$passkey === void 0 ? void 0 : _masterConfig$passkey.rpId,
timeout: ((_masterConfig$passkey2 = masterConfig.passkeyConfig) === null || _masterConfig$passkey2 === void 0 ? void 0 : _masterConfig$passkey2.timeout) || 60000,
// 60 seconds
userVerification: ((_masterConfig$passkey3 = masterConfig.passkeyConfig) === null || _masterConfig$passkey3 === void 0 ? void 0 : _masterConfig$passkey3.userVerification) || "preferred",
allowCredentials: ((_masterConfig$passkey4 = masterConfig.passkeyConfig) === null || _masterConfig$passkey4 === void 0 ? void 0 : _masterConfig$passkey4.allowCredentials) || []
},
walletConfig: _objectSpread2({
features: _objectSpread2({}, (_masterConfig$walletC = masterConfig.walletConfig) === null || _masterConfig$walletC === void 0 ? void 0 : _masterConfig$walletC.features),
chains: _objectSpread2({}, (_masterConfig$walletC2 = masterConfig.walletConfig) === null || _masterConfig$walletC2 === void 0 ? void 0 : _masterConfig$walletC2.chains)
}, ((_masterConfig$walletC3 = masterConfig.walletConfig) === null || _masterConfig$walletC3 === void 0 ? void 0 : _masterConfig$walletC3.walletConnect) && {
walletConnect: masterConfig.walletConfig.walletConnect
})
});
_context4.next = 7;
return turnkeyClient.init();
case 7:
setClient(turnkeyClient);
// Don't set clientState to ready until we fetch the proxy auth config (See other fetchProxyAuthConfig useEffect)
_context4.next = 14;
break;
case 10:
_context4.prev = 10;
_context4.t0 = _context4["catch"](2);
setClientState(ClientState.Error);
if (_context4.t0 instanceof TurnkeyError || _context4.t0 instanceof TurnkeyNetworkError) {
callbacks === null || callbacks === void 0 ? void 0 : (_callbacks$onError = callbacks.onError) === null || _callbacks$onError === void 0 ? void 0 : _callbacks$onError.call(callbacks, _context4.t0);
} else {
callbacks === null || callbacks === void 0 ? void 0 : (_callbacks$onError2 = callbacks.onError) === null || _callbacks$onError2 === void 0 ? void 0 : _callbacks$onError2.call(callbacks, new TurnkeyError("Failed to initialize Turnkey client", TurnkeyErrorCodes.INITIALIZE_CLIENT_ERROR, _context4.t0));
}
case 14:
case "end":
return _context4.stop();
}
}, _callee4, null, [[2, 10]]);
}));
return function initializeClient() {
return _ref4.apply(this, arguments);
};
}();
/**
* Initializes the user sessions by fetching all active sessions and setting up their state.
* @internal
*/
var initializeSessions = /*#__PURE__*/function () {
var _ref5 = _asyncToGenerator(/*#__PURE__*/_regeneratorRuntime().mark(function _callee6() {
var allLocalStorageSessions, activeSessionKey, _callbacks$onError3, _callbacks$onError4;
return _regeneratorRuntime().wrap(function _callee6$(_context6) {
while (1) switch (_context6.prev = _context6.next) {
case 0:
setSession(undefined);
setAllSessions(undefined);
_context6.prev = 2;
_context6.next = 5;
return getAllSessions();
case 5:
allLocalStorageSessions = _context6.sent;
if (allLocalStorageSessions) {
_context6.next = 8;
break;
}
return _context6.abrupt("return");
case 8:
_context6.next = 10;
return Promise.all(Object.keys(allLocalStorageSessions).map(/*#__PURE__*/function () {
var _ref6 = _asyncToGenerator(/*#__PURE__*/_regeneratorRuntime().mark(function _callee5(sessionKey) {
var session;
return _regeneratorRuntime().wrap(function _callee5$(_context5) {
while (1) switch (_context5.prev = _context5.next) {
case 0:
session = allLocalStorageSessions === null || allLocalStorageSessions === void 0 ? void 0 : allLocalStorageSessions[sessionKey];
if (isValidSession(session)) {
_context5.next = 12;
break;
}
_context5.next = 4;
return clearSession({
sessionKey: sessionKey
});
case 4:
_context5.t0 = sessionKey;
_context5.next = 7;
return getActiveSessionKey();
case 7:
_context5.t1 = _context5.sent;
if (!(_context5.t0 === _context5.t1)) {
_context5.next = 10;
break;
}
setSession(undefined);
case 10:
delete allLocalStorageSessions[sessionKey];
return _context5.abrupt("return");
case 12:
scheduleSessionExpiration({
sessionKey: sessionKey,
expiry: session.expiry
});
case 13:
case "end":
return _context5.stop();
}
}, _callee5);
}));
return function (_x) {
return _ref6.apply(this, arguments);
};
}()));
case 10:
setAllSessions(allLocalStorageSessions || undefined);
_context6.next = 13;
return client === null || client === void 0 ? void 0 : client.getActiveSessionKey();
case 13:
activeSessionKey = _context6.sent;
if (!activeSessionKey) {
_context6.next = 23;
break;
}
if (allLocalStorageSessions[activeSessionKey]) {
_context6.next = 17;
break;
}
return _context6.abrupt("return");
case 17:
setSession(allLocalStorageSessions[activeSessionKey]);
_context6.next = 20;
return refreshUser();
case 20:
_context6.next = 22;
return refreshWallets();
case 22:
return _context6.abrupt("return");
case 23:
_context6.next = 28;
break;
case 25:
_context6.prev = 25;
_context6.t0 = _context6["catch"](2);
if (_context6.t0 instanceof TurnkeyError || _context6.t0 instanceof TurnkeyNetworkError) {
callbacks === null || callbacks === void 0 ? void 0 : (_callbacks$onError3 = callbacks.onError) === null || _callbacks$onError3 === void 0 ? void 0 : _callbacks$onError3.call(callbacks, _context6.t0);
} else {
callbacks === null || callbacks === void 0 ? void 0 : (_callbacks$onError4 = callbacks.onError) === null || _callbacks$onError4 === void 0 ? void 0 : _callbacks$onError4.call(callbacks, new TurnkeyError("Failed to initialize sessions", TurnkeyErrorCodes.INITIALIZE_SESSION_ERROR, _context6.t0));
}
case 28:
case "end":
return _context6.stop();
}
}, _callee6, null, [[2, 25]]);
}));
return function initializeSessions() {
return _ref5.apply(this, arguments);
};
}();
/**
* @internal
* Attach listeners for connected wallet providers so we can refresh state on changes.
*
* - Ethereum: listens for disconnect and chain switches to trigger a refresh.
* - Solana: listens for disconnect via Wallet Standard `change` events to trigger a refresh.
* - WalletConnect: listens for disconnect via our custom wrapper’s `change` event to trigger a refresh.
*
* Notes:
* - Only providers that are connected are bound.
* - WalletConnect is excluded from the “native” paths and handled via its unified `change` event.
*
* @param walletProviders - Discovered providers; only connected ones are bound.
* @param onWalletsChanged - Invoked when a relevant provider event occurs.
* @returns Cleanup function that removes all listeners registered by this call.
*/
function initializeWalletProviderListeners(_x2, _x3) {
return _initializeWalletProviderListeners.apply(this, arguments);
}
/**
* @internal
* Schedules a session expiration and warning timeout for the given session key.
*
* - This function sets up two timeouts: one for warning before the session expires and another to expire the session.
* - The warning timeout is set to trigger before the session expires, allowing for actions like refreshing the session.
* - The expiration timeout clears the session and triggers any necessary callbacks.
*
* @param params.sessionKey - The key of the session to schedule expiration for.
* @param params.expiry - The expiration time in seconds for the session.
* @throws {TurnkeyError} If an error occurs while scheduling the session expiration.
*/
function _initializeWalletProviderListeners() {
_initializeWalletProviderListeners = _asyncToGenerator(/*#__PURE__*/_regeneratorRuntime().mark(function _callee89(walletProviders, onWalletsChanged) {
var _masterConfig$walletC6, _masterConfig$walletC7, _masterConfig$walletC8, _masterConfig$walletC9;
var cleanups, nativeOnly, ethProviders, solProviders, wcProviders, attachEthereumListeners, attachSolanaListeners;
return _regeneratorRuntime().wrap(function _callee89$(_context89) {
while (1) switch (_context89.prev = _context89.next) {
case 0:
attachSolanaListeners = function _attachSolanaListener(provider, onWalletsChanged) {
var _provider$features;
var cleanups = [];
var walletEvents = provider === null || provider === void 0 ? void 0 : (_provider$features = provider.features) === null || _provider$features === void 0 ? void 0 : _provider$features["standard:events"];
if (walletEvents !== null && walletEvents !== void 0 && walletEvents.on) {
var offChange = walletEvents.on("change", function (_evt) {
onWalletsChanged();
});
cleanups.push(offChange);
}
return function () {
return cleanups.forEach(function (fn) {
return fn();
});
};
};
attachEthereumListeners = function _attachEthereumListen(provider, onWalletsChanged) {
if (typeof provider.on !== "function") return;
var handleChainChanged = function handleChainChanged(_chainId) {
return onWalletsChanged();
};
var handleAccountsChanged = function handleAccountsChanged(accounts) {
if (accounts.length === 0) onWalletsChanged();
};
var handleDisconnect = function handleDisconnect() {
return onWalletsChanged();
};
provider.on("chainChanged", handleChainChanged);
provider.on("accountsChanged", handleAccountsChanged);
provider.on("disconnect", handleDisconnect);
return function () {
provider.removeListener("chainChanged", handleChainChanged);
provider.removeListener("accountsChanged", handleAccountsChanged);
provider.removeListener("disconnect", handleDisconnect);
};
};
if (!(walletProviders.length === 0)) {
_context89.next = 4;
break;
}
return _context89.abrupt("return", function () {});
case 4:
cleanups = []; // we only want to initialize these listeners for connected walletProviders
nativeOnly = function nativeOnly(provider) {
return provider.interfaceType !== WalletInterfaceType.WalletConnect;
};
ethProviders = masterConfig !== null && masterConfig !== void 0 && (_masterConfig$walletC6 = masterConfig.walletConfig) !== null && _masterConfig$walletC6 !== void 0 && (_masterConfig$walletC7 = _masterConfig$walletC6.chains.ethereum) !== null && _masterConfig$walletC7 !== void 0 && _masterConfig$walletC7["native"] ? walletProviders.filter(function (provider) {
return provider.chainInfo.namespace === Chain.Ethereum && nativeOnly(provider) && provider.connectedAddresses.length > 0;
}) : [];
solProviders = masterConfig !== null && masterConfig !== void 0 && (_masterConfig$walletC8 = masterConfig.walletConfig) !== null && _masterConfig$walletC8 !== void 0 && (_masterConfig$walletC9 = _masterConfig$walletC8.chains.solana) !== null && _masterConfig$walletC9 !== void 0 && _masterConfig$walletC9["native"] ? walletProviders.filter(function (provider) {
return provider.chainInfo.namespace === Chain.Solana && nativeOnly(provider) && provider.connectedAddresses.length > 0;
}) : []; // we exclude WalletConnect from the native event wiring
// this is because WC is handled separately with a custom wrapper’s
// `change` event
wcProviders = walletProviders.filter(function (p) {
return p.interfaceType === WalletInterfaceType.WalletConnect && p.connectedAddresses.length > 0;
});
ethProviders.forEach(function (p) {
var cleanup = attachEthereumListeners(p.provider, onWalletsChanged);
if (cleanup) cleanups.push(cleanup);
});
solProviders.forEach(function (p) {
var cleanup = attachSolanaListeners(p.provider, onWalletsChanged);
if (cleanup) cleanups.push(cleanup);
});
wcProviders.forEach(function (p) {
var _p$provider, _p$provider$features;
var standardEvents = (_p$provider = p.provider) === null || _p$provider === void 0 ? void 0 : (_p$provider$features = _p$provider.features) === null || _p$provider$features === void 0 ? void 0 : _p$provider$features["standard:events"];
if (standardEvents !== null && standardEvents !== void 0 && standardEvents.on) {
var unsubscribe = standardEvents.on("change", onWalletsChanged);
cleanups.push(unsubscribe);
}
});
return _context89.abrupt("return", function () {
cleanups.forEach(function (remove) {
return remove();
});
});
case 13:
case "end":
return _context89.stop();
}
}, _callee89);
}));
return _initializeWalletProviderListeners.apply(this, arguments);
}
function scheduleSessionExpiration(_x4) {
return _scheduleSessionExpiration.apply(this, arguments);
}
/**
* Clears all scheduled session expiration and warning timeouts for the client.
*
* - This function removes all active session expiration and warning timeouts managed by the provider.
* - It is called automatically when sessions are re-initialized or on logout to prevent memory leaks and ensure no stale timeouts remain.
* - All timeouts stored in `expiryTimeoutsRef` are cleared and the reference is reset.
*
* @throws {TurnkeyError} If an error occurs while clearing the timeouts.
*/
function _scheduleSessionExpiration() {
_scheduleSessionExpiration = _asyncToGenerator(/*#__PURE__*/_regeneratorRuntime().mark(function _callee92(params) {
var sessionKey, expiry, timeUntilExpiry, _beforeExpiry, expireSession, _callbacks$onError0, _callbacks$onError1;
return _regeneratorRuntime().wrap(function _callee92$(_context92) {
while (1) switch (_context92.prev = _context92.next) {
case 0:
sessionKey = params.sessionKey, expiry = params.expiry;
try {
// Clear any existing timeout for this session key
if (expiryTimeoutsRef.current[sessionKey]) {
clearTimeout(expiryTimeoutsRef.current[sessionKey]);
delete expiryTimeoutsRef.current[sessionKey];
}
if (expiryTimeoutsRef.current["".concat(sessionKey, "-warning")]) {
clearTimeout(expiryTimeoutsRef.current["".concat(sessionKey, "-warning")]);
delete expiryTimeoutsRef.current["".concat(sessionKey, "-warning")];
}
timeUntilExpiry = expiry * 1000 - Date.now();
_beforeExpiry = /*#__PURE__*/function () {
var _ref107 = _asyncToGenerator(/*#__PURE__*/_regeneratorRuntime().mark(function _callee90() {
var _callbacks$beforeSess, _masterConfig$auth28;
var activeSession, session;
return _regeneratorRuntime().wrap(function _callee90$(_context90) {
while (1) switch (_context90.prev = _context90.next) {
case 0:
_context90.next = 2;
return getSession();
case 2:
activeSession = _context90.sent;
if (!(!activeSession && expiryTimeoutsRef.current[sessionKey])) {
_context90.next = 7;
break;
}
clearTimeout(expiryTimeoutsRef.current["".concat(sessionKey, "-warning")]);
expiryTimeoutsRef.current["".concat(sessionKey, "-warning")] = setTimeout(_beforeExpiry, 10000);
return _context90.abrupt("return");
case 7:
_context90.next = 9;
return getSession({
sessionKey: sessionKey
});
case 9:
session = _context90.sent;
if (session) {
_context90.next = 12;
break;
}
return _context90.abrupt("return");
case 12:
callbacks === null || callbacks === void 0 ? void 0 : (_callbacks$beforeSess = callbacks.beforeSessionExpiry) === null || _callbacks$beforeSess === void 0 ? void 0 : _callbacks$beforeSess.call(callbacks, {
sessionKey: sessionKey
});
if (!(masterConfig !== null && masterConfig !== void 0 && (_masterConfig$auth28 = masterConfig.auth) !== null && _masterConfig$auth28 !== void 0 && _masterConfig$auth28.autoRefreshSession)) {
_context90.next = 16;
break;
}
_context90.next = 16;
return refreshSession({
expirationSeconds: session.expirationSeconds,
sessionKey: sessionKey
});
case 16:
case "end":
return _context90.stop();
}
}, _callee90);
}));
return function beforeExpiry() {
return _ref107.apply(this, arguments);
};
}();
expireSession = /*#__PURE__*/function () {
var _ref108 = _asyncToGenerator(/*#__PURE__*/_regeneratorRuntime().mark(function _callee91() {
var _callbacks$onSessionE;
var expiredSession;
return _regeneratorRuntime().wrap(function _callee91$(_context91) {
while (1) switch (_context91.prev = _context91.next) {
case 0:
_context91.next = 2;
return getSession({
sessionKey: sessionKey
});
case 2:
expiredSession = _context91.sent;
if (expiredSession) {
_context91.next = 5;
break;
}
return _context91.abrupt("return");
case 5:
callbacks === null || callbacks === void 0 ? void 0 : (_callbacks$onSessionE = callbacks.onSessionExpired) === null || _callbacks$onSessionE === void 0 ? void 0 : _callbacks$onSessionE.call(callbacks, {
sessionKey: sessionKey
});
_context91.next = 8;
return getActiveSessionKey();
case 8:
_context91.t0 = _context91.sent;
_context91.t1 = sessionKey;
if (!(_context91.t0 === _context91.t1)) {
_context91.next = 12;
break;
}
setSession(undefined);
case 12:
setAllSessions(function (prevSessions) {
if (!prevSessions) return prevSessions;
var newSessions = _objectSpread2({}, prevSessions);
delete newSessions[sessionKey];
return newSessions;
});
_context91.next = 15;
return clearSession({
sessionKey: sessionKey
});
case 15:
delete expiryTimeoutsRef.current[sessionKey];
delete expiryTimeoutsRef.current["".concat(sessionKey, "-warning")];
_context91.next = 19;
return logout();
case 19:
case "end":