-
-
Notifications
You must be signed in to change notification settings - Fork 1.1k
/
reconnect.ts
127 lines (110 loc) · 3.89 KB
/
reconnect.ts
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
import { type Address } from 'viem'
import { type CreateConnectorFn } from '../connectors/createConnector.js'
import type { Config, Connection, Connector } from '../createConfig.js'
import type { ErrorType } from '../errors/base.js'
import { type Evaluate } from '../types/utils.js'
export type ReconnectParameters = {
/** Connectors to attempt reconnect with */
connectors?: readonly (CreateConnectorFn | Connector)[] | undefined
}
export type ReconnectReturnType = Evaluate<Connection>[]
export type ReconnectErrorType = ErrorType
let isReconnecting = false
/** https://wagmi.sh/core/api/actions/reconnect */
export async function reconnect(
config: Config,
parameters: ReconnectParameters = {},
): Promise<ReconnectReturnType> {
// If already reconnecting, do nothing
if (isReconnecting) return []
isReconnecting = true
config.setState((x) => ({
...x,
status: x.current ? 'reconnecting' : 'connecting',
}))
const connectors: Connector[] = []
if (parameters.connectors?.length) {
for (const connector_ of parameters.connectors) {
let connector: Connector
// "Register" connector if not already created
if (typeof connector_ === 'function')
connector = config._internal.connectors.setup(connector_)
else connector = connector_
connectors.push(connector)
}
} else connectors.push(...config.connectors)
// Try recently-used connectors first
let recentConnectorId
try {
recentConnectorId = await config.storage?.getItem('recentConnectorId')
} catch {}
const scores: Record<string, number> = {}
for (const [, connection] of config.state.connections) {
scores[connection.connector.id] = 1
}
if (recentConnectorId) scores[recentConnectorId] = 0
const sorted =
Object.keys(scores).length > 0
? // .toSorted()
[...connectors].sort(
(a, b) => (scores[a.id] ?? 10) - (scores[b.id] ?? 10),
)
: connectors
// Iterate through each connector and try to connect
let connected = false
const connections: Connection[] = []
const providers: unknown[] = []
for (const connector of sorted) {
const provider_ = await connector.getProvider()
if (!provider_) continue
// If we already have an instance of this connector's provider,
// then we have already checked it (ie. injected connectors can
// share the same `window.ethereum` instance, so we don't want to
// connect to it again).
if (providers.some((provider) => provider === provider_)) continue
const isAuthorized = await connector.isAuthorized()
if (!isAuthorized) continue
const data = await connector
.connect({ isReconnecting: true })
.catch(() => null)
if (!data) continue
connector.emitter.off('connect', config._internal.events.connect)
connector.emitter.on('change', config._internal.events.change)
connector.emitter.on('disconnect', config._internal.events.disconnect)
config.setState((x) => {
const connections = new Map(connected ? x.connections : new Map()).set(
connector.uid,
{ accounts: data.accounts, chainId: data.chainId, connector },
)
return {
...x,
current: connected ? x.current : connector.uid,
connections,
}
})
connections.push({
accounts: data.accounts as readonly [Address, ...Address[]],
chainId: data.chainId,
connector,
})
providers.push(provider_)
connected = true
}
// Prevent overwriting connected status from race condition
if (
config.state.status === 'reconnecting' ||
config.state.status === 'connecting'
) {
// If connecting didn't succeed, set to disconnected
if (!connected)
config.setState((x) => ({
...x,
connections: new Map(),
current: undefined,
status: 'disconnected',
}))
else config.setState((x) => ({ ...x, status: 'connected' }))
}
isReconnecting = false
return connections
}