Skip to content

feat: fully migrate to @sentry/api SDK types (remove all as-unknown-as casts) #1068

@betegon

Description

@betegon

Background

The CLI already uses @sentry/api for all API calls (~60+ SDK functions in production). However, 30 as unknown as casts remain in src/lib/api/ — TypeScript bridges between SDK-generated response types and the CLI's internal SentryXxx wrapper types. These casts don't hide real bugs (the runtime shapes match), but they prevent TypeScript from catching future regressions and make the codebase harder to maintain.

This issue tracks the work to get to zero casts and fully adopt the SDK-generated types.


Three categories of work

Category 1 — Response type casts (~20 casts, CLI-only, ~2 days)

Pattern: return data as unknown as SentryTeam[]

The CLI defines SentryTeam = Partial<SdkTeam> & { id, slug, name }. TypeScript can't automatically narrow from the SDK's strict union type to this intersection. At runtime the shapes are identical.

Fix: Make unwrapResult<T> generic so the single cast lives in infrastructure, and all callers are clean:

// infrastructure.ts
export function unwrapResult<T>(result: SdkResult<unknown>, context: string): T {
  if (result.error !== undefined) { throwApiError(...) }
  return result.data as T; // one cast, all callers clean
}

// teams.ts — before
return data as unknown as SentryTeam[];
// after
return unwrapResult<SentryTeam[]>(result, "Failed to list teams");

Also simplify wrapper types that are already 100% compatible with SDK types:

  • SentryTeam → alias SdkTeam directly
  • SentryRelease → alias Partial<SdkReleaseResponse>
  • SentryDeploy → alias SDK type directly

Category 2 — Request body casts (~7 casts, needs backend spec fix)

Pattern: body as unknown as Parameters<typeof sdkFn>[0]["body"]

The SDK marks certain request body fields as required (per the spec), but the CLI passes them as optional and the API silently accepts it. Fixing the spec makes the cast unnecessary.

Backend spec changes needed (getsentry/sentry PRs):

Endpoint Field(s) to mark optional
createANewDashboardForAnOrganization widgets
editAnOrganization_sCustomDashboard various fields
createANewReleaseForAnOrganization projects
updateAnOrganization_sRelease various fields

After each backend fix ships in a new @sentry/api release, the corresponding CLI cast can be removed.


Category 3 — Path parameter casts (3 casts, CLI-only, trivial)

Pattern: dashboard_id: dashboardId as unknown as number

Already blocked on sentry#116836 (dashboard_id type fix). Once that ships:

// Before
dashboard_id: dashboardId as unknown as number,
// After
dashboard_id: dashboardId, // string, as the spec now correctly declares

Wrapper types that need to stay (for now)

Three types keep fields beyond the SDK spec that have never been formally documented:

Type Extra fields Fix
SentryOrganization allowMemberProjectCreation, orgRole Contribute to Sentry backend spec
SentryProject status (undocumented API field) Contribute to Sentry backend spec
SentryEvent dateCreated, fingerprints, sdkUpdates, typed contexts Some may be intentionally undocumented; contribute where possible

Work order

  • Phase 1 (CLI-only, ~2 days): Make unwrapResult<T> generic; drop response-type casts; simplify compatible wrapper types; replace dashboard_id cast with parseInt
  • Phase 2 (Backend spec, ~3 days + release): Fix dashboard and release request body schemas in getsentry/sentry; bump SDK; remove 7 body casts
  • Phase 3 (Ongoing): Contribute undocumented fields to spec; narrow/remove remaining wrapper types as each field lands

Success metric

grep -c "as unknown as" src/lib/api/*.ts  # 0

Metadata

Metadata

Assignees

No one assigned

    Labels

    jaredTrigger the Jared agent to work on stuff
    No fields configured for issues without a type.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions