Skip to content

ref: use @sentry/api client for requests#226

Merged
MathurAditya724 merged 16 commits intomainfrom
feat/api-client
Feb 13, 2026
Merged

ref: use @sentry/api client for requests#226
MathurAditya724 merged 16 commits intomainfrom
feat/api-client

Conversation

@MathurAditya724
Copy link
Member

@MathurAditya724 MathurAditya724 commented Feb 10, 2026

Summary

Migrates the Sentry API client from hand-rolled ky HTTP calls with Zod-validated responses to the @sentry/api SDK package. This gives us type-safe API calls generated from the OpenAPI spec, while keeping raw requests for internal/undocumented endpoints.

This supersedes #164, which generated the client in-repo using @hey-api/openapi-ts. Using the published @sentry/api package instead avoids maintaining ~20k lines of generated code in the repo.

What changed

New: src/lib/sentry-client.ts

Request configuration layer for @sentry/api SDK functions. Provides:

  • Authenticated fetch with Bearer token injection
  • Automatic retry on transient errors (408, 429, 5xx) with exponential backoff
  • 401 token refresh — force-refreshes OAuth token and retries once
  • Request timeout via AbortController (30s)
  • Per-region config via getSdkConfig(regionUrl)

Rewritten: src/lib/api-client.ts

All API functions now use @sentry/api SDK functions where possible:

Function SDK function used
listOrganizationsInRegion listYourOrganizations
getOrganization retrieveAnOrganization
listProjects listAnOrganization_sProjects
getProject retrieveAProject
getProjectKeys listAProject_sClientKeys
getIssueByShortId resolveAShortId
getLatestEvent retrieveAnIssueEvent
getEvent retrieveAnEventForAProject
triggerRootCauseAnalysis startSeerIssueFix
getAutofixState retrieveSeerIssueFixState
listLogs / getLog queryExploreEventsInTableFormat

Functions that use raw requests (no SDK equivalent):

  • getUserRegions/users/me/regions/ (internal endpoint)
  • getCurrentUser/users/me/ (internal endpoint)
  • findProjectByDsnKey/projects/?query=dsn:... (internal query param)
  • listIssues — SDK missing limit/sort params
  • getIssue / updateIssueStatus — legacy /issues/{id}/ endpoint (no org slug needed)
  • getDetailedTrace/organizations/{org}/trace/{traceId}/ (internal endpoint)
  • triggerSolutionPlanning — SDK doesn't support run_id + step body

Refactored: src/types/sentry.ts

  • SDK-backed types now derive from @sentry/api response types using Partial<SdkType> & RequiredCore
  • Keeps Zod schemas only for internal endpoints not covered by the SDK (Region, User, Logs)
  • Event entry types (exceptions, breadcrumbs, request, etc.) remain as plain TypeScript interfaces

Removed

  • ky dependency (replaced by @sentry/api + native fetch)
  • Most Zod schemas for SDK-covered types (Organization, Project, Issue, Event, ProjectKey, etc.)
  • SentryOrganizationSchema and other schema exports from types/index.ts

@github-actions
Copy link
Contributor

github-actions bot commented Feb 10, 2026

Semver Impact of This PR

🟢 Patch (bug fixes)

📋 Changelog Preview

This is how your changes will appear in the changelog.
Entries from this PR are highlighted with a left border (blockquote style).


New Features ✨

  • (formatters) Add Seer fixability score to issue list and detail views by betegon in #234
  • (team) Add team list command by betegon in #238

Bug Fixes 🐛

Telemetry

  • Use SDK session integration instead of manual management by BYK in #232
  • Correct runtime context for Bun binary by BYK in #231

Other

  • (setup) Use correct auth command in install welcome message by betegon in #241
  • (tests) Centralize test config dir lifecycle to prevent env var pollution by BYK in #242

Internal Changes 🔧

  • Use @sentry/api client for requests by MathurAditya724 in #226

🤖 This preview updates automatically when you update the PR.

@BYK BYK changed the title feat: using @sentry/api client for requests ref: use @sentry/api client for requests Feb 10, 2026
Resolve merge conflicts:
- package.json: keep @sentry/api as dependency, remove ky
- api-client.ts: adapt listRepositories and listTransactions to use
  SDK-based request pattern instead of ky-based orgScopedRequest
- types/index.ts: split type vs value exports for Zod schemas
- bun.lock: regenerated

Co-authored-by: Cursor <cursoragent@cursor.com>
@github-actions
Copy link
Contributor

github-actions bot commented Feb 11, 2026

Codecov Results 📊

❌ Patch coverage is 67.86%. Project has 4126 uncovered lines.
❌ Project coverage is 68.12%. Comparing base (base) to head (head).

Files with missing lines (71)
File Patch % Lines
human.ts 58.29% ⚠️ 395 Missing
resolve-target.ts 20.26% ⚠️ 366 Missing
list.ts 14.39% ⚠️ 345 Missing
api-client.ts 59.38% ⚠️ 262 Missing
list.ts 23.47% ⚠️ 212 Missing
oauth.ts 30.68% ⚠️ 183 Missing
list.ts 21.96% ⚠️ 167 Missing
plan.ts 19.37% ⚠️ 154 Missing
resolver.ts 3.23% ⚠️ 120 Missing
help.ts 19.85% ⚠️ 109 Missing
upgrade.ts 57.71% ⚠️ 107 Missing
view.ts 36.48% ⚠️ 101 Missing
interactive-login.ts 9.17% ⚠️ 99 Missing
errors.ts 5.94% ⚠️ 95 Missing
view.ts 25.81% ⚠️ 92 Missing
view.ts 39.44% ⚠️ 86 Missing
clipboard.ts 4.49% ⚠️ 85 Missing
status.ts 24.07% ⚠️ 82 Missing
migration.ts 47.44% ⚠️ 82 Missing
list.ts 27.18% ⚠️ 75 Missing
browser.ts 4.11% ⚠️ 70 Missing
login.ts 33.33% ⚠️ 64 Missing
span-tree.ts 5.00% ⚠️ 57 Missing
explain.ts 33.33% ⚠️ 56 Missing
api.ts 89.80% ⚠️ 47 Missing
upgrade.ts 66.91% ⚠️ 46 Missing
telemetry.ts 84.72% ⚠️ 46 Missing
seer.ts 75.54% ⚠️ 45 Missing
schema.ts 89.56% ⚠️ 40 Missing
refresh.ts 40.63% ⚠️ 38 Missing
seer.ts 79.87% ⚠️ 30 Missing
preload.ts 53.23% ⚠️ 29 Missing
view.ts 87.27% ⚠️ 28 Missing
utils.ts 88.94% ⚠️ 25 Missing
view.ts 61.54% ⚠️ 25 Missing
detector.ts 90.10% ⚠️ 20 Missing
binary.ts 88.67% ⚠️ 17 Missing
list.ts 91.16% ⚠️ 16 Missing
list.ts 90.70% ⚠️ 16 Missing
code-scanner.ts 95.00% ⚠️ 16 Missing
help.ts 57.14% ⚠️ 15 Missing
sentry-client.ts 92.22% ⚠️ 13 Missing
arg-parsing.ts 90.00% ⚠️ 12 Missing
dsn-cache.ts 94.62% ⚠️ 12 Missing
logout.ts 56.00% ⚠️ 11 Missing
token.ts 52.17% ⚠️ 11 Missing
fix.ts 83.61% ⚠️ 10 Missing
qrcode.ts 33.33% ⚠️ 10 Missing
fs-utils.ts 57.14% ⚠️ 9 Missing
view.ts 94.70% ⚠️ 7 Missing
project-root.ts 97.73% ⚠️ 7 Missing
version-check.ts 91.76% ⚠️ 7 Missing
feedback.ts 84.21% ⚠️ 6 Missing
auth.ts 95.52% ⚠️ 6 Missing
shell.ts 96.23% ⚠️ 6 Missing
app.ts 93.90% ⚠️ 5 Missing
region.ts 86.49% ⚠️ 5 Missing
setup.ts 97.84% ⚠️ 4 Missing
list.ts 97.33% ⚠️ 4 Missing
index.ts 95.96% ⚠️ 4 Missing
project-aliases.ts 97.40% ⚠️ 2 Missing
project-root-cache.ts 96.92% ⚠️ 2 Missing
output.ts 89.47% ⚠️ 2 Missing
alias.ts 99.42% ⚠️ 1 Missing
completions.ts 99.37% ⚠️ 1 Missing
env-file.ts 99.19% ⚠️ 1 Missing
parser.ts 98.63% ⚠️ 1 Missing
colors.ts 98.21% ⚠️ 1 Missing
trace.ts 99.16% ⚠️ 1 Missing
helpers.ts 97.62% ⚠️ 1 Missing
helpers.ts 94.74% ⚠️ 1 Missing
Coverage diff
@@            Coverage Diff             @@
##          main       #PR       +/-##
==========================================
- Coverage    69.08%    68.12%    -0.96%
==========================================
  Files          107       108        +1
  Lines        13195     12944      -251
  Branches         0         0         —
==========================================
+ Hits          9115      8818      -297
- Misses        4080      4126       +46
- Partials         0         0         —

Generated by Codecov Action

@MathurAditya724 MathurAditya724 marked this pull request as ready for review February 11, 2026 13:57
@MathurAditya724 MathurAditya724 requested review from BYK and betegon and removed request for BYK February 11, 2026 13:57
Copy link
Member

@BYK BYK left a comment

Choose a reason for hiding this comment

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

I guess we lost the retry logic now? (unless it is baked into the API SDK) We should get that back.

type DetailedLogsResponse,
listAnOrganization_sIssues,
listAnOrganization_sProjects,
listAProject_sClientKeys,
Copy link
Member

Choose a reason for hiding this comment

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

These are some weird-ass names lol

Copy link
Member Author

Choose a reason for hiding this comment

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

Auto generated, so can't change that

getControlSiloUrl,
getDefaultSdkConfig,
getSdkConfig,
} from "./sentry-client.js";
Copy link
Member

Choose a reason for hiding this comment

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

What's the value of splitting sentry-client off? the api-client is the Sentry Client and it cannot be anything else anyway?

Copy link
Member Author

Choose a reason for hiding this comment

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

I have 2 words for you - "Circular dependency", between sentry-client.ts, api-client.ts and region.ts

export async function getUserRegions(): Promise<Region[]> {
// Always use control silo for this endpoint
// /users/me/regions/ is an internal endpoint - use raw request
const response = await apiRequestToRegion<UserRegionsResponse>(
Copy link
Member

Choose a reason for hiding this comment

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

We should automate this logic: if the SDK has the endpoint, use that, if not fallback to our hand-rolled one.

Copy link
Member Author

Choose a reason for hiding this comment

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

These endpoints are not part of the public API Spec, and the reason why they are not in the SDK

Copy link
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 the types from this file should also come from the API based on the OpenAPI schema

Copy link
Member Author

Choose a reason for hiding this comment

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

The current state of the @sentry/api OpenAPI schema has significant gaps that make it impractical for many of these types. Either they are too generic, missing fields or internal endpoints

Copy link
Member

Choose a reason for hiding this comment

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

Let's make a note to fix this then?

@MathurAditya724
Copy link
Member Author

I guess we lost the retry logic now?

We have the retry logic in createAuthenticatedFetch

MathurAditya724 and others added 4 commits February 12, 2026 17:08
Resolve conflict in src/types/sentry.ts: keep SDK-derived SentryIssue type
from feat/api-client and add seerFixabilityScore field from main. Remove
duplicate Zod-based SentryIssueSchema and TraceContextSchema (unused).
Retain new non-conflicting types from main (ISSUE_PRIORITIES, ReleaseSchema,
SpanSchema).

Co-authored-by: Cursor <cursoragent@cursor.com>
/**
* Update an issue's status.
*/
export function updateIssueStatus(
Copy link
Member

Choose a reason for hiding this comment

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

Since when we can update issue statuses?! @betegon

Comment on lines +186 to +190
} else if (input instanceof URL) {
raw = input.href;
} else {
raw = input.url;
}
Copy link
Member

Choose a reason for hiding this comment

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

If it is already an instance of URL, why not just do return input.pathname??

Resolved conflicts in api-client.ts: converted new listTeams endpoint
from orgScopedRequest (ky-based) to @sentry/api SDK pattern using
listAnOrganization_sTeams, consistent with the rest of the branch.

Co-authored-by: Cursor <cursoragent@cursor.com>
throw new ApiError(
`Short ID ${normalizedShortId} resolved but no issue group returned`,
404,
"Issue not found"
Copy link

Choose a reason for hiding this comment

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

Bug: An unsafe type cast in getIssueByShortId can cause a runtime crash if the API response is missing required fields like shortId or title.
Severity: MEDIUM

Suggested Fix

Replace the unsafe type assertion with runtime validation. Use a library like Zod to define a schema for the expected API response and parse the data. This will ensure the group object has all required fields before it is used, preventing crashes from unexpected API structures.

Prompt for AI Agent
Review the code at the location below. A potential bug has been identified by an AI
agent.
Verify if this is a real issue. If it is, propose a fix; if not, explain why it's not
valid.

Location: src/lib/api-client.ts#L761

Potential issue: The function `getIssueByShortId` uses an unsafe type assertion `as
unknown as { group?: SentryIssue }` to cast the response from the Sentry API. This
bypasses TypeScript's type checking. While the code checks for the existence of the
`group` object, it does not validate its contents at runtime. Downstream functions like
`formatIssueRow()` unconditionally access required properties such as `issue.shortId`
and `issue.title`. If the API returns a `group` object that is missing these fields, the
application will crash with an error like "Cannot read property 'shortId' of undefined".

Did we get this right? 👍 / 👎 to inform future reviews.

@MathurAditya724 MathurAditya724 merged commit e0233bd into main Feb 13, 2026
22 checks passed
@MathurAditya724 MathurAditya724 deleted the feat/api-client branch February 13, 2026 20:39
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.

2 participants