Dashboard › cli › Distillation
83605196-1057-49b8-8755-f38d496a1632["lore_tm_v1_ynSTk3Vg3WZOd2kYoJ3oureBNRxcwnnMd64qAk4mbMA","lore_tm_v1_6JhHqsxjW_sKaduKDhPRU0Fs3e3p9qWzV0naIqu3dpA","lore_tm_v1_D1-VD1cDU7q-RWQ5pE2WJl9eZ1ZRImRFopwj5Tezrsw","lore_tm_v1_YVQ7xWiHobe3HLuEOmUEO59e7HHeMavIakRZzJ1q1l0","lore_tm_v1_8dhVvPtFvQ_JVoHuYs57fBqa7a70RuV6fCv7cCeeI50"]
Date: Sep 10, 2026
"done" or "throw"; its final unreachable path is documented accordingly.throwOnError is always false because the CLI handles errors itself.packages/cli/src/lib/sentry-client.ts recognizes final responses, retryable errors/401s, and terminal throws through action results including { action: "throw", error }; retryable errors continue until the final retry attempt, then propagate.packages/cli/src/lib/sentry-client.ts auto-invalidates cache entries only after successful non-GET mutations; it skips GET requests and non-OK responses.fetchWithRetry() snapshots request bodies with await new Response(body).arrayBuffer() so it can reconstruct a fresh (input, init) request per retry because fetch consumes request bodies.fetchWithRetry() obtains the current token via refreshToken() without forcing refresh for fast, Vary-correct cache lookups, then caches responses and carries updated headers returned by retry handling.refreshToken usage in packages/cli/src/lib/sentry-client.ts at lines 27, 183, 188, and 678; OAuth token endpoints in packages/cli/src/lib/oauth.ts include POST /oauth/device/code/ and POST /oauth/token/ for device-code and refresh-token grants.packages/cli/src/lib/oauth.ts contains a guard that refuses to POST a refresh token to a host that does not match the active token host, throwing HostScopeError.packages/cli/src/lib/oauth.ts implements RFC 8628 Device Authorization Grant. getSentryUrl() lazily resolves getConfiguredSentryUrl() ?? DEFAULT_SENTRY_URL, allowing SENTRY_URL set after module import—such as through self-hosted URL argument parsing—to affect device flow and token refresh.packages/cli/src/lib/oauth.ts is SENTRY_CLIENT_ID environment variable → SENTRY_CLIENT_ID_BUILD build-time define → committed DEFAULT_OAUTH_CLIENT_ID; the default public client ID is 1d673b81d60ef84c951359c36296972ca6fd41bd8f45acd2d3a783a3b3c28e41.OAUTH_SCOPES in packages/cli/src/lib/oauth.ts are, in order: 1. project:read, 2. project:write, 3. project:admin, 4. org:read, 5. event:read, 6. event:write, 7. member:read, 8. team:read, 9. team:write, 10. alerts:read, 11. alerts:write.resolveOAuthScopeString(selection) prioritizes explicit scopes, then the derived :read-only subset, then the complete default scope list. Explicit scope normalization trims and lowercases entries, validates against SENTRY_SCOPES, collapses duplicates while preserving first-seen order, throws ValidationError for an unknown scope, and throws ValidationError("No scopes provided to --scope", "scope") when normalization yields no scopes.fetchWithConnectionError(url, init) in packages/cli/src/lib/oauth.ts copies request headers, calls applyCustomHeaders(merged, url) for URL-scoped self-hosted proxy/IAP/mTLS headers, uses getCustomTlsOptions(), and calls warnIfSaasWithEnvCa(url) when custom TLS is configured.ApiError with buildTlsErrorDetail(error), status 0, and message TLS certificate error connecting to ${getSentryUrl()}; ECONNREFUSED, "fetch failed", or "network" errors become status-0 ApiError advising users to check network connectivity and SENTRY_URL.packages/cli/src/lib/token-host.ts defines host equivalence as exact normalized origin match (scheme, host, and explicit port) or strict SaaS equivalence: a token scoped to https://sentry.io permits *.sentry.io only when both origins use HTTPS and default port. Non-SaaS hosts require exact matches; sentry.acme.com does not trust sentry.acme.evil.com.getActiveTokenHost() mirrors authentication precedence: usable stored OAuth host wins over an environment token unless a raw environment token exists and SENTRY_FORCE_ENV_TOKEN is nonblank; otherwise it returns getEnvTokenHost() for the active environment token.loginTrustAnchor in packages/cli/src/lib/token-host.ts is process-local and is registered only through explicit applyLoginUrl sources (--url or boot-time environment snapshot), not the .sentryclirc shim. It permits custom headers during tokenless OAuth bootstrap against an IAP-protected self-hosted instance.isLoginTrustAnchorFor(host) compares the candidate to loginTrustAnchor using host-scoping equivalence rather than checking only whether an anchor exists, preventing a stale auth login --url <other-host> anchor from authorizing a different host in library/test mode. resetLoginTrustAnchorForTesting() clears the anchor.isOriginTrustedFor() trusts a request if it matches its anchor through isHostTrusted() or if its normalized origin is in dynamically trusted regional origins via isTrustedRegionOrigin(). isRequestOriginTrusted() returns true when no token is active; otherwise it evaluates against getActiveTokenHost().isRequestOriginTrustedForCustomHeaders() trusts custom headers by active-token host scope when a token exists; without a token, it trusts only an explicit matching login trust anchor; with neither, it fails closed.