Repository navigation
ref(cli): Move API calls with generated operations onto @sentry/api - #2073
Merged
Merged
Conversation
Bump @sentry/api to 1.44.0 and move the apiRequest* call sites that have a matching generated operation onto it: alert rule delete, chunk upload options and assemble (debug files, sourcemaps, dart symbols, proguard), AI conversation detail, short ID resolve, preprod install details and snapshot latest base, release commit refs, replay detail, trace meta, and the transactions/spans event pages. Add validateResponse/unwrapValidatedResult so call sites that already check responses with a Zod schema keep doing that on SDK results. This is step 1 of moving the CLI onto generated operations. The remaining sites are blocked on missing public schema entries or type mismatches and stay on the helpers for now. Co-Authored-By: BYK <[email protected]>
|
The latest updates on your projects. Learn more about Vercel for GitHub.
|
This was referenced Nov 7, 2026
Merged
BYK
added a commit
to getsentry/sentry
that referenced
this pull request
Nov 7, 2026
The OpenAPI schema for `PUT /organizations/{org}/issues/{issue_id}/`
(`updateOrganizationIssue`) and `PUT /organizations/{org}/issues/`
(`updateOrganizationIssues`) listed every `GroupValidator` field, and
every `statusDetails` field, as required. The endpoints always validate
with `partial=True` (`validate_request` in
`api/helpers/group_index/update.py`), so a request only sends the fields
it changes, for example `{"status": "resolved"}`.
This marks those fields `required=False`. Validation doesn't change,
because `partial=True` already skipped the required check. Only the two
operations above change in the generated schema. Their request body
schemas lose the `required` lists, and the body itself is no longer
marked required.
The Sentry CLI needs this to move its issue update calls onto the
generated `@sentry/api` operations (getsentry/toolkit#2073). Today the
generated body type makes every field mandatory, so a partial update
doesn't typecheck.
Checked locally with `make build-api-docs`, `pnpm run
validate-api-examples`, `tests/apidocs`,
`tests/sentry/issues/endpoints/test_group_details.py`, `GroupUpdateTest`
in `test_organization_group_index.py`,
`tests/sentry/api/helpers/test_group_index.py`, prek and mypy. Under
xdist, three snuba-backed `GroupUpdateTest` cases failed:
`test_resolve_with_integration`, `test_snooze_user_count` and
`test_bulk_resolve`. Run serially, they pass on this branch and on
master.
<!-- junior-request-attribution:start -->
via @BYK.
<!-- junior-request-attribution:end -->
<!-- junior-session-footer:start -->
<!-- junior-conversation-id:agent%3A80220b9d4c297e2a971f05dcb03af515 -->
--
[View
Session](https://junior-prod.sentry.dev/conversations/agent%3A80220b9d4c297e2a971f05dcb03af515)
[[Sentry]](https://sentry.sentry.io/explore/conversations/agent%3A80220b9d4c297e2a971f05dcb03af515/?project=4510944073809921)
<!-- junior-session-footer:end -->
Co-authored-by: sentry-junior[bot] <264270552+sentry-junior[bot]@users.noreply.github.com>
Co-authored-by: BYK <[email protected]>
BYK
added a commit
to getsentry/sentry
that referenced
this pull request
Nov 7, 2026
…estamp (#130349) Three query parameters on public Explore endpoints were documented differently from what the code accepts: - **`yAxis`** on `listOrganizationEventsTimeseries` was a single string. The endpoint reads `request.GET.getlist("yAxis")` and returns one timeseries per aggregate, so it's now an array (repeated `?yAxis=count()&yAxis=p95(span.duration)`). - **`interval`** (`VisibilityParams.INTERVAL`, used by `listOrganizationEventsTimeseries` and `listOrganizationEventsDropped`) was an integer. `get_rollup_from_request` parses it with `parse_stats_period`, which also takes a unit suffix such as `5m` or `1h`. It's now `anyOf: [integer, string matching ^\d+[smhdw]?$]`, so callers that pass a number keep working. - **`timestamp`** on `getOrganizationTrace` and `getOrganizationTraceMeta` wasn't listed. Both endpoints pass it to `update_snuba_params_with_timestamp`, which accepts ISO 8601 or Unix seconds and narrows the query window. I added it as `TraceParams.TIMESTAMP`. Only those four operations change in the generated schema. There's no runtime change. The Sentry CLI needs these to move its timeseries and trace calls onto the generated `@sentry/api` operations (getsentry/toolkit#2073). Right now the generated types reject repeated `yAxis`, `interval=1h` and `timestamp`. One thing to note for SDK consumers: the generated `yAxis` type changes from `string` to `string[]`. Checked locally with `make build-api-docs`, `pnpm run validate-api-examples`, `tests/apidocs`, prek and mypy. I also ran `tests/snuba/api/endpoints/test_organization_trace_meta.py` and `test_organization_events_timeseries.py::test_simple`. Under xdist those snuba tests miss rows from shared state, but run serially they pass. <!-- junior-request-attribution:start --> via @BYK. <!-- junior-request-attribution:end --> <!-- junior-session-footer:start --> <!-- junior-conversation-id:agent%3A80220b9d4c297e2a971f05dcb03af515 --> -- [View Session](https://junior-prod.sentry.dev/conversations/agent%3A80220b9d4c297e2a971f05dcb03af515) [[Sentry]](https://sentry.sentry.io/explore/conversations/agent%3A80220b9d4c297e2a971f05dcb03af515/?project=4510944073809921) <!-- junior-session-footer:end --> Co-authored-by: sentry-junior[bot] <264270552+sentry-junior[bot]@users.noreply.github.com> Co-authored-by: BYK <[email protected]>
BYK
added a commit
to getsentry/sentry
that referenced
this pull request
Nov 7, 2026
…0350) `GET /organizations/{org}/agents/conversations/` (`listOrganizationAIConversations`) accepts a `sort` query param. `OrganizationAIConversationsSerializer` validates it against `AI_CONVERSATIONS_FIELDS`, and it defaults to `-conversation.age`, but the OpenAPI docs didn't list it. This adds the parameter with an enum of the canonical fields, each with an optional `-` prefix. Only this operation changes in the generated schema, and there's no runtime change. The enum comes from a new `AI_CONVERSATIONS_SORT_FIELDS` tuple. It takes the keys of `AI_CONVERSATIONS_FIELDS` before the legacy spellings are added, so `messages`, the bare field names and the function aliases stay accepted but undocumented. The Sentry CLI's `agent-conversation list --sort` needs this to move onto the generated `@sentry/api` operation (getsentry/toolkit#2073). The generated query type has no `sort` today. Checked locally with `make build-api-docs`, `pnpm run validate-api-examples`, `tests/sentry/api/endpoints/test_organization_ai_conversations.py`, `tests/apidocs`, prek and mypy. <!-- junior-request-attribution:start --> via @BYK. <!-- junior-request-attribution:end --> <!-- junior-session-footer:start --> <!-- junior-conversation-id:agent%3A80220b9d4c297e2a971f05dcb03af515 --> -- [View Session](https://junior-prod.sentry.dev/conversations/agent%3A80220b9d4c297e2a971f05dcb03af515) [[Sentry]](https://sentry.sentry.io/explore/conversations/agent%3A80220b9d4c297e2a971f05dcb03af515/?project=4510944073809921) <!-- junior-session-footer:end --> Co-authored-by: sentry-junior[bot] <264270552+sentry-junior[bot]@users.noreply.github.com> Co-authored-by: BYK <[email protected]>
BYK
enabled stacked auto-merge (squash)
November 7, 2026 02:11
BYK
added a commit
that referenced
this pull request
Nov 7, 2026
Stacked on #2073. That PR moves the CLI onto the generated `@sentry/api` operations. This one fixes the cases where the CLI, not the API docs, was wrong. The full list is in getsentry/sentry#130351. Where the 1.44.0 operation now matches, the call moves onto it here too. Each fix was checked against the getsentry/sentry endpoint code. ### Moved onto generated operations | Area | Fix | Operation | | --- | --- | --- | | `alert issues list/view` | Filter workflows by `project` (the endpoint ignores `projectSlug`) and send `id` as a number | `listOrganizationWorkflows` (×2) | | `code-mappings upload` | Send the bulk body in snake_case: `default_branch`, `stack_root`, `source_root` | `bulkUpsertOrganizationCodeMappings` | | `explore`, `dashboard view` tables | Type `dataset` as a public Events dataset. Explore still falls back to `errors`, and unmapped widget types still render as unsupported | `listOrganizationEvents` (×2) | | `issue view` and other org-scoped issue lookups | Send only the `collapse` values the details endpoint reads (`release`, `stats`, `tags`). It ignored `lifetime`/`filtered`/`unhandled`, and the detail response keeps those fields either way. The short-ID endpoint still gets every value | `getOrganizationIssue` | | `issue view` replay lookup | Send `data_source=errors`. `events` isn't a value the endpoint accepts | `getOrganizationReplayCount` | | `issue explain/plan` | Drop `mode=explorer`, which the autofix endpoint never reads | `startOrganizationIssueAutofix` (×2), `getOrganizationIssueAutofixState` | ### Fixed, but still on the helper - **`issue merge`**: now sends `{merge: true}` with numeric IDs. `updateOrganizationIssues` marks every body field required until getsentry/sentry#130348 lands. - **`trace view`**: no longer sends `project` or `limit`, since the endpoint reads neither. It stays on the helper until getsentry/sentry#130349 documents `timestamp`. An unknown project in `trace view org/project/<id>` still fails as before. - **Dashboard and explore time series**: get the same typed `dataset`, but stay on the helper until #130349 fixes `yAxis`/`interval`. - **AI conversations list**: untouched, because it's waiting on getsentry/sentry#130350 (`sort`). ### Kept on purpose - **`replay list`** keeps requesting `info_ids` and `warning_ids`. The server computes them and `replay list --json` prints them, so dropping them would change the output. `fetchReplayPage` stays on the helper, and a comment says why. ### Behavior notes - On the moved calls, errors use the SDK wording already used by the moved calls in #2073 and by the metric alert path, e.g. `Failed to list issue alert rules: 403 Forbidden`. They no longer start with `API request failed:`, and they no longer have an `Endpoint:` line. Status codes and the 401/403 enrichment are unchanged. - Existing bug, not fixed here: `trace view org/project/<id>` prints "Filtered to project", but the trace endpoint has returned spans from every project since getsentry/sentry#87314. - Docs gap: with `returnIds=true`, the replay-count response maps each issue ID to a list of replay IDs. The documented schema describes counts. The CLI keeps validating that response with its own schema. ### Verification - `pnpm run tsc` and `pnpm run lint` pass. - CLI tests: 12884 pass and 5 fail. All 5 are the sandbox-only permission tests that fail on `main` too (`completions` ×2, `upgrade` acquireLock, `db/resilient` readonly, `dsn/code-scanner`). - Unit tests were updated or added for each changed request shape, including the new `test/lib/api/code-mappings.test.ts`. - API discovery no longer lists the moved call sites. <!-- junior-request-attribution:start --> via @BYK. <!-- junior-request-attribution:end --> <!-- junior-session-footer:start --> <!-- junior-conversation-id:agent%3A80220b9d4c297e2a971f05dcb03af515 --> -- [View Session](https://junior-prod.sentry.dev/conversations/agent%3A80220b9d4c297e2a971f05dcb03af515) [[Sentry]](https://sentry.sentry.io/explore/conversations/agent%3A80220b9d4c297e2a971f05dcb03af515/?project=4510944073809921) <!-- junior-session-footer:end --> Co-authored-by: sentry-junior[bot] <264270552+sentry-junior[bot]@users.noreply.github.com> Co-authored-by: BYK <[email protected]>
BYK
pushed a commit
that referenced
this pull request
Nov 7, 2026
…2078) Next step after #2073 and #2075, which moved the CLI onto the generated `@sentry/api` operations. `@sentry/api` 1.46.0 includes the API docs fixes from getsentry/sentry#130348, #130349 and #130350, so six more call sites now match their generated operation. This PR bumps the package and moves them. ### Moved onto generated operations | Command(s) | Call | Operation | Unblocked by | | --- | --- | --- | --- | | `issue resolve/unresolve/archive`, `feedback resolve/spam/…` (org-scoped) | `updateIssueStatus` | `updateOrganizationIssue` | sentry#130348 (body fields no longer all required) | | `issue merge` | `mergeIssues` | `updateOrganizationIssues` with numeric `id`s and `{merge: true}` | sentry#130348 | | `dashboard view` chart widgets | `queryWidgetTimeseries` | `listOrganizationEventsTimeseries` | sentry#130349 (`yAxis` array, `interval` int or duration) | | `explore` time series | `queryEventsTimeSeries` | `listOrganizationEventsTimeseries` | sentry#130349 | | `agent-conversation list` | `listConversations` | `listOrganizationAiConversations` with `sort` | sentry#130350 | | `trace view`, `span view`, `log view` | `getDetailedTrace` | `getOrganizationTrace` with `timestamp` | sentry#130349 | Trace meta already used `getOrganizationTraceMeta` and doesn't send `timestamp`, so nothing changes there. ### Behavior notes - Responses are validated exactly as before: `EventsTimeseriesResponseSchema` for widgets and `ConversationListItemSchema` for conversations. The explore time series and trace detail responses were not validated before and still aren't. - `issue merge` still turns a 204 (no matching issues) into the same friendly error, and still clears each affected issue's cross-origin cache. - `agent-conversation list --sort` is now typed with the endpoint's sort enum. The command's sort values are a subset of it. - Errors on the moved calls use the SDK wording, as in #2073 and #2075, e.g. `Failed to update issue: 403 Forbidden`. Status codes and the 401/403 enrichment are unchanged. - The 1.46.0 regen also changes `uniqueValues`/`key`/`name` descriptions in the generated `issue` skill reference, which is committed here. Typecheck is otherwise unaffected. ### Remaining `apiRequest*` call sites and raw fetches Details for each are in getsentry/sentry#130351. **Not in the public schema** (needs a getsentry/sentry API docs decision): - `organizations.ts:66`, `projects.ts:576/591`: region lookups - `users.ts:21`: current user - `trials.ts:30/70`: trials list/start - `org-auth-tokens.ts:77`: delete org auth token - `dashboards.ts:201/235`: dashboard revisions/restore - `issues.ts:329`: unscoped `GET /issues/{id}/` - `issues.ts:632`: legacy unscoped `PUT /issues/{id}/` - `logs.ts:486`: logs query - `traces.ts:225`: trace-items detail (experimental) - `releases.ts:425`: release set-commits - `preprod-artifacts.ts:283/449`: build/snapshot upload - Raw fetches: `getSharedIssue` (`issues.ts`) and `openSnapshotArchive` (`preprod-artifacts.ts`) **Dynamic request identity / transport:** - `auth.ts:17` - `org-auth-tokens.ts:37/59` - `preprod-artifacts.ts:508/526`: snapshot downloads **Kept on purpose:** - `replays.ts:201`: `replay list` keeps requesting `info_ids`/`warning_ids` because `--json` prints them (see #2075). The Oxlint rule that bans the helpers comes last, after these are resolved. ### Verification - `pnpm install --frozen-lockfile` passes with the committed lockfile. - `pnpm run tsc` and `pnpm run lint` pass. - CLI tests: 12919 pass and 5 fail. All 5 are the sandbox-only permission tests that also fail on `main` (`completions` ×2, `upgrade` acquireLock, `db/resilient` readonly, `dsn/code-scanner`). - The dashboard time series tests now mock `listOrganizationEventsTimeseries`. I added an org-scoped `updateIssueStatus` test. The conversation, explore and trace tests run at the fetch layer and pass unchanged. - API discovery no longer lists the moved call sites. <!-- junior-request-attribution:start --> via @BYK. <!-- junior-request-attribution:end --> <!-- junior-session-footer:start --> <!-- junior-conversation-id:agent%3A80220b9d4c297e2a971f05dcb03af515 --> -- [View Session](https://junior-prod.sentry.dev/conversations/agent%3A80220b9d4c297e2a971f05dcb03af515) [[Sentry]](https://sentry.sentry.io/explore/conversations/agent%3A80220b9d4c297e2a971f05dcb03af515/?project=4510944073809921) <!-- junior-session-footer:end --> Co-authored-by: sentry-junior[bot] <264270552+sentry-junior[bot]@users.noreply.github.com>
7 tasks done
This branch was successfully deployed
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.
This is step 1 of moving the CLI onto
@sentry/apigenerated operations. The goal is an Oxlint rule that bans theapiRequest*helpers with no allowlist. @BYK chose that scope ("Also ban apiRequest* helpers") when the lint follow-up to #2062 was scoped. Since the rule can't land until every call site has moved, it isn't in this PR.#2062 bumps
@sentry/apito 1.44.0 too and moveslib/objectstore.ts. This PR leavesobjectstore.tsalone, so whichever PR merges second only needs a lockfile rebase.What changed
@sentry/api1.26.0 → 1.44.0 in the catalog and inminimumReleaseAgeExclude. The regeneratedalert.mdandevent.mdskill references are included.apiRequest*call sites now use generated operations:deleteIssueAlertRule→deleteOrganizationWorkflowgetChunkUploadOptions→getOrganizationChunkUploadOptions.ChunkServerOptionsSchemastill validates the response because the SDK type doesn't includemaxWait.assembleDebugFiles→assembleProjectDebugFilesassembleArtifactBundle→assembleOrganizationArtifactBundlepollAssembly/pollDifAssemblytake anassemblecallback.getConversationSpans→retrieveOrganizationAiConversationgetIssueByShortId→resolveOrganizationShortIdgetBuildInstallDetails→getOrganizationPreprodArtifactInstallDetailsgetOrganizationPreprodArtifactSnapshotLatestBase(a 404 still returnsnull)setCommitsWithRefs→updateOrganizationRelease. The./..path-segment checks stay because the SDK's path serializer lets them through.getReplay→getOrganizationReplaygetTraceMeta→getOrganizationTraceMetafetchTransactionsPage/fetchSpansPage→listOrganizationEventsinfrastructure.tsgetsvalidateResponseandunwrapValidatedResult, so call sites that already validated responses with Zod still do that on SDK results. No newascasts on query or body types.Behavior notes
<context>: <status>(fromunwrapResult/throwApiError) instead ofAPI request failed: …. The 401/403 enrichment is unchanged.throwApiErrordoesn't attach theapi_response_headersSentry context that the helper path set.getOrgSdkConfig), caching and idempotency are unchanged.Tests
chunk-upload.test.tsandproguard.test.tsnow test at the fetch level (mockFetch+setOrgRegion). New cases covermaxWait, schema mismatch, 404, and both assemble endpoints.debug-files.test.tsmocks the newassembleDebugFiles.preprod-artifacts.test.tsmocksgetOrgSdkConfig, with new cases for a null body, a 500, and a schema mismatch.Gate
pnpm run tscandpnpm run lint: pass.pnpm run test: fails only on sandbox environment problems that also fail onmain. CI is the real check.codemod-cli3to4because the sandbox lacksGLIBC_2.35.pnpm -r --no-bail run test: every package passes except the CLI, which has 5 failures (12881 passed). All 5 are file-permission tests that fail onmainin the same sandbox:completions(2),upgradeacquireLock,db/resilientreadonly, anddsn/code-scannerunreadable files.Remaining call sites (39 + 2 raw fetches)
(a) Missing from the public schema: needs getsentry/sentry API docs
auth.tsGET/api/0/(root). Used for the token check; dynamic.dashboards.tsGET/organizations/{org}/dashboards/{id}/revisions/dashboards.tsPOST/organizations/{org}/dashboards/{id}/revisions/{rev}/restore/issues.tsGET/issues/{id}/(unscoped issue lookup)issues.tsPUT/issues/{id}/(unscoped update fallback)issues.tsrawcustomFetchGET/shared/issues/{shareId}/(getSharedIssue)logs.tsGET/organizations/{org}/trace-logs/org-auth-tokens.tsGET, POST/organizations/{org}/org-auth-tokens/, DELETE…/{tokenId}/organizations.tsGET/users/me/regions/preprod-artifacts.ts:/projects/{org}/{project}/files/preprodartifacts/assemble/(build assemble)…/preprodartifacts/snapshots/upload-options/…/snapshots/{id}/archive/customFetchopenSnapshotArchiveprojects.tsGET/organizations/{org}/projects/?query=dsn:{key}(×2). The list op has noqueryparam.releases.tsGET/organizations/{org}/releases/{version}/previous-with-commits/traces.tsGET/projects/{org}/{project}/trace-items/{itemId}/trials.tsGET/customers/{org}/and PUT/customers/{org}/product-trial/users.tsGET/auth/These look intentionally private, so publishing them needs a call from the API owners:
/customers/*(billing, getsentry),/users/me/regions/, the/api/0/root,/auth/,previous-with-commits,trace-logs,trace-items, and the preprod/snapshot internals.(b) In the schema, but the generated types don't match what the CLI sends or reads
alerts.ts×2, GET/organizations/{org}/workflows/: noprojectSlugfilter, and the CLI sends string ids.code-mappings.tsPOST bulk code mappings: the CLI sends a camelCase body; the schema is snake_case.conversations.tslist: nosortquery param.dashboards.tsevents-timeseries:yAxisis an array anddatasetis optional in the CLI.dashboards.tsevents:datasetcan be null or a value outside the enum.explore.tsevents-timeseries: arrayyAxis, stringinterval.explore.tsevents: free-form dataset.issues.tsGET org issue: thecollapseenum is onlyrelease|stats|tags.issues.tsPUT org issue: every update body field is required.issues.tsPUT/organizations/{org}/issues/(merge):updateOrganizationIssuesalso requires every body field.replays.tslist: thefieldenum lacksinfo_ids/warning_ids.replays.tsreplay-count: nodata_source=events.seer.ts×3,/organizations/{org}/issues/{id}/autofix/: nomode=explorer.traces.tsGET/organizations/{org}/trace/{id}/: notimestamp/limit/projectparams.preprod-artifacts.tsPOST…/preprodartifacts/snapshots/: the body type isnever, and the CLI sends a zstd body.(c) Dynamic or upload transport, not Sentry API operations
installUrl.rawApiRequest/prepareRawApiRequestback thesentry apipassthrough command.via @BYK.
--
View Session [Sentry]