Skip to content

fix: re-check installed wallets after mount for late-injecting extensions#66

Merged
satoshai-dev merged 1 commit intomainfrom
fix/wallet-detection-timing
Apr 6, 2026
Merged

fix: re-check installed wallets after mount for late-injecting extensions#66
satoshai-dev merged 1 commit intomainfrom
fix/wallet-detection-timing

Conversation

@satoshai-dev
Copy link
Copy Markdown
Owner

Summary

  • Browser wallet extensions (Xverse, Leather, etc.) inject their globals into window at document_end/document_idle, which can race with React 19 hydration on Next.js 16
  • The provider now stores detected wallets in state and re-checks once after mount via useEffect, so late-injecting extensions are picked up
  • No unnecessary re-render when extensions are already detected at mount time (comparison guard in setInstalled)

Test plan

  • Existing 209 tests pass
  • 2 new provider-level tests added:
    • Extensions injected after initial render are picked up
    • No state update when extensions are already detected at mount
  • Build passes (pnpm build)
  • Manual: open app with Xverse/Leather installed → Connect Wallet → verify both show as "Installed"

…ions

Browser wallet extensions (Xverse, Leather, etc.) inject their globals
into window at document_end/document_idle, which can race with React 19
hydration. The provider now stores detected wallets in state and
re-checks once after mount so late-injecting extensions are picked up.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
@satoshai-dev satoshai-dev merged commit 5cb876e into main Apr 6, 2026
1 check passed
satoshai-dev added a commit that referenced this pull request Apr 6, 2026
Instead of relying solely on the provider's render-time detection
(which can miss extensions that inject after React hydration),
useWallets now calls getStacksWallets() directly on every render.
This ensures fresh detection at the point of consumption — by the
time a user opens a connect-wallet drawer, extensions are detected.

Reverts the provider-level useState/useEffect approach from #66
in favor of this simpler hook-level solution.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
satoshai-dev added a commit that referenced this pull request Apr 6, 2026
Instead of relying solely on the provider's render-time detection
(which can miss extensions that inject after React hydration),
useWallets now calls getStacksWallets() directly on every render.
This ensures fresh detection at the point of consumption — by the
time a user opens a connect-wallet drawer, extensions are detected.

Reverts the provider-level useState/useEffect approach from #66
in favor of this simpler hook-level solution.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
satoshai-dev added a commit that referenced this pull request Apr 6, 2026
Instead of relying solely on the provider's render-time detection
(which can miss extensions that inject after React hydration),
useWallets now calls getStacksWallets() directly on every render.
This ensures fresh detection at the point of consumption — by the
time a user opens a connect-wallet drawer, extensions are detected.

Reverts the provider-level useState/useEffect approach from #66
in favor of this simpler hook-level solution.

Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant