SEC-359: Replace compare app with server-rendered RPC performance overview#9
SEC-359: Replace compare app with server-rendered RPC performance overview#9smypmsa wants to merge 8 commits into
Conversation
|
The latest updates on your projects. Learn more about Vercel for GitHub.
|
|
No actionable comments were generated in the recent review. 🎉 ℹ️ Recent review info⚙️ Run configurationConfiguration used: defaults Review profile: CHILL Plan: Pro Run ID: 📒 Files selected for processing (1)
🚧 Files skipped from review as they are similar to previous changes (1)
📝 WalkthroughWalkthroughThe PR replaces the client-side RPC comparison UI with a server-rendered Grafana/Prometheus-backed dashboard: adds server Grafana/Prometheus helpers and queries, cached chain data aggregation, server async components (ChainTOC, ChainCard) with Suspense, and removes the old comparison pages and related client state/components. ChangesServer-Side Performance Dashboard Implementation
Estimated code review effort🎯 4 (Complex) | ⏱️ ~60 minutes Poem
🚥 Pre-merge checks | ✅ 4 | ❌ 1❌ Failed checks (1 warning)
✅ Passed checks (4 passed)
✏️ Tip: You can configure your own custom pre-merge checks in the settings. ✨ Finishing Touches📝 Generate docstrings
🧪 Generate unit tests (beta)
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
f132307 to
f0dd123
Compare
- Home page rewritten as server-rendered RPC provider overview via Grafana Cloud Prometheus API; ISR revalidate=60 - Streaming SSR: per-ChainCard + Headline + ChainTOC <Suspense> boundaries so cards stream as their PromQL resolves - Bullet bars: p50/p95/p99 layered horizontal bars per provider, leader emerald, others slate - Inline-SVG 24h sparkline per provider row, no chart library - Regional heatmap per chain: provider × region p95 grid, HSL-tinted from chain-wide min/max - Headline strip: fastest-right-now, most-p95-wins, tail-latency leader across all chains - Mini-sparkline TOC: 4×2 chain grid with leader trend + anchor jumps - lib/grafana.js: runPromQuery + runPromRangeQuery - lib/chain-data.js: React.cache-wrapped per-chain fetcher, parallel queries, partial-data tolerant; TOC/Headline/Cards share results - lib/queries.js: providerByRegionQuery(chain, q) for any quantile + providerTrendQuery for range data - Route deletions: compare-single/, compare-double/, injection-start/, injection-result-double/ — all hit the backend's /scenarios/* SSRF surface; legacy URLs 301 to / in next.config.js - next.config.js: dropped wide-open /api/* CORS; CSP with frame-ancestors 'none', HSTS, nosniff, Referrer-Policy - store/store.js emptied; .env.sample drops NEXT_PUBLIC_BACKEND_APP_URL and adds GRAFANA_API_TOKEN - Dead components removed: Bento, Faq, Performance, ProtocolIcon (+ SVGs), ResultCard, orphaned icons
f0dd123 to
660888f
Compare
- Subtitle: drop jargon and middle dot, cap line width - Remove the dynamic headline stat line - Per-provider success rate (sum by provider) replaces the chain aggregate; shown under each provider, amber below 99.9% - Region codes shown as short country labels (US, DE, SG …) with full name in the column tooltip - Merge the region heatmap into the provider table as right-hand columns, sticky provider column; no duplicated provider names - Rename Trend column to "p95, 24h"; fix trend query comment
There was a problem hiding this comment.
Actionable comments posted: 4
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Inline comments:
In @.env.sample:
- Line 2: The env sample has spaces around the equals sign for assignments
(e.g., NEXT_PUBLIC_CLIENT_DOMAIN =), which can cause parsing issues; update the
assignment to remove spaces so it reads NEXT_PUBLIC_CLIENT_DOMAIN= and similarly
normalize other keys mentioned (line 8) to KEY= format throughout the file to
ensure valid .env syntax.
In `@next.config.js`:
- Line 26: Update the Referrer-Policy header value to a stricter setting to
reduce cross-origin data leakage: locate the header object with key
'Referrer-Policy' in next.config.js and change its value from
'no-referrer-when-downgrade' to 'strict-origin-when-cross-origin' (or a stricter
policy if desired), ensuring the header entry remains otherwise unchanged.
In `@src/lib/grafana.js`:
- Around line 20-23: The Grafana fetch call currently has no abort path; wrap
the request in an AbortController: create an AbortController before calling
fetch, pass controller.signal in the fetch options alongside headers:
authHeaders() and next: { revalidate }, start a timer (configurable timeout,
e.g. 3–5s) that calls controller.abort() on expiry, and clear the timer once the
response is received; also ensure any fetch errors from abort are
handled/translated appropriately where res is used so SSR doesn't hang.
- Around line 39-44: runPromRangeQuery currently passes start, end, and step
straight into fetchProm which can produce "undefined" query params; update
runPromRangeQuery to validate that start, end, and step are provided and not
undefined/null (and optionally coercible to valid values) before calling
fetchProm, and throw a clear error (e.g., TypeError or rejected Promise) if any
are missing; reference the runPromRangeQuery function and its call to
fetchProm('/api/v1/query_range', { query: promql, start, end, step }, opts) so
you enforce the checks there and only build/pass the params when valid.
🪄 Autofix (Beta)
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: defaults
Review profile: CHILL
Plan: Pro
Run ID: 275bc1dd-78bd-4675-ac0f-7a4f46d89dbc
⛔ Files ignored due to path filters (25)
package-lock.jsonis excluded by!**/package-lock.jsonsrc/components/ProtocolIcon/aptos.svgis excluded by!**/*.svgsrc/components/ProtocolIcon/arbitrum.svgis excluded by!**/*.svgsrc/components/ProtocolIcon/aurora.svgis excluded by!**/*.svgsrc/components/ProtocolIcon/avalanche.svgis excluded by!**/*.svgsrc/components/ProtocolIcon/base.svgis excluded by!**/*.svgsrc/components/ProtocolIcon/bitcoin.svgis excluded by!**/*.svgsrc/components/ProtocolIcon/bnb.svgis excluded by!**/*.svgsrc/components/ProtocolIcon/cronos.svgis excluded by!**/*.svgsrc/components/ProtocolIcon/ethereum.svgis excluded by!**/*.svgsrc/components/ProtocolIcon/fantom.svgis excluded by!**/*.svgsrc/components/ProtocolIcon/filecoin.svgis excluded by!**/*.svgsrc/components/ProtocolIcon/fuse.svgis excluded by!**/*.svgsrc/components/ProtocolIcon/gnosis.svgis excluded by!**/*.svgsrc/components/ProtocolIcon/harmony.svgis excluded by!**/*.svgsrc/components/ProtocolIcon/near.svgis excluded by!**/*.svgsrc/components/ProtocolIcon/optimism.svgis excluded by!**/*.svgsrc/components/ProtocolIcon/polygonPOS.svgis excluded by!**/*.svgsrc/components/ProtocolIcon/polygonZkEvm.svgis excluded by!**/*.svgsrc/components/ProtocolIcon/ronin.svgis excluded by!**/*.svgsrc/components/ProtocolIcon/scroll.svgis excluded by!**/*.svgsrc/components/ProtocolIcon/solana.svgis excluded by!**/*.svgsrc/components/ProtocolIcon/starknet.svgis excluded by!**/*.svgsrc/components/ProtocolIcon/tezos.svgis excluded by!**/*.svgsrc/components/ProtocolIcon/zkSync.svgis excluded by!**/*.svg
📒 Files selected for processing (33)
.env.samplenext.config.jspackage.jsonsrc/app/compare-double/page.jssrc/app/compare-single/page.jssrc/app/injection-result-double/page.jssrc/app/injection-start/page.jssrc/app/page.jssrc/app/store/store.jssrc/components/Bento/Bento.jssrc/components/Chain/BulletBar.jssrc/components/Chain/ChainCard.jssrc/components/Chain/ChainCardSkeleton.jssrc/components/Chain/Sparkline.jssrc/components/ChainTOC.jssrc/components/ChainTOCSkeleton.jssrc/components/Faq/FaqAccordion.jssrc/components/Faq/FaqBasic.jssrc/components/Faq/post.mdxsrc/components/Header/Header.jssrc/components/Icons/BarChartIcon.jssrc/components/Icons/Customization.jssrc/components/Icons/ExplainResultsIcon.jssrc/components/Icons/GrafanaIcon.jssrc/components/Icons/Profiling.jssrc/components/Performance/Compare.jssrc/components/Performance/Preformance.jssrc/components/ProtocolIcon/ProtocolIcon.jssrc/components/ResultCard/ResultCard.jssrc/lib/chain-data.jssrc/lib/format.jssrc/lib/grafana.jssrc/lib/queries.js
💤 Files with no reviewable changes (18)
- src/components/Faq/post.mdx
- src/components/Faq/FaqAccordion.js
- src/components/Icons/Customization.js
- src/components/Faq/FaqBasic.js
- src/app/injection-start/page.js
- src/components/Performance/Compare.js
- src/components/Icons/GrafanaIcon.js
- src/components/Icons/BarChartIcon.js
- src/components/Bento/Bento.js
- src/components/Performance/Preformance.js
- src/components/Icons/ExplainResultsIcon.js
- src/components/Icons/Profiling.js
- src/components/ProtocolIcon/ProtocolIcon.js
- src/components/Header/Header.js
- src/components/ResultCard/ResultCard.js
- src/app/compare-single/page.js
- src/app/compare-double/page.js
- src/app/injection-result-double/page.js
…h timeout, range param validation
The CSP added in this PR blocked the Vercel toolbar (vercel.live + Pusher websockets), so comments/live feedback couldn't load or be submitted on preview deployments. Allowlist vercel.live and Pusher in script/style/font/ frame/connect-src, gated to VERCEL_ENV=preview so production stays locked down.
The latency table is w-full with auto layout, and the BulletBar column was the only flexible one, so it absorbed all leftover width. Chains with fewer region columns (e.g. TON) left more slack, stretching the bar and pushing the p50/p95/p99 numbers further from the provider name. Add a flexible spacer column before the region block so slack lands there instead, pinning every data column to a consistent width across all chains and keeping the region heatmap flush-right.
Each chain rendered its own auto-layout table, so column widths were computed per-card from content: chains with long provider names (TON) pushed the bars and numbers further right, and slack pooled unpredictably. The earlier spacer column made it worse by parking all slack between p99 and the heatmap. Switch to table-fixed with a generated colgroup: fixed widths on the metric columns (provider/bar/sparkline/p50/p95/p99) so they're identical in every card — bars start at the same x and numbers line up regardless of name length (long names truncate) — and auto-width region columns that split the remaining space, keeping the heatmap flush-right with no gap. Sparkline/p99 columns collapse to 0 width on mobile in step with their hidden cells.
Summary
Replaces the interactive comparison flow on
compare.chainstack.comwith a server-rendered RPC provider performance overview built from the Grafana Cloud Prometheus API. The routes that proxied the backend/scenarios/*endpoints (the SSRF surface) are removed. Pairs with backend PR #19, which scales/scenariosto 0.SEC-359 — https://chainstack.myjetbrains.com/youtrack/issue/SEC-359
Changes
src/lib/grafana.js— server-only Prometheus client (instant + range queries) against the Grafana Cloud proxy,GRAFANA_API_TOKENbearer, 60s ISR.src/lib/queries.js— 8 chains with public dashboard tokens; PromQL for per-provider/per-region p50/p95/p99 latency, per-provider success rate, and a p95 trend series (successes only,TEST_*excluded).src/lib/chain-data.js— fetches and shapes each chain's provider list (sorted by p95).src/app/page.js+src/components/**— server components rendering a chain nav and a per-chain card: p50/p95/p99 bar, p95 24h sparkline, per-provider success rate, and a p95-by-region heatmap, plus an "Open in Grafana ↗" link. Streamed with Suspense skeletons.compare-single,compare-double,injection-start,injection-result-double.next.config.js301-redirects/compare-singleand/compare-doubleto/; the injection routes now 404./dashboardstill 301s to the prod Grafana dashboard.next.config.js— dropped the open/api/*CORS rule; added CSP (frame-ancestors 'none'), HSTS,nosniff,Referrer-Policy..env.sample—NEXT_PUBLIC_BACKEND_APP_URLremoved,GRAFANA_API_TOKENadded. Store emptied; dead compare-app components and icons removed.Deploy
Set
GRAFANA_API_TOKEN(Grafana Cloud service account, Viewer role) in Vercel for Production and Preview.Testing
npm run buildgreen. PromQL validated against the source dashboards' regional p95 panels.Follow-ups (not in this PR)
frame-src https://chainstack.grafana.net— leftover from the iframe approach; nothing frames Grafana now.package.jsonlikely has dead deps (react-google-charts,react-type-animation,simpler-state,immer,@mdx-js/*) — rundepcheck.Summary by CodeRabbit
New Features
Refactoring
Chores