feat(api): add api list command and deprecate openapi *#1070
Conversation
|
Claude finished @gu-stav's task in 2m 24s —— View job Review
Issues1. method: Flags.string({
description: 'Filter by HTTP method (case-insensitive)',
options: [...METHODS], // METHODS is uppercase only
}),With 2. Deprecated Pre-PR: The PR description states the deprecated command's output is preserved. The user-visible error message dropped "Please". The existing test ( 3. Streaming responses can be advertised under other 2xx codes (e.g. 4. Empty-slug entries from the docs index aren't filtered — When the docs API returns a malformed entry, Notes (not blocking)
|
📦 Bundle Stats —
|
| Metric | Value | vs main (3e479c0) |
|---|---|---|
| Internal (raw) | 2.1 KB | -8 B, -0.4% |
| Internal (gzip) | 799 B | -2 B, -0.2% |
| Bundled (raw) | 10.97 MB | -106 B, -0.0% |
| Bundled (gzip) | 2.06 MB | -33 B, -0.0% |
| Import time | 762ms | +45ms, +6.3% |
bin:sanity
| Metric | Value | vs main (3e479c0) |
|---|---|---|
| Internal (raw) | 975 B | - |
| Internal (gzip) | 460 B | - |
| Bundled (raw) | 9.84 MB | - |
| Bundled (gzip) | 1.77 MB | - |
| Import time | 1.93s | +169ms, +9.6% |
🗺️ View treemap · Artifacts
Details
- Import time regressions over 10% are flagged with
⚠️ - Sizes shown as raw / gzip 🗜️. Internal bytes = own code only. Total bytes = with all dependencies. Import time = Node.js cold-start median.
📦 Bundle Stats — @sanity/cli-core
Compared against main (3e479c08)
| Metric | Value | vs main (3e479c0) |
|---|---|---|
| Internal (raw) | 95.5 KB | -721 B, -0.7% |
| Internal (gzip) | 22.5 KB | -40 B, -0.2% |
| Bundled (raw) | 21.60 MB | -721 B, -0.0% |
| Bundled (gzip) | 3.42 MB | -93 B, -0.0% |
| Import time | 738ms | +56ms, +8.2% |
🗺️ View treemap · Artifacts
Details
- Import time regressions over 10% are flagged with
⚠️ - Sizes shown as raw / gzip 🗜️. Internal bytes = own code only. Total bytes = with all dependencies. Import time = Node.js cold-start median.
📦 Bundle Stats — create-sanity
Compared against main (3e479c08)
| Metric | Value | vs main (3e479c0) |
|---|---|---|
| Internal (raw) | 976 B | - |
| Internal (gzip) | 507 B | - |
| Bundled (raw) | 50.7 KB | - |
| Bundled (gzip) | 12.6 KB | - |
| Import time | ❌ ChildProcess denied: node | - |
Details
- Import time regressions over 10% are flagged with
⚠️ - Sizes shown as raw / gzip 🗜️. Internal bytes = own code only. Total bytes = with all dependencies. Import time = Node.js cold-start median.
Coverage Delta
Comparing 6 changed files against main @ Overall Coverage
|
58db56d to
0660c0d
Compare
api list command and deprecate openapi *
The deprecation forwarder pattern changed `openapi list`'s output
from one row per spec to one row per operation — a silent breaking
change for anyone piping `openapi list --json` into a script.
Restores the pre-deprecation shape: `{title, slug, description}` per
spec, same human format, byte-identical stdout. The deprecation
warning still surfaces on stderr, and the new operation-level shape
remains on the canonical `sanity api list`.
Addresses review comment on PR #1070.
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
Adds `sanity api list` rendering a flat operation table across all public Sanity HTTP specs. Replaces the existing `sanity openapi list` with a thin deprecation forwarder that delegates to the canonical implementation. Brings the shared infrastructure: revision-keyed cache (cache.ts), docs endpoint client (docsClient.ts), OpenAPI parser (parser.ts), revalidation orchestration (revalidate.ts), table + JSON renderers (views.ts). All under packages/@sanity/cli/src/api/. Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
Replaces the hand-rolled YAML walk + manual asObject/asArray casts with @scalar/openapi-parser's validate(), which returns a typed OpenAPI 3.x AST. Keeps $refs in place — link-not-resolve behavior is preserved. Strict validation warnings (missing descriptions, unbound path params, etc.) are not fatal; the parser surfaces whatever it can read. Only hard parse failures abort. parseOpenApi is now async. Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
Drops the revision-keyed YAML cache (cache.ts + revalidate.ts) and fetches the index + per-spec YAML directly from the docs endpoint on every `sanity api list` invocation. The 22 spec fetches run in parallel, keeping cold runs around 1s end-to-end. `loadParsedSpecs` now pulls specs from `docsClient.fetchSpec` and parses them in memory; nothing is written to disk. Tests no longer seed a temp cache dir — they mock the per-spec endpoint via nock. Cache invalidation, the `SANITY_CLI_CACHE_PATH` test override, and the pre-merge `revision: ''` fallback all go away with the cache. Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
Replaces the three-step fetch + parse + flatten recipe in list.ts with a single `loadOperationsIndex()` seam in parser.ts. The intermediate helpers (`loadParsedSpecs`, `buildOperationsIndex`) are now private — they were never useful in isolation. Also drops the unused `contentType` field from `fetchSpec`'s return shape; callers only ever read the YAML body, so `fetchSpec(slug): Promise<string | null>` is the honest signature. Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
The deprecation forwarder pattern changed `openapi list`'s output
from one row per spec to one row per operation — a silent breaking
change for anyone piping `openapi list --json` into a script.
Restores the pre-deprecation shape: `{title, slug, description}` per
spec, same human format, byte-identical stdout. The deprecation
warning still surfaces on stderr, and the new operation-level shape
remains on the canonical `sanity api list`.
Addresses review comment on PR #1070.
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
Walks through the review comments on #1070: - Push `--spec` filter into `loadOperationsIndex` so single-spec invocations make 1 + 1 requests instead of 1 + 22. Adds the `onlySlug` option and drops the post-hoc filter from list.ts. - Drop unused `ParsedSpec` (description/title/version/serverTemplate) in favor of a flat `ParsedOperation[]` return from `parseOpenApi`. None of those fields were consumed downstream. - URL-encode the slug when building `docsUrl` in the JSON projection (parity with `fetchSpec`). - Skip operations without an `operationId` instead of emitting them with `operationId: ''` — agent consumers index by operationId, and empty strings would collide silently. - Drop stale doc-comment references to `revalidate.ts` (deleted) and the "Phase 2 destructive guard" (doesn't exist in this PR). Plus the test gaps the review flagged: - `--spec=<unknown-slug>` empty path - empty-operationId skipping - `SANITY_DOCS_API_URL` / `SANITY_DOCS_API_BYPASS_TOKEN` env overrides Adds a changeset for the runtime change (minor bump on @sanity/cli). Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
d94ae26 to
f093299
Compare
- Widen try/catch in fetchAndParseEntry to wrap fetchSpec too. The docstring promises one spec's failure doesn't poison the run; the prior code let any 5xx / network error reject the whole Promise.all. Adds a per-spec 5xx test that locks the contract. - Dedup collectParamNames by (name, in). Per OpenAPI 3.x, operation- level params override path-item-level with the same key. Prior code pushed both, surfacing duplicate names in pathParams / requiredQueryParams. - Drop the `revision` field from OpenApiSpecIndexEntry — no consumer reads it now that the cache is gone. - Lift HTTP_REFERENCE_URL into docsClient.ts, dropping three duplicate definitions (list, openapi/list, views). - Clarify the capability classification docstring: `POST` and any other method (including `TRACE`/`CONNECT`) fall back to `write`. Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
Two small de-dup wins from the architecture review:
- Add `docsUrlFor(slug)` in api/docsClient.ts; replace the inline
`${HTTP_REFERENCE_URL}/${encodeURIComponent(slug)}` template at
the one site already using it (views.ts).
- Add `loadOperationsIndexOrThrow()` + `DOCS_SERVICE_UNAVAILABLE`
in api/parser.ts so commands can drop their bespoke try/catch
+ literal "service unavailable" string. `commands/api/list.ts`
loses its `loadOperations` wrapper entirely; `commands/openapi/list.ts`
references the shared constant.
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
…column Three additions in response to agent-discoverability review: - `--method`, `--capability`, `--grep` filter flags on `api list` so an agent searching for "delete a document" can narrow the result set without piping the full JSON through `jq`. - New `OPERATION` column in the human table — the `operationId` is the cross-reference key for `sanity api spec --operation=<id>`, and omitting it from the table forced an extra `--json` round-trip just to recover the id. - `optionalQueryParams: string[]` on the JSON row alongside `requiredQueryParams`, so callers get a full query-param picture from `list` without hopping to `spec`. Also clarifies in `--web` help text that it's a human-only mode (no machine-readable output). Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
Pulls `mockIndexAndSpecs`, the standard `afterEach` cleanup, and the canonical Jobs/Mutate spec YAMLs into `__tests__/fixtures.ts`. The three `api/*` test files (list, spec, call — added in the upstack PRs) all reach for the same shapes; this is the first step toward each test file containing only what it actually asserts. Extends the ESLint dep-exemption to cover any `**/__tests__/**/*.ts` file (was: only the legacy `test/__fixtures__/` dir) so colocated test helpers can import nock/vitest like `*.test.ts` files do. Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
The previous commit widened the eslint extraneous-deps exemption to `**/__tests__/**/*.ts`, which loosened lint coverage for an entire class of files. Reverts that and uses two narrowly-scoped `eslint-disable-next-line` comments on the nock/vitest imports in the colocated fixtures module — same effect, no global config drift. Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
…on-ids The OPERATION column was bloating the table beyond any reasonable terminal width: synthesized operationIds for spec operations missing one (added on the call branch) can reach ~90 chars (`delete_organizations_organizationId_providers_…`), and that single row sets the column width for every other line. Drops the column from the default human render; readers who want it on screen pass `--operation-ids`. The id is always present in `--json`, so this is a display preference, not a data loss. Long endpoints are still soft-wrapped in `wrapForCell` so deeply-nested paths don't blow out the ENDPOINT column either. Also drops "human-only" / "agent-friendly" qualifiers from `--web` and `--json` copy — these flags are useful for everyone, the audience tag was noise. Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
- Description: drop "OpenAPI"/"public" qualifiers — the topic already implies it, and the doc URL the table points at uses the same shorthand. - Example "Render a table" → "Show a table" — render is unusual phrasing in CLI help. - `--capability` flag: drop "bucket" jargon; spell out the values inline so the hint is self-describing. - `--operation-ids` flag: shorter rationale — say *why* it's off (synthesized ids are long), drop the meta about JSON output. Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
- docsClient: drop stale "until the docs-team PR adding `revision` merges" comment; `revision` was already removed from the index entry. - docsClient: drop unnecessary `body?.specs` optional chain (the `await` cannot produce a nullish value). - list.ts: empty-state copy framed "service may be unreachable" but that branch is unreachable when the loader threw — replaced with the actual condition: "No operations to list." - list.ts: `--web --spec=<slug>` opens the per-spec docs page; the flag was silently ignored before. - Tests: drop the now-noise `revision: ''` from the api/* nock mocks (single regression test in `openapi/list.test.ts` still asserts the field isn't leaked to consumers); assert exit code on the `openapi/list` "service unavailable" error. - Changeset: trim to one sentence per project convention. Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
|
Review the following changes in direct dependencies. Learn more about Socket for GitHub.
|
Description
Adds
sanity api listfor discovering Sanity's public HTTP API endpoints. Renders a flat operation table by default;--jsonemits one row per operation;--spec=<slug>narrows to a single spec;--webopens the HTTP Reference site.Deprecates
sanity openapi list— output shape preserved during the back-compat window, with a one-line stderr warning pointing at the canonical command.This PR is the first in a stack:
api listcommand and deprecateopenapi *#1070 (this PR) —sanity api listapi spec <spec>command #1073 —sanity api spec <slug>sanity api <endpoint>command #1074 —sanity api <endpoint>(default)Architecture refactors (post-review)
revisionfromOpenApiSpecIndexEntry(unused).docsUrlFor(slug)helper indocsClient.tsinstead of inline template literals at every site.loadOperationsIndexOrThrow()+ sharedDOCS_SERVICE_UNAVAILABLEconstant so commands stop redefining the same try/catch + literal copy.PR review items addressed
revisionfieldfetchAndParseEntryso one 5xx doesn't poison the whole listingWhat to review
packages/@sanity/cli/src/commands/api/list.ts— the new command.packages/@sanity/cli/src/api/parser.ts—loadOperationsIndexorchestration and parallel fetch behavior.packages/@sanity/cli/src/commands/openapi/list.ts— verify the deprecation forwarder's output is byte-identical apart from the stderr warning.Testing
10 unit tests in
commands/api/__tests__/list.test.tscovering: table render, JSON output,--specnarrowing, unknown slug empty state,--webflow, network unavailable, per-spec 404 skip, per-spec 5xx skip, base-URL env override, bypass-token header.