Skip to content

fix(#724): guard window access for SSR in SorokitProvider - #1018

Merged
k-deejah merged 3 commits into
Sorokit:mainfrom
BernardOnuh:fix/ssr-localStorage-sorokit-provider
Oct 25, 2026
Merged

k-deejah merged 3 commits into
Sorokit:mainfrom
BernardOnuh:fix/ssr-localStorage-sorokit-provider

Conversation

@BernardOnuh

Copy link
Copy Markdown
Contributor

Closes #724

Problem

SorokitProvider reads window.localStorage synchronously in two places:

  1. The customNetworks useState initializer (SorokitProvider.tsx:48).
  2. The network-restore useEffect (SorokitProvider.tsx:131).

The existing try/catch only guards against SecurityError from storage access; it does not make the window reference itself safe in environments where window is unavailable. The typeof window !== "undefined" guard used elsewhere (src/lib/adapter.ts, WalletConnectButton.tsx) was missing here.

Changes

  • src/context/SorokitProvider.tsx
    • customNetworks initializer now returns [] early when typeof window === "undefined", before touching window.localStorage.
    • The network-restore effect wraps the localStorage.getItem(STORAGE_KEY_NETWORK) access in a typeof window !== "undefined" check, so it is skipped entirely when there is no browser storage.
  • src/context/SorokitProvider.test.tsx
    • Adds an SSR safety (#724) suite that renders the provider with renderToString while window is stubbed as undefined:
      • renders without throwing, and
      • customNetworks initializes to [].

Why explicit guards instead of relying on catch

The bare catch happened to swallow the reference error, but relying on a catch-all for control flow is fragile and silent. The explicit guard matches the convention already used throughout the codebase and makes the SSR intent obvious. It also covers the case where window exists but localStorage does not.

Testing

  • npm test — 100 files / 2033 tests pass
  • npm run typecheck — clean
  • npm run lint — clean

Screenshots

Not applicable (SSR/Node.js behavior).

SorokitProvider's customNetworks useState initializer and the
network-restore effect read window.localStorage directly. The existing
try/catch only covers SecurityError from storage access, not the case
where window itself is unavailable in SSR/Node.js.

Add explicit typeof window !== "undefined" guards (matching adapter.ts
and WalletConnectButton.tsx) so:
- no ReferenceError is thrown when rendered in Node.js/SSR
- customNetworks initializes to [] without browser storage

Add SSR regression tests that render via renderToString with window
stubbed as undefined.
@drips-wave

drips-wave Bot commented Oct 19, 2026

Copy link
Copy Markdown

@BernardOnuh Great news! 🎉 Based on an automated assessment of this PR, the linked Wave issue(s) no longer count against your application limits.

You can now already apply to more issues while waiting for a review of this PR. Keep up the great work! 🚀

Learn more about application limits

BernardOnuh and others added 2 commits October 25, 2026 15:23
Resolve the import conflict in SorokitProvider.test.tsx (keep
renderToString from this branch and afterEach from main).

Also repair two broken merge artifacts on main that stopped the
provider suite from parsing:
- SorokitProvider.test.tsx: restore the missing closers of the
  top-level afterEach block
- SorokitContext.ts: restore the opening of the isHardware doc
  comment and drop the duplicated optional declaration

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
- TransactionPanel: drop interleaved duplicate MEMO_TYPES tail,
  isMemoHexType/isMemoHashValid redeclaration, duplicated label/
  placeholder/error ternaries and canSubmit tail
- budget.ts: restore closing brace of calculateMonthlySpending
- SwapExecutionTracker: remove unreachable "signing" branch inside the
  isPending banner (isPending never includes signing)
- payment-flow, useOutsideClick, budget tests: restore missing block
  closers; merge duplicate budget import; align Sorokit#968 memo assertions with
  the component's label and message
- lint autofix: import sort and prefer-const

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@BernardOnuh

Copy link
Copy Markdown
Contributor Author

@k-deejah this PR is ready for review and merge. Conflicts with main are resolved, and the branch also fixes the broken merge artifacts on main that were failing lint/typecheck. Thanks!

@k-deejah
k-deejah merged commit 2852318 into Sorokit:main Oct 25, 2026
2 of 4 checks passed
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.

SorokitProvider — window.localStorage accessed synchronously in useState initializer — throws in SSR/Node.js

3 participants