Skip to content

fix(users): cap huge follow-list offsets before Supabase range queries#376

Merged
ralyodio merged 1 commit into
profullstack:masterfrom
Nexu0ps:fix/follow-list-offset-cap
Jun 4, 2026
Merged

fix(users): cap huge follow-list offsets before Supabase range queries#376
ralyodio merged 1 commit into
profullstack:masterfrom
Nexu0ps:fix/follow-list-offset-cap

Conversation

@Nexu0ps
Copy link
Copy Markdown
Contributor

@Nexu0ps Nexu0ps commented Jun 2, 2026

Fixes #356

Caps offset at 100_000 for GET /api/users/[username]/followers and GET /api/users/[username]/following before building the Supabase .range() call, matching the pagination-hardening pattern used across other public endpoints.

Extreme offsets like ?offset=999999999 now cap at 100_000 for both
followers and following endpoints, matching the pagination-hardening
pattern used across other public endpoints.

Fixes profullstack#356
@greptile-apps
Copy link
Copy Markdown

greptile-apps Bot commented Jun 2, 2026

Greptile Summary

Caps the offset query parameter at 100_000 on the GET /api/users/[username]/followers and GET /api/users/[username]/following endpoints, preventing unbounded Supabase .range() calls that could degrade database performance.

  • Both route files receive an identical one-line change wrapping parseNonNegativeInt(...) with Math.min(..., 100_000), matching the cap already in place on the activity endpoint.
  • The existing test suites cover invalid params and large limits but do not include a case asserting that an offset above 100_000 is clamped — worth adding to lock in the new behaviour.
  • A shared parsePaginationParam utility in @/lib/api-pagination already supports an upper bound argument and could consolidate this logic in a future cleanup.

Confidence Score: 4/5

Safe to merge — both changes are a single-line guard that can only make the offset smaller, with no effect on valid queries.

The two changed lines are straightforward and do exactly what the PR description says. The only gaps are style-level: the test suites don't assert on the new cap, and the inline helper duplicates logic that a shared utility already handles elsewhere.

The companion test files (followers/route.test.ts and following/route.test.ts) are missing a case for large-offset capping introduced by this change.

Important Files Changed

Filename Overview
src/app/api/users/[username]/followers/route.ts Adds Math.min(..., 100_000) guard on offset before the Supabase range call; functionally correct and matches the pattern used on other endpoints.
src/app/api/users/[username]/following/route.ts Identical one-line change to cap offset at 100_000; same logic and same considerations as the followers route.

Sequence Diagram

sequenceDiagram
    participant Client
    participant Route as followers / following route
    participant Supabase

    Client->>Route: "GET ?offset=<any value>"
    Note over Route: parseNonNegativeInt(offset, 0)
    Note over Route: Math.min(parsed, 100_000) new cap
    Route->>Supabase: profiles.select().eq(username).single()
    Supabase-->>Route: targetProfile
    Route->>Supabase: follows.select().range(offset, offset+limit-1)
    Note over Supabase: offset is now <= 100_000
    Supabase-->>Route: rows + count
    Route-->>Client: "{ data, pagination: { offset (capped), limit, total } }"
Loading

Reviews (1): Last reviewed commit: "fix(users): cap follow-list offset at 10..." | Re-trigger Greptile

Comment on lines 29 to +30
const limit = parsePositiveInt(searchParams.get("limit"), 20, 100);
const offset = parseNonNegativeInt(searchParams.get("offset"), 0);
const offset = Math.min(parseNonNegativeInt(searchParams.get("offset"), 0), 100_000);
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 Inconsistent pagination helper vs. sibling endpoints

The activity route uses a shared parsePaginationParam utility from @/lib/api-pagination which already accepts a max argument (e.g. parsePaginationParam(searchParams.get("offset"), 0, 0, 100_000)). This file (and following/route.ts) duplicates parsePositiveInt / parseNonNegativeInt locally and wraps them with an inline Math.min. Using the shared helper would keep the offset-cap boundary in one place and reduce the surface for future drift.

Note: If this suggestion doesn't match your team's coding style, reply to this and let me know. I'll remember it for next time!

@ralyodio ralyodio merged commit 709838f into profullstack:master Jun 4, 2026
4 checks passed
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.

Cap huge public follow-list offsets before Supabase range queries

2 participants