UNPKG

@web3auth/no-modal

Version:
1,154 lines 55.7 kB
'use strict';

var _objectSpread = require('@babel/runtime/helpers/objectSpread2');
var _defineProperty = require('@babel/runtime/helpers/defineProperty');
var baseControllers = require('@toruslabs/base-controllers');
var constants$1 = require('@toruslabs/constants');
var httpHelpers = require('@toruslabs/http-helpers');
var securePubSub = require('@toruslabs/secure-pub-sub');
var auth = require('@web3auth/auth');
var wsEmbed = require('@web3auth/ws-embed');
var deepmerge = require('deepmerge');
var analytics = require('../../base/analytics.js');
var IChainInterface = require('../../base/chain/IChainInterface.js');
var baseConnector = require('../../base/connector/baseConnector.js');
var connectorStatus = require('../../base/connector/connectorStatus.js');
var constants = require('../../base/connector/constants.js');
require('jwt-decode');
require('../../base/constants.js');
var index = require('../../base/errors/index.js');
var loglevel = require('../../base/loglevel.js');
require('../../base/plugin/errors.js');
require('../../base/plugin/IPlugin.js');
var utils = require('../../base/utils.js');
var index$1 = require('../../base/wallet/index.js');
var utils$1 = require('../utils.js');
var authSolanaWallet = require('./authSolanaWallet.js');
var errors = require('../../account-linking/errors.js');
var rest = require('../../account-linking/rest.js');

// Auth connections that have been deprecated and are no longer supported by the SDK.
// Passing any of these as `authConnection` results in a hard error so consumers
// migrate off the removed providers instead of silently continuing.
const DEPRECATED_AUTH_CONNECTIONS = new Set(["farcaster"]);
function assertAuthConnectionSupported(authConnection) {
  if (DEPRECATED_AUTH_CONNECTIONS.has(authConnection)) {
    throw index.WalletInitializationError.invalidParams(`Auth connection "${authConnection}" has been deprecated and is no longer supported by the Web3Auth SDKs. ` + `Please use a different authConnection value.`);
  }
}
class AuthConnector extends baseConnector.BaseConnector {
  constructor(params) {
    super(params);
    _defineProperty(this, "name", index$1.WALLET_CONNECTORS.AUTH);
    _defineProperty(this, "connectorNamespace", IChainInterface.CONNECTOR_NAMESPACES.MULTICHAIN);
    _defineProperty(this, "type", constants.CONNECTOR_CATEGORY.IN_APP);
    _defineProperty(this, "authInstance", null);
    _defineProperty(this, "status", constants.CONNECTOR_STATUS.NOT_READY);
    _defineProperty(this, "privateKeyProvider", null);
    _defineProperty(this, "authOptions", void 0);
    _defineProperty(this, "loginSettings", {
      authConnection: ""
    });
    _defineProperty(this, "wsSettings", void 0);
    _defineProperty(this, "wsEmbedInstance", null);
    _defineProperty(this, "authConnectionConfig", []);
    _defineProperty(this, "wsEmbedInstancePromise", null);
    _defineProperty(this, "wsEmbedProviderListenerTarget", null);
    _defineProperty(this, "_solanaWallet", null);
    _defineProperty(this, "analytics", void 0);
    _defineProperty(this, "handleWsEmbedAccountsChanged", accounts => {
      if (accounts.length === 0) {
        if (!connectorStatus.CONNECTED_STATUSES.includes(this.status)) {
          return;
        }
        loglevel.log.info("No accounts found in the wallet, disconnecting");
        void this.disconnect({
          cleanup: true
        }).catch(error => {
          loglevel.log.error("Failed to disconnect auth connector after wallet accounts changed", error);
        });
      }
    });
    this.authOptions = params.connectorSettings;
    this.loginSettings = params.loginSettings || {
      authConnection: ""
    };
    this.wsSettings = params.walletServicesSettings || {
      loginMode: wsEmbed.WS_EMBED_LOGIN_MODE.PLUGIN
    };
    this.authConnectionConfig = params.authConnectionConfig || [];
    this.analytics = params.analytics || new analytics.Analytics();
  }
  get provider() {
    if (this.status !== constants.CONNECTOR_STATUS.NOT_READY) {
      const wsEmbedProvider = this.getWsEmbedProvider();
      return wsEmbedProvider || this.privateKeyProvider;
    }
    return null;
  }
  get wsEmbed() {
    return this.wsEmbedInstance;
  }
  get solanaWallet() {
    return this._solanaWallet;
  }
  set provider(_) {
    throw new Error("Not implemented");
  }
  async init(options) {
    const {
      chains
    } = this.coreOptions;
    const {
      chainId
    } = options;
    const chainConfig = chains.find(x => x.chainId === chainId);
    super.checkInitializationRequirements({
      chainConfig
    });
    if (!this.coreOptions.clientId) throw index.WalletInitializationError.invalidParams("clientId is required before auth's initialization");
    if (!this.authOptions) throw index.WalletInitializationError.invalidParams("authOptions is required before auth's initialization");
    if (this.authConnectionConfig.length === 0) throw index.WalletInitializationError.invalidParams("authConnectionConfig is required before auth's initialization");
    const isRedirectResult = this.authOptions.uxMode === auth.UX_MODE.REDIRECT;
    this.authOptions = _objectSpread(_objectSpread({}, this.authOptions), {}, {
      replaceUrlOnRedirect: isRedirectResult,
      useCoreKitKey: this.coreOptions.useSFAKey
    });
    this.authInstance = new auth.Auth(_objectSpread(_objectSpread({}, this.authOptions), {}, {
      clientId: this.coreOptions.clientId,
      network: this.coreOptions.web3AuthNetwork,
      sdkMode: auth.SDK_MODE.IFRAME,
      authConnectionConfig: this.authConnectionConfig.filter(x => !x.isDefault),
      mfaSettings: this.coreOptions.mfaSettings
    }));
    loglevel.log.debug("initializing auth connector init", this.authOptions);
    // making it async here to initialize provider.
    const authInstancePromise = this.authInstance.init();
    // Use this for xrpl cases
    if (this.coreOptions.privateKeyProvider) {
      this.privateKeyProvider = this.coreOptions.privateKeyProvider;
    } else {
      // initialize ws embed or private key provider based on chain namespace
      switch (chainConfig.chainNamespace) {
        case baseControllers.CHAIN_NAMESPACES.EIP155:
        case baseControllers.CHAIN_NAMESPACES.SOLANA:
          {
            const {
              default: WsEmbed
            } = await import('@web3auth/ws-embed');
            this.wsEmbedInstance = new WsEmbed({
              web3AuthClientId: this.coreOptions.clientId,
              web3AuthNetwork: this.coreOptions.web3AuthNetwork,
              modalZIndex: this.wsSettings.modalZIndex
            });
            const wsSupportedChains = chains.filter(x => x.chainNamespace === baseControllers.CHAIN_NAMESPACES.EIP155 || x.chainNamespace === baseControllers.CHAIN_NAMESPACES.SOLANA);
            this.wsEmbedInstancePromise = this.wsEmbedInstance.init(_objectSpread(_objectSpread({}, this.wsSettings), {}, {
              loginMode: wsEmbed.WS_EMBED_LOGIN_MODE.PLUGIN,
              chains: wsSupportedChains,
              chainId,
              buildEnv: this.authOptions.buildEnv,
              whiteLabel: _objectSpread(_objectSpread({}, this.authOptions.whiteLabel), this.wsSettings.whiteLabel)
            })).then(() => {
              this.bindWsEmbedProviderEvents();
              this.wsEmbedInstancePromise = null;
              return;
            });
            break;
          }
        case baseControllers.CHAIN_NAMESPACES.XRPL:
          throw index.WalletLoginError.connectionError("Private key provider is required for XRPL");
        default:
          {
            const {
              CommonPrivateKeyProvider
            } = await Promise.resolve().then(function () { return require('../../providers/base-provider/index.js'); });
            this.privateKeyProvider = new CommonPrivateKeyProvider({
              config: {
                chain: chainConfig,
                chains: this.coreOptions.chains
              }
            });
          }
      }
    }
    // wait for auth instance to be ready.
    loglevel.log.debug("initializing auth connector");
    await authInstancePromise;
    this.status = constants.CONNECTOR_STATUS.READY;
    this.emit(constants.CONNECTOR_EVENTS.READY, index$1.WALLET_CONNECTORS.AUTH);
    try {
      const {
        sessionId
      } = this.authInstance || {};
      // connect only if it is redirect result or if connect (connector is cached/already connected in same session) is true
      if (sessionId && (options.autoConnect || isRedirectResult)) {
        this.rehydrated = true;
        await this.connect({
          chainId: options.chainId,
          getAuthTokenInfo: options.getAuthTokenInfo
        });
      } else if (!sessionId && options.autoConnect) {
        // if here, this means that the connector is cached but the sessionId is not available.
        // this can happen if the sessionId has expired.
        // we are throwing an error to reset the cached state.
        throw index.WalletLoginError.connectionError("Failed to rehydrate");
      }
    } catch (error) {
      this.emit(constants.CONNECTOR_EVENTS.REHYDRATION_ERROR, error);
    }
  }
  async connect(params) {
    assertAuthConnectionSupported(params === null || params === void 0 ? void 0 : params.authConnection);
    super.checkConnectionRequirements();
    this.status = constants.CONNECTOR_STATUS.CONNECTING;
    this.emit(constants.CONNECTOR_EVENTS.CONNECTING, _objectSpread(_objectSpread({}, params), {}, {
      connector: index$1.WALLET_CONNECTORS.AUTH
    }));
    try {
      await this.connectWithProvider(params);
      return {
        ethereumProvider: this.provider,
        solanaWallet: this._solanaWallet,
        connectorName: this.name,
        connectorNamespace: this.connectorNamespace
      };
    } catch (error) {
      var _error$message;
      loglevel.log.error("Failed to connect with auth provider", error);
      // ready again to be connected
      this.status = constants.CONNECTOR_STATUS.READY;
      this.emit(constants.CONNECTOR_EVENTS.ERRORED, error);
      if (error !== null && error !== void 0 && (_error$message = error.message) !== null && _error$message !== void 0 && _error$message.includes("user closed popup")) {
        throw index.WalletLoginError.popupClosed();
      } else if (error instanceof index.Web3AuthError) {
        throw error;
      }
      throw index.WalletLoginError.connectionError("Failed to login with auth", error);
    }
  }
  async enableMFA(params = {
    authConnection: ""
  }) {
    assertAuthConnectionSupported(params === null || params === void 0 ? void 0 : params.authConnection);
    if (!this.connected) throw index.WalletLoginError.notConnectedError("Not connected with wallet");
    if (!this.authInstance) throw index.WalletInitializationError.notReady("authInstance is not ready");
    try {
      const result = await this.authInstance.enableMFA(params);
      // In redirect mode, the result is not available immediately, so we emit the event when the result is available.
      if (result) this.emit(constants.CONNECTOR_EVENTS.MFA_ENABLED, result);
    } catch (error) {
      loglevel.log.error("Failed to enable MFA with auth provider", error);
      if (error instanceof index.Web3AuthError) {
        throw error;
      }
      throw index.WalletLoginError.connectionError("Failed to enable MFA with auth", error);
    }
  }
  async manageMFA(params = {
    authConnection: ""
  }) {
    assertAuthConnectionSupported(params === null || params === void 0 ? void 0 : params.authConnection);
    if (!this.connected) throw index.WalletLoginError.notConnectedError("Not connected with wallet");
    if (!this.authInstance) throw index.WalletInitializationError.notReady("authInstance is not ready");
    try {
      await this.authInstance.manageMFA(params);
    } catch (error) {
      loglevel.log.error("Failed to manage MFA with auth provider", error);
      if (error instanceof index.Web3AuthError) {
        throw error;
      }
      throw index.WalletLoginError.connectionError("Failed to manage MFA with auth", error);
    }
  }
  async disconnect(options = {
    cleanup: false
  }) {
    if (!this.connected) throw index.WalletLoginError.notConnectedError("Not connected with wallet");
    if (!this.authInstance) throw index.WalletInitializationError.notReady("authInstance is not ready");
    this.status = constants.CONNECTOR_STATUS.DISCONNECTING;
    await this.authInstance.logout();
    if (this.wsEmbedInstance) await this.wsEmbedInstance.logout();
    if (options.cleanup) {
      this.status = constants.CONNECTOR_STATUS.NOT_READY;
      this.authInstance = null;
      if (this.wsEmbedInstance) this.wsEmbedInstance = null;
      if (this.privateKeyProvider) this.privateKeyProvider = null;
    } else {
      // ready to be connected again
      this.status = constants.CONNECTOR_STATUS.READY;
    }
    this.rehydrated = false;
    this._solanaWallet = null;
    this.unbindWsEmbedProviderEvents();
    this.emit(constants.CONNECTOR_EVENTS.DISCONNECTED, {
      connector: index$1.WALLET_CONNECTORS.AUTH
    });
  }
  async getAuthTokenInfo() {
    if (!this.canAuthorize) throw index.WalletLoginError.notConnectedError("Not connected with wallet, Please login/connect first");
    this.status = constants.CONNECTOR_STATUS.AUTHORIZING;
    this.emit(constants.CONNECTOR_EVENTS.AUTHORIZING, {
      connector: index$1.WALLET_CONNECTORS.AUTH
    });
    const userInfo = await this.getUserInfo();
    this.status = constants.CONNECTOR_STATUS.AUTHORIZED;
    const [accessToken, refreshToken] = await Promise.all([this.authInstance.authSessionManager.getAccessToken(), this.authInstance.authSessionManager.getRefreshToken()]);
    this.emit(constants.CONNECTOR_EVENTS.AUTHORIZED, {
      connector: index$1.WALLET_CONNECTORS.AUTH,
      authTokenInfo: {
        idToken: userInfo.idToken,
        accessToken,
        refreshToken
      }
    });
    return {
      idToken: userInfo.idToken,
      accessToken,
      refreshToken
    };
  }
  async getUserInfo() {
    if (!this.canAuthorize) throw index.WalletLoginError.notConnectedError("Not connected with wallet");
    if (!this.authInstance) throw index.WalletInitializationError.notReady("authInstance is not ready");
    const [userInfo, linkedAccounts] = await Promise.all([this.authInstance.getUserInfo(), this.getLinkedAccounts()]);
    return _objectSpread(_objectSpread({}, userInfo), {}, {
      linkedAccounts
    });
  }
  async getLinkedAccounts() {
    var _citadelUserInfo$acco, _this$solanaWallet;
    const accessToken = await this.authInstance.authSessionManager.getAccessToken();
    if (!accessToken) throw index.WalletLoginError.connectionError("Could not obtain an access token from the current AUTH session.");
    const citadelUserInfo = await httpHelpers.get(`${utils.citadelServerUrl(this.coreOptions.authBuildEnv)}/v1/user`, {
      headers: {
        Authorization: `Bearer ${accessToken}`
      }
    });
    if (!(citadelUserInfo !== null && citadelUserInfo !== void 0 && (_citadelUserInfo$acco = citadelUserInfo.accounts) !== null && _citadelUserInfo$acco !== void 0 && _citadelUserInfo$acco.length)) return [];
    const currentChainNamespace = ((_this$solanaWallet = this.solanaWallet) === null || _this$solanaWallet === void 0 ? void 0 : _this$solanaWallet.accounts.length) > 0 ? baseControllers.CHAIN_NAMESPACES.SOLANA : "evm"; // Note: citadel chain namespace is "evm" for EVM chains
    const filteredLinkedAccounts = [];
    for (const account of citadelUserInfo.accounts) {
      const {
        chainNamespace,
        isPrimary,
        accountType
      } = account;
      // for now, we will take all primary accounts as a **SINGLE** linked account
      // we don't wanna populate the multiple primary accounts as different linked accounts
      // so, we hide the primary accounts for other chain namespaces
      // also, linked `account_abstraction` accounts are derived from the primary account, so we don't need to show them separately
      // TODO: revisit this logic once we have a concrete plan for handling multiple primary accounts
      if (isPrimary && chainNamespace && chainNamespace !== currentChainNamespace || accountType === "account_abstraction") continue;
      filteredLinkedAccounts.push(_objectSpread(_objectSpread({}, account), {}, {
        // by default, the primary account is the active account
        active: isPrimary
      }));
    }
    return filteredLinkedAccounts;
  }
  async switchChain(params, init = false) {
    super.checkSwitchChainRequirements(params, init);
    const {
      chainId: newChainId
    } = params;
    const {
      chainId: currentChainId
    } = this.provider;
    if (currentChainId === newChainId) return;
    const newChainConfig = this.coreOptions.chains.find(c => c.chainId === newChainId);
    if (!newChainConfig) throw index.WalletInitializationError.invalidParams("Chain config is not available");
    if (newChainConfig.chainNamespace === baseControllers.CHAIN_NAMESPACES.SOLANA || newChainConfig.chainNamespace === baseControllers.CHAIN_NAMESPACES.EIP155) {
      var _this$wsEmbedInstance;
      if (!((_this$wsEmbedInstance = this.wsEmbedInstance) !== null && _this$wsEmbedInstance !== void 0 && _this$wsEmbedInstance.provider)) throw index.WalletInitializationError.notReady("Wallet embed is not ready");
      const caipChainId = baseControllers.getCaipChainId(newChainConfig);
      await this.wsEmbedInstance.provider.request({
        method: "wallet_switchChain",
        params: {
          chainId: caipChainId
        }
      });
    } else {
      var _this$privateKeyProvi;
      await ((_this$privateKeyProvi = this.privateKeyProvider) === null || _this$privateKeyProvi === void 0 ? void 0 : _this$privateKeyProvi.switchChain(params));
    }
  }
  async cleanup() {
    var _this$authInstance, _this$wsEmbedInstance2;
    await ((_this$authInstance = this.authInstance) === null || _this$authInstance === void 0 ? void 0 : _this$authInstance.cleanup());
    (_this$wsEmbedInstance2 = this.wsEmbedInstance) === null || _this$wsEmbedInstance2 === void 0 || _this$wsEmbedInstance2.clearInit();
    this._solanaWallet = null;
    this.unbindWsEmbedProviderEvents();
  }
  getOAuthProviderConfig(params) {
    const {
      authConnection,
      authConnectionId,
      groupedAuthConnectionId
    } = params;
    const providerConfig = this.authConnectionConfig.find(x => {
      if (groupedAuthConnectionId && authConnectionId) {
        return x.authConnection === authConnection && x.groupedAuthConnectionId === groupedAuthConnectionId && x.authConnectionId === authConnectionId;
      }
      if (authConnectionId) {
        return x.authConnection === authConnection && x.authConnectionId === authConnectionId;
      }
      // return the default auth connection, if not found, return undefined
      return x.authConnection === authConnection && x.isDefault;
    });
    return providerConfig;
  }
  async generateChallengeAndSign() {
    // we do not support this for auth connector, as of now. since auth login returns a valid idToken
    throw new Error("Not implemented");
  }
  async switchAccount(account, context) {
    if (!connectorStatus.CONNECTED_STATUSES.includes(this.status)) {
      throw index.WalletLoginError.notConnectedError("No wallet is connected. Connect with AUTH before switching accounts.");
    }
    try {
      var _userInfo$linkedAccou;
      const userInfo = await this.getUserInfo();
      const linkedAccounts = (_userInfo$linkedAccou = userInfo.linkedAccounts) !== null && _userInfo$linkedAccou !== void 0 ? _userInfo$linkedAccou : [];
      const targetAccount = linkedAccounts.find(candidate => candidate.id === account.id);
      if (!targetAccount) {
        throw errors.AccountLinkingError.requestFailed(`No connected wallet matches account id "${account.id}". Refresh user info and try again.`);
      }
      const currentActiveAccount = context.activeAccount;
      const isTargetAlreadyActive = currentActiveAccount ? currentActiveAccount.id === targetAccount.id : targetAccount.isPrimary;
      if (isTargetAlreadyActive) {
        return;
      }
      this.analytics.track(analytics.ANALYTICS_EVENTS.ACCOUNT_SWITCH_STARTED, this.getSwitchAccountTrackData(targetAccount));
      if (targetAccount.connector === index$1.WALLET_CONNECTORS.AUTH && targetAccount.isPrimary) {
        var _this$provider$chainI, _this$provider;
        const activeChainId = this.getChainIdForLinkedAccount(targetAccount, (_this$provider$chainI = (_this$provider = this.provider) === null || _this$provider === void 0 ? void 0 : _this$provider.chainId) !== null && _this$provider$chainI !== void 0 ? _this$provider$chainI : context.currentChainId);
        const ethereumProvider = this.provider;
        const solanaWallet = this.solanaWallet;
        if (!ethereumProvider && !solanaWallet) {
          throw errors.AccountLinkingError.requestFailed("Failed to restore the primary AUTH session for account switch.");
        }
        return {
          kind: "primary",
          targetAccount,
          activeAccount: null,
          activeChainId,
          connectorName: this.name,
          connectorNamespace: this.connectorNamespace,
          ethereumProvider,
          solanaWallet
        };
      }
      return {
        kind: "external",
        targetAccount,
        activeAccount: targetAccount,
        activeChainId: this.getChainIdForLinkedAccount(targetAccount, context.currentChainId)
      };
    } catch (error) {
      await this.trackSwitchAccountFailed(account, error);
      throw error;
    }
  }
  async trackSwitchAccountCompleted(account) {
    await this.analytics.track(analytics.ANALYTICS_EVENTS.ACCOUNT_SWITCH_COMPLETED, _objectSpread(_objectSpread({}, this.getSwitchAccountTrackData(account)), {}, {
      connector: account.connector
    }));
  }
  async trackSwitchAccountFailed(account, error) {
    await this.analytics.track(analytics.ANALYTICS_EVENTS.ACCOUNT_SWITCH_FAILED, _objectSpread(_objectSpread({}, this.getSwitchAccountTrackData(account)), utils.getErrorAnalyticsProperties(error)));
  }
  async linkAccount(params) {
    if (!connectorStatus.CONNECTED_STATUSES.includes(this.status)) {
      throw index.WalletLoginError.notConnectedError("No wallet is connected. Connect with AUTH before linking an account.");
    }
    const {
      connectorName,
      chainId,
      connectorToLink
    } = params;
    try {
      if (!connectorToLink.connected) {
        const connection = await connectorToLink.connect({
          chainId,
          isAccountLinking: true
        });
        if (!connection) {
          throw errors.AccountLinkingError.walletProofFailed(`Failed to connect to "${params.connectorName}" for account linking.`);
        }
      }
    } catch (error) {
      if (error instanceof index.Web3AuthError) throw error;
      throw errors.AccountLinkingError.walletProofFailed(error instanceof Error ? error.message : String(error), error);
    }
    const trackData = {
      connector: this.name,
      linking_connector: connectorName,
      chain_id: params.chainId
    };
    try {
      await this.analytics.track(analytics.ANALYTICS_EVENTS.ACCOUNT_LINKING_STARTED, trackData);
      const {
        accessToken,
        idToken
      } = await this.getPrimaryAuthSession(params.authSessionTokens);
      const walletProof = await this.createWalletLinkingProof(params.connectorToLink, chainId);
      const authServerUrl = utils.citadelServerUrl(this.coreOptions.authBuildEnv);
      const result = await rest.makeAccountLinkingRequest(authServerUrl, accessToken, {
        idToken,
        network: walletProof.network,
        connector: params.connectorName,
        message: walletProof.challenge,
        signature: {
          s: walletProof.signature,
          t: walletProof.signatureType
        }
      });
      this.analytics.track(analytics.ANALYTICS_EVENTS.ACCOUNT_LINKING_COMPLETED, _objectSpread(_objectSpread({}, trackData), {}, {
        linked_address: walletProof.address
      }));
      return result;
    } catch (error) {
      this.analytics.track(analytics.ANALYTICS_EVENTS.ACCOUNT_LINKING_FAILED, _objectSpread(_objectSpread({}, trackData), utils.getErrorAnalyticsProperties(error)));
      // disconnect the wallet connector to avoid any leftover state
      try {
        if (connectorToLink.connected) {
          await connectorToLink.disconnect({
            cleanup: true
          });
        }
      } catch (disconnectError) {
        loglevel.log.debug("Failed to disconnect wallet connector after linking failure", disconnectError);
      }
      throw error;
    }
  }
  async unlinkAccount(params) {
    if (!connectorStatus.CONNECTED_STATUSES.includes(this.status)) {
      throw index.WalletLoginError.notConnectedError("No wallet is connected. Connect with AUTH before unlinking an account.");
    }
    const {
      address,
      authSessionTokens
    } = params;
    const trackData = {
      connector: this.name,
      address
    };
    await this.analytics.track(analytics.ANALYTICS_EVENTS.ACCOUNT_UNLINKING_STARTED, trackData);
    try {
      const {
        accessToken,
        idToken,
        linkedAccounts
      } = await this.getPrimaryAuthSession(authSessionTokens, {
        includeLinkedAccounts: true
      });
      const network = this.getNetworkForUnlinkAddress(linkedAccounts, address);
      const authServerUrl = utils.citadelServerUrl(this.coreOptions.authBuildEnv);
      const result = await rest.makeAccountUnlinkingRequest(authServerUrl, accessToken, {
        idToken,
        address,
        network
      });
      await this.analytics.track(analytics.ANALYTICS_EVENTS.ACCOUNT_UNLINKING_COMPLETED, _objectSpread(_objectSpread({}, trackData), {}, {
        linked_address: address
      }));
      return result;
    } catch (error) {
      await this.analytics.track(analytics.ANALYTICS_EVENTS.ACCOUNT_UNLINKING_FAILED, _objectSpread(_objectSpread({}, trackData), utils.getErrorAnalyticsProperties(error)));
      throw error;
    }
  }
  getChainIdForLinkedAccount(account, preferredChainId) {
    const accountChainNamespace = account.chainNamespace ? utils.parseChainNamespaceFromCitadelResponse(account.chainNamespace) : null;
    if (preferredChainId) {
      const preferredChain = this.coreOptions.chains.find(chain => chain.chainId === preferredChainId);
      if (preferredChain && (!accountChainNamespace || preferredChain.chainNamespace === accountChainNamespace)) {
        return preferredChainId;
      }
    }
    if (accountChainNamespace) {
      const namespaceChain = this.coreOptions.chains.find(chain => chain.chainNamespace === accountChainNamespace);
      if (namespaceChain) {
        return namespaceChain.chainId;
      }
    }
    throw index.WalletInitializationError.invalidParams(`No compatible chainId found for connector "${account.connector}".`);
  }
  async assertSwitchAccountConnectorMatchesTarget(connector, account) {
    if (!account.chainNamespace) {
      throw errors.AccountLinkingError.requestFailed(`Could not determine the chain namespace for linked account "${account.eoaAddress}".`);
    }
    const chainNamespace = utils.parseChainNamespaceFromCitadelResponse(account.chainNamespace);
    let connectedAddress = null;
    if (chainNamespace === baseControllers.CHAIN_NAMESPACES.EIP155) {
      var _accounts$;
      const accounts = connector.provider ? await connector.provider.request({
        method: "eth_accounts"
      }) : [];
      connectedAddress = (_accounts$ = accounts === null || accounts === void 0 ? void 0 : accounts[0]) !== null && _accounts$ !== void 0 ? _accounts$ : null;
    } else if (chainNamespace === baseControllers.CHAIN_NAMESPACES.SOLANA) {
      var _connector$solanaWall, _connector$solanaWall2;
      connectedAddress = (_connector$solanaWall = (_connector$solanaWall2 = connector.solanaWallet) === null || _connector$solanaWall2 === void 0 || (_connector$solanaWall2 = _connector$solanaWall2.accounts) === null || _connector$solanaWall2 === void 0 || (_connector$solanaWall2 = _connector$solanaWall2[0]) === null || _connector$solanaWall2 === void 0 ? void 0 : _connector$solanaWall2.address) !== null && _connector$solanaWall !== void 0 ? _connector$solanaWall : null;
    } else {
      throw errors.AccountLinkingError.requestFailed(`Unsupported chain namespace "${account.chainNamespace}" for linked account "${account.eoaAddress}".`);
    }
    if (!connectedAddress) {
      throw errors.AccountLinkingError.requestFailed(`Connector "${account.connector}" is not connected to linked account "${account.eoaAddress}". Connect the intended wallet account and try again.`);
    }
    const isExpectedAddress = chainNamespace === baseControllers.CHAIN_NAMESPACES.EIP155 ? connectedAddress.toLowerCase() === account.eoaAddress.toLowerCase() : connectedAddress === account.eoaAddress;
    if (!isExpectedAddress) {
      throw errors.AccountLinkingError.requestFailed(`Connector "${account.connector}" is connected to "${connectedAddress}" instead of linked account "${account.eoaAddress}". Connect the intended wallet account and try again.`);
    }
  }
  toSwitchAccountConnectorError(account, error) {
    if (error instanceof errors.AccountLinkingError && error.code === 5401) {
      return error;
    }
    const message = error instanceof Error ? error.message : String(error);
    const isUnavailableConnectorError = error instanceof errors.AccountLinkingError && error.code === 5405 || /not available|not initialized|not ready/i.test(message);
    if (isUnavailableConnectorError) {
      return errors.AccountLinkingError.requestFailed(`Connector "${account.connector}" is not available for linked account "${account.eoaAddress}". Make sure the wallet is installed, unlocked, and accessible, then try again.`, error);
    }
    return errors.AccountLinkingError.requestFailed(`Failed to connect connector "${account.connector}" for linked account "${account.eoaAddress}". ${message}`, error);
  }
  getSwitchAccountTrackData(account) {
    var _account$eoaAddress;
    return {
      connector: this.name,
      account_id: account.id,
      account_type: account.accountType,
      switched_to_address: (_account$eoaAddress = account.eoaAddress) !== null && _account$eoaAddress !== void 0 ? _account$eoaAddress : null
    };
  }
  async getPrimaryAuthSession(authSessionTokens, options = {}) {
    const {
      accessToken: cachedAccessToken,
      idToken: cachedIdToken
    } = authSessionTokens;
    const {
      includeLinkedAccounts = false
    } = options;
    let accessToken = cachedAccessToken;
    let idToken = cachedIdToken;
    let linkedAccounts = [];
    if (includeLinkedAccounts) {
      const userInfoPromise = this.getUserInfo();
      if (!accessToken || !idToken) {
        var _userInfo$linkedAccou2;
        const [tokenInfo, userInfo] = await Promise.all([this.getAuthTokenInfo(), userInfoPromise]);
        accessToken = tokenInfo.accessToken;
        idToken = tokenInfo.idToken;
        linkedAccounts = (_userInfo$linkedAccou2 = userInfo.linkedAccounts) !== null && _userInfo$linkedAccou2 !== void 0 ? _userInfo$linkedAccou2 : [];
      } else {
        var _userInfo$linkedAccou3;
        const userInfo = await userInfoPromise;
        linkedAccounts = (_userInfo$linkedAccou3 = userInfo.linkedAccounts) !== null && _userInfo$linkedAccou3 !== void 0 ? _userInfo$linkedAccou3 : [];
      }
    } else if (!accessToken || !idToken) {
      const tokenInfo = await this.getAuthTokenInfo();
      accessToken = tokenInfo.accessToken;
      idToken = tokenInfo.idToken;
    }
    if (!accessToken || !idToken) {
      throw errors.AccountLinkingError.primaryTokenNotAvailable("Could not obtain an identity token from the current AUTH session.");
    }
    return {
      accessToken,
      idToken,
      linkedAccounts
    };
  }
  getNetworkForUnlinkAddress(accounts, address) {
    const matchedAccount = accounts.find(account => {
      var _account$address, _account$eoaAddress2;
      if (!account.chainNamespace || utils.parseChainNamespaceFromCitadelResponse(account.chainNamespace) !== baseControllers.CHAIN_NAMESPACES.EIP155) {
        return false;
      }
      const normalizedAddress = address.toLowerCase();
      return ((_account$address = account.address) === null || _account$address === void 0 ? void 0 : _account$address.toLowerCase()) === normalizedAddress || ((_account$eoaAddress2 = account.eoaAddress) === null || _account$eoaAddress2 === void 0 ? void 0 : _account$eoaAddress2.toLowerCase()) === normalizedAddress;
    });
    if (!matchedAccount) {
      throw errors.AccountLinkingError.requestFailed(`No connected wallet matches address "${address}".`);
    }
    if (!matchedAccount.chainNamespace) {
      throw errors.AccountLinkingError.requestFailed(`Could not determine the chain namespace for address "${address}".`);
    }
    const chainNamespace = utils.parseChainNamespaceFromCitadelResponse(matchedAccount.chainNamespace);
    if (chainNamespace === baseControllers.CHAIN_NAMESPACES.EIP155) {
      return "ethereum";
    }
    if (chainNamespace === baseControllers.CHAIN_NAMESPACES.SOLANA) {
      return "solana";
    }
    throw errors.AccountLinkingError.requestFailed(`Unsupported chain namespace "${matchedAccount.chainNamespace}" for address "${address}".`);
  }
  async createWalletLinkingProof(connector, chainId) {
    // Notify listeners that the linking wallet is about to be asked for a signature so the UI
    // (e.g. modal) can switch from a "connecting" loader to an "authorizing" prompt while the
    // user reviews the signature request inside their wallet. Emitted on the isolated wallet
    // connector (not the auth connector) so it doesn't mutate the global SDK status.
    connector.emit(constants.CONNECTOR_EVENTS.AUTHORIZING, {
      connector: connector.name
    });
    // Reuse the caller's target chain so multichain wallets generate the linking
    // proof for the same namespace they were connected for.
    const {
      challenge,
      signature,
      chainNamespace
    } = await connector.generateChallengeAndSign(undefined, undefined, chainId);
    const address = await this.getLinkingWalletAddress(connector, chainNamespace);
    if (chainNamespace === baseControllers.CHAIN_NAMESPACES.EIP155) {
      return {
        address,
        challenge,
        signature,
        signatureType: "eip191",
        network: "ethereum"
      };
    }
    if (chainNamespace === baseControllers.CHAIN_NAMESPACES.SOLANA) {
      return {
        address,
        challenge,
        signature,
        signatureType: "sip99",
        network: "solana"
      };
    }
    throw errors.AccountLinkingError.unsupportedConnector(`Connector "${connector.name}" returned unsupported chain namespace "${chainNamespace}".`);
  }
  async getLinkingWalletAddress(connector, chainNamespace) {
    if (chainNamespace === baseControllers.CHAIN_NAMESPACES.SOLANA) {
      var _connector$solanaWall3;
      const address = (_connector$solanaWall3 = connector.solanaWallet) === null || _connector$solanaWall3 === void 0 || (_connector$solanaWall3 = _connector$solanaWall3.accounts) === null || _connector$solanaWall3 === void 0 || (_connector$solanaWall3 = _connector$solanaWall3[0]) === null || _connector$solanaWall3 === void 0 ? void 0 : _connector$solanaWall3.address;
      if (!address) {
        throw errors.AccountLinkingError.walletProofFailed("No connected Solana account found for account linking.");
      }
      return address;
    }
    if (!connector.provider) {
      throw errors.AccountLinkingError.walletProofFailed("No connected EVM account found for account linking.");
    }
    const accounts = await connector.provider.request({
      method: "eth_accounts"
    });
    if (!(accounts !== null && accounts !== void 0 && accounts.length)) {
      throw errors.AccountLinkingError.walletProofFailed("No connected EVM account found for account linking.");
    }
    return accounts[0];
  }
  getWsEmbedProvider() {
    var _this$wsEmbedInstance3, _this$wsEmbedInstance4;
    return (_this$wsEmbedInstance3 = (_this$wsEmbedInstance4 = this.wsEmbedInstance) === null || _this$wsEmbedInstance4 === void 0 ? void 0 : _this$wsEmbedInstance4.provider) !== null && _this$wsEmbedInstance3 !== void 0 ? _this$wsEmbedInstance3 : null;
  }
  bindWsEmbedProviderEvents() {
    const rawProvider = this.getWsEmbedProvider();
    if (this.wsEmbedProviderListenerTarget === rawProvider) {
      return;
    }
    this.unbindWsEmbedProviderEvents();
    if (!rawProvider) {
      return;
    }
    rawProvider.on("accountsChanged", this.handleWsEmbedAccountsChanged);
    this.wsEmbedProviderListenerTarget = rawProvider;
  }
  unbindWsEmbedProviderEvents() {
    if (!this.wsEmbedProviderListenerTarget) {
      return;
    }
    this.wsEmbedProviderListenerTarget.removeListener("accountsChanged", this.handleWsEmbedAccountsChanged);
    this.wsEmbedProviderListenerTarget = null;
  }
  setupSolanaWallet() {
    const solanaChains = this.coreOptions.chains.filter(c => c.chainNamespace === baseControllers.CHAIN_NAMESPACES.SOLANA);
    if (solanaChains.length === 0 || !this.provider) return;
    if (this._solanaWallet instanceof authSolanaWallet.AuthSolanaWallet) {
      return;
    }
    this._solanaWallet = new authSolanaWallet.AuthSolanaWallet(this.provider, solanaChains);
  }
  _getFinalPrivKey() {
    if (!this.authInstance) return "";
    let finalPrivKey = this.authInstance.privKey;
    // coreKitKey is available only for custom connections by default
    if (this.coreOptions.useSFAKey) {
      // this is to check if the user has already logged in but coreKitKey is not available.
      // when useSFAKey is set to true.
      // This is to ensure that when there is no user session active, we don't throw an exception.
      if (this.authInstance.privKey && !this.authInstance.coreKitKey) {
        throw index.WalletLoginError.sfaKeyNotFound();
      }
      finalPrivKey = this.authInstance.coreKitKey;
    }
    return finalPrivKey;
  }
  async connectWithProvider(params) {
    var _this$authInstance2, _params$extraLoginOpt, _this$authInstance3, _this$authInstance4;
    if (!this.authInstance) throw index.WalletInitializationError.notReady("authInstance is not ready");
    const chainConfig = this.coreOptions.chains.find(x => x.chainId === params.chainId);
    if (!chainConfig) throw index.WalletLoginError.connectionError("Chain config is not available");
    const {
      chainNamespace
    } = chainConfig;
    // if not logged in then login
    const keyAvailable = chainNamespace === baseControllers.CHAIN_NAMESPACES.EIP155 || chainNamespace === baseControllers.CHAIN_NAMESPACES.SOLANA ? (_this$authInstance2 = this.authInstance) === null || _this$authInstance2 === void 0 ? void 0 : _this$authInstance2.sessionId : this._getFinalPrivKey();
    if (params.idToken) params.extraLoginOptions = _objectSpread(_objectSpread({}, params.extraLoginOptions), {}, {
      id_token: params.idToken
    });
    if (!keyAvailable || (_params$extraLoginOpt = params.extraLoginOptions) !== null && _params$extraLoginOpt !== void 0 && _params$extraLoginOpt.id_token) {
      var _params$extraLoginOpt2;
      // always use "other" curve to return token with all keys encoded so wallet service can switch between evm and solana namespace
      this.loginSettings.curve = auth.SUPPORTED_KEY_CURVES.OTHER;
      const loginParams = deepmerge(this.loginSettings, params);
      if ((_params$extraLoginOpt2 = params.extraLoginOptions) !== null && _params$extraLoginOpt2 !== void 0 && _params$extraLoginOpt2.id_token) {
        await this.connectWithJwtLogin(loginParams);
      } else {
        await this.connectWithSocialLogin(loginParams);
      }
    }
    // if useSFAKey is true and privKey is available but coreKitKey is not available, throw an error
    if (this.coreOptions.useSFAKey && (_this$authInstance3 = this.authInstance) !== null && _this$authInstance3 !== void 0 && _this$authInstance3.privKey && !((_this$authInstance4 = this.authInstance) !== null && _this$authInstance4 !== void 0 && _this$authInstance4.coreKitKey)) {
      // If the user is already logged in, logout and throw an error
      if (this.authInstance.sessionId) {
        await this.authInstance.logout();
      }
      throw index.WalletLoginError.sfaKeyNotFound("This typically occurs when the authentication method used does not provide SFA keys (e.g., default auth connection).");
    }
    const connectorNamespace = this.connectorNamespace;
    // setup WS embed if chainNamespace is EIP155 or SOLANA
    if (chainNamespace === baseControllers.CHAIN_NAMESPACES.EIP155 || chainNamespace === baseControllers.CHAIN_NAMESPACES.SOLANA) {
      // wait for ws embed instance to be ready.
      if (this.wsEmbedInstancePromise) await this.wsEmbedInstancePromise;
      const {
        sessionId,
        sessionNamespace
      } = this.authInstance || {};
      if (sessionId) {
        this.wsEmbedInstance.setAccessTokenProvider(this.accessTokenProvider.bind(this));
        this.bindWsEmbedProviderEvents();
        const isLoggedIn = await this.wsEmbedInstance.connectWithSession({
          sessionId,
          sessionNamespace,
          idToken: await this.getIdToken()
        });
        if (isLoggedIn) {
          this.setupSolanaWallet();
          // if getAuthTokenInfo is true, then get auth token info
          // No need to get auth token info for auth connector as it is already handled
          this.status = constants.CONNECTOR_STATUS.CONNECTED;
          this.emit(constants.CONNECTOR_EVENTS.CONNECTED, {
            connectorName: index$1.WALLET_CONNECTORS.AUTH,
            reconnected: this.rehydrated,
            ethereumProvider: this.provider,
            solanaWallet: this._solanaWallet,
            connectorNamespace
          });
          if (params.getAuthTokenInfo) {
            await this.getAuthTokenInfo();
          }
        }
      }
    } else {
      // setup private key provider if chainNamespace is other
      const finalPrivKey = this._getFinalPrivKey();
      if (finalPrivKey) {
        await this.privateKeyProvider.setupProvider(finalPrivKey, params.chainId);
        this.status = constants.CONNECTOR_STATUS.CONNECTED;
        this.emit(constants.CONNECTOR_EVENTS.CONNECTED, {
          connectorName: index$1.WALLET_CONNECTORS.AUTH,
          ethereumProvider: this.provider,
          solanaWallet: this._solanaWallet,
          reconnected: this.rehydrated,
          connectorNamespace
        });
      }
    }
  }
  async connectWithSocialLogin(params) {
    var _params$extraLoginOpt3, _params$extraLoginOpt4;
    const providerConfig = this.getOAuthProviderConfig({
      authConnection: params.authConnection,
      authConnectionId: params.authConnectionId,
      groupedAuthConnectionId: params.groupedAuthConnectionId
    });
    if (!(providerConfig !== null && providerConfig !== void 0 && providerConfig.authConnection)) throw index.WalletLoginError.connectionError("Invalid auth connection.");
    const jwtParams = _objectSpread(_objectSpread(_objectSpread({}, providerConfig.jwtParameters || {}), params.extraLoginOptions || {}), {}, {
      login_hint: params.loginHint || ((_params$extraLoginOpt3 = params.extraLoginOptions) === null || _params$extraLoginOpt3 === void 0 ? void 0 : _params$extraLoginOpt3.login_hint)
    });
    const nonce = utils$1.generateNonce();
    // post a message to the auth provider to indicate that login has been initiated.
    const loginParams = _objectSpread(_objectSpread({}, baseControllers.cloneDeep(params)), {}, {
      recordId: auth.generateRecordId(),
      loginSource: "web3auth-web"
    });
    loginParams.extraLoginOptions = _objectSpread(_objectSpread({}, loginParams.extraLoginOptions || {}), {}, {
      login_hint: params.loginHint || ((_params$extraLoginOpt4 = params.extraLoginOptions) === null || _params$extraLoginOpt4 === void 0 ? void 0 : _params$extraLoginOpt4.login_hint)
    });
    delete loginParams.chainId;
    const popupParams = {
      authConnection: params.authConnection,
      authConnectionId: providerConfig.authConnectionId,
      clientId: providerConfig.clientId || jwtParams.client_id,
      groupedAuthConnectionId: providerConfig.groupedAuthConnectionId,
      redirect_uri: `${this.authInstance.options.sdkUrl}/auth`,
      jwtParams,
      customState: {
        nonce,
        appState: params.appState,
        // use the default settings from the auth instance.
        dapp_redirect_url: this.authInstance.options.redirectUrl,
        uxMode: this.authInstance.options.uxMode,
        whiteLabel: JSON.stringify(this.authInstance.options.whiteLabel),
        loginParams: JSON.stringify(loginParams),
        version: auth.version.split(".")[0],
        web3AuthNetwork: this.coreOptions.web3AuthNetwork,
        web3AuthClientId: this.coreOptions.clientId,
        originData: this.getOriginData()
      },
      web3AuthClientId: this.coreOptions.clientId,
      web3AuthNetwork: this.coreOptions.web3AuthNetwork,
      storageServerUrl: this.authInstance.options.storageServerUrl
    };
    const loginHandler = auth.createHandler(popupParams);
    const verifierWindow = new auth.PopupHandler({
      url: loginHandler.finalURL,
      timeout: 0
    });
    if (this.authOptions.uxMode === auth.UX_MODE.REDIRECT) return verifierWindow.redirect(this.authOptions.replaceUrlOnRedirect);
    let isClosedWindow = false;
    this.auditOAuditProgress(loginParams).catch(error => {
      loglevel.log.error("Error reporting `oauthInitiated` audit progress", error);
    });
    return new Promise((resolve, reject) => {
      verifierWindow.open().catch(error => {
        loglevel.log.error("Error during login with social", error);
        this.authInstance.postLoginCancelledMessage(nonce);
        reject(error);
      });
      // this is to close the popup when the login is finished.
      const securePubSub$1 = new securePubSub.SecurePubSub({
        sameIpCheck: true,
        serverUrl: this.authInstance.options.storageServerUrl,
        socketUrl: this.authInstance.options.sessionSocketUrl
      });
      securePubSub$1.subscribe(`web3auth-login-${nonce}`).then(data => {
        const parsedData = JSON.parse(data || "{}");
        if ((parsedData === null || parsedData === void 0 ? void 0 : parsedData.message) === "login_finished") {
          if (parsedData !== null && parsedData !== void 0 && parsedData.error) {
            this.authInstance.postLoginCancelledMessage(nonce);
            reject(parsedData.error);
          }
          isClosedWindow = true;
          securePubSub$1.cleanup();
          verifierWindow.close();
        }
        return true;
      }).catch(error => {
        // swallow the error, dont need to throw.
        loglevel.log.error("Error during login with social", error);
        this.reportFailedOauthAudit(loginParams);
      });
      verifierWindow.once("close", () => {
        if (!isClosedWindow) {
          securePubSub$1.cleanup();
          this.authInstance.postLoginCancelledMessage(nonce);
          reject(index.WalletLoginError.popupClosed());
        }
      });
      this.authInstance.postLoginInitiatedMessage(loginParams, nonce).then(resolve).catch(error => {
        this.reportFailedOauthAudit(loginParams);
        if (error instanceof index.Web3AuthError) {
          throw error;
        }
        const errorMessage = error instanceof Error ? error.message : error;
        if (errorMessage === "Access control denied") {
          reject(index.WalletLoginError.userBlocked(errorMessage, error));
          return;
        }
        reject(index.WalletLoginError.connectionError(errorMessage || "Failed to login with social"));
      });
    });
  }
  async accessTokenProvider({
    forceRefresh
  }) {
    if (forceRefresh) {
      await this.authInstance.refreshSession();
    }
    return this.authInstance.getAccessToken();
  }
  async getIdToken() {
    if (!this.authInstance) throw index.WalletInitializationError.notReady("authInstance is not ready");
    return this.authInstance.authSessionManager.getIdToken();
  }
  getOriginData() {
    try {
      const {
        originData,
        redirectUrl
      } = this.authInstance.options;
      const origin = new URL(redirectUrl).origin;
      if (originData) {
        const dappOriginData = originData[origin];
        if (dappOriginData) {
          return JSON.stringify({
            [origin]: dappOriginData
          });
        }
      }
      return undefined;
    } catch (error) {
      loglevel.log.error("Error getting origin data", error);
      return undefined;
    }
  }
  connectWithJwtLogin(params) {
    var _params$extraLoginOpt5, _params$extraLoginOpt7;
    const loginConfig = this.getOAuthProviderConfig({
      authConnection: params.authConnection,
      authConnectionId: params.authConnectionId,
      groupedAuthConnectionId: params.groupedAuthConnectionId
    });
    // throw error only when we cannot find the login config and authConnectionId is not provided in the params.
    // otherwise, we will use the params to create a new auth connection config in the auth instance.
    if (!(loginConfig !== null && loginConfig !== void 0 && loginConfig.authConnection) && !params.authConnectionId) throw index.WalletLoginError.connectionError("Invalid auth connection.");
    if (!(loginConfig !== null && loginConfig !== void 0 && loginConfig.authConnection)) {
      this.authInstance.options.authConnectionConfig.push({
        authConnection: params.authConnection,
        authConnectionId: params.authConnectionId,
        groupedAuthConnectionId: params.groupedAuthConnectionId
      });
    }
    const loginParams = baseControllers.cloneDeep(params);
    const finalExtraLoginOptions = _objectSpread(_objectSpread({}, (loginConfig === null || loginConfig === void 0 ? void 0 : loginConfig.jwtParameters) || {}), params.extraLoginOptions || {});
    let finalUserId;
    if (params.loginHint || (_params$extraLoginOpt5 = params.extraLoginOptions) !== null && _params$extraLoginOpt5 !== void 0 && _params$extraLoginOpt5.login_hint) {
      var _params$extraLoginOpt6;
      finalUserId = params.loginHint || ((_params$extraLoginOpt6 = params.extraLoginOptions) === null || _params$extraLoginOpt6 === void 0 ? void 0 : _params$extraLoginOpt6.login_hint);
    } else if ((_params$extraLoginOpt7 = params.extraLoginOptions) !== null && _params$extraLoginOpt7 !== void 0 && _params$extraLoginOpt7.id_token) {
      const {
        payload
      } = utils$1.parseToken(params.extraLoginOptions.id_token);
      finalUserId = auth.getUserId(payload, loginParams.authConnection, finalExtraLoginOptions.userIdField, finalExtraLoginOptions.isUserIdCaseSensitive);
    } else {
      throw index.WalletLoginError.connectionError("Invalid login hint or id_token");
    }
    // Adds the login_hint to the extraLoginOptions.
    loginParams.extraLoginOptions = _objectSpread(_objectSpread({}, finalExtraLoginOptions), {}, {
      login_hint: finalUserId
    });
    delete loginParams.chainId;
    return this.authInstance.postLoginInitiatedMessage(loginParams);
  }
  async auditOAuditProgress(loginParams, status) {
    const {
      authConnection,
      authConnectionId,
      groupedAuthConnectionId,
      recordId,
      loginSource
    } = loginParams;
    const {
      authBuildEnv = auth.BUILD_ENV.PRODUCTION,
      web3AuthNetwork,
      clientId
    } = this.coreOptions;
    const auditServerUrl = `${constants$1.CITADEL_SERVER_MAP[authBuildEnv]}/v1/auth/audit`;
    const progressFlag = {
      oauthInitiated: true
    };
    const auditPayload = _objectSpread({
      authConnection,
      authConnectionId,
      groupedAuthConnectionId,
      recordId,
      source: loginSource,
      web3AuthNetwork,
      web3AuthClientId: clientId
    }, progressFlag);
    if (status === "failed") {
      auditPayload.oauthFailed = true;
    } else if (status === "completed") {
      auditPayload.oauthCompleted = true;
    } else {
      auditPayload.oauthInitiated = true;
    }
    await httpHelpers.put(auditServerUrl, auditPayload);
  }
  reportFailedOauthAudit(loginParams) {
    void this.auditOAuditProgress(loginParams, "failed").catch(error => {
      loglevel.log.error("Error reporting `oauthFailed` audit progress", error);
    });
  }
}
const authConnector = params => {
  return ({
    projectConfig,
    coreOptions,
    analytics
  }) => {
    var _coreOptions$uiConfig, _coreOptions$walletSe, _coreOptions$walletSe2, _coreOptions$walletSe3;
    // Connector settings
    const connectorSettings = {};
    const {
      whitelist,
      sessionTime
    } = projectConfig;
    if (whitelist) connectorSettings.originData = whitelist.signed_urls;
    // If sessionTime is provided in the coreOptions, it takes precedence over the sessionTime in the projectConfig.
    if (coreOptions.sessionTime) {
      connectorSettings.sessionTime = coreOptions.sessionTime;
    } else if (sessionTime) {
      connectorSettings.sessionTime = sessionTime;
    }
    if ((_coreOptions$uiConfig = coreOptions.uiConfig) !== null && _coreOptions$uiConfig !== void 0 && _coreOptions$uiConfig.uxMode) connectorSettings.uxMode = coreOptions.uiConfig.uxMode;
    const uiConfig = coreOptions.uiConfig || {};
    connectorSettings.whiteLabel = uiConfig;
    const finalConnectorSettings = deepmerge.all([{
      uxMode: auth.UX_MODE.POPUP,
      buildEnv: coreOptions.authBuildEnv || auth.BUILD_ENV.PRODUCTION
    },
    // default settings
    connectorSettings, (params === null || params === void 0 ? void 0 : params.connectorSettings) || {}]);
    // WS settings
    const whiteLabel = deepmerge.all([uiConfig, ((_coreOptions$walletSe = coreOptions.walletServicesConfig) === null || _coreOptions$walletSe === void 0 ? void 0 : _coreOptions$walletSe.whiteLabel) || {}]);
    const finalWsSettings = _objectSpread(_objectSpread({}, coreOptions.walletServicesConfig), {}, {
      whiteLabel,
      accountAbstractionConfig: coreOptions.accountAbstractionConfig,
      enableLogging: coreOptions.enableLogging
    });
    // Core options
    const isKeyExportEnabled = (_coreOptions$walletSe2 = (_coreOptions$walletSe3 = coreOptions.walletServicesConfig) === null || _coreOptions$walletSe3 === void 0 ? void 0 : _coreOptions$walletSe3.enableKeyExport) !== null && _coreOptions$walletSe2 !== void 0 ? _coreOptions$walletSe2 : true;
    if (coreOptions.privateKeyProvider) coreOptions.privateKeyProvider.setKeyExportFlag(isKeyExportEnabled);
    return new AuthConnector({
      connectorSettings: finalConnectorSettings,
      walletServicesSettings: finalWsSettings,
      loginSettings: _objectSpread(_objectSpread({}, (params === null || params === void 0 ? void 0 : params.loginSettings) || {}), {}, {
        mfaLevel: coreOptions.mfaLevel
      }),
      coreOptions,
      analytics,
      authConnectionConfig: projectConfig.embeddedWalletAuth
    });
  };
};
function isAuthConnector(connector) {
  if (!connector || connector.name !== index$1.WALLET_CONNECTORS.AUTH) {
    return false;
  }
  const maybeAuthConnector = connector;
  return typeof maybeAuthConnector.switchAccount === "function" && typeof maybeAuthConnector.linkAccount === "function" && typeof maybeAuthConnector.unlinkAccount === "function";
}
function assertAuthConnector(connector, errorMessage = "Account linking is only supported when connected with the AUTH connector.") {
  if (!isAuthConnector(connector)) {
    throw index.WalletLoginError.unsupportedOperation(errorMessage);
  }
}

exports.assertAuthConnector = assertAuthConnector;
exports.authConnector = authConnector;
exports.isAuthConnector = isAuthConnector;