fix(pagination): cursor-driven paginate to stop duplicate page fetches (Closes #403) - #561
Merged
David-patrick-chuks-02 merged 1 commit intoSep 6, 2026
Conversation
…hing the first page
paginate() rebuilt a fresh { limit } query on every loop iteration and
never read cursor metadata, so any page containing exactly limit items
was re-requested forever, yielding duplicate items. The sibling helpers
parseCursorPage/buildPaginationQuery were never used by paginate.
- paginate() now accepts a fetch that returns CursorPage<T> and feeds
nextCursor back through buildPaginationQuery for the next request
- stops when the cursor is null/empty, a page is shorter than limit,
or maxPages is reached (hasMore=false is also honored)
- rewrote the paginate test block: cursor advancement, no-duplicate
guarantee for a full page, maxPages, empty page, short page, and
hasMore=false stop conditions (16 tests, all passing)
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Closes #403
Problem
paginate()insrc/pagination.ts:46-77built a fresh{ limit }query on every loop iteration and never read cursor metadata from the response, so a page containing exactlylimititems was re-requested untilmaxPages, yielding the same items repeatedly. The sibling helpersparseCursorPageandbuildPaginationQuery(same file) were never called bypaginate, andtests/pagination-helper.test.tsexplicitly asserted the duplicate behavior (6 yielded items for a single-page dataset).Changes
src/pagination.ts
paginate()now accepts afetchPagethat returnsCursorPage<T>(items +nextCursor+hasMore) instead of a bare arraynextCursoris fed back throughbuildPaginationQueryfor the next request; the first call carries only thelimitnextCursoris null/empty,hasMoreis false, a page is shorter thanlimit(whenlimitis set), ormaxPagesis reachedtests/pagination-helper.test.ts
{ cursor: 'c1' }), no-duplicate guarantee for a full page,maxPagesstop while cursors keep coming, empty page, short page,hasMore: falsestop, single cursor-less pageVerification
npx vitest run tests/pagination-helper.test.ts— 16/16 passnpm run typecheck— cleannpm run test:unit— 873 passed, only the 4 pre-existing Windows path-resolution failures inexports-subpath-resolves/tree-shakingremain (zero new failures vs. baseline)prettier --checkandeslintclean on both touched files