Skip to content

[SDK] Fix SiteLink and SiteEmbed stripping URL hash fragments#8663

Merged
joaquim-verges merged 1 commit intomainfrom
fix/sitelink-hash-fragment-preservation
Feb 5, 2026
Merged

[SDK] Fix SiteLink and SiteEmbed stripping URL hash fragments#8663
joaquim-verges merged 1 commit intomainfrom
fix/sitelink-hash-fragment-preservation

Conversation

@eabdelmoneim
Copy link
Contributor

@eabdelmoneim eabdelmoneim commented Feb 5, 2026

https://linear.app/thirdweb/issue/PRO-186/bug-in-sitelink-and-siteembed-for-urls

SiteLink/SiteEmbed now append wallet params inside the hash fragment for hash-routed URLs (e.g. https://snapshot.org/#/s:wampei.eth) instead of placing them in the standard query string where they get separated from the hash router. Also fix getUrlToken dropping window.location.hash when cleaning up auth params via pushState.


PR-Codex overview

This PR focuses on enhancing the handling of URL parameters in hash-routed applications, ensuring that both query parameters and hash fragments are processed correctly. It includes tests to validate the preservation of hash fragments and modifies the getUrlToken function to accommodate these changes.

Detailed summary

  • Added a test in SiteLink.test.tsx to verify preservation of hash fragments in URLs.
  • Updated get-url-token.test.tsx to:
    • Check for hash fragments and their parameters.
    • Ensure authFlow and authProvider return undefined instead of null.
  • Modified get-url-token.ts to:
    • Read parameters from both the query string and hash fragments.
    • Preserve hash fragments when constructing the URL for pushState.

✨ Ask PR-Codex anything about this PR by commenting with /codex {your question}

Summary by CodeRabbit

  • Bug Fixes

    • Better handling of hash-routed URLs: authentication parameters are now read from both query and hash fragments, and URL cleanup preserves the original hash path while removing auth tokens.
  • Tests

    • Added coverage for hash-fragment preservation and parsing of authentication parameters embedded in hashed URLs; updated expectations for parsed auth values.

@eabdelmoneim eabdelmoneim requested review from a team as code owners February 5, 2026 00:47
@vercel
Copy link

vercel bot commented Feb 5, 2026

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

Project Deployment Actions Updated (UTC)
docs-v2 Ready Ready Preview, Comment Feb 5, 2026 1:21am
nebula Ready Ready Preview, Comment Feb 5, 2026 1:21am
thirdweb_playground Ready Ready Preview, Comment Feb 5, 2026 1:21am
thirdweb-www Error Error Feb 5, 2026 1:21am
wallet-ui Ready Ready Preview, Comment Feb 5, 2026 1:21am

@changeset-bot
Copy link

changeset-bot bot commented Feb 5, 2026

⚠️ No Changeset found

Latest commit: 105db79

Merging this PR will not cause a version bump for any packages. If these changes should not result in a new version, you're good to go. If these changes should result in a version bump, you need to add a changeset.

This PR includes no changesets

When changesets are added to this PR, you'll see the packages that this PR includes changesets for and the associated semver types

Click here to learn what changesets are, and how to add one.

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

@coderabbitai
Copy link
Contributor

coderabbitai bot commented Feb 5, 2026

Walkthrough

getUrlToken now reads auth params from both the query string and the hash fragment, removes those tokens while preserving the original hash path when updating history, and tests were added to verify hash-fragment preservation and parsing.

Changes

Cohort / File(s) Summary
Tests (hash handling)
packages/thirdweb/src/react/web/ui/SiteLink.test.tsx, packages/thirdweb/src/wallets/in-app/web/lib/get-url-token.test.tsx
Added tests verifying preservation of hash fragments when appending/parsing wallet/auth params; updated expectations (null → undefined) and added cases for cleaning URLs while preserving hash and parsing auth params inside hashes.
URL parsing & cleanup
packages/thirdweb/src/wallets/in-app/web/lib/get-url-token.ts
Updated getUrlToken to merge params from both the standard query string and the hash fragment (preferring query values), decode and remove auth tokens from both locations, reconstruct remaining query and hash (preserving original hash path), and update history without dropping the hash. No signature changes.

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~25 minutes

🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Title check ✅ Passed The title clearly and concisely describes the main fix: preventing SiteLink and SiteEmbed from stripping URL hash fragments, which directly addresses the primary issue in the changeset.
Description check ✅ Passed The PR description includes the issue reference (PRO-186), a clear explanation of the problem and solution, technical details about changes, and a note about added tests, matching the repository template structure.
Linked Issues check ✅ Passed The code changes comprehensively address all objectives from PRO-186: getUrlToken now reads and preserves hash fragments, tests verify hash preservation in both SiteLink and URL token handling.
Out of Scope Changes check ✅ Passed All changes directly support the stated objectives: test additions validate hash preservation, get-url-token.ts modifications implement hash fragment handling, and test expectations are updated to reflect correct behavior.
Docstring Coverage ✅ Passed Docstring coverage is 100.00% which is sufficient. The required threshold is 80.00%.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing touches
  • 📝 Generate docstrings
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment
  • Commit unit tests in branch fix/sitelink-hash-fragment-preservation

Comment @coderabbitai help to get the list of available commands and usage tips.

@github-actions
Copy link
Contributor

github-actions bot commented Feb 5, 2026

size-limit report 📦

Path Size
@thirdweb-dev/nexus (esm) 105.66 KB (0%)
@thirdweb-dev/nexus (cjs) 319.47 KB (0%)

Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

🤖 Fix all issues with AI agents
In `@packages/thirdweb/src/react/web/ui/SiteLink.tsx`:
- Around line 84-96: SiteLink.tsx currently appends auth params into the URL
hash for hash-routed URLs which makes them invisible to the existing
getUrlToken() logic (used by autoConnectCore) that only reads
window.location.search; fix by either updating getUrlToken() to also parse URL
hash parameters (split window.location.hash to extract a query string and merge
those params with search) or change SiteLink.tsx to place auth params back into
the search portion for non-history routers; reference getUrlToken() and
autoConnectCore.ts for the parser update, or modify SiteLink.tsx where finalUrl
is constructed to keep params in window.location.search for compatibility.

@codecov
Copy link

codecov bot commented Feb 5, 2026

Codecov Report

❌ Patch coverage is 86.84211% with 5 lines in your changes missing coverage. Please review.
✅ Project coverage is 52.73%. Comparing base (b9d93e4) to head (105db79).
⚠️ Report is 3 commits behind head on main.

Files with missing lines Patch % Lines
...irdweb/src/wallets/in-app/web/lib/get-url-token.ts 86.84% 5 Missing ⚠️
Additional details and impacted files
@@            Coverage Diff             @@
##             main    #8663      +/-   ##
==========================================
+ Coverage   52.72%   52.73%   +0.01%     
==========================================
  Files         934      934              
  Lines       62945    62975      +30     
  Branches     4117     4137      +20     
==========================================
+ Hits        33185    33210      +25     
- Misses      29660    29665       +5     
  Partials      100      100              
Flag Coverage Δ
packages 52.73% <86.84%> (+0.01%) ⬆️
Files with missing lines Coverage Δ
...irdweb/src/wallets/in-app/web/lib/get-url-token.ts 91.93% <86.84%> (-8.07%) ⬇️
🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.
  • 📦 JS Bundle Analysis: Save yourself from yourself by tracking and limiting bundle sizes in JS merges.

SiteLink/SiteEmbed already preserve hash fragments via the URL API
(searchParams.set keeps the hash at end). The real bug was in getUrlToken()
which dropped window.location.hash when cleaning up auth params via
pushState. Also updated getUrlToken() to parse auth params from inside
the hash fragment as a fallback, supporting hash-routed apps where
params may appear after #/route?params.

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
@eabdelmoneim eabdelmoneim force-pushed the fix/sitelink-hash-fragment-preservation branch from 57b0912 to 105db79 Compare February 5, 2026 01:07
Comment on lines +37 to +66
hashParams?.get("walletId") ??
undefined) as WalletId | undefined;
const authResultString =
params.get("authResult") ?? hashParams?.get("authResult") ?? undefined;
const authProvider = (params.get("authProvider") ??
hashParams?.get("authProvider") ??
undefined) as AuthOption | undefined;
const authCookie = (params.get("authCookie") ??
hashParams?.get("authCookie") ??
undefined) as string | undefined;
const authFlow = (params.get("authFlow") ??
hashParams?.get("authFlow") ??
undefined) as "connect" | "link" | undefined;

if ((authCookie || authResultString) && walletId) {
const authResult = (() => {
if (authResultString) {
params.delete("authResult");
hashParams?.delete("authResult");
return JSON.parse(decodeURIComponent(authResultString));
}
})();
params.delete("walletId");
params.delete("authProvider");
params.delete("authCookie");
params.delete("authFlow");
hashParams?.delete("walletId");
hashParams?.delete("authProvider");
hashParams?.delete("authCookie");
hashParams?.delete("authFlow");
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Missing params.delete("walletId") in the cleanup logic. The code deletes walletId from hashParams (line 63) but not from the standard params. If walletId is in the standard query string, it will remain in the reconstructed URL after authentication.

Impact: walletId will not be cleaned up from the query string, potentially causing it to persist in the URL after auth completion.

Fix: Add params.delete("walletId"); before line 63:

params.delete("authProvider");
params.delete("authCookie");
params.delete("authFlow");
params.delete("walletId");  // Add this line
hashParams?.delete("walletId");
Suggested change
hashParams?.get("walletId") ??
undefined) as WalletId | undefined;
const authResultString =
params.get("authResult") ?? hashParams?.get("authResult") ?? undefined;
const authProvider = (params.get("authProvider") ??
hashParams?.get("authProvider") ??
undefined) as AuthOption | undefined;
const authCookie = (params.get("authCookie") ??
hashParams?.get("authCookie") ??
undefined) as string | undefined;
const authFlow = (params.get("authFlow") ??
hashParams?.get("authFlow") ??
undefined) as "connect" | "link" | undefined;
if ((authCookie || authResultString) && walletId) {
const authResult = (() => {
if (authResultString) {
params.delete("authResult");
hashParams?.delete("authResult");
return JSON.parse(decodeURIComponent(authResultString));
}
})();
params.delete("walletId");
params.delete("authProvider");
params.delete("authCookie");
params.delete("authFlow");
hashParams?.delete("walletId");
hashParams?.delete("authProvider");
hashParams?.delete("authCookie");
hashParams?.delete("authFlow");
hashParams?.get("walletId") ??
undefined) as WalletId | undefined;
const authResultString =
params.get("authResult") ?? hashParams?.get("authResult") ?? undefined;
const authProvider = (params.get("authProvider") ??
hashParams?.get("authProvider") ??
undefined) as AuthOption | undefined;
const authCookie = (params.get("authCookie") ??
hashParams?.get("authCookie") ??
undefined) as string | undefined;
const authFlow = (params.get("authFlow") ??
hashParams?.get("authFlow") ??
undefined) as "connect" | "link" | undefined;
if ((authCookie || authResultString) && walletId) {
const authResult = (() => {
if (authResultString) {
params.delete("authResult");
hashParams?.delete("authResult");
return JSON.parse(decodeURIComponent(authResultString));
}
})();
params.delete("authProvider");
params.delete("authCookie");
params.delete("authFlow");
params.delete("walletId");
hashParams?.delete("walletId");
hashParams?.delete("authProvider");
hashParams?.delete("authCookie");
hashParams?.delete("authFlow");

Spotted by Graphite Agent

Fix in Graphite


Is this helpful? React 👍 or 👎 to let us know.

@joaquim-verges joaquim-verges deleted the fix/sitelink-hash-fragment-preservation branch February 5, 2026 01:55
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

packages SDK Involves changes to the thirdweb SDK

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants