Skip to content

feat: Sentry source maps, login lockout UI, Stellar address validation, Storybook - #617

Open
WebDeveloper-Jose wants to merge 1 commit into
kellymusk:devfrom
WebDeveloper-Jose:fix/481-482-483-484-security-storybook
Open

feat: Sentry source maps, login lockout UI, Stellar address validation, Storybook#617
WebDeveloper-Jose wants to merge 1 commit into
kellymusk:devfrom
WebDeveloper-Jose:fix/481-482-483-484-security-storybook

Conversation

@WebDeveloper-Jose

Copy link
Copy Markdown

Summary

Four small, independent fixes/additions bundled together.

Closes #481, closes #482, closes #483, closes #484


Type of Change

  • 🐛 Bug fix (non-breaking change that fixes an issue)
  • 🚀 New feature (non-breaking change that adds functionality)
  • 💥 Breaking change (fix or feature that would cause existing behaviour to change)
  • ♻️ Refactor (no functional change, code quality improvement)
  • 🎨 UI / design update
  • 📦 Dependency update
  • 🔧 Configuration / tooling change
  • 📝 Documentation update
  • 🔒 Security fix

Changes Made

  • security: harden Sentry config to avoid leaking source maps in production #481: next.config.mjswithSentryConfig's sourcemaps.deleteSourcemapsAfterUpload: true set explicitly (the v8+ SDK's replacement for the old hideSourceMaps option, which no longer exists in the installed @sentry/nextjs@^10). Source maps are still uploaded to Sentry for stack-trace symbolication, then removed from the production build output so they aren't fetchable from the browser.
  • security: add rate-limiting feedback on login form (lockout after N failed attempts) #482: lib/api.ts / app/api/auth/login/route.tsApiError now carries retryAfterSeconds parsed from a 429's Retry-After header, forwarded through the login proxy route (which previously dropped every header on an error response). app/login/page.tsx shows a live cooldown countdown and disables the submit button — using the header's value when present, falling back to a 30s default, and also triggering after 5 failed attempts even without an explicit 429 from the backend.
  • security: validate Stellar address format client-side before API calls #483: lib/stellar-address.ts (new) — client-side Stellar (classic) address validation: a full base32 + CRC16/XMODEM checksum check, not just a length/charset regex. Wired into the one manual address-entry point across onramp, offramp, and wallet flows (components/send/send-page-client.tsx, which previously only checked recipientInput.trim().length > 5). Checked onramp and offramp: onramp's address comes from the session (auto-filled, never typed), and offramp has no Stellar-address field at all (it's fiat bank details) — so there was nothing to change in either.
  • dx: set up Storybook for shared UI components #484: Storybook installed for Next.js + Tailwind v4 (@storybook/nextjs-vite), with stories for Button, Badge, Alert, Input, Select, Card, LoadingSpinner, and EmptyStateIllustration, plus a build-only storybook-build CI job. Trimmed storybook init's default scaffold down to just what the issue asked for — dropped the Vitest/Playwright/Chromatic/MCP addons it adds by default, none of which were requested.

Review Notes

components/session-provider.tsx had two competing session-restore implementations (cookie-based and an older localStorage one) concatenated instead of merged at some point — duplicate declarations, signOut defined twice, and a call to an undefined persist() — which failed to compile. Reconstructed it from the two commits that diverged (6ce830f, 650f0965), keeping the newer httpOnly-cookie design and re-adding signInWithFreighter on top of it. This file is in the direct path of #482's signIn error handling, so it had to compile for anything else in this PR to build or test — not part of any of the four issues on its own, but unavoidable.


Testing

  • Existing tests still pass (npm test)
  • Unit tests added or updated (npm test)
  • Manual testing in local development (npm run dev)
  • Tested on Stellar Testnet
  • Tested with demo mode OFF
  • Verified on mobile viewport

Commands run:

npx tsc --noEmit
npx eslint <changed files>
npx prettier --check <changed files>
CI=true npx jest lib/__tests__/stellar-address.test.ts components/send/__tests__/send-page-client.test.tsx app/login/__tests__/page.test.tsx
npm run build-storybook

All pass. The pre-push hook additionally ran the full suite (51/51 passing across 8 test files, including the 3 new/updated ones here).

…n, storybook

- next.config.mjs: withSentryConfig's sourcemaps.deleteSourcemapsAfterUpload
  is set explicitly (the v8+ SDK's replacement for the old hideSourceMaps
  option) — source maps are still uploaded to Sentry for stack-trace
  symbolication, then removed from the production build output so they
  aren't fetchable from the browser. (kellymusk#481)

- lib/api.ts / app/api/auth/login/route.ts: ApiError now carries
  retryAfterSeconds parsed from a 429's Retry-After header, forwarded
  through the login proxy route (which previously dropped every header
  on an error response). app/login/page.tsx shows a live cooldown
  countdown and disables the submit button — using the header's value
  when present, falling back to a default, and also triggering after 5
  failed attempts even without an explicit 429 from the backend. (kellymusk#482)

- lib/stellar-address.ts: client-side Stellar (classic) address
  validation — a full base32 + CRC16/XMODEM checksum check, not just a
  length/charset regex — used in the one manual address-entry point
  across onramp, offramp, and wallet flows
  (components/send/send-page-client.tsx, which previously only checked
  recipientInput.trim().length > 5). onramp's address is filled from
  session and offramp has no address field, so there was nothing to
  change in either. (kellymusk#483)

- Storybook installed for Next.js + Tailwind v4 (@storybook/nextjs-vite),
  with stories for Button, Badge, Alert, Input, Select, Card,
  LoadingSpinner, and EmptyStateIllustration, plus a build-only CI job.
  Trimmed storybook init's default scaffold down to what was asked for,
  dropping the Vitest/Playwright/Chromatic/MCP addons it adds by
  default. (kellymusk#484)

Also fixes components/session-provider.tsx, which had two competing
session-restore implementations (cookie-based and an older localStorage
one) concatenated instead of merged: duplicate declarations, a signOut
defined twice, and a call to an undefined persist(). Reconstructed from
the two commits that diverged (6ce830f, 650f096), keeping the newer
httpOnly-cookie design and re-adding signInWithFreighter on top of it.
It sits directly in the path of kellymusk#482's signIn error handling and had to
compile for anything else here to build or test.

Ran: tsc --noEmit, eslint, prettier --check, jest on the new/changed
test files, and npm run build-storybook — all pass.

Closes kellymusk#481, closes kellymusk#482, closes kellymusk#483, closes kellymusk#484
@vercel

vercel Bot commented Aug 31, 2026

Copy link
Copy Markdown

@WebDeveloper-Jose is attempting to deploy a commit to the kelly musk's projects Team on Vercel.

A member of the Team first needs to authorize it.

@drips-wave

drips-wave Bot commented Aug 31, 2026

Copy link
Copy Markdown

@WebDeveloper-Jose 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

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