Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
26 commits
Select commit Hold shift + click to select a range
8f406de
feat: add reconnectOnInit flag defaulting to true
tomiir Jun 19, 2025
b8d1bf4
fix: on by defualt
tomiir Jun 19, 2025
12e03d1
feat: do not initialize on auth nor wc
tomiir Jun 19, 2025
807f3f4
chore: remove logs
tomiir Jun 19, 2025
bb8c725
refactor: update property name as `enableReconnect`, update lab examp…
enesozturk Jun 20, 2025
f794960
chore: add e2e test flows
enesozturk Jun 20, 2025
d4948ca
chore: linter and ts issues
enesozturk Jun 20, 2025
b77686a
chore: check status on e2e test
enesozturk Jun 20, 2025
d52e891
Merge branch 'main' into feat/reconnect-flag
enesozturk Jun 20, 2025
b654334
chore: remove skip for extension tests
enesozturk Jun 20, 2025
1fd9db4
chore: revert e2e project settings
enesozturk Jun 20, 2025
1448787
chore: flag boolean logics
enesozturk Jun 20, 2025
bdb8731
chore: ts and linter issues
enesozturk Jun 20, 2025
cc63af5
Merge branch 'main' into feat/reconnect-flag
enesozturk Jun 20, 2025
132e6a2
chore: try catch the namespace disconnections
enesozturk Jun 20, 2025
5398bcd
chore: linter issue
enesozturk Jun 20, 2025
cb878f2
chore: use context instead of browser in playwright
0xmkh Jun 20, 2025
6c12644
chore: fix flag logic for status
enesozturk Jun 20, 2025
fa15cee
chore: fix flag logics
enesozturk Jun 20, 2025
9288b8e
chore: linter issues
enesozturk Jun 20, 2025
659d188
Merge branch 'main' into feat/reconnect-flag
enesozturk Jun 20, 2025
7daf8c6
chore: handle request
enesozturk Jun 20, 2025
34b01bb
Merge branch 'main' into feat/reconnect-flag
tomiir Jun 20, 2025
7a06d55
chore: use email first
enesozturk Jun 20, 2025
204ccb1
chore: add 500ms timeout after promptSiwe
0xmkh Jun 20, 2025
eff1bb4
chore: disable siwx on examples
enesozturk Jun 22, 2025
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
27 changes: 27 additions & 0 deletions .changeset/rude-worlds-attend.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
---
'@reown/appkit': patch
'@reown/appkit-adapter-bitcoin': patch
'@reown/appkit-adapter-ethers': patch
'@reown/appkit-adapter-ethers5': patch
'@reown/appkit-adapter-solana': patch
'@reown/appkit-adapter-wagmi': patch
'@reown/appkit-utils': patch
'@reown/appkit-cdn': patch
'@reown/appkit-cli': patch
'@reown/appkit-codemod': patch
'@reown/appkit-common': patch
'@reown/appkit-controllers': patch
'@reown/appkit-core': patch
'@reown/appkit-experimental': patch
'@reown/appkit-pay': patch
'@reown/appkit-polyfills': patch
'@reown/appkit-scaffold-ui': patch
'@reown/appkit-siwe': patch
'@reown/appkit-siwx': patch
'@reown/appkit-testing': patch
'@reown/appkit-ui': patch
'@reown/appkit-wallet': patch
'@reown/appkit-wallet-button': patch
---

Adds reconnectOnInit flag to prevent automatic reconnection
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -20,3 +20,4 @@ tsconfig.tsbuildinfo
.coverage
.cursor
.envrc*
test-results.json
39 changes: 39 additions & 0 deletions apps/laboratory/app/flag/enable-reconnect/ethers/page.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
'use client'

import { BitcoinAdapter } from '@reown/appkit-adapter-bitcoin'
import { EthersAdapter } from '@reown/appkit-adapter-ethers'
import { SolanaAdapter } from '@reown/appkit-adapter-solana/react'
import { mainnet } from '@reown/appkit/networks'

import { AppKitButtons } from '@/src/components/AppKitButtons'
import { AppKitConnections } from '@/src/components/AppKitConnections'
import { AppKitInfo } from '@/src/components/AppKitInfo'
import { EthersTests } from '@/src/components/Ethers/EthersTests'
import { AppKitProvider } from '@/src/context/AppKitContext'
import { ConstantsUtil } from '@/src/utils/ConstantsUtil'

const ethersAdapter = new EthersAdapter()
const solanaAdapter = new SolanaAdapter()
const bitcoinAdapter = new BitcoinAdapter()

const config = {
adapters: [ethersAdapter, solanaAdapter, bitcoinAdapter],
networks: ConstantsUtil.AllNetworks,
defaultNetwork: mainnet,
projectId: ConstantsUtil.ProjectId,
customWallets: ConstantsUtil.CustomWallets,
enableReconnect: false
}

export default function Ethers() {
return (
<AppKitProvider config={config}>
<AppKitButtons />
<AppKitConnections namespace="eip155" title="EVM Connections" />
<AppKitConnections namespace="solana" title="Solana Connections" />
<AppKitConnections namespace="bip122" title="Bitcoin Connections" />
<AppKitInfo />
<EthersTests />
</AppKitProvider>
)
}
39 changes: 39 additions & 0 deletions apps/laboratory/app/flag/enable-reconnect/ethers5/page.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
'use client'

import { BitcoinAdapter } from '@reown/appkit-adapter-bitcoin'
import { Ethers5Adapter } from '@reown/appkit-adapter-ethers5'
import { SolanaAdapter } from '@reown/appkit-adapter-solana/react'
import { mainnet } from '@reown/appkit/networks'

import { AppKitButtons } from '@/src/components/AppKitButtons'
import { AppKitConnections } from '@/src/components/AppKitConnections'
import { AppKitInfo } from '@/src/components/AppKitInfo'
import { EthersTests } from '@/src/components/Ethers/EthersTests'
import { AppKitProvider } from '@/src/context/AppKitContext'
import { ConstantsUtil } from '@/src/utils/ConstantsUtil'

const ethersAdapter = new Ethers5Adapter()
const solanaAdapter = new SolanaAdapter()
const bitcoinAdapter = new BitcoinAdapter()

const config = {
adapters: [ethersAdapter, solanaAdapter, bitcoinAdapter],
networks: ConstantsUtil.AllNetworks,
defaultNetwork: mainnet,
projectId: ConstantsUtil.ProjectId,
customWallets: ConstantsUtil.CustomWallets,
enableReconnect: false
}

export default function Ethers() {
return (
<AppKitProvider config={config}>
<AppKitButtons />
<AppKitConnections namespace="eip155" title="EVM Connections" />
<AppKitConnections namespace="solana" title="Solana Connections" />
<AppKitConnections namespace="bip122" title="Bitcoin Connections" />
<AppKitInfo />
<EthersTests />
</AppKitProvider>
)
}
49 changes: 49 additions & 0 deletions apps/laboratory/app/flag/enable-reconnect/wagmi/page.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
'use client'

import { QueryClient, QueryClientProvider } from '@tanstack/react-query'
import { WagmiProvider } from 'wagmi'

import { BitcoinAdapter } from '@reown/appkit-adapter-bitcoin'
import { SolanaAdapter } from '@reown/appkit-adapter-solana/react'
import { WagmiAdapter } from '@reown/appkit-adapter-wagmi'

import { AppKitButtons } from '@/src/components/AppKitButtons'
import { AppKitConnections } from '@/src/components/AppKitConnections'
import { AppKitInfo } from '@/src/components/AppKitInfo'
import { WagmiTests } from '@/src/components/Wagmi/WagmiTests'
import { AppKitProvider } from '@/src/context/AppKitContext'
import { ConstantsUtil } from '@/src/utils/ConstantsUtil'

const queryClient = new QueryClient()

const wagmiAdapter = new WagmiAdapter({
ssr: true,
networks: ConstantsUtil.EvmNetworks,
projectId: ConstantsUtil.ProjectId
})
const solanaAdapter = new SolanaAdapter()
const bitcoinAdapter = new BitcoinAdapter()

const config = {
adapters: [wagmiAdapter, solanaAdapter, bitcoinAdapter],
networks: ConstantsUtil.AllNetworks,
projectId: ConstantsUtil.ProjectId,
customWallets: ConstantsUtil.CustomWallets,
enableReconnect: false
}
const wagmiConfig = wagmiAdapter.wagmiConfig

export default function Wagmi() {
return (
<WagmiProvider config={wagmiConfig} reconnectOnMount={false}>
<QueryClientProvider client={queryClient}>
<AppKitProvider config={config}>
<AppKitButtons />
<AppKitConnections namespace="eip155" />
<AppKitInfo />
<WagmiTests config={wagmiConfig} />
</AppKitProvider>
</QueryClientProvider>
</WagmiProvider>
)
}
2 changes: 2 additions & 0 deletions apps/laboratory/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@
"playwright:test": "HEADLESS=true playwright test",
"playwright:test:mobile-wallet-features": "playwright test --grep 'mobile-wallet-features.spec.ts'",
"playwright:test:basic": "playwright test --grep 'basic-tests.spec.ts'",
"playwright:test:flag-enable-reconnect": "HEADLESS=true playwright test --grep 'flag-enable-reconnect.spec.ts'",
"playwright:test:config": "playwright test --grep 'config.spec.ts'",
"playwright:test:extension": "HEADLESS=true playwright test --grep 'extension.spec.ts'",
"playwright:test:siwe-extension": "HEADLESS=true playwright test --grep 'siwe-extension.spec.ts'",
Expand Down Expand Up @@ -63,6 +64,7 @@
"playwright:debug": "pnpm playwright:test --debug",
"playwright:debug:mobile-wallet-features": "pnpm playwright:test:mobile-wallet-features --debug",
"playwright:debug:basic": "pnpm playwright:test:basic --debug",
"playwright:debug:flag-enable-reconnect": "playwright test --grep flag-enable-reconnect.spec.ts --debug",
"playwright:debug:extension": "playwright test --grep 'extension.spec.ts' --debug",
"playwright:debug:siwe-extension": "playwright test --grep 'siwe-extension.spec.ts' --debug",
"playwright:debug:siwx-extension": "playwright test --grep 'siwx-extension.spec.ts' --debug",
Expand Down
10 changes: 10 additions & 0 deletions apps/laboratory/src/components/AppKitInfo.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ export function AppKitInfo() {
const { caipAddress, address, embeddedWalletInfo } = useAppKitAccount()
const { walletInfo } = useWalletInfo()
const { chainId } = useAppKitNetwork()
const appKitAccount = useAppKitAccount()

const isEIP155 = caipAddress?.startsWith('eip155:')
const erc3770Address = React.useMemo(() => {
Expand Down Expand Up @@ -99,6 +100,15 @@ export function AppKitInfo() {
</Box>
)}

{appKitAccount?.status && (
<Box>
<Heading size="xs" textTransform="uppercase" pb="2">
Status
</Heading>
<Text data-testid="apkt-account-status">{appKitAccount.status}</Text>
</Box>
)}

<RelayClientInfo />

<EmbeddedWalletInfo />
Expand Down
91 changes: 91 additions & 0 deletions apps/laboratory/tests/flag-enable-reconnect.spec.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,91 @@
import { type BrowserContext } from '@playwright/test'

import { WalletPage } from '@reown/appkit-testing'

import { extensionFixture } from './shared/fixtures/extension-fixture'
import { ModalPage } from './shared/pages/ModalPage'
import { Email } from './shared/utils/email'
import { ModalValidator } from './shared/validators/ModalValidator'

/* eslint-disable init-declarations */
let modalPage: ModalPage
let modalValidator: ModalValidator
let walletPage: WalletPage
let context: BrowserContext
/* eslint-enable init-declarations */

// -- Setup --------------------------------------------------------------------
const test = extensionFixture.extend<{ library: string }>({
library: ['wagmi', { option: true }]
})

test.describe.configure({ mode: 'serial' })

test.beforeAll(async ({ context: browserContext, library }) => {
context = browserContext
const browserPage = await context.newPage()

modalPage = new ModalPage(browserPage, library, 'flag-enable-reconnect')
walletPage = new WalletPage(await context.newPage())
modalValidator = new ModalValidator(browserPage)

await modalPage.load()
})

test.afterAll(async () => {
await modalPage.page.close()
})

// -- Tests --------------------------------------------------------------------
test.describe('Email', () => {
test('it should connect with Email and got disconnected after page refresh', async () => {
const mailsacApiKey = process.env['MAILSAC_API_KEY']
if (!mailsacApiKey) {
throw new Error('MAILSAC_API_KEY is not set')
}
const email = new Email(mailsacApiKey)
const tempEmail = await email.getEmailAddressToUse()

// Connect with email
modalValidator.expectSecureSiteFrameNotInjected()
await modalPage.emailFlow({ emailAddress: tempEmail, context, mailsacApiKey })
await modalValidator.expectConnected()

// Reload and check connection
await modalPage.page.reload()
await modalValidator.expectDisconnected()
await modalValidator.expectStatus('disconnected')
})
})

test.describe('WC', () => {
test('it should connect with WC and got disconnected after page refresh', async () => {
// Connect with WC
await modalPage.qrCodeFlow(modalPage, walletPage)
await modalValidator.expectConnected()

// Reload and check connection
await modalPage.page.reload()
await modalValidator.expectDisconnected()
await modalValidator.expectStatus('disconnected')
})
})

test.describe('Extension', () => {
test('it should connect with Reown Extension and got disconnected after page refresh', async ({
browserName
}) => {
const isFirefox = browserName === 'firefox'

if (isFirefox) {
return
}
// Connect with Reown Extension
await modalPage.connectToExtensionMultichain('solana')

// Reload and check connection
await modalPage.page.reload()
await modalValidator.expectDisconnected()
await modalValidator.expectStatus('disconnected')
})
})
3 changes: 3 additions & 0 deletions apps/laboratory/tests/shared/pages/ModalPage.ts
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,7 @@ export type ModalFlavor =
| 'core-universal-provider'
| 'core'
| 'all'
| 'flag-enable-reconnect'

function getUrlByFlavor(baseUrl: string, library: string, flavor: ModalFlavor) {
const urlsByFlavor: Partial<Record<ModalFlavor, string>> = {
Expand Down Expand Up @@ -80,6 +81,8 @@ export class ModalPage {
this.url = `${this.baseURL}library/multichain-ethers-solana/`
} else if (library === 'default-account-types-sa' || library === 'default-account-types-eoa') {
this.url = `${this.baseURL}flag/${library}/`
} else if (flavor === 'flag-enable-reconnect') {
this.url = `${this.baseURL}flag/enable-reconnect/${library}`
} else {
this.url = getUrlByFlavor(this.baseURL, library, flavor)
}
Expand Down
3 changes: 2 additions & 1 deletion apps/laboratory/tests/shared/utils/project.ts
Original file line number Diff line number Diff line change
Expand Up @@ -79,7 +79,8 @@ const SINGLE_ADAPTER_EVM_TESTS = [
'verify.spec.ts',
'email-after-farcaster.spec.ts',
'multi-wallet.spec.ts',
'multi-wallet-siwx.spec.ts'
'multi-wallet-siwx.spec.ts',
'flag-enable-reconnect.spec.ts'
]

const CORE_TESTS = ['sign-client.spec.ts', 'universal-provider.spec.ts', 'core.spec.ts']
Expand Down
5 changes: 5 additions & 0 deletions apps/laboratory/tests/shared/validators/ModalValidator.ts
Original file line number Diff line number Diff line change
Expand Up @@ -96,6 +96,11 @@ export class ModalValidator {
)
}

async expectStatus(status: 'connecting' | 'connected' | 'disconnected') {
const connectButton = this.page.getByTestId('apkt-account-status')
await expect(connectButton, `Account status should be ${status}`).toHaveText(status)
}

async expectActiveProfileWalletItemToExist() {
const activeProfileWalletItem = this.page.getByTestId('wui-active-profile-wallet-item')
await expect(activeProfileWalletItem).toBeVisible({
Expand Down
29 changes: 26 additions & 3 deletions packages/appkit/src/client/appkit-base-client.ts
Original file line number Diff line number Diff line change
Expand Up @@ -164,8 +164,12 @@ export abstract class AppKitBaseClient {
this.initControllers(options)
await this.initChainAdapters()
this.sendInitializeEvent(options)
await this.syncExistingConnection()
await this.syncAdapterConnections()
if (options.enableReconnect === false) {
await this.unSyncExistingConnection()
} else {
await this.syncExistingConnection()
await this.syncAdapterConnections()
}
this.remoteFeatures = await ConfigUtil.fetchRemoteFeatures(options)
OptionsController.setRemoteFeatures(this.remoteFeatures)
if (this.remoteFeatures.onramp) {
Expand Down Expand Up @@ -304,6 +308,7 @@ export abstract class AppKitBaseClient {
OptionsController.setEnableWallets(options.enableWallets !== false)
OptionsController.setEIP6963Enabled(options.enableEIP6963 !== false)
OptionsController.setEnableNetworkSwitch(options.enableNetworkSwitch !== false)
OptionsController.setEnableReconnect(options.enableReconnect !== false)

OptionsController.setEnableAuthLogger(options.enableAuthLogger !== false)
OptionsController.setCustomRpcUrls(options.customRpcUrls)
Expand Down Expand Up @@ -867,7 +872,10 @@ export abstract class AppKitBaseClient {
}

const connectionStatus = StorageUtil.getConnectionStatus()
if (connectionStatus === 'connected') {

if (this.options.enableReconnect === false) {
this.setStatus('disconnected', chainNamespace)
} else if (connectionStatus === 'connected') {
this.setStatus('connecting', chainNamespace)
} else if (connectionStatus === 'disconnected') {
/*
Expand Down Expand Up @@ -987,6 +995,17 @@ export abstract class AppKitBaseClient {
)
}

protected async unSyncExistingConnection() {
try {
await Promise.allSettled(
this.chainNamespaces.map(namespace => ConnectionController.disconnect({ namespace }))
)
} catch (error) {
// eslint-disable-next-line no-console
console.error('Error disconnecting existing connections:', error)
}
}

protected async syncNamespaceConnection(namespace: ChainNamespace) {
try {
if (namespace === ConstantsUtil.CHAIN.EVM && CoreHelperUtil.isSafeApp()) {
Expand Down Expand Up @@ -1393,6 +1412,10 @@ export abstract class AppKitBaseClient {
OptionsController.setManualWCControl(Boolean(this.options?.manualWCControl))
this.universalProvider =
this.options.universalProvider ?? (await UniversalProvider.init(universalProviderOptions))
// Clear the session if we don't want to reconnect on init
if (this.options.enableReconnect === false && this.universalProvider.session) {
await this.universalProvider.disconnect()
}
this.listenWalletConnect()
}

Expand Down
Loading