Skip to content

Commit 5bc8c88

Browse files
committedJul 17, 2024··
fix: #4150
1 parent 8d81df5 commit 5bc8c88

File tree

3 files changed

+71
-4
lines changed

3 files changed

+71
-4
lines changed
 

‎.changeset/pink-years-agree.md

+5
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
---
2+
"@wagmi/core": patch
3+
---
4+
5+
Fixed reconnection when `status` is defined.

‎packages/core/src/actions/reconnect.test.ts

+51-2
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,13 @@
1-
import { accounts, config } from '@wagmi/test'
2-
import { afterEach, expect, test } from 'vitest'
1+
import { accounts, config, mainnet } from '@wagmi/test'
2+
import { afterEach, expect, test, vi } from 'vitest'
3+
import { http } from 'viem'
34

45
import { mock } from '../connectors/mock.js'
56
import { connect } from './connect.js'
67
import { disconnect } from './disconnect.js'
78
import { reconnect } from './reconnect.js'
9+
import { createStorage } from '../createStorage.js'
10+
import { createConfig } from '../createConfig.js'
811

912
const connector = config._internal.connectors.setup(
1013
mock({
@@ -68,3 +71,49 @@ test("behavior: doesn't reconnect if already reconnecting", async () => {
6871
).resolves.toStrictEqual([])
6972
config.setState((x) => ({ ...x, status: previousStatus }))
7073
})
74+
75+
test('behavior: recovers from invalid state', async () => {
76+
const state = {
77+
'wagmi.store': JSON.stringify({
78+
state: {
79+
status: 'connected', // <-- invalid - `status` should not be kept in storage
80+
chainId: 1,
81+
current: '983b8aca245',
82+
},
83+
version: Number.NaN, // mocked version is `'x.y.z'`, which will get interpreted as `NaN`
84+
}),
85+
} as Record<string, string>
86+
Object.defineProperty(window, 'localStorage', {
87+
value: {
88+
getItem: vi.fn((key) => state[key] ?? null),
89+
removeItem: vi.fn((key) => state.delete?.[key]),
90+
setItem: vi.fn((key, value) => {
91+
state[key] = value
92+
}),
93+
},
94+
writable: true,
95+
})
96+
97+
const storage = createStorage<{ store: object }>({
98+
storage: window.localStorage,
99+
})
100+
101+
const config = createConfig({
102+
chains: [mainnet],
103+
storage,
104+
transports: {
105+
[mainnet.id]: http(),
106+
},
107+
})
108+
109+
await reconnect(config, { connectors: [connector] })
110+
111+
expect(config.state).toMatchInlineSnapshot(`
112+
{
113+
"chainId": 1,
114+
"connections": Map {},
115+
"current": null,
116+
"status": "disconnected",
117+
}
118+
`)
119+
})

‎packages/core/src/createConfig.ts

+15-2
Original file line numberDiff line numberDiff line change
@@ -206,6 +206,7 @@ export function createConfig<
206206
const prefix = '0.0.0-canary-'
207207
if (version.startsWith(prefix))
208208
currentVersion = Number.parseInt(version.replace(prefix, ''))
209+
// use package major version to version store
209210
else currentVersion = Number.parseInt(version.split('.')[0] ?? '0')
210211

211212
const store = createStore(
@@ -243,9 +244,21 @@ export function createConfig<
243244
} as unknown as PartializedState['connections'],
244245
chainId: state.chainId,
245246
current: state.current,
246-
status: state.status,
247247
} satisfies PartializedState
248248
},
249+
merge(persistedState, currentState) {
250+
// `status` should not be persisted as it messes with reconnection
251+
if (
252+
typeof persistedState === 'object' &&
253+
persistedState &&
254+
'status' in persistedState
255+
)
256+
delete persistedState.status
257+
return {
258+
...currentState,
259+
...(persistedState as object),
260+
}
261+
},
249262
skipHydration: ssr,
250263
storage: storage as Storage<Record<string, unknown>>,
251264
version: currentVersion,
@@ -550,7 +563,7 @@ export type State<
550563
}
551564

552565
export type PartializedState = Compute<
553-
ExactPartial<Pick<State, 'chainId' | 'connections' | 'current' | 'status'>>
566+
ExactPartial<Pick<State, 'chainId' | 'connections' | 'current'>>
554567
>
555568

556569
export type Connection = {

0 commit comments

Comments
 (0)
Please sign in to comment.