Skip to content

Commit 7a3dff0

Browse files
committed
[SDK]: move autoConnect function into it's own standalone function (#5889)
--- title: "[SDK/Dashboard/Portal] Feature/Fix: Concise title for the changes" --- https://linear.app/thirdweb/issue/TOOL-2697/add-js-autoconnect ## Notes for the reviewer Anything important to call out? Be sure to also clarify these in your comments. ## How to test Unit tests, playground, etc. <!-- start pr-codex --> --- ## PR-Codex overview This PR primarily focuses on refactoring the auto-connect functionality for wallets in the `thirdweb` library. It enhances the modularity and usability of the `autoConnect` feature, allowing it to be used outside of React components and streamlining wallet connection processes. ### Detailed summary - Modified `if` condition in `timeoutPromise.ts` to check for `typeof window`. - Updated import paths for `AutoConnectProps` in `AutoConnect.tsx` files. - Exposed `autoConnect` function in `wallets.ts` for external use. - Adjusted exports in `react.ts` and `react.native.ts` for `AutoConnectProps`. - Refactored `useAutoConnectCore` to use `autoConnectCore`. - Consolidated wallet connection logic in `autoConnect` and `autoConnectCore`. - Updated tests to reflect changes in wallet connection handling and added new test cases for `autoConnect`. - Enhanced error handling and timeout logic in wallet connection processes. > ✨ Ask PR-Codex anything about this PR by commenting with `/codex {your question}` <!-- end pr-codex -->
1 parent e331e43 commit 7a3dff0

File tree

24 files changed

+767
-217
lines changed

24 files changed

+767
-217
lines changed

.changeset/green-rockets-lie.md

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
---
2+
"thirdweb": minor
3+
---
4+
5+
Exposes autoConnect as a standalone function for use outside of react.
6+
7+
```tsx
8+
import { autoConnect } from "thirdweb/wallets";
9+
10+
const autoConnected = await autoConnect({
11+
client,
12+
onConnect: (wallet) => {
13+
console.log("wallet", wallet); /// wallet that is have been auto connected.
14+
},
15+
});
16+
console.log('isAutoConnected', isAutoConnected) // true or false
17+
```

packages/thirdweb/src/exports/react.native.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -86,7 +86,7 @@ export {
8686

8787
// Components
8888
export { AutoConnect } from "../react/native/ui/AutoConnect/AutoConnect.js";
89-
export type { AutoConnectProps } from "../react/core/hooks/connection/types.js";
89+
export type { AutoConnectProps } from "../wallets/connection/types.js";
9090

9191
export { TransactionButton } from "../react/native/ui/transaction/TransactionButton.js";
9292
export type { TransactionButtonProps } from "../react/core/hooks/transaction/transaction-button-utils.js";

packages/thirdweb/src/exports/react.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -121,7 +121,7 @@ export {
121121
} from "../react/core/hooks/pay/usePostOnrampQuote.js";
122122

123123
export { AutoConnect } from "../react/web/ui/AutoConnect/AutoConnect.js";
124-
export type { AutoConnectProps } from "../react/core/hooks/connection/types.js";
124+
export type { AutoConnectProps } from "../wallets/connection/types.js";
125125

126126
// auth
127127
export type { SiweAuthOptions } from "../react/core/hooks/auth/useSiweAuth.js";

packages/thirdweb/src/exports/wallets.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -161,4 +161,6 @@ export { injectedProvider } from "../wallets/injected/mipdStore.js";
161161

162162
export type { ConnectionManager } from "../wallets/manager/index.js";
163163

164+
export type { AutoConnectProps } from "../wallets/connection/types.js";
165+
export { autoConnect } from "../wallets/connection/autoConnect.js";
164166
export { deploySmartAccount } from "../wallets/smart/lib/signing.js";
Lines changed: 12 additions & 158 deletions
Original file line numberDiff line numberDiff line change
@@ -1,26 +1,14 @@
11
"use client";
22

33
import { useQuery } from "@tanstack/react-query";
4-
import type { Chain } from "../../../../chains/types.js";
5-
import type { ThirdwebClient } from "../../../../client/client.js";
64
import type { AsyncStorage } from "../../../../utils/storage/AsyncStorage.js";
7-
import { isEcosystemWallet } from "../../../../wallets/ecosystem/is-ecosystem-wallet.js";
8-
import { ClientScopedStorage } from "../../../../wallets/in-app/core/authentication/client-scoped-storage.js";
9-
import type { AuthStoredTokenWithCookieReturnType } from "../../../../wallets/in-app/core/authentication/types.js";
10-
import { getUrlToken } from "../../../../wallets/in-app/web/lib/get-url-token.js";
5+
import { autoConnectCore } from "../../../../wallets/connection/autoConnectCore.js";
6+
import type { AutoConnectProps } from "../../../../wallets/connection/types.js";
117
import type { Wallet } from "../../../../wallets/interfaces/wallet.js";
12-
import {
13-
getLastConnectedChain,
14-
getStoredActiveWalletId,
15-
getStoredConnectedWalletIds,
16-
} from "../../../../wallets/manager/index.js";
178
import type { WalletId } from "../../../../wallets/wallet-types.js";
189
import { useConnectionManagerCtx } from "../../providers/connection-manager.js";
1910
import { setLastAuthProvider } from "../../utils/storage.js";
20-
import { timeoutPromise } from "../../utils/timeoutPromise.js";
21-
import type { AutoConnectProps } from "../connection/types.js";
2211
import { useConnect } from "./useConnect.js";
23-
import { useSetActiveWalletConnectionStatus } from "./useSetActiveWalletConnectionStatus.js";
2412

2513
export function useAutoConnectCore(
2614
storage: AsyncStorage,
@@ -29,161 +17,27 @@ export function useAutoConnectCore(
2917
getInstalledWallets?: () => Wallet[],
3018
) {
3119
const manager = useConnectionManagerCtx("useAutoConnect");
32-
const setConnectionStatus = useSetActiveWalletConnectionStatus();
3320
const { connect } = useConnect({
3421
client: props.client,
3522
accountAbstraction: props.accountAbstraction,
3623
});
37-
const { isAutoConnecting } = manager;
38-
const { wallets, onConnect } = props;
39-
const timeout = props.timeout ?? 15000;
40-
// get the supported wallets from thirdweb provider
41-
// check the storage for last connected wallets and connect them all
42-
// check the storage for last active wallet and set it as active
43-
const autoConnect = async (): Promise<boolean> => {
44-
let autoConnected = false;
45-
isAutoConnecting.setValue(true);
46-
let [lastConnectedWalletIds, lastActiveWalletId] = await Promise.all([
47-
getStoredConnectedWalletIds(storage),
48-
getStoredActiveWalletId(storage),
49-
]);
50-
51-
const { authResult, walletId, authProvider, authCookie } = getUrlToken();
52-
const wallet = wallets.find((w) => w.id === walletId);
53-
54-
// If an auth cookie is found and this site supports the wallet, we'll set the auth cookie in the client storage
55-
if (authCookie && wallet) {
56-
const clientStorage = new ClientScopedStorage({
57-
storage,
58-
clientId: props.client.clientId,
59-
ecosystem: isEcosystemWallet(wallet)
60-
? {
61-
id: wallet.id,
62-
partnerId: wallet.getConfig()?.partnerId,
63-
}
64-
: undefined,
65-
});
66-
await clientStorage.saveAuthCookie(authCookie);
67-
}
68-
69-
if (walletId) {
70-
lastActiveWalletId = walletId;
71-
lastConnectedWalletIds = lastConnectedWalletIds?.includes(walletId)
72-
? lastConnectedWalletIds
73-
: [walletId, ...(lastConnectedWalletIds || [])];
74-
}
75-
if (authProvider) {
76-
await setLastAuthProvider(authProvider, storage);
77-
}
78-
79-
// if no wallets were last connected or we didn't receive an auth token
80-
if (!lastConnectedWalletIds) {
81-
return autoConnected;
82-
}
83-
84-
// this flow can actually be used for a first connection in the case of a redirect
85-
// in that case, we default to the passed chain to connect to
86-
const lastConnectedChain =
87-
(await getLastConnectedChain(storage)) || props.chain;
88-
89-
const availableWallets = [...wallets, ...(getInstalledWallets?.() ?? [])];
90-
const activeWallet =
91-
lastActiveWalletId &&
92-
(availableWallets.find((w) => w.id === lastActiveWalletId) ||
93-
createWalletFn(lastActiveWalletId));
94-
95-
if (activeWallet) {
96-
try {
97-
setConnectionStatus("connecting"); // only set connecting status if we are connecting the last active EOA
98-
await timeoutPromise(
99-
handleWalletConnection({
100-
wallet: activeWallet,
101-
client: props.client,
102-
lastConnectedChain,
103-
authResult,
104-
}),
105-
{
106-
ms: timeout,
107-
message: `AutoConnect timeout: ${timeout}ms limit exceeded.`,
108-
},
109-
).catch((err) => {
110-
console.warn(err.message);
111-
if (props.onTimeout) {
112-
props.onTimeout();
113-
}
114-
});
115-
116-
// connected wallet could be activeWallet or smart wallet
117-
const connectedWallet = await connect(activeWallet);
118-
119-
if (connectedWallet) {
120-
if (onConnect) {
121-
try {
122-
onConnect(connectedWallet);
123-
autoConnected = true;
124-
} catch {
125-
// ignore
126-
}
127-
}
128-
} else {
129-
setConnectionStatus("disconnected");
130-
}
131-
} catch (e) {
132-
if (e instanceof Error) {
133-
console.warn("Error auto connecting wallet:", e.message);
134-
}
135-
setConnectionStatus("disconnected");
136-
}
137-
} else {
138-
setConnectionStatus("disconnected");
139-
}
140-
141-
// then connect wallets that were last connected but were not set as active
142-
const otherWallets = availableWallets.filter(
143-
(w) =>
144-
w.id !== lastActiveWalletId && lastConnectedWalletIds.includes(w.id),
145-
);
146-
147-
for (const wallet of otherWallets) {
148-
try {
149-
await handleWalletConnection({
150-
wallet,
151-
client: props.client,
152-
lastConnectedChain,
153-
authResult,
154-
});
155-
manager.addConnectedWallet(wallet);
156-
} catch {
157-
// no-op
158-
}
159-
}
160-
isAutoConnecting.setValue(false);
161-
return autoConnected; // useQuery needs a return value
162-
};
16324

16425
// trigger the auto connect on first mount only
16526
const query = useQuery({
16627
queryKey: ["autoConnect", props.client.clientId],
167-
queryFn: autoConnect,
28+
queryFn: () =>
29+
autoConnectCore({
30+
createWalletFn,
31+
manager,
32+
props,
33+
storage,
34+
connectOverride: connect,
35+
getInstalledWallets,
36+
setLastAuthProvider,
37+
}),
16838
refetchOnMount: false,
16939
refetchOnWindowFocus: false,
17040
});
17141

17242
return query;
17343
}
174-
175-
/**
176-
* @internal
177-
*/
178-
export async function handleWalletConnection(props: {
179-
wallet: Wallet;
180-
client: ThirdwebClient;
181-
authResult: AuthStoredTokenWithCookieReturnType | undefined;
182-
lastConnectedChain: Chain | undefined;
183-
}) {
184-
return props.wallet.autoConnect({
185-
client: props.client,
186-
chain: props.lastConnectedChain,
187-
authResult: props.authResult,
188-
});
189-
}

packages/thirdweb/src/react/core/hooks/wallets/useAutoConnectCore.test.tsx

Lines changed: 1 addition & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -6,15 +6,11 @@ import { TEST_CLIENT } from "~test/test-clients.js";
66
import { TEST_ACCOUNT_A } from "~test/test-wallets.js";
77
import { createWalletAdapter } from "../../../../adapters/wallet-adapter.js";
88
import { ethereum } from "../../../../chains/chain-definitions/ethereum.js";
9-
import { isAddress } from "../../../../utils/address.js";
109
import { createConnectionManager } from "../../../../wallets/manager/index.js";
1110
import type { WalletId } from "../../../../wallets/wallet-types.js";
1211
import { ThirdwebProvider } from "../../../web/providers/thirdweb-provider.js";
1312
import { ConnectionManagerCtx } from "../../providers/connection-manager.js";
14-
import {
15-
handleWalletConnection,
16-
useAutoConnectCore,
17-
} from "./useAutoConnect.js";
13+
import { useAutoConnectCore } from "./useAutoConnect.js";
1814

1915
describe("useAutoConnectCore", () => {
2016
const mockStorage = new MockStorage();
@@ -159,29 +155,3 @@ describe("useAutoConnectCore", () => {
159155
);
160156
});
161157
});
162-
163-
describe("handleWalletConnection", () => {
164-
const wallet = createWalletAdapter({
165-
adaptedAccount: TEST_ACCOUNT_A,
166-
client: TEST_CLIENT,
167-
chain: ethereum,
168-
onDisconnect: () => {},
169-
switchChain: () => {},
170-
});
171-
it("should return the correct result", async () => {
172-
const result = await handleWalletConnection({
173-
client: TEST_CLIENT,
174-
lastConnectedChain: ethereum,
175-
authResult: undefined,
176-
wallet,
177-
});
178-
179-
expect("address" in result).toBe(true);
180-
expect(isAddress(result.address)).toBe(true);
181-
expect("sendTransaction" in result).toBe(true);
182-
expect(typeof result.sendTransaction).toBe("function");
183-
expect("signMessage" in result).toBe(true);
184-
expect("signTypedData" in result).toBe(true);
185-
expect("signTransaction" in result).toBe(true);
186-
});
187-
});

packages/thirdweb/src/react/native/hooks/wallets/useAutoConnect.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
import { nativeLocalStorage } from "../../../../utils/storage/nativeStorage.js";
2+
import type { AutoConnectProps } from "../../../../wallets/connection/types.js";
23
import { createWallet } from "../../../../wallets/native/create-wallet.js";
3-
import type { AutoConnectProps } from "../../../core/hooks/connection/types.js";
44
import { useAutoConnectCore } from "../../../core/hooks/wallets/useAutoConnect.js";
55
import { getDefaultWallets } from "../../wallets/defaultWallets.js";
66

packages/thirdweb/src/react/native/ui/AutoConnect/AutoConnect.tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
"use client";
2-
import type { AutoConnectProps } from "../../../core/hooks/connection/types.js";
2+
import type { AutoConnectProps } from "../../../../wallets/connection/types.js";
33
import { useAutoConnect } from "../../hooks/wallets/useAutoConnect.js";
44

55
/**

packages/thirdweb/src/react/web/hooks/wallets/useAutoConnect.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,9 @@
11
import { webLocalStorage } from "../../../../utils/storage/webStorage.js";
2+
import type { AutoConnectProps } from "../../../../wallets/connection/types.js";
23
import { createWallet } from "../../../../wallets/create-wallet.js";
4+
import { getDefaultWallets } from "../../../../wallets/defaultWallets.js";
35
import { getInstalledWalletProviders } from "../../../../wallets/injected/mipdStore.js";
4-
import type { AutoConnectProps } from "../../../core/hooks/connection/types.js";
56
import { useAutoConnectCore } from "../../../core/hooks/wallets/useAutoConnect.js";
6-
import { getDefaultWallets } from "../../wallets/defaultWallets.js";
77

88
/**
99
* Autoconnect the last previously connected wallet.

packages/thirdweb/src/react/web/ui/AutoConnect/AutoConnect.tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
"use client";
2-
import type { AutoConnectProps } from "../../../core/hooks/connection/types.js";
2+
import type { AutoConnectProps } from "../../../../wallets/connection/types.js";
33
import { useAutoConnect } from "../../hooks/wallets/useAutoConnect.js";
44

55
/**

packages/thirdweb/src/react/web/ui/ConnectWallet/ConnectButton.tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22

33
import styled from "@emotion/styled";
44
import { useEffect, useMemo, useState } from "react";
5+
import { getDefaultWallets } from "../../../../wallets/defaultWallets.js";
56
import { iconSize } from "../../../core/design-system/index.js";
67
import { useSiweAuth } from "../../../core/hooks/auth/useSiweAuth.js";
78
import type { ConnectButtonProps } from "../../../core/hooks/connection/ConnectButtonProps.js";
@@ -16,7 +17,6 @@ import {
1617
} from "../../providers/wallet-ui-states-provider.js";
1718
import { canFitWideModal } from "../../utils/canFitWideModal.js";
1819
import { usePreloadWalletProviders } from "../../utils/usePreloadWalletProviders.js";
19-
import { getDefaultWallets } from "../../wallets/defaultWallets.js";
2020
import { AutoConnect } from "../AutoConnect/AutoConnect.js";
2121
import { Modal } from "../components/Modal.js";
2222
import { Spinner } from "../components/Spinner.js";

packages/thirdweb/src/react/web/ui/ConnectWallet/Modal/ConnectEmbed.tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22
import { useEffect, useMemo } from "react";
33
import type { Chain } from "../../../../../chains/types.js";
44
import type { ThirdwebClient } from "../../../../../client/client.js";
5+
import { getDefaultWallets } from "../../../../../wallets/defaultWallets.js";
56
import type { Wallet } from "../../../../../wallets/interfaces/wallet.js";
67
import type { SmartWalletOptions } from "../../../../../wallets/smart/types.js";
78
import {
@@ -21,7 +22,6 @@ import { useConnectionManager } from "../../../../core/providers/connection-mana
2122
import { WalletUIStatesProvider } from "../../../providers/wallet-ui-states-provider.js";
2223
import { canFitWideModal } from "../../../utils/canFitWideModal.js";
2324
import { usePreloadWalletProviders } from "../../../utils/usePreloadWalletProviders.js";
24-
import { getDefaultWallets } from "../../../wallets/defaultWallets.js";
2525
import { LoadingScreen } from "../../../wallets/shared/LoadingScreen.js";
2626
import { AutoConnect } from "../../AutoConnect/AutoConnect.js";
2727
import { DynamicHeight } from "../../components/DynamicHeight.js";

packages/thirdweb/src/react/web/ui/ConnectWallet/screens/WalletSwitcherConnectionScreen.tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,11 @@
11
import type { Chain } from "../../../../../chains/types.js";
22
import type { ThirdwebClient } from "../../../../../client/client.js";
3+
import { getDefaultWallets } from "../../../../../wallets/defaultWallets.js";
34
import type { Wallet } from "../../../../../wallets/interfaces/wallet.js";
45
import type { SmartWalletOptions } from "../../../../../wallets/smart/types.js";
56
import type { AppMetadata } from "../../../../../wallets/types.js";
67
import type { WalletId } from "../../../../../wallets/wallet-types.js";
78
import { useConnectedWallets } from "../../../../core/hooks/wallets/useConnectedWallets.js";
8-
import { getDefaultWallets } from "../../../wallets/defaultWallets.js";
99
import { ConnectModalContent } from "../Modal/ConnectModalContent.js";
1010
import { useSetupScreen } from "../Modal/screen.js";
1111
import type { ConnectLocale } from "../locale/types.js";

packages/thirdweb/src/react/web/ui/ConnectWallet/useConnectModal.tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,14 @@
11
import { useCallback, useContext, useMemo, useState } from "react";
22
import type { Chain } from "../../../../chains/types.js";
33
import type { ThirdwebClient } from "../../../../client/client.js";
4+
import { getDefaultWallets } from "../../../../wallets/defaultWallets.js";
45
import type { Wallet } from "../../../../wallets/interfaces/wallet.js";
56
import type { SmartWalletOptions } from "../../../../wallets/smart/types.js";
67
import type { AppMetadata } from "../../../../wallets/types.js";
78
import type { Theme } from "../../../core/design-system/index.js";
89
import { SetRootElementContext } from "../../../core/providers/RootElementContext.js";
910
import { WalletUIStatesProvider } from "../../providers/wallet-ui-states-provider.js";
1011
import { canFitWideModal } from "../../utils/canFitWideModal.js";
11-
import { getDefaultWallets } from "../../wallets/defaultWallets.js";
1212
import type { LocaleId } from "../types.js";
1313
import ConnectModal from "./Modal/ConnectModal.js";
1414
import { getConnectLocale } from "./locale/getConnectLocale.js";

0 commit comments

Comments
 (0)