Skip to content

Comments

refactor: URL generation for application state#1772

Draft
teeohhem wants to merge 5 commits intomainfrom
tom/new-url-state
Draft

refactor: URL generation for application state#1772
teeohhem wants to merge 5 commits intomainfrom
tom/new-url-state

Conversation

@teeohhem
Copy link
Contributor

@teeohhem teeohhem commented Feb 20, 2026

Fixes: HDX-3184

Problem
HyperDX URLs can become very long due to JSON-encoded state in query parameters (filters, SQL clauses, chart configs). This caused two issues:

  1. URL truncation — Microsoft Teams and some other platforms truncate URLs beyond ~2048 characters, breaking links shared in chats
  2. Character mangling — JSON characters like [, {, ", : get corrupted when copy-pasted from browser address bars in certain environments

Solution
Compress all URL parameters using https://github.com/pieroxy/lz-string's compressToEncodedURIComponent, which:

  • Produces alphanumeric-only output — no brackets, quotes, or special characters that could be mangled
  • Reduces URL length by ~60–70% on typical payloads (filters, SQL, chart configs)
  • No new infrastructure required — pure client-side compression/decompression

Changes

  • New urlCompression.ts — core compressUrlParam / decompressUrlParam (for JSON values) and compressStringParam / decompressStringParam (for plain strings)
  • Updated queryParsers.ts — added parseAsCompressedJson() and parseAsCompressedString nuqs parsers
  • Applied everywhere — DBSearchPage, DBDashboardPage, DBChartPage, DBTracePanel, BenchmarkPage, dashboard.ts, useDashboardFilters, and URL builders in ChartUtils

Backwards Compatibility
Existing bookmarks and shared URLs will continue to work. The decompressor tries LZ-string first; if that fails it falls back to plain JSON.parse (for JSON params) or the raw string value (for string params). The %0A → \n legacy encoding is also preserved.

@vercel
Copy link

vercel bot commented Feb 20, 2026

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

Project Deployment Actions Updated (UTC)
hyperdx-v2-oss-app Ready Ready Preview, Comment Feb 20, 2026 8:24pm

Request Review

@changeset-bot
Copy link

changeset-bot bot commented Feb 20, 2026

⚠️ No Changeset found

Latest commit: 3a68991

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

@github-actions
Copy link
Contributor

github-actions bot commented Feb 20, 2026

PR Review: URL State Compression

Overall: Solid approach with good backwards compatibility design and comprehensive tests.

Issues

  • ⚠️ URL length regression for small payloads → The docstring claims compressUrlParam is "typically 60-70% shorter" but the tests themselves acknowledge LZ-string has overhead on small payloads. For the most common cases (1-3 filters, short SQL queries), URLs will actually be longer after this change. Consider adding a size threshold to only compress when JSON.stringify(value).length > N (e.g., 100 chars), or update the docstring to be accurate.

  • ⚠️ False-positive decompression risk in decompressStringParam → Unlike decompressUrlParam, the string decompressor has no error handling when LZString returns a non-null result. If LZString.decompressFromEncodedURIComponent(oldValue) returns non-null garbage (not just null), the corrupted value is returned with no fallback. In practice, old SQL strings contain spaces/quotes outside the base64url alphabet so LZString returns null — but this is implicit, not enforced. The test for status=200 covers one case; adding a test for a value that only contains base64url-safe chars (e.g., A1B2C3) would increase confidence.

  • ℹ️ compressStringParam('') returns a non-empty string → Compressed empty string is truthy, which could break any code that checks if (params.get('where')) to detect an absent param. Appears safe given current usage with nuqs but worth keeping in mind.

Positives

  • Backwards compat logic is solid: old JSON/SQL strings contain [, {, spaces, quotes — none valid in base64url — so LZString correctly returns null and falls through to legacy parsers.
  • Removing parseAsStringWithNewLines and parseAsJson is clean; no remaining callers missed.
  • Good test coverage including backwards compat cases.

Resolved conflict in DBDashboardPage.tsx: kept useBrandDisplayName from
main and parseAsCompressedString from our branch (replacing old
parseAsStringWithNewLines).

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
@teeohhem teeohhem changed the title Tom/new url state refactor: URL generation for application state Feb 20, 2026
@github-actions
Copy link
Contributor

github-actions bot commented Feb 20, 2026

PR Review: URL Compression

Approach looks solid — LZ-prefix guard for string params, backwards-compatible fallback chain, good test coverage. Two bugs to address:


Bug 1: decompressStringParam silent corruption on failed decompression

In urlCompression.ts, when a ~-prefixed value fails LZString decompression, the function falls through and returns the raw string (e.g. ~brokendata) instead of a safe fallback:

if (value.startsWith(LZ_PREFIX)) {
  const decompressed = LZString.decompressFromEncodedURIComponent(value.slice(LZ_PREFIX.length));
  if (decompressed \!= null) return decompressed;
}
// Falls through here with '~brokendata' — user sees garbage in UI
return value.replace(/%0A/g, '\n');

Fix: return null (or empty string) when the prefixed value fails decompression, not the raw prefixed string.


Bug 2: parseAsCompressedString.parse never returns null — nuqs default is unreachable

decompressStringParam always returns string, so the nuqs parser can never signal "use default". Callers using .withDefault('') won't get their default for corrupted/invalid values.

Fix: Change decompressStringParam to return string | null (returning null for unrecoverable values), and update parseAsCompressedString.parse accordingly.


Minor: decompressUrlParam has no format prefix (inconsistency)

JSON params use try-LZString-first with no LZ_PREFIX, relying on the fact that old JSON always contains [, {, " (chars outside LZString's alphabet). Works in practice, but inconsistent with how string params are handled. Low risk but worth aligning for maintainability.


Note: E2E shows 1 failing test from the CI run — worth confirming that's unrelated before merge.

@github-actions
Copy link
Contributor

E2E Test Results

All tests passed • 70 passed • 4 skipped • 806s

Status Count
✅ Passed 70
❌ Failed 0
⚠️ Flaky 1
⏭️ Skipped 4

Tests ran across 4 shards in parallel.

View full report →

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