@web3auth/no-modal 11.0.0-beta.0 → 11.0.0-beta.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (101) hide show
  1. package/dist/lib.cjs/account-linking/index.js +8 -0
  2. package/dist/lib.cjs/account-linking/react.js +95 -0
  3. package/dist/lib.cjs/account-linking/rest.js +54 -0
  4. package/dist/lib.cjs/account-linking/vue.js +98 -0
  5. package/dist/lib.cjs/base/analytics.js +17 -2
  6. package/dist/lib.cjs/base/connector/constants.js +2 -0
  7. package/dist/lib.cjs/base/errors/index.js +48 -0
  8. package/dist/lib.cjs/base/utils.js +15 -3
  9. package/dist/lib.cjs/connectors/auth-connector/authConnector.js +501 -70
  10. package/dist/lib.cjs/connectors/base-evm-connector/baseEvmConnector.js +42 -23
  11. package/dist/lib.cjs/connectors/base-solana-connector/baseSolanaConnector.js +41 -24
  12. package/dist/lib.cjs/connectors/metamask-connector/metamaskConnector.js +76 -45
  13. package/dist/lib.cjs/connectors/wallet-connect-v2-connector/walletConnectV2Connector.js +41 -13
  14. package/dist/lib.cjs/index.js +20 -13
  15. package/dist/lib.cjs/noModal.js +834 -117
  16. package/dist/lib.cjs/plugins/wallet-services-plugin/plugin.js +1 -1
  17. package/dist/lib.cjs/providers/base-provider/baseProvider.js +65 -33
  18. package/dist/lib.cjs/react/context/useWeb3AuthInnerContextValue.js +43 -20
  19. package/dist/lib.cjs/react/hooks/useWallets.js +51 -0
  20. package/dist/lib.cjs/react/hooks/useWeb3AuthConnect.js +2 -2
  21. package/dist/lib.cjs/react/index.js +2 -0
  22. package/dist/lib.cjs/react/solana/hooks/useSolanaWallet.js +2 -2
  23. package/dist/lib.cjs/react/solana/provider.js +7 -1
  24. package/dist/lib.cjs/react/wagmi/provider.js +37 -5
  25. package/dist/lib.cjs/types/account-linking/index.d.ts +2 -0
  26. package/dist/lib.cjs/types/account-linking/interfaces.d.ts +90 -0
  27. package/dist/lib.cjs/types/account-linking/react.d.ts +19 -0
  28. package/dist/lib.cjs/types/account-linking/rest.d.ts +9 -0
  29. package/dist/lib.cjs/types/account-linking/vue.d.ts +20 -0
  30. package/dist/lib.cjs/types/base/analytics.d.ts +9 -0
  31. package/dist/lib.cjs/types/base/connector/baseConnector.d.ts +5 -0
  32. package/dist/lib.cjs/types/base/connector/constants.d.ts +2 -0
  33. package/dist/lib.cjs/types/base/connector/interfaces.d.ts +51 -6
  34. package/dist/lib.cjs/types/base/core/IWeb3Auth.d.ts +39 -2
  35. package/dist/lib.cjs/types/base/errors/index.d.ts +13 -0
  36. package/dist/lib.cjs/types/base/interfaces.d.ts +3 -1
  37. package/dist/lib.cjs/types/base/utils.d.ts +7 -1
  38. package/dist/lib.cjs/types/connectors/auth-connector/authConnector.d.ts +33 -3
  39. package/dist/lib.cjs/types/connectors/auth-connector/interface.d.ts +77 -2
  40. package/dist/lib.cjs/types/connectors/base-evm-connector/baseEvmConnector.d.ts +6 -0
  41. package/dist/lib.cjs/types/connectors/base-solana-connector/baseSolanaConnector.d.ts +6 -0
  42. package/dist/lib.cjs/types/index.d.ts +1 -0
  43. package/dist/lib.cjs/types/noModal.d.ts +104 -5
  44. package/dist/lib.cjs/types/providers/base-provider/baseProvider.d.ts +7 -0
  45. package/dist/lib.cjs/types/react/hooks/index.d.ts +1 -0
  46. package/dist/lib.cjs/types/react/hooks/useWallets.d.ts +8 -0
  47. package/dist/lib.cjs/types/vue/composables/index.d.ts +1 -0
  48. package/dist/lib.cjs/types/vue/composables/useWallets.d.ts +9 -0
  49. package/dist/lib.cjs/vue/composables/useWallets.js +52 -0
  50. package/dist/lib.cjs/vue/composables/useWeb3AuthConnect.js +2 -2
  51. package/dist/lib.cjs/vue/index.js +2 -0
  52. package/dist/lib.cjs/vue/solana/composables/useSolanaWallet.js +2 -2
  53. package/dist/lib.cjs/vue/solana/provider.js +50 -23
  54. package/dist/lib.cjs/vue/useWeb3AuthInnerContextValue.js +13 -4
  55. package/dist/lib.cjs/vue/wagmi/provider.js +35 -7
  56. package/dist/lib.esm/account-linking/index.js +1 -0
  57. package/dist/lib.esm/account-linking/react.js +74 -0
  58. package/dist/lib.esm/account-linking/rest.js +51 -0
  59. package/dist/lib.esm/account-linking/vue.js +78 -0
  60. package/dist/lib.esm/base/analytics.js +17 -2
  61. package/dist/lib.esm/base/connector/constants.js +2 -0
  62. package/dist/lib.esm/base/errors/index.js +48 -1
  63. package/dist/lib.esm/base/utils.js +16 -4
  64. package/dist/lib.esm/connectors/auth-connector/authConnector.js +462 -31
  65. package/dist/lib.esm/connectors/base-evm-connector/baseEvmConnector.js +43 -24
  66. package/dist/lib.esm/connectors/base-solana-connector/baseSolanaConnector.js +43 -26
  67. package/dist/lib.esm/connectors/coinbase-connector/coinbaseConnector.js +2 -2
  68. package/dist/lib.esm/connectors/injected-evm-connector/injectedEvmConnector.js +2 -2
  69. package/dist/lib.esm/connectors/injected-solana-connector/walletStandardConnector.js +3 -3
  70. package/dist/lib.esm/connectors/metamask-connector/metamaskConnector.js +80 -49
  71. package/dist/lib.esm/connectors/wallet-connect-v2-connector/WalletConnectV2Provider.js +2 -2
  72. package/dist/lib.esm/connectors/wallet-connect-v2-connector/walletConnectV2Connector.js +43 -15
  73. package/dist/lib.esm/connectors/wallet-connect-v2-connector/wcSolanaWallet.js +1 -1
  74. package/dist/lib.esm/index.js +4 -3
  75. package/dist/lib.esm/noModal.js +851 -126
  76. package/dist/lib.esm/plugins/wallet-services-plugin/plugin.js +3 -3
  77. package/dist/lib.esm/providers/base-provider/baseProvider.js +68 -38
  78. package/dist/lib.esm/react/context/useWeb3AuthInnerContextValue.js +45 -21
  79. package/dist/lib.esm/react/hooks/useWallets.js +33 -0
  80. package/dist/lib.esm/react/hooks/useWeb3AuthConnect.js +2 -2
  81. package/dist/lib.esm/react/index.js +1 -0
  82. package/dist/lib.esm/react/solana/hooks/useSolanaWallet.js +2 -2
  83. package/dist/lib.esm/react/solana/provider.js +9 -2
  84. package/dist/lib.esm/react/wagmi/provider.js +39 -7
  85. package/dist/lib.esm/vue/composables/useCheckout.js +1 -1
  86. package/dist/lib.esm/vue/composables/useFunding.js +1 -1
  87. package/dist/lib.esm/vue/composables/useReceive.js +1 -1
  88. package/dist/lib.esm/vue/composables/useSwap.js +1 -1
  89. package/dist/lib.esm/vue/composables/useWalletConnectScanner.js +1 -1
  90. package/dist/lib.esm/vue/composables/useWalletUI.js +1 -1
  91. package/dist/lib.esm/vue/composables/useWallets.js +35 -0
  92. package/dist/lib.esm/vue/composables/useWeb3AuthConnect.js +2 -2
  93. package/dist/lib.esm/vue/index.js +1 -0
  94. package/dist/lib.esm/vue/solana/composables/useSignAndSendTransaction.js +1 -1
  95. package/dist/lib.esm/vue/solana/composables/useSignMessage.js +1 -1
  96. package/dist/lib.esm/vue/solana/composables/useSignTransaction.js +1 -1
  97. package/dist/lib.esm/vue/solana/composables/useSolanaWallet.js +2 -2
  98. package/dist/lib.esm/vue/solana/provider.js +51 -24
  99. package/dist/lib.esm/vue/useWeb3AuthInnerContextValue.js +12 -3
  100. package/dist/lib.esm/vue/wagmi/provider.js +36 -8
  101. package/package.json +44 -20
@@ -1,23 +1,35 @@
1
1
  import _objectSpread from '@babel/runtime/helpers/objectSpread2';
2
2
  import _defineProperty from '@babel/runtime/helpers/defineProperty';
3
3
  import { CITADEL_SERVER_MAP } from '@toruslabs/constants';
4
- import { put } from '@toruslabs/http-helpers';
4
+ import { get, put } from '@toruslabs/http-helpers';
5
5
  import { SecurePubSub } from '@toruslabs/secure-pub-sub';
6
6
  import { BUILD_ENV, UX_MODE, Auth, SDK_MODE, SUPPORTED_KEY_CURVES, generateRecordId, version, createHandler, PopupHandler, getUserId } from '@web3auth/auth';
7
7
  import { WS_EMBED_LOGIN_MODE } from '@web3auth/ws-embed';
8
8
  import deepmerge from 'deepmerge';
9
+ import { numberToHex } from 'viem';
9
10
  import { generateNonce, parseToken } from '../utils.js';
10
11
  import { AuthSolanaWallet } from './authSolanaWallet.js';
11
- import { BaseConnector } from '../../base/connector/baseConnector.js';
12
+ import { WalletLoginError, WalletInitializationError, Web3AuthError, AccountLinkingError } from '../../base/errors/index.js';
12
13
  import { WALLET_CONNECTORS } from '../../base/wallet/index.js';
14
+ import { BaseConnector } from '../../base/connector/baseConnector.js';
13
15
  import { CONNECTOR_NAMESPACES } from '../../base/chain/IChainInterface.js';
14
16
  import { CONNECTOR_CATEGORY, CONNECTOR_STATUS, CONNECTOR_EVENTS } from '../../base/connector/constants.js';
15
- import { WalletInitializationError, WalletLoginError, Web3AuthError } from '../../base/errors/index.js';
16
- import { log } from '../../base/loglevel.js';
17
- import { getCaipChainId } from '../../base/utils.js';
18
17
  import { CONNECTED_STATUSES } from '../../base/connector/connectorStatus.js';
18
+ import { log } from '../../base/loglevel.js';
19
+ import { Analytics, ANALYTICS_EVENTS } from '../../base/analytics.js';
20
+ import { citadelServerUrl, getErrorAnalyticsProperties, parseChainNamespaceFromCitadelResponse } from '../../base/utils.js';
21
+ import { makeAccountLinkingRequest, makeAccountUnlinkingRequest } from '../../account-linking/rest.js';
19
22
  import { CHAIN_NAMESPACES, cloneDeep } from '@toruslabs/base-controllers';
20
23
 
24
+ // Auth connections that have been deprecated and are no longer supported by the SDK.
25
+ // Passing any of these as `authConnection` results in a hard error so consumers
26
+ // migrate off the removed providers instead of silently continuing.
27
+ const DEPRECATED_AUTH_CONNECTIONS = new Set(["farcaster"]);
28
+ function assertAuthConnectionSupported(authConnection) {
29
+ if (DEPRECATED_AUTH_CONNECTIONS.has(authConnection)) {
30
+ throw WalletInitializationError.invalidParams(`Auth connection "${authConnection}" has been deprecated and is no longer supported by the Web3Auth SDKs. ` + `Please use a different authConnection value.`);
31
+ }
32
+ }
21
33
  class AuthConnector extends BaseConnector {
22
34
  constructor(params) {
23
35
  super(params);
@@ -35,7 +47,22 @@ class AuthConnector extends BaseConnector {
35
47
  _defineProperty(this, "wsEmbedInstance", null);
36
48
  _defineProperty(this, "authConnectionConfig", []);
37
49
  _defineProperty(this, "wsEmbedInstancePromise", null);
50
+ _defineProperty(this, "wsEmbedProviderListenerTarget", null);
38
51
  _defineProperty(this, "_solanaWallet", null);
52
+ _defineProperty(this, "analytics", void 0);
53
+ _defineProperty(this, "handleWsEmbedAccountsChanged", accounts => {
54
+ if (accounts.length === 0) {
55
+ if (!CONNECTED_STATUSES.includes(this.status)) {
56
+ return;
57
+ }
58
+ log.info("No accounts found in the wallet, disconnecting");
59
+ void this.disconnect({
60
+ cleanup: true
61
+ }).catch(error => {
62
+ log.error("Failed to disconnect auth connector after wallet accounts changed", error);
63
+ });
64
+ }
65
+ });
39
66
  this.authOptions = params.connectorSettings;
40
67
  this.loginSettings = params.loginSettings || {
41
68
  authConnection: ""
@@ -44,13 +71,12 @@ class AuthConnector extends BaseConnector {
44
71
  loginMode: WS_EMBED_LOGIN_MODE.PLUGIN
45
72
  };
46
73
  this.authConnectionConfig = params.authConnectionConfig || [];
74
+ this.analytics = params.analytics || new Analytics();
47
75
  }
48
76
  get provider() {
49
77
  if (this.status !== CONNECTOR_STATUS.NOT_READY) {
50
- var _this$wsEmbedInstance;
51
- if ((_this$wsEmbedInstance = this.wsEmbedInstance) !== null && _this$wsEmbedInstance !== void 0 && _this$wsEmbedInstance.provider) {
52
- return this.wsEmbedInstance.provider;
53
- } else if (this.privateKeyProvider) return this.privateKeyProvider;
78
+ const wsEmbedProvider = this.getWsEmbedProvider();
79
+ return wsEmbedProvider || this.privateKeyProvider;
54
80
  }
55
81
  return null;
56
82
  }
@@ -119,6 +145,7 @@ class AuthConnector extends BaseConnector {
119
145
  buildEnv: this.authOptions.buildEnv,
120
146
  whiteLabel: _objectSpread(_objectSpread({}, this.authOptions.whiteLabel), this.wsSettings.whiteLabel)
121
147
  })).then(() => {
148
+ this.bindWsEmbedProviderEvents();
122
149
  this.wsEmbedInstancePromise = null;
123
150
  return;
124
151
  });
@@ -168,6 +195,7 @@ class AuthConnector extends BaseConnector {
168
195
  }
169
196
  }
170
197
  async connect(params) {
198
+ assertAuthConnectionSupported(params === null || params === void 0 ? void 0 : params.authConnection);
171
199
  super.checkConnectionRequirements();
172
200
  this.status = CONNECTOR_STATUS.CONNECTING;
173
201
  this.emit(CONNECTOR_EVENTS.CONNECTING, _objectSpread(_objectSpread({}, params), {}, {
@@ -197,6 +225,7 @@ class AuthConnector extends BaseConnector {
197
225
  async enableMFA(params = {
198
226
  authConnection: ""
199
227
  }) {
228
+ assertAuthConnectionSupported(params === null || params === void 0 ? void 0 : params.authConnection);
200
229
  if (!this.connected) throw WalletLoginError.notConnectedError("Not connected with wallet");
201
230
  if (!this.authInstance) throw WalletInitializationError.notReady("authInstance is not ready");
202
231
  try {
@@ -214,6 +243,7 @@ class AuthConnector extends BaseConnector {
214
243
  async manageMFA(params = {
215
244
  authConnection: ""
216
245
  }) {
246
+ assertAuthConnectionSupported(params === null || params === void 0 ? void 0 : params.authConnection);
217
247
  if (!this.connected) throw WalletLoginError.notConnectedError("Not connected with wallet");
218
248
  if (!this.authInstance) throw WalletInitializationError.notReady("authInstance is not ready");
219
249
  try {
@@ -245,7 +275,10 @@ class AuthConnector extends BaseConnector {
245
275
  }
246
276
  this.rehydrated = false;
247
277
  this._solanaWallet = null;
248
- this.emit(CONNECTOR_EVENTS.DISCONNECTED);
278
+ this.unbindWsEmbedProviderEvents();
279
+ this.emit(CONNECTOR_EVENTS.DISCONNECTED, {
280
+ connector: WALLET_CONNECTORS.AUTH
281
+ });
249
282
  }
250
283
  async getAuthTokenInfo() {
251
284
  if (!this.canAuthorize) throw WalletLoginError.notConnectedError("Not connected with wallet, Please login/connect first");
@@ -273,8 +306,24 @@ class AuthConnector extends BaseConnector {
273
306
  async getUserInfo() {
274
307
  if (!this.canAuthorize) throw WalletLoginError.notConnectedError("Not connected with wallet");
275
308
  if (!this.authInstance) throw WalletInitializationError.notReady("authInstance is not ready");
276
- const userInfo = this.authInstance.getUserInfo();
277
- return userInfo;
309
+ const [userInfo, linkedAccounts] = await Promise.all([this.authInstance.getUserInfo(), this.getLinkedAccounts()]);
310
+ return _objectSpread(_objectSpread({}, userInfo), {}, {
311
+ linkedAccounts
312
+ });
313
+ }
314
+ async getLinkedAccounts() {
315
+ const accessToken = await this.authInstance.authSessionManager.getAccessToken();
316
+ if (!accessToken) throw WalletLoginError.connectionError("Could not obtain an access token from the current AUTH session.");
317
+ const citadelUserInfo = await get(`${citadelServerUrl(this.coreOptions.authBuildEnv)}/v1/user`, {
318
+ headers: {
319
+ Authorization: `Bearer ${accessToken}`
320
+ }
321
+ });
322
+ const linkedAccounts = (citadelUserInfo === null || citadelUserInfo === void 0 ? void 0 : citadelUserInfo.accounts) || [];
323
+ return linkedAccounts.map(account => _objectSpread(_objectSpread({}, account), {}, {
324
+ // by default, the primary account is the active account
325
+ active: account.isPrimary
326
+ }));
278
327
  }
279
328
  async switchChain(params, init = false) {
280
329
  super.checkSwitchChainRequirements(params, init);
@@ -288,13 +337,15 @@ class AuthConnector extends BaseConnector {
288
337
  const newChainConfig = this.coreOptions.chains.find(c => c.chainId === newChainId);
289
338
  if (!newChainConfig) throw WalletInitializationError.invalidParams("Chain config is not available");
290
339
  if (newChainConfig.chainNamespace === CHAIN_NAMESPACES.SOLANA || newChainConfig.chainNamespace === CHAIN_NAMESPACES.EIP155) {
291
- var _this$wsEmbedInstance2;
292
- if (!((_this$wsEmbedInstance2 = this.wsEmbedInstance) !== null && _this$wsEmbedInstance2 !== void 0 && _this$wsEmbedInstance2.provider)) throw WalletInitializationError.notReady("Wallet embed is not ready");
293
- const fullChainId = getCaipChainId(newChainConfig);
340
+ var _this$wsEmbedInstance;
341
+ if (!((_this$wsEmbedInstance = this.wsEmbedInstance) !== null && _this$wsEmbedInstance !== void 0 && _this$wsEmbedInstance.provider)) throw WalletInitializationError.notReady("Wallet embed is not ready");
342
+ const chainIdNum = parseInt(newChainConfig.chainId, 16);
343
+ // WsEmbed expects the chainId in hex format
344
+ const chainIdHex = numberToHex(chainIdNum);
294
345
  await this.wsEmbedInstance.provider.request({
295
346
  method: "wallet_switchChain",
296
347
  params: {
297
- chainId: fullChainId
348
+ chainId: chainIdHex
298
349
  }
299
350
  });
300
351
  } else {
@@ -308,6 +359,8 @@ class AuthConnector extends BaseConnector {
308
359
  if (this.wsEmbedInstance) {
309
360
  this.wsEmbedInstance.clearInit();
310
361
  }
362
+ this._solanaWallet = null;
363
+ this.unbindWsEmbedProviderEvents();
311
364
  }
312
365
  getOAuthProviderConfig(params) {
313
366
  const {
@@ -327,9 +380,378 @@ class AuthConnector extends BaseConnector {
327
380
  });
328
381
  return providerConfig;
329
382
  }
383
+ async generateChallengeAndSign() {
384
+ // we do not support this for auth connector, as of now. since auth login returns a valid idToken
385
+ throw new Error("Not implemented");
386
+ }
387
+ async switchAccount(account, context) {
388
+ if (!CONNECTED_STATUSES.includes(this.status)) {
389
+ throw WalletLoginError.notConnectedError("No wallet is connected. Connect with AUTH before switching accounts.");
390
+ }
391
+ try {
392
+ var _userInfo$linkedAccou;
393
+ const userInfo = await this.getUserInfo();
394
+ const linkedAccounts = (_userInfo$linkedAccou = userInfo.linkedAccounts) !== null && _userInfo$linkedAccou !== void 0 ? _userInfo$linkedAccou : [];
395
+ const targetAccount = linkedAccounts.find(candidate => candidate.id === account.id);
396
+ if (!targetAccount) {
397
+ throw AccountLinkingError.requestFailed(`No connected wallet matches account id "${account.id}". Refresh user info and try again.`);
398
+ }
399
+ const currentActiveAccount = context.activeAccount;
400
+ const isTargetAlreadyActive = currentActiveAccount ? currentActiveAccount.id === targetAccount.id : targetAccount.isPrimary;
401
+ if (isTargetAlreadyActive) {
402
+ return;
403
+ }
404
+ this.analytics.track(ANALYTICS_EVENTS.ACCOUNT_SWITCH_STARTED, this.getSwitchAccountTrackData(targetAccount));
405
+ if (targetAccount.connector === WALLET_CONNECTORS.AUTH && targetAccount.isPrimary) {
406
+ var _this$provider$chainI, _this$provider;
407
+ 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);
408
+ const ethereumProvider = this.provider;
409
+ const solanaWallet = this.solanaWallet;
410
+ if (!ethereumProvider && !solanaWallet) {
411
+ throw AccountLinkingError.requestFailed("Failed to restore the primary AUTH session for account switch.");
412
+ }
413
+ return {
414
+ kind: "primary",
415
+ targetAccount,
416
+ activeAccount: null,
417
+ activeChainId,
418
+ connectorName: this.name,
419
+ connectorNamespace: this.connectorNamespace,
420
+ ethereumProvider,
421
+ solanaWallet
422
+ };
423
+ }
424
+ return {
425
+ kind: "external",
426
+ targetAccount,
427
+ activeAccount: targetAccount,
428
+ activeChainId: this.getChainIdForLinkedAccount(targetAccount, context.currentChainId)
429
+ };
430
+ } catch (error) {
431
+ await this.trackSwitchAccountFailed(account, error);
432
+ throw error;
433
+ }
434
+ }
435
+ async trackSwitchAccountCompleted(account) {
436
+ await this.analytics.track(ANALYTICS_EVENTS.ACCOUNT_SWITCH_COMPLETED, _objectSpread(_objectSpread({}, this.getSwitchAccountTrackData(account)), {}, {
437
+ connector: account.connector
438
+ }));
439
+ }
440
+ async trackSwitchAccountFailed(account, error) {
441
+ await this.analytics.track(ANALYTICS_EVENTS.ACCOUNT_SWITCH_FAILED, _objectSpread(_objectSpread({}, this.getSwitchAccountTrackData(account)), getErrorAnalyticsProperties(error)));
442
+ }
443
+ async linkAccount(params) {
444
+ if (!CONNECTED_STATUSES.includes(this.status)) {
445
+ throw WalletLoginError.notConnectedError("No wallet is connected. Connect with AUTH before linking an account.");
446
+ }
447
+ const {
448
+ connectorName,
449
+ chainId,
450
+ connectorToLink
451
+ } = params;
452
+ try {
453
+ if (!connectorToLink.connected) {
454
+ const connection = await connectorToLink.connect({
455
+ chainId,
456
+ isAccountLinking: true
457
+ });
458
+ if (!connection) {
459
+ throw AccountLinkingError.walletProofFailed(`Failed to connect to "${params.connectorName}" for account linking.`);
460
+ }
461
+ }
462
+ } catch (error) {
463
+ if (error instanceof AccountLinkingError) {
464
+ throw error;
465
+ }
466
+ throw AccountLinkingError.walletProofFailed(error instanceof Error ? error.message : String(error), error);
467
+ }
468
+ const trackData = {
469
+ connector: this.name,
470
+ linking_connector: connectorName,
471
+ chain_id: params.chainId
472
+ };
473
+ try {
474
+ await this.analytics.track(ANALYTICS_EVENTS.ACCOUNT_LINKING_STARTED, trackData);
475
+ const {
476
+ accessToken,
477
+ idToken
478
+ } = await this.getPrimaryAuthSession(params.authSessionTokens);
479
+ const walletProof = await this.createWalletLinkingProof(params.connectorToLink);
480
+ const authServerUrl = citadelServerUrl(this.coreOptions.authBuildEnv);
481
+ const result = await makeAccountLinkingRequest(authServerUrl, accessToken, {
482
+ idToken,
483
+ network: walletProof.network,
484
+ connector: params.connectorName,
485
+ message: walletProof.challenge,
486
+ signature: {
487
+ s: walletProof.signature,
488
+ t: walletProof.signatureType
489
+ }
490
+ });
491
+ this.analytics.track(ANALYTICS_EVENTS.ACCOUNT_LINKING_COMPLETED, _objectSpread(_objectSpread({}, trackData), {}, {
492
+ linked_address: walletProof.address
493
+ }));
494
+ return result;
495
+ } catch (error) {
496
+ this.analytics.track(ANALYTICS_EVENTS.ACCOUNT_LINKING_FAILED, _objectSpread(_objectSpread({}, trackData), getErrorAnalyticsProperties(error)));
497
+
498
+ // disconnect the wallet connector to avoid any leftover state
499
+ try {
500
+ if (connectorToLink.connected) {
501
+ await connectorToLink.disconnect({
502
+ cleanup: true
503
+ });
504
+ }
505
+ } catch (disconnectError) {
506
+ log.debug("Failed to disconnect wallet connector after linking failure", disconnectError);
507
+ }
508
+ throw error;
509
+ }
510
+ }
511
+ async unlinkAccount(params) {
512
+ if (!CONNECTED_STATUSES.includes(this.status)) {
513
+ throw WalletLoginError.notConnectedError("No wallet is connected. Connect with AUTH before unlinking an account.");
514
+ }
515
+ const {
516
+ address,
517
+ authSessionTokens
518
+ } = params;
519
+ const trackData = {
520
+ connector: this.name,
521
+ address
522
+ };
523
+ await this.analytics.track(ANALYTICS_EVENTS.ACCOUNT_UNLINKING_STARTED, trackData);
524
+ try {
525
+ const {
526
+ accessToken,
527
+ idToken,
528
+ linkedAccounts
529
+ } = await this.getPrimaryAuthSession(authSessionTokens, {
530
+ includeLinkedAccounts: true
531
+ });
532
+ const network = this.getNetworkForUnlinkAddress(linkedAccounts, address);
533
+ const authServerUrl = citadelServerUrl(this.coreOptions.authBuildEnv);
534
+ const result = await makeAccountUnlinkingRequest(authServerUrl, accessToken, {
535
+ idToken,
536
+ address,
537
+ network
538
+ });
539
+ await this.analytics.track(ANALYTICS_EVENTS.ACCOUNT_UNLINKING_COMPLETED, _objectSpread(_objectSpread({}, trackData), {}, {
540
+ linked_address: address
541
+ }));
542
+ return result;
543
+ } catch (error) {
544
+ await this.analytics.track(ANALYTICS_EVENTS.ACCOUNT_UNLINKING_FAILED, _objectSpread(_objectSpread({}, trackData), getErrorAnalyticsProperties(error)));
545
+ throw error;
546
+ }
547
+ }
548
+ getChainIdForLinkedAccount(account, preferredChainId) {
549
+ const accountChainNamespace = account.chainNamespace ? parseChainNamespaceFromCitadelResponse(account.chainNamespace) : null;
550
+ if (preferredChainId) {
551
+ const preferredChain = this.coreOptions.chains.find(chain => chain.chainId === preferredChainId);
552
+ if (preferredChain && (!accountChainNamespace || preferredChain.chainNamespace === accountChainNamespace)) {
553
+ return preferredChainId;
554
+ }
555
+ }
556
+ if (accountChainNamespace) {
557
+ const namespaceChain = this.coreOptions.chains.find(chain => chain.chainNamespace === accountChainNamespace);
558
+ if (namespaceChain) {
559
+ return namespaceChain.chainId;
560
+ }
561
+ }
562
+ throw WalletInitializationError.invalidParams(`No compatible chainId found for connector "${account.connector}".`);
563
+ }
564
+ async assertSwitchAccountConnectorMatchesTarget(connector, account) {
565
+ if (!account.chainNamespace) {
566
+ throw AccountLinkingError.requestFailed(`Could not determine the chain namespace for linked account "${account.eoaAddress}".`);
567
+ }
568
+ const chainNamespace = parseChainNamespaceFromCitadelResponse(account.chainNamespace);
569
+ let connectedAddress = null;
570
+ if (chainNamespace === CHAIN_NAMESPACES.EIP155) {
571
+ var _accounts$;
572
+ const accounts = connector.provider ? await connector.provider.request({
573
+ method: "eth_accounts"
574
+ }) : [];
575
+ connectedAddress = (_accounts$ = accounts === null || accounts === void 0 ? void 0 : accounts[0]) !== null && _accounts$ !== void 0 ? _accounts$ : null;
576
+ } else if (chainNamespace === CHAIN_NAMESPACES.SOLANA) {
577
+ var _connector$solanaWall, _connector$solanaWall2;
578
+ 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;
579
+ } else {
580
+ throw AccountLinkingError.requestFailed(`Unsupported chain namespace "${account.chainNamespace}" for linked account "${account.eoaAddress}".`);
581
+ }
582
+ if (!connectedAddress) {
583
+ throw AccountLinkingError.requestFailed(`Connector "${account.connector}" is not connected to linked account "${account.eoaAddress}". Connect the intended wallet account and try again.`);
584
+ }
585
+ const isExpectedAddress = chainNamespace === CHAIN_NAMESPACES.EIP155 ? connectedAddress.toLowerCase() === account.eoaAddress.toLowerCase() : connectedAddress === account.eoaAddress;
586
+ if (!isExpectedAddress) {
587
+ throw AccountLinkingError.requestFailed(`Connector "${account.connector}" is connected to "${connectedAddress}" instead of linked account "${account.eoaAddress}". Connect the intended wallet account and try again.`);
588
+ }
589
+ }
590
+ toSwitchAccountConnectorError(account, error) {
591
+ if (error instanceof AccountLinkingError && error.code === 5401) {
592
+ return error;
593
+ }
594
+ const message = error instanceof Error ? error.message : String(error);
595
+ const isUnavailableConnectorError = error instanceof AccountLinkingError && error.code === 5405 || /not available|not initialized|not ready/i.test(message);
596
+ if (isUnavailableConnectorError) {
597
+ return 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);
598
+ }
599
+ return AccountLinkingError.requestFailed(`Failed to connect connector "${account.connector}" for linked account "${account.eoaAddress}". ${message}`, error);
600
+ }
601
+ getSwitchAccountTrackData(account) {
602
+ var _account$eoaAddress;
603
+ return {
604
+ connector: this.name,
605
+ account_id: account.id,
606
+ account_type: account.accountType,
607
+ switched_to_address: (_account$eoaAddress = account.eoaAddress) !== null && _account$eoaAddress !== void 0 ? _account$eoaAddress : null
608
+ };
609
+ }
610
+ async getPrimaryAuthSession(authSessionTokens, options = {}) {
611
+ const {
612
+ accessToken: cachedAccessToken,
613
+ idToken: cachedIdToken
614
+ } = authSessionTokens;
615
+ const {
616
+ includeLinkedAccounts = false
617
+ } = options;
618
+ let accessToken = cachedAccessToken;
619
+ let idToken = cachedIdToken;
620
+ let linkedAccounts = [];
621
+ if (includeLinkedAccounts) {
622
+ const userInfoPromise = this.getUserInfo();
623
+ if (!accessToken || !idToken) {
624
+ var _userInfo$linkedAccou2;
625
+ const [tokenInfo, userInfo] = await Promise.all([this.getAuthTokenInfo(), userInfoPromise]);
626
+ accessToken = tokenInfo.accessToken;
627
+ idToken = tokenInfo.idToken;
628
+ linkedAccounts = (_userInfo$linkedAccou2 = userInfo.linkedAccounts) !== null && _userInfo$linkedAccou2 !== void 0 ? _userInfo$linkedAccou2 : [];
629
+ } else {
630
+ var _userInfo$linkedAccou3;
631
+ const userInfo = await userInfoPromise;
632
+ linkedAccounts = (_userInfo$linkedAccou3 = userInfo.linkedAccounts) !== null && _userInfo$linkedAccou3 !== void 0 ? _userInfo$linkedAccou3 : [];
633
+ }
634
+ } else if (!accessToken || !idToken) {
635
+ const tokenInfo = await this.getAuthTokenInfo();
636
+ accessToken = tokenInfo.accessToken;
637
+ idToken = tokenInfo.idToken;
638
+ }
639
+ if (!accessToken || !idToken) {
640
+ throw AccountLinkingError.primaryTokenNotAvailable("Could not obtain an identity token from the current AUTH session.");
641
+ }
642
+ return {
643
+ accessToken,
644
+ idToken,
645
+ linkedAccounts
646
+ };
647
+ }
648
+ getNetworkForUnlinkAddress(accounts, address) {
649
+ const matchedAccount = accounts.find(account => {
650
+ var _account$address, _account$eoaAddress2;
651
+ if (!account.chainNamespace || parseChainNamespaceFromCitadelResponse(account.chainNamespace) !== CHAIN_NAMESPACES.EIP155) {
652
+ return false;
653
+ }
654
+ const normalizedAddress = address.toLowerCase();
655
+ 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;
656
+ });
657
+ if (!matchedAccount) {
658
+ throw AccountLinkingError.requestFailed(`No connected wallet matches address "${address}".`);
659
+ }
660
+ if (!matchedAccount.chainNamespace) {
661
+ throw AccountLinkingError.requestFailed(`Could not determine the chain namespace for address "${address}".`);
662
+ }
663
+ const chainNamespace = parseChainNamespaceFromCitadelResponse(matchedAccount.chainNamespace);
664
+ if (chainNamespace === CHAIN_NAMESPACES.EIP155) {
665
+ return "ethereum";
666
+ }
667
+ if (chainNamespace === CHAIN_NAMESPACES.SOLANA) {
668
+ return "solana";
669
+ }
670
+ throw AccountLinkingError.requestFailed(`Unsupported chain namespace "${matchedAccount.chainNamespace}" for address "${address}".`);
671
+ }
672
+ async createWalletLinkingProof(connector) {
673
+ // Notify listeners that the linking wallet is about to be asked for a signature so the UI
674
+ // (e.g. modal) can switch from a "connecting" loader to an "authorizing" prompt while the
675
+ // user reviews the signature request inside their wallet. Emitted on the isolated wallet
676
+ // connector (not the auth connector) so it doesn't mutate the global SDK status.
677
+ connector.emit(CONNECTOR_EVENTS.AUTHORIZING, {
678
+ connector: connector.name
679
+ });
680
+ const {
681
+ challenge,
682
+ signature,
683
+ chainNamespace
684
+ } = await connector.generateChallengeAndSign();
685
+ const address = await this.getLinkingWalletAddress(connector, chainNamespace);
686
+ if (chainNamespace === CHAIN_NAMESPACES.EIP155) {
687
+ return {
688
+ address,
689
+ challenge,
690
+ signature,
691
+ signatureType: "eip191",
692
+ network: "ethereum"
693
+ };
694
+ }
695
+ if (chainNamespace === CHAIN_NAMESPACES.SOLANA) {
696
+ return {
697
+ address,
698
+ challenge,
699
+ signature,
700
+ signatureType: "sip99",
701
+ network: "solana"
702
+ };
703
+ }
704
+ throw AccountLinkingError.unsupportedConnector(`Connector "${connector.name}" returned unsupported chain namespace "${chainNamespace}".`);
705
+ }
706
+ async getLinkingWalletAddress(connector, chainNamespace) {
707
+ if (chainNamespace === CHAIN_NAMESPACES.SOLANA) {
708
+ var _connector$solanaWall3;
709
+ 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;
710
+ if (!address) {
711
+ throw AccountLinkingError.walletProofFailed("No connected Solana account found for account linking.");
712
+ }
713
+ return address;
714
+ }
715
+ if (!connector.provider) {
716
+ throw AccountLinkingError.walletProofFailed("No connected EVM account found for account linking.");
717
+ }
718
+ const accounts = await connector.provider.request({
719
+ method: "eth_accounts"
720
+ });
721
+ if (!(accounts !== null && accounts !== void 0 && accounts.length)) {
722
+ throw AccountLinkingError.walletProofFailed("No connected EVM account found for account linking.");
723
+ }
724
+ return accounts[0];
725
+ }
726
+ getWsEmbedProvider() {
727
+ var _ref, _this$wsEmbedInstance2;
728
+ return (_ref = (_this$wsEmbedInstance2 = this.wsEmbedInstance) === null || _this$wsEmbedInstance2 === void 0 ? void 0 : _this$wsEmbedInstance2.provider) !== null && _ref !== void 0 ? _ref : null;
729
+ }
730
+ bindWsEmbedProviderEvents() {
731
+ const rawProvider = this.getWsEmbedProvider();
732
+ if (this.wsEmbedProviderListenerTarget === rawProvider) {
733
+ return;
734
+ }
735
+ this.unbindWsEmbedProviderEvents();
736
+ if (!rawProvider) {
737
+ return;
738
+ }
739
+ rawProvider.on("accountsChanged", this.handleWsEmbedAccountsChanged);
740
+ this.wsEmbedProviderListenerTarget = rawProvider;
741
+ }
742
+ unbindWsEmbedProviderEvents() {
743
+ if (!this.wsEmbedProviderListenerTarget) {
744
+ return;
745
+ }
746
+ this.wsEmbedProviderListenerTarget.removeListener("accountsChanged", this.handleWsEmbedAccountsChanged);
747
+ this.wsEmbedProviderListenerTarget = null;
748
+ }
330
749
  setupSolanaWallet() {
331
750
  const solanaChains = this.coreOptions.chains.filter(c => c.chainNamespace === CHAIN_NAMESPACES.SOLANA);
332
751
  if (solanaChains.length === 0 || !this.provider) return;
752
+ if (this._solanaWallet instanceof AuthSolanaWallet) {
753
+ return;
754
+ }
333
755
  this._solanaWallet = new AuthSolanaWallet(this.provider, solanaChains);
334
756
  }
335
757
  _getFinalPrivKey() {
@@ -392,13 +814,13 @@ class AuthConnector extends BaseConnector {
392
814
  } = this.authInstance || {};
393
815
  if (sessionId) {
394
816
  this.wsEmbedInstance.setAccessTokenProvider(this.accessTokenProvider.bind(this));
817
+ this.bindWsEmbedProviderEvents();
395
818
  const isLoggedIn = await this.wsEmbedInstance.connectWithSession({
396
819
  sessionId,
397
820
  sessionNamespace,
398
821
  idToken: await this.getIdToken()
399
822
  });
400
823
  if (isLoggedIn) {
401
- var _this$wsEmbedInstance3;
402
824
  this.setupSolanaWallet();
403
825
  // if getAuthTokenInfo is true, then get auth token info
404
826
  // No need to get auth token info for auth connector as it is already handled
@@ -412,12 +834,6 @@ class AuthConnector extends BaseConnector {
412
834
  if (params.getAuthTokenInfo) {
413
835
  await this.getAuthTokenInfo();
414
836
  }
415
- // handle disconnect from ws embed
416
- (_this$wsEmbedInstance3 = this.wsEmbedInstance) === null || _this$wsEmbedInstance3 === void 0 || _this$wsEmbedInstance3.provider.on("accountsChanged", (accounts = []) => {
417
- if (accounts.length === 0 && CONNECTED_STATUSES.includes(this.status)) this.disconnect({
418
- cleanup: false
419
- });
420
- });
421
837
  }
422
838
  }
423
839
  } else {
@@ -519,9 +935,7 @@ class AuthConnector extends BaseConnector {
519
935
  }).catch(error => {
520
936
  // swallow the error, dont need to throw.
521
937
  log.error("Error during login with social", error);
522
- this.auditOAuditProgress(loginParams, "failed").catch(error => {
523
- log.error("Error reporting `oauthFailed` audit progress", error);
524
- });
938
+ this.reportFailedOauthAudit(loginParams);
525
939
  });
526
940
  verifierWindow.once("close", () => {
527
941
  if (!isClosedWindow) {
@@ -531,9 +945,7 @@ class AuthConnector extends BaseConnector {
531
945
  }
532
946
  });
533
947
  this.authInstance.postLoginInitiatedMessage(loginParams, nonce).then(resolve).catch(error => {
534
- this.auditOAuditProgress(loginParams, "failed").catch(error => {
535
- log.error("Error reporting `oauthFailed` audit progress", error);
536
- });
948
+ this.reportFailedOauthAudit(loginParams);
537
949
  if (error instanceof Web3AuthError) {
538
950
  throw error;
539
951
  }
@@ -649,11 +1061,17 @@ class AuthConnector extends BaseConnector {
649
1061
  }
650
1062
  await put(auditServerUrl, auditPayload);
651
1063
  }
1064
+ reportFailedOauthAudit(loginParams) {
1065
+ void this.auditOAuditProgress(loginParams, "failed").catch(error => {
1066
+ log.error("Error reporting `oauthFailed` audit progress", error);
1067
+ });
1068
+ }
652
1069
  }
653
1070
  const authConnector = params => {
654
1071
  return ({
655
1072
  projectConfig,
656
- coreOptions
1073
+ coreOptions,
1074
+ analytics
657
1075
  }) => {
658
1076
  var _coreOptions$uiConfig, _coreOptions$walletSe, _coreOptions$walletSe2, _coreOptions$walletSe3;
659
1077
  // Connector settings
@@ -698,9 +1116,22 @@ const authConnector = params => {
698
1116
  mfaLevel: coreOptions.mfaLevel
699
1117
  }),
700
1118
  coreOptions,
1119
+ analytics,
701
1120
  authConnectionConfig: projectConfig.embeddedWalletAuth
702
1121
  });
703
1122
  };
704
1123
  };
1124
+ function isAuthConnector(connector) {
1125
+ if (!connector || connector.name !== WALLET_CONNECTORS.AUTH) {
1126
+ return false;
1127
+ }
1128
+ const maybeAuthConnector = connector;
1129
+ return typeof maybeAuthConnector.switchAccount === "function" && typeof maybeAuthConnector.linkAccount === "function" && typeof maybeAuthConnector.unlinkAccount === "function";
1130
+ }
1131
+ function assertAuthConnector(connector, errorMessage = "Account linking is only supported when connected with the AUTH connector.") {
1132
+ if (!isAuthConnector(connector)) {
1133
+ throw WalletLoginError.unsupportedOperation(errorMessage);
1134
+ }
1135
+ }
705
1136
 
706
- export { authConnector };
1137
+ export { assertAuthConnector, authConnector, isAuthConnector };