tiwiflix-wallet-connector 1.5.3 → 1.5.5

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.esm.js CHANGED
@@ -2344,11 +2344,6 @@ class WalletConnector {
2344
2344
  ...savedState,
2345
2345
  error: null, // Don't restore errors
2346
2346
  };
2347
- // PATCH: Prevent invalid connected state
2348
- if (this.state.status === ConnectionStatus.CONNECTED && !this.state.account) {
2349
- this.state.status = ConnectionStatus.DISCONNECTED;
2350
- this.state.wallet = null;
2351
- }
2352
2347
  }
2353
2348
  this.eventEmitter = new EventEmitter$1();
2354
2349
  // Initialize advanced SDK management
@@ -2513,9 +2508,37 @@ class WalletConnector {
2513
2508
  });
2514
2509
  this.eventEmitter.emit(WalletEvent.CONNECTED, account);
2515
2510
  }
2511
+ else {
2512
+ // No account found - user likely cancelled or connection failed
2513
+ this.debugTools.info('WALLET_CONNECTOR', 'No account found after visibility change - resetting state');
2514
+ clearTimeout(connectionTimeout);
2515
+ clearTimeout(safetyTimeout);
2516
+ document.removeEventListener('visibilitychange', handleVisibilityChange);
2517
+ this.updateState({
2518
+ status: ConnectionStatus.DISCONNECTED,
2519
+ wallet: null,
2520
+ error: new Error('Connection cancelled or failed'),
2521
+ });
2522
+ this.eventEmitter.emit(WalletEvent.ERROR, new Error('Connection cancelled or failed'));
2523
+ }
2516
2524
  }
2517
2525
  catch (err) {
2518
2526
  this.debugTools.warn('WALLET_CONNECTOR', 'Failed to check account on visibility change', err);
2527
+ // On error checking account, reset state after a longer delay
2528
+ setTimeout(() => {
2529
+ if (this.state.status === ConnectionStatus.CONNECTING) {
2530
+ this.debugTools.info('WALLET_CONNECTOR', 'Still connecting after visibility check error - resetting state');
2531
+ clearTimeout(connectionTimeout);
2532
+ clearTimeout(safetyTimeout);
2533
+ document.removeEventListener('visibilitychange', handleVisibilityChange);
2534
+ this.updateState({
2535
+ status: ConnectionStatus.DISCONNECTED,
2536
+ wallet: null,
2537
+ error: new Error('Connection timeout'),
2538
+ });
2539
+ this.eventEmitter.emit(WalletEvent.ERROR, new Error('Connection timeout'));
2540
+ }
2541
+ }, 3000); // Give it 3 more seconds
2519
2542
  }
2520
2543
  }
2521
2544
  }, 1000);
@@ -7861,6 +7884,8 @@ const ConnectButton = ({ connector, onConnect, onDisconnect, onError, className,
7861
7884
  // Get initial state
7862
7885
  const initialState = connector.getState();
7863
7886
  setStatus(initialState.status);
7887
+ // Safety: Clear isConnecting on mount (in case it was stuck from previous session)
7888
+ setIsConnecting(false);
7864
7889
  // Only set wallets once to prevent re-renders
7865
7890
  if (!walletsRef.current) {
7866
7891
  walletsRef.current = connector.getAllWallets();
@@ -8064,10 +8089,10 @@ const ConnectButton = ({ connector, onConnect, onDisconnect, onError, className,
8064
8089
  });
8065
8090
  }
8066
8091
  // Subscribe to events
8067
- // Prevent repeated onConnect calls for the same account
8068
- const lastOnConnectAddress = React.useRef(null);
8069
8092
  const unsubscribeAccount = connector.on(WalletEvent.ACCOUNT_CHANGED, async (acc) => {
8070
8093
  setAccount(acc);
8094
+ // Clear isConnecting when account changes (connection succeeded)
8095
+ setIsConnecting(false);
8071
8096
  // Don't set isInitializing to false yet - wait for balance to load
8072
8097
  // Load cached balance for new account immediately
8073
8098
  if (acc?.address) {
@@ -8078,7 +8103,8 @@ const ConnectButton = ({ connector, onConnect, onDisconnect, onError, className,
8078
8103
  }
8079
8104
  }
8080
8105
  if (acc && acc.chainType === 'ton') {
8081
- setTwcBalance('0');
8106
+ // For TON: fetch both balance and NFTs
8107
+ setTwcBalance('0'); // TON wallets don't have TWC
8082
8108
  try {
8083
8109
  await Promise.all([
8084
8110
  fetchTONBalance(acc),
@@ -8102,15 +8128,18 @@ const ConnectButton = ({ connector, onConnect, onDisconnect, onError, className,
8102
8128
  }
8103
8129
  }
8104
8130
  else if (acc) {
8131
+ // No fetchBalance, check for TWC balance
8105
8132
  const state = connector.getState();
8106
8133
  if (state.twcBalance && state.twcBalance !== '0' && state.twcBalance !== '0.00') {
8107
8134
  setTwcBalance(state.twcBalance);
8108
8135
  setUsdValueStable(state.usdValue ?? null);
8136
+ // Save to cache
8109
8137
  if (acc.address) {
8110
8138
  saveTWCBalanceToCache(acc.address, state.twcBalance, state.usdValue ?? null);
8111
8139
  }
8112
8140
  }
8113
8141
  else if (acc.address) {
8142
+ // Try to load from cache as fallback
8114
8143
  const cached = loadTWCBalanceFromCache(acc.address);
8115
8144
  if (cached?.balance) {
8116
8145
  setTwcBalance(cached.balance);
@@ -8123,17 +8152,19 @@ const ConnectButton = ({ connector, onConnect, onDisconnect, onError, className,
8123
8152
  setIsInitializing(false);
8124
8153
  }
8125
8154
  if (acc && onConnect) {
8126
- if (lastOnConnectAddress.current !== acc.address) {
8127
- onConnect(acc);
8128
- lastOnConnectAddress.current = acc.address;
8129
- }
8155
+ onConnect(acc);
8130
8156
  }
8131
8157
  });
8132
8158
  const unsubscribeStatus = connector.on(WalletEvent.STATUS_CHANGED, (newStatus) => {
8133
8159
  setStatus(newStatus);
8134
- // If status changes to disconnected, stop initializing
8160
+ // If status changes to disconnected, stop initializing and connecting
8135
8161
  if (newStatus === ConnectionStatus.DISCONNECTED) {
8136
8162
  setIsInitializing(false);
8163
+ setIsConnecting(false);
8164
+ }
8165
+ // If status changes to connected, clear connecting state
8166
+ if (newStatus === ConnectionStatus.CONNECTED) {
8167
+ setIsConnecting(false);
8137
8168
  }
8138
8169
  });
8139
8170
  const unsubscribeDisconnect = connector.on(WalletEvent.DISCONNECTED, () => {
@@ -8361,19 +8392,16 @@ const ConnectButton = ({ connector, onConnect, onDisconnect, onError, className,
8361
8392
  useEffect(() => {
8362
8393
  if (account && fetchBalance) {
8363
8394
  setBalanceLoading(true);
8364
- loadBalance().then((hasRealBalance) => {
8365
- setBalanceLoading(false);
8366
- // For TON wallets, always stop initializing after balance fetch completes (even if balance is 0)
8367
- // For other chains, only stop if we got a real balance
8368
- if (account.chainType === 'ton' || hasRealBalance) {
8369
- setIsInitializing(false);
8370
- }
8371
- }).catch(() => {
8395
+ loadBalance()
8396
+ .then(() => {
8397
+ // Always stop initializing once balance request completes
8398
+ })
8399
+ .catch(() => {
8400
+ // Ignore errors, we still clear loading states
8401
+ })
8402
+ .finally(() => {
8372
8403
  setBalanceLoading(false);
8373
- // Always stop initializing on error for TON
8374
- if (account.chainType === 'ton') {
8375
- setIsInitializing(false);
8376
- }
8404
+ setIsInitializing(false);
8377
8405
  });
8378
8406
  }
8379
8407
  else if (account && !fetchBalance) {
@@ -8487,6 +8515,11 @@ const ConnectButton = ({ connector, onConnect, onDisconnect, onError, className,
8487
8515
  const handleConnect = useCallback(async (walletType) => {
8488
8516
  setIsConnecting(true);
8489
8517
  setError(null);
8518
+ // Safety timeout: ensure isConnecting is cleared after 75 seconds maximum
8519
+ const safetyTimeout = setTimeout(() => {
8520
+ setIsConnecting(false);
8521
+ setIsInitializing(false);
8522
+ }, 75000);
8490
8523
  // Close modal BEFORE connecting for TON wallets and WalletConnect
8491
8524
  // so external modals can show
8492
8525
  const isTonWallet = ['tonkeeper', 'tonhub', 'mytonwallet'].includes(walletType);
@@ -8500,27 +8533,20 @@ const ConnectButton = ({ connector, onConnect, onDisconnect, onError, className,
8500
8533
  setShowSendModal(false);
8501
8534
  }
8502
8535
  try {
8503
- const result = await connector.connect(walletType);
8504
- // Set account from connection result immediately
8505
- if (result?.account) {
8506
- setAccount(result.account);
8507
- setIsInitializing(false);
8508
- }
8509
- else {
8510
- // Fallback: get account after connection
8511
- const newAccount = await connector.getAccount();
8512
- if (newAccount) {
8513
- setAccount(newAccount);
8514
- setIsInitializing(false);
8515
- }
8516
- }
8536
+ // connector.connect() returns void - state updates happen via events
8537
+ await connector.connect(walletType);
8538
+ // Connection succeeded - state is updated via ACCOUNT_CHANGED event
8539
+ // which also clears isConnecting
8517
8540
  // Close modal after connection for non-TON/walletconnect wallets
8518
8541
  if (!isTonWallet && !isWalletConnect) {
8519
8542
  setShowModal(false);
8520
8543
  }
8521
- setIsConnecting(false);
8544
+ // Clear safety timeout on success
8545
+ clearTimeout(safetyTimeout);
8522
8546
  }
8523
8547
  catch (err) {
8548
+ // Clear safety timeout on error
8549
+ clearTimeout(safetyTimeout);
8524
8550
  // Always clear connection state on error
8525
8551
  setAccount(null);
8526
8552
  setStatus(ConnectionStatus.DISCONNECTED);
@@ -8636,15 +8662,6 @@ const ConnectButton = ({ connector, onConnect, onDisconnect, onError, className,
8636
8662
  isBalanceResolved = !balanceLoading && !isInitializing;
8637
8663
  }
8638
8664
  const waitingForBalance = account && !isBalanceResolved;
8639
- // Patch: If account is null and status is disconnected, always stop initializing/loading
8640
- if (!account && status === ConnectionStatus.DISCONNECTED && (isInitializing || isConnecting || balanceLoading)) {
8641
- if (isInitializing)
8642
- setIsInitializing(false);
8643
- if (isConnecting)
8644
- setIsConnecting(false);
8645
- if (balanceLoading)
8646
- setBalanceLoading(false);
8647
- }
8648
8665
  const isCheckingConnection = isInitializing || waitingForBalance || ((status === ConnectionStatus.CONNECTING || isConnecting) && !account);
8649
8666
  const isActuallyConnecting = (status === ConnectionStatus.CONNECTING || isConnecting) && account && isBalanceResolved;
8650
8667
  // Check connection state
package/dist/index.js CHANGED
@@ -2346,11 +2346,6 @@ class WalletConnector {
2346
2346
  ...savedState,
2347
2347
  error: null, // Don't restore errors
2348
2348
  };
2349
- // PATCH: Prevent invalid connected state
2350
- if (this.state.status === exports.ConnectionStatus.CONNECTED && !this.state.account) {
2351
- this.state.status = exports.ConnectionStatus.DISCONNECTED;
2352
- this.state.wallet = null;
2353
- }
2354
2349
  }
2355
2350
  this.eventEmitter = new EventEmitter$1();
2356
2351
  // Initialize advanced SDK management
@@ -2515,9 +2510,37 @@ class WalletConnector {
2515
2510
  });
2516
2511
  this.eventEmitter.emit(exports.WalletEvent.CONNECTED, account);
2517
2512
  }
2513
+ else {
2514
+ // No account found - user likely cancelled or connection failed
2515
+ this.debugTools.info('WALLET_CONNECTOR', 'No account found after visibility change - resetting state');
2516
+ clearTimeout(connectionTimeout);
2517
+ clearTimeout(safetyTimeout);
2518
+ document.removeEventListener('visibilitychange', handleVisibilityChange);
2519
+ this.updateState({
2520
+ status: exports.ConnectionStatus.DISCONNECTED,
2521
+ wallet: null,
2522
+ error: new Error('Connection cancelled or failed'),
2523
+ });
2524
+ this.eventEmitter.emit(exports.WalletEvent.ERROR, new Error('Connection cancelled or failed'));
2525
+ }
2518
2526
  }
2519
2527
  catch (err) {
2520
2528
  this.debugTools.warn('WALLET_CONNECTOR', 'Failed to check account on visibility change', err);
2529
+ // On error checking account, reset state after a longer delay
2530
+ setTimeout(() => {
2531
+ if (this.state.status === exports.ConnectionStatus.CONNECTING) {
2532
+ this.debugTools.info('WALLET_CONNECTOR', 'Still connecting after visibility check error - resetting state');
2533
+ clearTimeout(connectionTimeout);
2534
+ clearTimeout(safetyTimeout);
2535
+ document.removeEventListener('visibilitychange', handleVisibilityChange);
2536
+ this.updateState({
2537
+ status: exports.ConnectionStatus.DISCONNECTED,
2538
+ wallet: null,
2539
+ error: new Error('Connection timeout'),
2540
+ });
2541
+ this.eventEmitter.emit(exports.WalletEvent.ERROR, new Error('Connection timeout'));
2542
+ }
2543
+ }, 3000); // Give it 3 more seconds
2521
2544
  }
2522
2545
  }
2523
2546
  }, 1000);
@@ -7863,6 +7886,8 @@ const ConnectButton = ({ connector, onConnect, onDisconnect, onError, className,
7863
7886
  // Get initial state
7864
7887
  const initialState = connector.getState();
7865
7888
  setStatus(initialState.status);
7889
+ // Safety: Clear isConnecting on mount (in case it was stuck from previous session)
7890
+ setIsConnecting(false);
7866
7891
  // Only set wallets once to prevent re-renders
7867
7892
  if (!walletsRef.current) {
7868
7893
  walletsRef.current = connector.getAllWallets();
@@ -8066,10 +8091,10 @@ const ConnectButton = ({ connector, onConnect, onDisconnect, onError, className,
8066
8091
  });
8067
8092
  }
8068
8093
  // Subscribe to events
8069
- // Prevent repeated onConnect calls for the same account
8070
- const lastOnConnectAddress = React.useRef(null);
8071
8094
  const unsubscribeAccount = connector.on(exports.WalletEvent.ACCOUNT_CHANGED, async (acc) => {
8072
8095
  setAccount(acc);
8096
+ // Clear isConnecting when account changes (connection succeeded)
8097
+ setIsConnecting(false);
8073
8098
  // Don't set isInitializing to false yet - wait for balance to load
8074
8099
  // Load cached balance for new account immediately
8075
8100
  if (acc?.address) {
@@ -8080,7 +8105,8 @@ const ConnectButton = ({ connector, onConnect, onDisconnect, onError, className,
8080
8105
  }
8081
8106
  }
8082
8107
  if (acc && acc.chainType === 'ton') {
8083
- setTwcBalance('0');
8108
+ // For TON: fetch both balance and NFTs
8109
+ setTwcBalance('0'); // TON wallets don't have TWC
8084
8110
  try {
8085
8111
  await Promise.all([
8086
8112
  fetchTONBalance(acc),
@@ -8104,15 +8130,18 @@ const ConnectButton = ({ connector, onConnect, onDisconnect, onError, className,
8104
8130
  }
8105
8131
  }
8106
8132
  else if (acc) {
8133
+ // No fetchBalance, check for TWC balance
8107
8134
  const state = connector.getState();
8108
8135
  if (state.twcBalance && state.twcBalance !== '0' && state.twcBalance !== '0.00') {
8109
8136
  setTwcBalance(state.twcBalance);
8110
8137
  setUsdValueStable(state.usdValue ?? null);
8138
+ // Save to cache
8111
8139
  if (acc.address) {
8112
8140
  saveTWCBalanceToCache(acc.address, state.twcBalance, state.usdValue ?? null);
8113
8141
  }
8114
8142
  }
8115
8143
  else if (acc.address) {
8144
+ // Try to load from cache as fallback
8116
8145
  const cached = loadTWCBalanceFromCache(acc.address);
8117
8146
  if (cached?.balance) {
8118
8147
  setTwcBalance(cached.balance);
@@ -8125,17 +8154,19 @@ const ConnectButton = ({ connector, onConnect, onDisconnect, onError, className,
8125
8154
  setIsInitializing(false);
8126
8155
  }
8127
8156
  if (acc && onConnect) {
8128
- if (lastOnConnectAddress.current !== acc.address) {
8129
- onConnect(acc);
8130
- lastOnConnectAddress.current = acc.address;
8131
- }
8157
+ onConnect(acc);
8132
8158
  }
8133
8159
  });
8134
8160
  const unsubscribeStatus = connector.on(exports.WalletEvent.STATUS_CHANGED, (newStatus) => {
8135
8161
  setStatus(newStatus);
8136
- // If status changes to disconnected, stop initializing
8162
+ // If status changes to disconnected, stop initializing and connecting
8137
8163
  if (newStatus === exports.ConnectionStatus.DISCONNECTED) {
8138
8164
  setIsInitializing(false);
8165
+ setIsConnecting(false);
8166
+ }
8167
+ // If status changes to connected, clear connecting state
8168
+ if (newStatus === exports.ConnectionStatus.CONNECTED) {
8169
+ setIsConnecting(false);
8139
8170
  }
8140
8171
  });
8141
8172
  const unsubscribeDisconnect = connector.on(exports.WalletEvent.DISCONNECTED, () => {
@@ -8363,19 +8394,16 @@ const ConnectButton = ({ connector, onConnect, onDisconnect, onError, className,
8363
8394
  React.useEffect(() => {
8364
8395
  if (account && fetchBalance) {
8365
8396
  setBalanceLoading(true);
8366
- loadBalance().then((hasRealBalance) => {
8367
- setBalanceLoading(false);
8368
- // For TON wallets, always stop initializing after balance fetch completes (even if balance is 0)
8369
- // For other chains, only stop if we got a real balance
8370
- if (account.chainType === 'ton' || hasRealBalance) {
8371
- setIsInitializing(false);
8372
- }
8373
- }).catch(() => {
8397
+ loadBalance()
8398
+ .then(() => {
8399
+ // Always stop initializing once balance request completes
8400
+ })
8401
+ .catch(() => {
8402
+ // Ignore errors, we still clear loading states
8403
+ })
8404
+ .finally(() => {
8374
8405
  setBalanceLoading(false);
8375
- // Always stop initializing on error for TON
8376
- if (account.chainType === 'ton') {
8377
- setIsInitializing(false);
8378
- }
8406
+ setIsInitializing(false);
8379
8407
  });
8380
8408
  }
8381
8409
  else if (account && !fetchBalance) {
@@ -8489,6 +8517,11 @@ const ConnectButton = ({ connector, onConnect, onDisconnect, onError, className,
8489
8517
  const handleConnect = React.useCallback(async (walletType) => {
8490
8518
  setIsConnecting(true);
8491
8519
  setError(null);
8520
+ // Safety timeout: ensure isConnecting is cleared after 75 seconds maximum
8521
+ const safetyTimeout = setTimeout(() => {
8522
+ setIsConnecting(false);
8523
+ setIsInitializing(false);
8524
+ }, 75000);
8492
8525
  // Close modal BEFORE connecting for TON wallets and WalletConnect
8493
8526
  // so external modals can show
8494
8527
  const isTonWallet = ['tonkeeper', 'tonhub', 'mytonwallet'].includes(walletType);
@@ -8502,27 +8535,20 @@ const ConnectButton = ({ connector, onConnect, onDisconnect, onError, className,
8502
8535
  setShowSendModal(false);
8503
8536
  }
8504
8537
  try {
8505
- const result = await connector.connect(walletType);
8506
- // Set account from connection result immediately
8507
- if (result?.account) {
8508
- setAccount(result.account);
8509
- setIsInitializing(false);
8510
- }
8511
- else {
8512
- // Fallback: get account after connection
8513
- const newAccount = await connector.getAccount();
8514
- if (newAccount) {
8515
- setAccount(newAccount);
8516
- setIsInitializing(false);
8517
- }
8518
- }
8538
+ // connector.connect() returns void - state updates happen via events
8539
+ await connector.connect(walletType);
8540
+ // Connection succeeded - state is updated via ACCOUNT_CHANGED event
8541
+ // which also clears isConnecting
8519
8542
  // Close modal after connection for non-TON/walletconnect wallets
8520
8543
  if (!isTonWallet && !isWalletConnect) {
8521
8544
  setShowModal(false);
8522
8545
  }
8523
- setIsConnecting(false);
8546
+ // Clear safety timeout on success
8547
+ clearTimeout(safetyTimeout);
8524
8548
  }
8525
8549
  catch (err) {
8550
+ // Clear safety timeout on error
8551
+ clearTimeout(safetyTimeout);
8526
8552
  // Always clear connection state on error
8527
8553
  setAccount(null);
8528
8554
  setStatus(exports.ConnectionStatus.DISCONNECTED);
@@ -8638,15 +8664,6 @@ const ConnectButton = ({ connector, onConnect, onDisconnect, onError, className,
8638
8664
  isBalanceResolved = !balanceLoading && !isInitializing;
8639
8665
  }
8640
8666
  const waitingForBalance = account && !isBalanceResolved;
8641
- // Patch: If account is null and status is disconnected, always stop initializing/loading
8642
- if (!account && status === exports.ConnectionStatus.DISCONNECTED && (isInitializing || isConnecting || balanceLoading)) {
8643
- if (isInitializing)
8644
- setIsInitializing(false);
8645
- if (isConnecting)
8646
- setIsConnecting(false);
8647
- if (balanceLoading)
8648
- setBalanceLoading(false);
8649
- }
8650
8667
  const isCheckingConnection = isInitializing || waitingForBalance || ((status === exports.ConnectionStatus.CONNECTING || isConnecting) && !account);
8651
8668
  const isActuallyConnecting = (status === exports.ConnectionStatus.CONNECTING || isConnecting) && account && isBalanceResolved;
8652
8669
  // Check connection state
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "tiwiflix-wallet-connector",
3
- "version": "1.5.3",
3
+ "version": "1.5.5",
4
4
  "description": "Multi-chain wallet connector for Tiwiflix supporting EVM, TON, Solana, and Tron wallets",
5
5
  "main": "dist/index.js",
6
6
  "module": "dist/index.esm.js",