Skip to content

fix(pages): clamp public listing page values#337

Merged
ralyodio merged 9 commits into
profullstack:masterfrom
Jorel97:codex/fix-public-page-pagination-336
May 29, 2026
Merged

fix(pages): clamp public listing page values#337
ralyodio merged 9 commits into
profullstack:masterfrom
Jorel97:codex/fix-public-page-pagination-336

Conversation

@Jorel97
Copy link
Copy Markdown
Contributor

@Jorel97 Jorel97 commented May 29, 2026

Summary

  • add a shared parsePageParam helper for public listing pages
  • clamp invalid, negative, and extremely large page query values before computing pagination offsets
  • cover the helper with regression tests for malformed, negative, and oversized page values

Fixes #336.

Verification

  • Not run locally: this Codex workspace has Node available but no npm/package runner installed, so I could not execute the repo test suite here.

@greptile-apps
Copy link
Copy Markdown

greptile-apps Bot commented May 29, 2026

Greptile Summary

This PR introduces a shared parsePageParam helper in src/lib/pagination.ts that clamps page query parameters to valid, bounded integers before computing Supabase .range() offsets, replacing bare parseInt calls across seven public listing pages. It also adds a Vitest test suite covering missing, negative, non-numeric, fractional, and oversized inputs.

  • src/lib/pagination.ts / pagination.test.ts: New helper correctly uses radix-10 parseInt, guards against NaN via Number.isFinite, and clamps to [1, 100_000]; tests cover all documented edge cases.
  • Seven page files (affiliates, directory, for-hire, gigs, mcp, prompts, skills): Pagination clamping applied uniformly, but every non-ASCII character in the touched lines has been replaced with its UTF-8-bytes-as-Latin-1 mojibake equivalent (e.g. ≈, â€\", â†'), corrupting visible text across all affected pages.
  • The DEFAULT_MAX_PAGE of 100,000 allows offsets up to ~2 million rows, which could cause slow PostgreSQL queries on deep page requests.

Confidence Score: 3/5

Not safe to merge as-is: the pagination logic is correct, but the tool that wrote this PR corrupted every non-ASCII character it touched across all seven listing pages, replacing them with multi-character mojibake sequences that will render visibly broken in browsers.

The encoding corruption affects visible user-facing content (approximate price hints, em-dashes in headings, arrows in links, lightning-bolt icons) on every public marketplace page. The pagination helper itself is sound and the tests are thorough, but the character corruption must be fixed before merging.

All seven page files (affiliates, directory, for-hire, gigs, mcp, prompts, skills) need their non-ASCII characters restored to their original Unicode code points; src/lib/pagination.ts should have its DEFAULT_MAX_PAGE cap reconsidered.

Important Files Changed

Filename Overview
src/lib/pagination.ts New parsePageParam helper correctly clamps negative, NaN, and oversized page values; radix-10 parseInt avoids hex parsing; max-page cap of 100,000 is very generous and could allow large DB offsets.
src/lib/pagination.test.ts New test file covers undefined/null/empty, negative, zero, non-numeric, fractional, and oversized inputs; all cases aligned with the implementation.
src/app/affiliates/page.tsx Pagination fix applied correctly, but the file contains corrupted Unicode: ≈ (U+2248) and — (U+2014) are replaced with mojibake sequences that will render incorrectly in browsers.
src/app/directory/page.tsx Pagination fix applied correctly; — (em dash) and ⚡ (lightning bolt) characters corrupted to mojibake sequences.
src/app/for-hire/[[...tags]]/page.tsx Pagination fix applied correctly; — and → characters corrupted in metadata title and inline comment.
src/app/gigs/[[...tags]]/page.tsx Pagination fix applied correctly; → character corrupted in page text and inline comment.
src/app/mcp/page.tsx Pagination fix applied correctly; — (em dash) and ≈ corrupted across metadata description fields and price display strings.
src/app/prompts/page.tsx Pagination fix applied correctly; — and ≈ corrupted in metadata descriptions and price display strings.
src/app/skills/page.tsx Pagination fix applied correctly; — and ≈ corrupted in page description and price strings; ✕ corrupted in badge clear links.

Reviews (1): Last reviewed commit: "fix(pages): clamp public listing pages" | Re-trigger Greptile

Comment on lines +64 to +67
return `≈ $${(offer.price_sats * offer.commission_rate).toFixed(2)} USD`;
}
if (offer.commission_type === "flat" && offer.commission_flat_sats > 0 && btcUsd) {
return ` $${((offer.commission_flat_sats / 1e8) * btcUsd).toFixed(2)} USD`;
return `≈ $${((offer.commission_flat_sats / 1e8) * btcUsd).toFixed(2)} USD`;
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P1 Unicode characters corrupted across all seven pages

Every non-ASCII decorative character in the PR's changed files has been replaced with a mojibake equivalent: ≈, â€", â†', ✕, âš¡. These are the raw UTF-8 byte sequences of the originals re-encoded as Latin-1 then stored back as UTF-8 — a classic double-encoding error. A browser serving the UTF-8 page will render these literally (e.g. showing "â€" 50 âš¡" instead of "— 50 ⚡"), breaking visible content for all affected listing pages. The same corruption appears in src/app/directory/page.tsx, src/app/for-hire/[[...tags]]/page.tsx, src/app/gigs/[[...tags]]/page.tsx, src/app/mcp/page.tsx, src/app/prompts/page.tsx, and src/app/skills/page.tsx — the pattern is present throughout the PR.

Comment thread src/lib/pagination.ts
Comment on lines +1 to +11
const DEFAULT_MAX_PAGE = 100_000;

export function parsePageParam(
value: string | null | undefined,
maxPage = DEFAULT_MAX_PAGE
) {
const parsed = parseInt(value || "1", 10);
return Number.isFinite(parsed)
? Math.min(Math.max(parsed, 1), maxPage)
: 1;
}
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P2 Max page cap of 100,000 permits database offsets up to ~2 million rows

DEFAULT_MAX_PAGE = 100_000 with a typical limit of 20 allows offset = (100_000 - 1) * 20 = 1_999_980. PostgreSQL evaluates large offsets by scanning and discarding all preceding rows, so a request near the cap could cause significant query latency even against an otherwise small table. A tighter ceiling (e.g. 10,000) would still be far beyond any realistic catalog depth while avoiding full-table scans on malicious or accidental edge requests.

@ralyodio ralyodio merged commit a0ec903 into profullstack:master May 29, 2026
4 checks passed
@Jorel97
Copy link
Copy Markdown
Contributor Author

Jorel97 commented May 29, 2026

Addressed the Greptile note in 1352479: restored the touched page files with proper Unicode characters and switched the public page cap from 100,000 to 1,000 pages to avoid very deep offsets. The pagination helper/tests were updated to match the tighter cap.

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.

Public listing pages accept invalid page values

2 participants