feat(trace): add cursor pagination to trace list#324
Conversation
Add `--cursor` / `-c` flag to `sentry trace list`, enabling users to
page through large result sets instead of being limited to a single
`--limit`-bounded response.
Changes:
- `listTransactions()` now returns `PaginatedResponse<TransactionListItem[]>`
and passes the `cursor` param to the Sentry events API, extracting
the next-page cursor from the `Link` response header.
- `trace list` resolves and stores the pagination cursor via the shared
DB pagination module (same pattern as `issue list`). A composite
context key (host + org/project + sort + query) scopes each cursor so
different searches never share state.
- `--cursor last` resumes from the saved cursor; raw cursor strings are
accepted too (bare integers are rejected with a clear error).
- JSON output now follows the `{ data, nextCursor?, hasMore }` envelope
used by other list commands.
- Human output shows a `Next page: sentry trace list <target> -c last`
footer when more pages exist, preserving active `--sort` / `-q` flags.
- Tests updated to reflect the new `PaginatedResponse` shape and cover
pagination hint rendering, JSON envelope, and cursor passthrough.
Semver Impact of This PR🟡 Minor (new features) 📋 Changelog PreviewThis is how your changes will appear in the changelog. New Features ✨Trace
Other
Bug Fixes 🐛Api
Formatters
Other
Internal Changes 🔧Api
🤖 This preview updates automatically when you update the PR. |
Extract two pieces of duplicated pagination logic into shared infrastructure: 1. Add buildPaginationContextKey() to src/lib/db/pagination.ts - a generalized context key builder that encodes host, type, scope, and optional key-value params. Rewrite buildOrgContextKey() to delegate to it. 2. Add parseCursorFlag() to src/lib/list-command.ts - extracts the cursor flag validation logic (reject bare integers, accept 'last' keyword and opaque cursor strings). Update LIST_CURSOR_FLAG to use it. Simplify trace/list.ts: - Remove local ALL_DIGITS_RE, buildContextKey(), and inline cursor parse fn - Use buildPaginationContextKey() and LIST_CURSOR_FLAG instead - Remove unused escapeContextKeyValue and getApiBaseUrl imports Simplify issue/list.ts: - Remove local ALL_DIGITS_RE constant - Replace inline cursor parse function with parseCursorFlag - Replace manual context key construction in handleOrgAllIssues with buildPaginationContextKey() - Keep escapeContextKeyValue and getApiBaseUrl imports (still used by buildMultiTargetContextKey) Add tests for both new functions.
Codecov Results 📊✅ 2431 passed | Total: 2431 | Pass Rate: 100% | Execution Time: 0ms 📊 Comparison with Base Branch
All tests are passing successfully. ✅ Patch coverage is 100.00%. Project has 3137 uncovered lines. Files with missing lines (3)
Coverage diff@@ Coverage Diff @@
## main #PR +/-##
==========================================
+ Coverage 80.84% 81.23% +0.39%
==========================================
Files 121 121 —
Lines 16662 16711 +49
Branches 0 0 —
==========================================
+ Hits 13470 13574 +104
- Misses 3192 3137 -55
- Partials 0 0 —Generated by Codecov Action |
There was a problem hiding this comment.
Cursor Bugbot has reviewed your changes and found 1 potential issue.
Bugbot Autofix is OFF. To automatically fix reported issues with cloud agents, enable autofix in the Cursor dashboard.
…x E2E
- Fix E2E trace list --json test: expect { data, hasMore } envelope
instead of plain array (matches updated JSON output format)
- Add HTTP-level unit tests for listTransactions in api-client.test.ts:
nextCursor from Link header, no nextCursor when results=false, cursor/
sort/limit/query params, numeric vs slug project handling
- Add HTTP-level unit tests for listTraceLogs in api-client.test.ts:
returns entries, traceId/statsPeriod/limit/query params, default 14d
- Add edge case tests to trace list command: empty page with hasMore,
nextPageHint with --query flag, JSON output hasMore=false when no cursor
Improves patch coverage for the PR above the 80% threshold.
…consistency buildPaginationContextKey escapes all param values via escapeContextKeyValue, but buildMultiTargetContextKey only escaped period and query, leaving sort unescaped. Fix the inconsistency by escaping sort too. Current sort values (date/duration) don't contain pipes so there's no active bug, but consistent escaping prevents future issues if sort values change.
|
Good catch on the escaping inconsistency — fixed in the latest commit by escaping On the incomplete refactoring: |
Summary
sentry trace listpreviously had no pagination —--limitwas the only way to get more results, with no way to continue to the next page.This PR adds
--cursor/-cpagination and extracts shared infrastructure from duplicated code inissue list.Usage
Changes
Commit 1:
feat(trace)— Add cursor paginationsrc/lib/api-client.tslistTransactions()returnsPaginatedResponse<TransactionListItem[]>instead of a raw arraycursorto the Sentry events API; extracts next cursor from theLinkheadersrc/commands/trace/list.ts--cursor/-cflag:"last"resumes from stored cursor; bare integers rejected early{ data, nextCursor?, hasMore }envelope (consistent withissue list)Next page: sentry trace list <target> -c lastfooter when more existCommit 2:
refactor— Extract shared pagination infrastructuresrc/lib/db/pagination.ts— newbuildPaginationContextKey(type, scope, params?)host:…|type:…[|key:value]*pattern hand-rolled in 3 placesbuildOrgContextKeynow delegates to it (backward compatible)src/lib/list-command.ts— newparseCursorFlag()issue listandtrace listLIST_CURSOR_FLAGupdated to use it — all commands get cursor validation for freesrc/commands/trace/list.ts— usesLIST_CURSOR_FLAGandbuildPaginationContextKeydirectlysrc/commands/issue/list.ts— usesparseCursorFlagandbuildPaginationContextKey; removes localALL_DIGITS_REand manual context key construction inhandleOrgAllIssues