Skip to content

feat(controllers): expose WalletConnect URI on public state for headless QR#5697

Merged
0xmkh merged 2 commits into
mainfrom
feat/headless-expose-wcuri
Jul 2, 2026
Merged

feat(controllers): expose WalletConnect URI on public state for headless QR#5697
0xmkh merged 2 commits into
mainfrom
feat/headless-expose-wcuri

Conversation

@enesozturk

Copy link
Copy Markdown
Contributor

What

Exposes the WalletConnect URI on the public AppKit state so a headless host can render a QR without the useAppKitWallets React hook.

getState() / subscribeState() now include:

  • wcUri: string | undefined
  • wcError: boolean
  • wcFetchingUri: boolean

These are the symmetric read for the existing getWalletConnectUri() trigger added in #5695 — that PR exposed the imperative wallet-list + URI trigger on the client, but the only way to read the generated URI back was subscribeConnections, which is gated behind the multiWallet remote feature (no-ops when off) and so can't serve the URI for a single-wallet QR.

How

A single one-way valtio subscription in ConnectionController mirrors wcUri / wcError / wcFetchingUri onto PublicStateController whenever any of them changes — so the mirror stays correct regardless of which setter (setUri, setWcError, resetUri, resetWcConnection, connectWalletConnect, …) mutated it. PublicState never writes back, so there's no feedback loop. This matches the existing precedent where ConnectionController already writes connectingWallet onto the public state.

Why

A framework-neutral host (e.g. a plain-JS integration, or @walletconnect/pay-appkit) drives everything else through the AppKit instance (getWalletList, getAccount, getState, subscribeState, …). The WC URI was the one piece with no ungated instance read — forcing consumers to import @reown/appkit-controllers directly, which breaks when the package resolves to a different physical instance than the host's @reown/appkit (duplicate valtio singleton → the QR reads a copy that's never written). Reading wcUri off the public state removes that footgun entirely.

Tests

  • ConnectionController.test.ts: asserts the mirror reflects setUri / setWcError / resetUri onto the public state.
  • PublicStateController.test.ts: updated default/set() shape assertions for the new fields.
  • pnpm --filter @reown/appkit-controllers typecheck clean; controllers tests green; prettier + eslint clean on changed files.

Follow-up

Once this lands in a canary, @walletconnect/pay-appkit will read appKit.getState().wcUri / subscribeState() instead of the direct ConnectionController import.

…ess QR

`getState()` / `subscribeState()` now include `wcUri`, `wcError`, and
`wcFetchingUri` — the symmetric *read* for the existing `getWalletConnectUri()`
trigger. They're mirrored one-way from `ConnectionController` onto
`PublicStateController` via a single subscription, so a headless host can render
a QR through the AppKit instance without the `useAppKitWallets` React hook.

The connection-level `subscribeConnections` is gated behind the `multiWallet`
remote feature and so can't serve the URI for a single-wallet QR; the public
state is ungated. This completes the headless read surface started in #5695.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
@changeset-bot

changeset-bot Bot commented Jun 29, 2026

Copy link
Copy Markdown

🦋 Changeset detected

Latest commit: 633c3ab

The changes in this PR will be included in the next version bump.

This PR includes changesets to release 26 packages
Name Type
@reown/appkit-utils Patch
@reown/appkit Patch
@reown/appkit-cdn Patch
@reown/appkit-cli Patch
@reown/appkit-codemod Patch
@reown/appkit-common 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-universal-connector Patch
@reown/appkit-wallet-button Patch
@reown/appkit-wallet Patch
@reown/appkit-controllers Patch
@reown/appkit-adapter-bitcoin Patch
@reown/appkit-adapter-ethers Patch
@reown/appkit-adapter-ethers5 Patch
@reown/appkit-adapter-solana Patch
@reown/appkit-adapter-ton Patch
@reown/appkit-adapter-tron Patch
@reown/appkit-adapter-wagmi Patch

Not sure what this means? Click here to learn what changesets are.

Click here if you're a maintainer who wants to add another changeset to this PR

@vercel

vercel Bot commented Jun 29, 2026

Copy link
Copy Markdown

The latest updates on your projects. Learn more about Vercel for GitHub.

Project Deployment Actions Updated (UTC)
appkit-demo Ready Ready Preview, Comment Jul 2, 2026 11:19am
appkit-gallery Ready Ready Preview, Comment Jul 2, 2026 11:19am
appkit-headless-sample-app Ready Ready Preview, Comment Jul 2, 2026 11:19am
appkit-laboratory Ready Ready Preview, Comment Jul 2, 2026 11:19am
9 Skipped Deployments
Project Deployment Actions Updated (UTC)
appkit-basic-example Ignored Ignored Jul 2, 2026 11:19am
appkit-basic-sign-client-example Ignored Ignored Jul 2, 2026 11:19am
appkit-basic-up-example Ignored Ignored Jul 2, 2026 11:19am
appkit-ethers5-bera Ignored Ignored Jul 2, 2026 11:19am
appkit-nansen-demo Ignored Ignored Jul 2, 2026 11:19am
appkit-wagmi-cdn-example Ignored Ignored Jul 2, 2026 11:19am
ethereum-provider-wagmi-example Ignored Ignored Jul 2, 2026 11:19am
next-wagmi-solana-bitcoin-example Ignored Ignored Jul 2, 2026 11:19am
vue-wagmi-example Ignored Ignored Jul 2, 2026 11:19am

Request Review

@github-actions

github-actions Bot commented Jun 29, 2026

Copy link
Copy Markdown
Contributor

Visual Regression Test Results ✅ Passed

⚠️ 20 visual change(s) detected

Chromatic Build: https://www.chromatic.com/build?appId=6493191bf4b10fed8ca7353f&number=945
Storybook Preview: https://6493191bf4b10fed8ca7353f-mbjtuopozk.chromatic.com/

👉 Please review the visual changes in Chromatic and accept or reject them.

@github-actions

github-actions Bot commented Jun 29, 2026

Copy link
Copy Markdown
Contributor

📦 Bundle Size Check

All bundles are within size limits

📊 View detailed bundle sizes

> @reown/appkit-monorepo@1.7.1 size /home/runner/work/appkit/appkit


> size-limit

@reown/appkit - Main Entry
Size limit:   80 kB
Size:         75.84 kB with all dependencies, minified and gzipped
Loading time: 1.5 s    on slow 3G
Running time: 3.5 s    on Snapdragon 410
Total time:   4.9 s
@reown/appkit/react
Size limit:   236 kB
Size:         235.08 kB with all dependencies, minified and gzipped
Loading time: 4.6 s     on slow 3G
Running time: 5.5 s     on Snapdragon 410
Total time:   10.1 s
@reown/appkit/vue
Size limit:   80 kB
Size:         75.84 kB with all dependencies, minified and gzipped
Loading time: 1.5 s    on slow 3G
Running time: 2.6 s    on Snapdragon 410
Total time:   4.1 s
@reown/appkit-scaffold-ui
Size limit:   220 kB
Size:         214.38 kB with all dependencies, minified and gzipped
Loading time: 4.2 s     on slow 3G
Running time: 3.5 s     on Snapdragon 410
Total time:   7.7 s
@reown/appkit-ui
Size limit:   500 kB
Size:         13.16 kB with all dependencies, minified and gzipped
Loading time: 258 ms   on slow 3G
Running time: 389 ms   on Snapdragon 410
Total time:   646 ms

@github-actions

github-actions Bot commented Jun 29, 2026

Copy link
Copy Markdown
Contributor

Coverage Report

Status Category Percentage Covered / Total
🔵 Lines 78.57% 40058 / 50979
🔵 Statements 78.57% 40058 / 50979
🔵 Functions 76.07% 4279 / 5625
🔵 Branches 86.69% 9783 / 11284
File Coverage
File Stmts Branches Functions Lines Uncovered Lines
Changed Files
packages/appkit/src/client/appkit-base-client.ts 73.16% 85.68% 73.57% 73.16% 190-196, 216, 229-232, 235, 247-248, 254-255, 258, 267, 314-315, 361-362, 400-401, 403-404, 409-410, 492-493, 529-535, 606-607, 629-644, 647, 685, 726-730, 737-738, 741-742, 747-748, 759-782, 791-792, 809-829, 833-854, 857-883, 886-892, 895-901, 904-910, 913-919, 922-932, 935-941, 944-951, 965-974, 977-983, 986-987, 990-991, 1010-1011, 1034-1074, 1081-1093, 1099-1126, 1129-1139, 1171-1172, 1197-1198, 1203, 1218-1234, 1248, 1252-1260, 1291-1292, 1311-1314, 1318-1319, 1321-1322, 1356-1358, 1362-1383, 1388-1389, 1397-1398, 1400-1401, 1495-1496, 1508-1509, 1514, 1537-1542, 1589, 1610-1611, 1620, 1622-1638, 1643, 1689-1690, 1702-1713, 1760-1777, 1822, 1828-1832, 1853-1868, 1871-1872, 1898-1901, 1937-1956, 1988, 2031-2032, 2038-2064, 2294-2295, 2338-2339, 2343-2344, 2348-2349, 2357-2358, 2366-2367, 2371-2372, 2379-2384, 2392-2393, 2396-2397, 2413-2416, 2419-2420, 2440-2441, 2444-2445, 2466, 2487-2488, 2496-2497, 2509-2510, 2524, 2551-2552, 2558-2559, 2593-2598, 2616-2617, 2620-2621, 2668-2669, 2740-2741, 2744-2745, 2748-2751, 2754-2755, 2758-2759, 2762-2763, 2766-2767, 2770-2774, 2783-2792, 2801-2812, 1381, 2382
packages/controllers/exports/index.ts 100% 100% 100% 100%
packages/controllers/src/utils/HeadlessWalletUtil.ts 92.03% 96.87% 88.23% 92.03% 122-129, 187, 201
Generated in workflow #17160 for commit 633c3ab by the Vitest Coverage Report Action

Comment thread packages/controllers/src/controllers/PublicStateController.ts Outdated
Comment thread packages/controllers/src/controllers/ConnectionController.ts Outdated
…ot public state

Replace the PublicStateController mirror with a direct read/subscribe pair on
HeadlessWalletUtil, mirroring the existing getWalletList/subscribeWalletList
pattern. A headless host reads the URI ungated through the AppKit instance with
a single source of truth and no controllers import.

- Add HeadlessWalletUtil.getWalletConnectUri() (returns { wcUri, wcError,
  wcFetchingUri }) and subscribeWalletConnectUri(), both reading
  ConnectionController directly; export WalletConnectUriSnapshot.
- Rename the pre-fetch trigger getWalletConnectUri() -> prefetchWalletConnectUri()
  (breaking) to free the natural name for the read.
- Revert the wcUri/wcError/wcFetchingUri fields on PublicStateController and the
  module-scope mirror subscription on ConnectionController.
- Update tests + changeset accordingly.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
@0xmkh 0xmkh merged commit 6b9c313 into main Jul 2, 2026
36 of 44 checks passed
@0xmkh 0xmkh deleted the feat/headless-expose-wcuri branch July 2, 2026 13:48
@github-actions github-actions Bot locked and limited conversation to collaborators Jul 2, 2026
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants