Repository navigation
Description
Part of the adoption and compatibility plan in v1.0.0 #93. The package is already on 1.x; version numbering does not complete this issue's consumer acceptance criteria. This plan supersedes the historical #78 → #79 → #80 stack.
Current state — 2026-11-05
- Backend metadata is merged: sentry#127778 exports
x-sentry-routingwithout changing runtime routing or endpoint publication. The current schema contains metadata for all 274 operations, including explicit unknowns. - The shared client exists and is adopted by CLI/MCP: SDK #122 moved transport, retries, credential refresh, errors, response-cache mechanics and pagination into
@sentry/api/client. Toolkit #1942 adopted it and deleted the Toolkit copy; #1961 removed further duplicate helpers. Routing must reuse these implementations and the host's existing stores. - Per-request composition exists: #129 passes URL scope to credential selection; #130 adds
resolveBaseUrlto generated request preparation. Both are merged. Path scope identifies a target for consumer policy; it does not classify control/cell availability. - Build pipeline: #131 merged on 2026-11-05. It runs generators in one process with shared
emit({ sourceSpec, normalizedSpec })inputs and patch helpers; it does not change routing semantics. The current metadata-routing implementation uses that pipeline and its helpers, preserving identical generated runtime/types while avoiding duplicate schema reads or patch helpers. Package 1.29.0 includes the feat(client): Pick each request's base URL from its path with resolveBaseUrl #130 hook; use it as the current published baseline in addition to the version declared by each consumer. - Still missing: authoritative operation metadata in the SDK routing decision, composition with the shared client, and current consumer parity evidence. Keep one URL-resolution path; enrich the existing contract rather than introducing a competing hook or restoring the October prototype wholesale.
- #78 and #79 are closed without merge. Neither is a dependency. #80 remains independent.
Outcome
Configure one logical client per deployment/authentication context. Resource modules call generated methods without selecting a regional client:
const sentry = getAPIClient(); // Consumer-owned invocation/request context.
await sentry.listOrganizationProjects({
path: { organization_id_or_slug: organizationSlug },
});This illustrates the adoption target, not a new exported SDK getter. Multiple organizations/localities can share one logical client; destinations are selected per request without mutating shared defaults. Consumers retain credential storage, account selection, access restrictions, persistence and application policy. The SDK owns shared request mechanics, not CLI command orchestration or MCP tool permissions.
Two kinds of metadata
| Information | Source | Extra request? |
|---|---|---|
| Declared execution contexts and the organization's path parameter | Backend declarations → OpenAPI → generated operation | None; shipped in the package |
| An organization's public locality URL | Bootstrap, organization listing (links.regionUrl), configuration, existing cache or optional discovery |
Only when discovery is explicitly used |
Classify known operations from authoritative metadata, not URL-prefix heuristics. Generated operations already have their method, path template and arguments; any lookup for a concrete path must match a known operation, not infer a silo from /organizations, /projects or /teams. Raw/private/unmatched requests retain the consumer's existing context and fallback.
An organization-scoped operation can be control-only. Declared both availability does not imply equivalent results: listing organizations in control returns the authorized global catalog; listing in a cell is local. Preserve explicit context rather than selecting a host from both alone. Declarations also do not guarantee method-level behavior inside handlers or universal gateway support.
Delivery order
- Backend/OpenAPI metadata — complete. The additive extension is
x-sentry-routing: { silo: "control" | "cell" | "both" | "unknown", organizationParameter?: string }.silodeclares availability, not a preferred destination or gateway guarantee. Preserve the metadata through the current SDK generation pipeline. - Current SDK slice: metadata-aware per-request routing. Build on feat(client): Pick each request's base URL from its path with resolveBaseUrl #130's request preparation and feat(client): Move the shared API client from toolkit into @sentry/api #122's shared client. Supply authoritative operation context, reuse known locality or the consumer's existing resolver, and preserve cancellation, explicit-destination precedence, dual-context semantics, unknown-operation fallback and destination trust. Cover bound/standalone operations and
prepareRequestwithout duplicate resolution. Do not add a response cache, a second locality cache, another retry/redirect engine or gateway learning. - Current consumer adoption and simplification. Validate CLI, MCP and frontend against their current shared infrastructure. Reuse CLI memory/SQLite, MCP verified/request-local metadata and frontend
ConfigStore. Remove repeated call-site routing in the adopted path and verify output, errors, response metadata, request counts, cache hits, identity isolation and concurrency. Reassess Toolkit #1502 and #1508 against already-merged client/pagination work; their historical implementations and order are not prerequisites. - Separate follow-ups: optional built-in discovery for consumers without existing locality infrastructure; frontend runtime adoption under Integrate the SDK runtime with frontend apiOptions and RequestError #103; and gateway locality learning in a separate PR with its backend capability and deployment/runtime validation. The current routing slice must not depend on gateway response headers or that backend change.
Toolkit #1669 is an open, docs-only CLI-first MCP proposal. Keep the SDK compatible with its proposed request-scoped hosted execution, but do not treat it as shipped or move command execution into the API SDK. A Worker must be able to run without a database, filesystem or durable routing cache.
Routing and cache contract
- For a regional operation, reuse a locality known for that organization without discovery. A known locality must not redirect control operations or become a default for every organization accessible to the credential.
- When locality is unknown, preserve the existing gateway/configured-destination behavior where supported, with no mandatory preflight or regional fanout. This existing gateway path is distinct from the deferred optimization that learns and persists locality from response headers. Unknown and legacy resource-ID operations retain explicit context; the gateway does not cover everything.
- Distinguish metadata-only lookup from a resolver that performs HTTP. Reusing the CLI's existing resolver preserves its cold lookup cost; merely relocating it does not turn two requests into one. Do not add discovery to MCP reads that currently need only one request.
- Caller-owned metadata/resolvers retain locality-cache ownership. Do not overlay another opaque SDK cache on CLI memory/SQLite, frontend
ConfigStoreor MCP invocation state. Reuse existing in-flight deduplication rather than adding a second layer. - Keep locality storage separate from HTTP response caching. Reuse the shared transport/cache hooks and host storage from feat(client): Move the shared API client from toolkit into @sentry/api #122. Routing must settle the destination before the transport selects credentials and constructs response-cache identity; preserve fresh/reload/no-store semantics and mutation invalidation.
- Frontend
ConfigStoreis page memory populated from bootstrap. Reuse it centrally; components need no resolver/cache plumbing. Preserve admin/proxy and development-host behavior. - MCP verified OAuth constraints may contain locality, but also establish access. Reuse already-loaded matching metadata without turning a locality hint into authorization. Request-local memory is not guaranteed to persist across hosted requests; do not require Workers KV or another persistence service for routing.
- Preserve configured SaaS, dedicated, custom-domain and self-hosted deployments, including supported path prefixes. Use public locality URLs, keep web URLs separate, and never construct private cell addresses or infer deployment/trust from loose hostname suffixes.
- Validate the selected destination before forwarding credentials/CSRF/private-proxy headers. Keep destination selection, discovery and credential resolution in the same authentication context. Reuse the current transport's trust/redirect mechanisms without broadening their opt-in behavior or silently bypassing cache. Final-response validation cannot protect an earlier cross-origin redirect hop.
- Preserve request-local cancellation and consumer error/response contracts. Do not replay requests or introduce another retry owner. The shared bridge's expected path/method guards remain meaningful after destination selection.
Deferred built-in discovery contract
For consumers that opt in and have no locality store, use bounded instance-owned memory, finite TTL, explicit invalidation/reconfiguration, concurrent lookup deduplication and failure eviction. Scope state to deployment/authentication context/organization; no process-global or persistent cache by default, and no permanent caching of missing metadata.
Reusing the same client in a long-lived process retains that cache until expiry/invalidation/disposal; a new client/process starts independently. Hosted Workers must work correctly when every incoming request starts cold. Provide sensible defaults rather than requiring many settings. This is not part of the current metadata-routing slice.
Acceptance
- Backend exports declared silo and actual organization parameter by HTTP operation, with explicit unknowns and no runtime-routing/publication changes: sentry#127778.
- Current SDK generation preserves and exposes that metadata, reusing the existing operation mapping/catalog without changing operation names, query defaults or pagination contracts.
- Routing covers control-with-org, regional team/project/organization paths, dual-context and unknown/raw/private fallbacks. Explicit deployment/context semantics remain documented and tested.
- Known locality adds zero discovery requests. An existing consumer resolver retains its current cold/warm lookup cost and deduplication. Supported existing gateway requests gain no new preflight.
- Current CLI/MCP/frontend comparisons show equal or fewer network requests, unchanged cache-hit behavior, preserved outputs/errors/cursors/headers and no newly serialized independent work. Count client requests separately from proxy forwards when relevant; fewer calls alone is not a latency guarantee.
- Verify concurrent organizations/identities, explicit hosts/path prefixes, redirects, failures, cancellation and final response/error preservation through the current shared transport.
- Validate packed SDK compositions for CLI, MCP, frontend and a standalone consumer. Preserve frontend
apiOptions/RequestError, admin/dev proxies and private-operation fallback. Distinguish source/fixture checks from deployed Workers, browser/auth and live-tenant validation. - A reviewable consumer adoption diff removes repeated routing plumbing; do not count added integration code or unimplemented deletion opportunities as achieved simplification.
#92 remains a separate contract/acceptance review over the retry/cache mechanics now shipped in #122; do not add a competing retry implementation or silently change current retry policy in this routing slice. Progressive accuracy in #80 is separate. Complete migration of every consumer is not a prerequisite for a first safe pilot.
Activity
feat(api): export OpenAPI routing metadata (getsentry#127778)
ref(cli): Fold the detail cache tier into stable
fix(cli): Stop caching events and traces for 24 hours (#1681)