Skip to content

feat(cli): expose api pagination and shared cursor navigation - #1659

Open
betegon wants to merge 5 commits into
mainfrom
bt/api-pagination-cursor
Open

betegon wants to merge 5 commits into
mainfrom
bt/api-pagination-cursor

Conversation

@betegon

@betegon betegon commented Oct 25, 2026 •

Copy link
Copy Markdown
Member

sentry api --json discarded pagination metadata, leaving agents without a way to continue a successful query. It now exposes continuation metadata and uses the CLI's shared cursor history for next, prev, and first.

Before

sentry api organizations/ -f per_page=1 --json

Even when another page existed, the output had no continuation (bodies abbreviated):

{"status":200,"statusText":"OK","body":[{"slug":"example-org"}]}

After

The same command includes navigation metadata:

{"status":200,"statusText":"OK","body":[{"slug":"example-org"}],"pagination":{"nextCursor":"1:1:0","hasPrev":false}}

Repeat the endpoint and filters to navigate:

sentry api organizations/ -f per_page=1 --cursor next --json
sentry api organizations/ -f per_page=1 --cursor prev --json
sentry api organizations/ -f per_page=1 --cursor first --json

Raw cursors and shared custom bookmarks are accepted, including legacy cli1~ bookmarks. Resuming restores the required page size and skips rows already read; forward/back navigation retains that exact bookmark. Arrays and Events {data, meta} envelopes are supported, preserving envelope metadata.

Shared SDK ownership

Uses published @sentry/api@0.428.0, including getsentry/sentry-api-schema#116 and getsentry/sentry-api-schema#117. The SDK owns generic URL, header, and body preparation through client.prepareRequest(), plus partial-page consumption and bounded traversal through consumePage and paginateUpTo. The API command uses the same prepared Request for preview and dispatch, removing its duplicate URL/header builders.

Toolkit keeps authentication and trusted-host checks, raw response decoding, request/identity fingerprints, bookmark encoding, page-sizing policy, and navigation history. The SDK accepts decoded server cursors and offsets without depending on CLI storage or cursor formats. Existing MCP and frontend consumers do not need to opt into request preparation.

Each api invocation still fetches one server page, and the endpoint remains required. History is scoped to the request and identity; dry-runs and failed requests do not advance it. hasPrev describes local navigation, while prevCursor is server-provided. --fields filters only the body. Raw text, binary downloads, explicit Content-Type headers, and non-2xx response bodies retain their behavior. URL fragments are excluded without losing encoded # characters. Command help, docs, and the generated skill reference are updated.

Continuing without an endpoint is stacked in #1691. Native logs pagination remains a separate follow-up.

Validation

  • Installed published @sentry/api@0.428.0 from the configured registry with a frozen lockfile; regenerated the API schema.
  • Workspace typecheck and lint pass. Review and cleanup found no remaining implementation concerns.
  • Fresh CLI bundle: 61 API/library E2E tests pass, including shared/legacy custom bookmarks, Events envelopes, navigation, failure recovery, request/identity isolation, and preview-to-dispatch parity for JSON, raw text, and explicit Content-Type headers.
  • Full workspace pnpm run test passed on Linux x64 before the final sync with main, including 12,054 CLI tests and all shared, frontend, and MCP suites. The existing platform-specific skips remain unchanged.
  • The final sync follows the new toolkit-core/api-client/pagination path. On that source, workspace typecheck, lint, 562 focused API tests, 306 shared tests, and the 61 fresh-bundle E2E tests pass again. The full workspace suite was not repeated after this path update.
  • The earlier full macOS suite encountered missing Xcode actool, a Linux musl fixture, and two intermittent tests that passed both in isolation and in the complete Linux run; no unrelated tests were changed.

@vercel

vercel Bot commented Oct 25, 2026 •

Copy link
Copy Markdown

The latest updates on your projects. Learn more about Vercel for GitHub.

Project Deployment Actions Updated
sentry-local Ready Ready Preview Oct 29, 2026 9:53pm UTC

Request Review

@betegon
betegon marked this pull request as ready for review October 26, 2026 15:13
@github-actions github-actions Bot added the risk: medium PR risk score: medium label Oct 26, 2026
@betegon
betegon force-pushed the bt/api-pagination-cursor branch from b4cb377 to 4fe80fe Compare October 26, 2026 15:16

@BYK BYK left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

This should use the common pagination system in the repo now. We even have some custom cursors now. I'm surprised the lint rule did not catch this.

Otherwise, great change thanks a lot!

@BYK

BYK commented Oct 26, 2026

Copy link
Copy Markdown
Member

I'd even argue we should let omitting the endpoint and other args or something so one can do sentry api --cursor next to keep paging through? Or something closer to this?

@betegon betegon changed the title feat(cli): expose api pagination and cursor continuation feat(cli): expose api pagination and shared cursor navigation Oct 27, 2026
@betegon
betegon force-pushed the bt/api-pagination-cursor branch from b754e53 to f2d8d61 Compare October 28, 2026 10:28
@betegon
betegon requested a review from BYK October 28, 2026 10:41
Comment thread packages/cli/src/commands/api.ts Outdated
* repeating the same arguments with `next` finds the same walk. Header/body
* values participate in an opaque fingerprint and are never stored as plaintext.
*/
async function resolveApiPagination(

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

I'd argue all this stuff needs to live in @sentry/api

@betegon
betegon force-pushed the bt/api-pagination-cursor branch from f2d8d61 to dae73bb Compare October 29, 2026 16:29
@betegon
betegon force-pushed the bt/api-pagination-cursor branch from dae73bb to 58fdcac Compare October 29, 2026 16:32
betegon added a commit to getsentry/sentry-api-schema that referenced this pull request Oct 29, 2026
Consumers that inspect a raw request before sending it currently have to
repeat URL, header and body preparation. Expose
`sentry.client.prepareRequest(options): Promise<Request>` from the
concrete client, and extract the same preparation stage used by ordinary
SDK requests. This lets consumers inspect and dispatch one native
request through their existing transport.

## Before / after

Before, the CLI prepares URLs and effective headers for pagination
identity and previews, then rebuilds them during raw dispatch. The SDK
cannot expose its prepared request without sending it. Passing `query`
alongside a URL that already has query parameters also appends a second
`?`.

After:

```ts
const sentry = createSentryClient({ baseUrl: "https://example.test/sentry" });
const request = await sentry.client.prepareRequest({
  method: "GET",
  url: "/api/0/organizations/example/events/?field=id&field=title&cursor=old",
  query: { cursor: "opaque-next", per_page: 50 },
});
// No fetch yet. Both field values remain and the old cursor is replaced:
// https://example.test/sentry/api/0/organizations/example/events/?field=id&field=title&cursor=opaque-next&per_page=50
const response = await fetch(request);
// The consumer retains raw status, headers and body handling.
```

Preparation runs configured auth, validation, serialization and request
interceptors once. It preserves the native signal and does not invoke
fetch or response/error processing. Transports can still attach browser
CSRF, credentials or routing when dispatching. Existing custom `Client`
implementations accepted by generated operations need no new method.

The shared URL builder replaces explicitly serialized query keys while
retaining unrelated repeated values and encoding. With the default
serializer, `null` clears a parameter and `undefined` leaves it
unchanged. Custom serializers and opaque cursor strings remain
supported. Ordinary requests use the same behavior.

## Validation and scope

Build, typecheck, 253 SDK tests and 2 Node cancellation tests pass.
Coverage compares preparation with ordinary dispatch, exercises raw and
browser transports, custom cursors/serializers, body handling,
cancellation, concurrent clients and reconfiguration. The packed npm
artifact is exercised in a clean Node consumer, including public types
and raw non-2xx responses. Review and cleanup completed.

Refs #93 and #99. This is the generic preparation slice for [Toolkit
#1659](getsentry/toolkit#1659); CLI adoption
follows publication. Request identity, navigation history, bookmark
codecs, output and endpoint recovery remain consumer policy. No
production or browser-login validation is claimed, and the remaining v1
adoption gates stay open.
@betegon
betegon force-pushed the bt/api-pagination-cursor branch from 58fdcac to 76ea3f5 Compare October 29, 2026 21:06
@betegon
betegon force-pushed the bt/api-pagination-cursor branch from 76ea3f5 to 880d622 Compare October 29, 2026 21:50

This branch was successfully deployed

1 active deployment
Preview — 880d6229 Deployed Oct 29, 2026 by vercel[bot]
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

risk: medium PR risk score: medium

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants