feat(api-docs): Redoc-rendered /api/docs + consolidate OpenAPI spec to docs/openapi.yaml (#4781)

Redoc /api/docs + OpenAPI spec consolidated to docs/openapi.yaml (canonical 201-path complete spec; old path → legacy fallback). All refs/gates/tests/CI updated. Integrated into release/v3.8.35.
This commit is contained in:
KooshaPari
2026-06-23 06:29:40 -07:00
committed by GitHub
parent 34a4645646
commit 463565c71a
94 changed files with 6923 additions and 110 deletions

View File

@@ -227,7 +227,7 @@ jobs:
runs-on: ubuntu-latest
steps:
# fetch-depth: 0 — the OpenAPI breaking-change gate (oasdiff) reads the base
# spec via `git show <base_ref>:docs/reference/openapi.yaml`; a shallow clone
# spec via `git show <base_ref>:docs/openapi.yaml`; a shallow clone
# would lack the base ref and the gate would self-skip (base-unresolved).
- uses: actions/checkout@v7
with:
@@ -318,7 +318,7 @@ jobs:
- name: Workflow lint (actionlint+zizmor, ratchet, blocking)
run: npm run check:workflows -- --ratchet
# OpenAPI breaking-change detection (oasdiff). Diffs the PR's public API
# contract (docs/reference/openapi.yaml) against the base branch's spec.
# contract (docs/openapi.yaml) against the base branch's spec.
# BLOCKING ratchet (Fase 9 Onda 0): reads metrics.openapiBreaking.value and
# exits 1 ONLY on a measured regression (count > baseline). It SKIPs (exit 0)
# when oasdiff is absent or the base spec can't be resolved — a missing

View File

@@ -42,7 +42,7 @@ jobs:
- run: pip install schemathesis
- name: Schemathesis smoke (high-risk endpoints, blocking)
run: |
schemathesis run docs/reference/openapi.yaml --url http://localhost:20128 \
schemathesis run docs/openapi.yaml --url http://localhost:20128 \
--include-path-regex '^/v1/(chat/completions|models)$|^/api/(auth|keys)' \
--max-examples 8 --workers 4 --checks all --max-response-time 30 \
--request-timeout 20 --suppress-health-check all --no-color

View File

@@ -45,7 +45,7 @@ jobs:
# PROVE the contract is fuzzable and surface regressions, not to gate the build.
continue-on-error: true
run: |
schemathesis run docs/reference/openapi.yaml \
schemathesis run docs/openapi.yaml \
--url http://localhost:20128 \
--max-examples 20 \
--workers 4 \

View File

@@ -554,7 +554,7 @@ For any non-trivial change, read the matching deep-dive first:
| Agent protocols (A2A / ACP / Cloud) | [`docs/frameworks/AGENT_PROTOCOLS_GUIDE.md`](docs/frameworks/AGENT_PROTOCOLS_GUIDE.md) |
| MCP server | [`docs/frameworks/MCP-SERVER.md`](docs/frameworks/MCP-SERVER.md) |
| A2A server | [`docs/frameworks/A2A-SERVER.md`](docs/frameworks/A2A-SERVER.md) |
| API reference | [`docs/reference/API_REFERENCE.md`](docs/reference/API_REFERENCE.md) + [`docs/reference/openapi.yaml`](docs/reference/openapi.yaml) |
| API reference | [`docs/reference/API_REFERENCE.md`](docs/reference/API_REFERENCE.md) + [`docs/openapi.yaml`](docs/openapi.yaml) |
| Provider catalog (auto-generated) | [`docs/reference/PROVIDER_REFERENCE.md`](docs/reference/PROVIDER_REFERENCE.md) |
| Tunnels | [`docs/ops/TUNNELS_GUIDE.md`](docs/ops/TUNNELS_GUIDE.md) |
| Electron desktop | [`docs/guides/ELECTRON_GUIDE.md`](docs/guides/ELECTRON_GUIDE.md) |

View File

@@ -1625,7 +1625,7 @@ And thank you to the OmniRoute community for the bug reports, reproductions, and
`tests/e2e/traffic-inspector.spec.ts`, `tests/e2e/agent-bridge-traffic-cross.spec.ts`
(skip-gated on CI by `RUN_AGENT_BRIDGE_E2E` / `RUN_TRAFFIC_INSPECTOR_E2E` / `RUN_CROSS_E2E`).
- **Documentation**`docs/frameworks/AGENTBRIDGE.md` and `docs/frameworks/TRAFFIC_INSPECTOR.md`;
`docs/architecture/REPOSITORY_MAP.md` updated; `docs/reference/openapi.yaml` updated with
`docs/architecture/REPOSITORY_MAP.md` updated; `docs/openapi.yaml` updated with
~28 new routes and 20+ new schemas.
- **i18n:** translate Ukrainian (uk-UA) menu and UI strings, plus complete uk-UA UI coverage (#2981 / #2988 — thanks @Lion-killer)
- **providers:** add SiliconFlow endpoint selector (#2975 — thanks @xz-dev)

View File

@@ -311,7 +311,7 @@ connection continue serving other models.
4. Create 7 API endpoints under `src/app/api/services/{name}/` (`_lib.ts`, `install`, `start`, `stop`, `restart`, `update`, `status`, `auto-start`). All delegate errors through `createErrorResponse()`. The shared `logs` endpoint is already wired via `[name]/logs/route.ts`.
5. Verify `/api/services/` is in `LOCAL_ONLY_API_PREFIXES` in `src/server/authz/routeGuard.ts`; add a test asserting `isLocalOnlyPath()` returns `true` for the new prefix if you add one (hard rule #17).
6. Add a UI tab in `src/app/(dashboard)/dashboard/providers/services/tabs/` reusing `ServiceStatusCard`, `ServiceLifecycleButtons`, `ServiceLogsPanel`.
7. Document in `docs/frameworks/EMBEDDED-SERVICES.md` (update §1 service table + §4 API reference) and `docs/reference/openapi.yaml`.
7. Document in `docs/frameworks/EMBEDDED-SERVICES.md` (update §1 service table + §4 API reference) and `docs/openapi.yaml`.
8. Write tests: unit (`tests/unit/services/`), integration (`tests/integration/services/`, gated by `RUN_SERVICES_INT=1`), and update `docs/ops/RELEASE_CHECKLIST.md` smoke section.
### Adding a New Guardrail / Eval / Skill / Webhook event
@@ -349,7 +349,7 @@ For any non-trivial change, read the matching deep-dive first:
| Agent protocols (A2A / ACP / Cloud) | `docs/frameworks/AGENT_PROTOCOLS_GUIDE.md` |
| MCP server | `docs/frameworks/MCP-SERVER.md` |
| A2A server | `docs/frameworks/A2A-SERVER.md` |
| API reference + OpenAPI | `docs/reference/API_REFERENCE.md` + `docs/reference/openapi.yaml` |
| API reference + OpenAPI | `docs/reference/API_REFERENCE.md` + `docs/openapi.yaml` |
| Provider catalog (auto-generated) | `docs/reference/PROVIDER_REFERENCE.md` |
| Release flow | `docs/ops/RELEASE_CHECKLIST.md` |
| Embedded services | `docs/frameworks/EMBEDDED-SERVICES.md` |

View File

@@ -921,7 +921,7 @@ Compression: aggressive (~50%) → double your free quota · Cost: $0/mo
| Document | Description |
| ------------------------------------------------- | --------------------------------------------------- |
| [API Reference](docs/reference/API_REFERENCE.md) | All endpoints with examples |
| [OpenAPI Spec](docs/reference/openapi.yaml) | OpenAPI 3.0 specification |
| [OpenAPI Spec](docs/openapi.yaml) | OpenAPI 3.0 specification |
| [MCP Server](open-sse/mcp-server/README.md) | 87 MCP tools, IDE configs, Python/TS/Go clients |
| [MCP Server Guide](docs/frameworks/MCP-SERVER.md) | MCP installation, transports, and tool reference |
| [A2A Server](src/lib/a2a/README.md) | JSON-RPC 2.0 protocol, skills, streaming, task mgmt |

View File

@@ -1,4 +1,4 @@
// AUTO-GENERATED from docs/reference/openapi.yaml. Do not edit.
// AUTO-GENERATED from docs/openapi.yaml. Do not edit.
import { apiFetch } from "../api.mjs";
import { emit } from "../output.mjs";
import { readFileSync } from "node:fs";

View File

@@ -1,4 +1,4 @@
// AUTO-GENERATED from docs/reference/openapi.yaml. Do not edit.
// AUTO-GENERATED from docs/openapi.yaml. Do not edit.
import { apiFetch } from "../api.mjs";
import { emit } from "../output.mjs";
import { readFileSync } from "node:fs";

View File

@@ -1,4 +1,4 @@
// AUTO-GENERATED from docs/reference/openapi.yaml. Do not edit.
// AUTO-GENERATED from docs/openapi.yaml. Do not edit.
import { apiFetch } from "../api.mjs";
import { emit } from "../output.mjs";
import { readFileSync } from "node:fs";

View File

@@ -1,4 +1,4 @@
// AUTO-GENERATED from docs/reference/openapi.yaml. Do not edit.
// AUTO-GENERATED from docs/openapi.yaml. Do not edit.
import { apiFetch } from "../api.mjs";
import { emit } from "../output.mjs";
import { readFileSync } from "node:fs";

View File

@@ -1,4 +1,4 @@
// AUTO-GENERATED from docs/reference/openapi.yaml. Do not edit.
// AUTO-GENERATED from docs/openapi.yaml. Do not edit.
import { apiFetch } from "../api.mjs";
import { emit } from "../output.mjs";
import { readFileSync } from "node:fs";

View File

@@ -1,4 +1,4 @@
// AUTO-GENERATED from docs/reference/openapi.yaml. Do not edit.
// AUTO-GENERATED from docs/openapi.yaml. Do not edit.
import { apiFetch } from "../api.mjs";
import { emit } from "../output.mjs";
import { readFileSync } from "node:fs";

View File

@@ -1,4 +1,4 @@
// AUTO-GENERATED from docs/reference/openapi.yaml. Do not edit.
// AUTO-GENERATED from docs/openapi.yaml. Do not edit.
import { apiFetch } from "../api.mjs";
import { emit } from "../output.mjs";
import { readFileSync } from "node:fs";

View File

@@ -1,4 +1,4 @@
// AUTO-GENERATED from docs/reference/openapi.yaml. Do not edit.
// AUTO-GENERATED from docs/openapi.yaml. Do not edit.
import { apiFetch } from "../api.mjs";
import { emit } from "../output.mjs";
import { readFileSync } from "node:fs";

View File

@@ -1,4 +1,4 @@
// AUTO-GENERATED from docs/reference/openapi.yaml. Do not edit.
// AUTO-GENERATED from docs/openapi.yaml. Do not edit.
import { apiFetch } from "../api.mjs";
import { emit } from "../output.mjs";
import { readFileSync } from "node:fs";

View File

@@ -1,4 +1,4 @@
// AUTO-GENERATED from docs/reference/openapi.yaml. Do not edit.
// AUTO-GENERATED from docs/openapi.yaml. Do not edit.
import { apiFetch } from "../api.mjs";
import { emit } from "../output.mjs";
import { readFileSync } from "node:fs";

View File

@@ -1,4 +1,4 @@
// AUTO-GENERATED from docs/reference/openapi.yaml. Do not edit.
// AUTO-GENERATED from docs/openapi.yaml. Do not edit.
import { apiFetch } from "../api.mjs";
import { emit } from "../output.mjs";
import { readFileSync } from "node:fs";

View File

@@ -1,4 +1,4 @@
// AUTO-GENERATED from docs/reference/openapi.yaml. Do not edit.
// AUTO-GENERATED from docs/openapi.yaml. Do not edit.
import { apiFetch } from "../api.mjs";
import { emit } from "../output.mjs";
import { readFileSync } from "node:fs";

View File

@@ -1,4 +1,4 @@
// AUTO-GENERATED from docs/reference/openapi.yaml. Do not edit.
// AUTO-GENERATED from docs/openapi.yaml. Do not edit.
import { apiFetch } from "../api.mjs";
import { emit } from "../output.mjs";
import { readFileSync } from "node:fs";

View File

@@ -1,4 +1,4 @@
// AUTO-GENERATED from docs/reference/openapi.yaml. Do not edit.
// AUTO-GENERATED from docs/openapi.yaml. Do not edit.
import { apiFetch } from "../api.mjs";
import { emit } from "../output.mjs";
import { readFileSync } from "node:fs";

View File

@@ -1,4 +1,4 @@
// AUTO-GENERATED from docs/reference/openapi.yaml. Do not edit.
// AUTO-GENERATED from docs/openapi.yaml. Do not edit.
import { apiFetch } from "../api.mjs";
import { emit } from "../output.mjs";
import { readFileSync } from "node:fs";

View File

@@ -1,4 +1,4 @@
// AUTO-GENERATED from docs/reference/openapi.yaml. Do not edit.
// AUTO-GENERATED from docs/openapi.yaml. Do not edit.
import { apiFetch } from "../api.mjs";
import { emit } from "../output.mjs";
import { readFileSync } from "node:fs";

View File

@@ -1,4 +1,4 @@
// AUTO-GENERATED from docs/reference/openapi.yaml. Do not edit.
// AUTO-GENERATED from docs/openapi.yaml. Do not edit.
import { apiFetch } from "../api.mjs";
import { emit } from "../output.mjs";
import { readFileSync } from "node:fs";

View File

@@ -1,4 +1,4 @@
// AUTO-GENERATED from docs/reference/openapi.yaml. Do not edit.
// AUTO-GENERATED from docs/openapi.yaml. Do not edit.
import { apiFetch } from "../api.mjs";
import { emit } from "../output.mjs";
import { readFileSync } from "node:fs";

View File

@@ -1,4 +1,4 @@
// AUTO-GENERATED from docs/reference/openapi.yaml. Do not edit.
// AUTO-GENERATED from docs/openapi.yaml. Do not edit.
import { apiFetch } from "../api.mjs";
import { emit } from "../output.mjs";
import { readFileSync } from "node:fs";

View File

@@ -1,4 +1,4 @@
// AUTO-GENERATED from docs/reference/openapi.yaml. Do not edit.
// AUTO-GENERATED from docs/openapi.yaml. Do not edit.
import { apiFetch } from "../api.mjs";
import { emit } from "../output.mjs";
import { readFileSync } from "node:fs";

View File

@@ -1,4 +1,4 @@
// AUTO-GENERATED from docs/reference/openapi.yaml. Do not edit.
// AUTO-GENERATED from docs/openapi.yaml. Do not edit.
import { apiFetch } from "../api.mjs";
import { emit } from "../output.mjs";
import { readFileSync } from "node:fs";

View File

@@ -1,4 +1,4 @@
// AUTO-GENERATED from docs/reference/openapi.yaml. Do not edit.
// AUTO-GENERATED from docs/openapi.yaml. Do not edit.
import { apiFetch } from "../api.mjs";
import { emit } from "../output.mjs";
import { readFileSync } from "node:fs";

View File

@@ -1,4 +1,4 @@
// AUTO-GENERATED from docs/reference/openapi.yaml. Do not edit.
// AUTO-GENERATED from docs/openapi.yaml. Do not edit.
import { apiFetch } from "../api.mjs";
import { emit } from "../output.mjs";
import { readFileSync } from "node:fs";

View File

@@ -1,4 +1,4 @@
// AUTO-GENERATED from docs/reference/openapi.yaml. Do not edit.
// AUTO-GENERATED from docs/openapi.yaml. Do not edit.
import { apiFetch } from "../api.mjs";
import { emit } from "../output.mjs";
import { readFileSync } from "node:fs";

View File

@@ -1,4 +1,4 @@
// AUTO-GENERATED from docs/reference/openapi.yaml. Do not edit.
// AUTO-GENERATED from docs/openapi.yaml. Do not edit.
import { apiFetch } from "../api.mjs";
import { emit } from "../output.mjs";
import { readFileSync } from "node:fs";

View File

@@ -1,4 +1,4 @@
// AUTO-GENERATED from docs/reference/openapi.yaml. Do not edit.
// AUTO-GENERATED from docs/openapi.yaml. Do not edit.
import { apiFetch } from "../api.mjs";
import { emit } from "../output.mjs";
import { readFileSync } from "node:fs";

View File

@@ -1,4 +1,4 @@
// AUTO-GENERATED from docs/reference/openapi.yaml. Do not edit.
// AUTO-GENERATED from docs/openapi.yaml. Do not edit.
import { apiFetch } from "../api.mjs";
import { emit } from "../output.mjs";
import { readFileSync } from "node:fs";

View File

@@ -1,4 +1,4 @@
// AUTO-GENERATED from docs/reference/openapi.yaml. Do not edit.
// AUTO-GENERATED from docs/openapi.yaml. Do not edit.
import { apiFetch } from "../api.mjs";
import { emit } from "../output.mjs";
import { readFileSync } from "node:fs";

View File

@@ -1,4 +1,4 @@
// AUTO-GENERATED from docs/reference/openapi.yaml. Do not edit.
// AUTO-GENERATED from docs/openapi.yaml. Do not edit.
import { apiFetch } from "../api.mjs";
import { emit } from "../output.mjs";
import { readFileSync } from "node:fs";

View File

@@ -1,4 +1,4 @@
// AUTO-GENERATED from docs/reference/openapi.yaml. Do not edit.
// AUTO-GENERATED from docs/openapi.yaml. Do not edit.
import { apiFetch } from "../api.mjs";
import { emit } from "../output.mjs";
import { readFileSync } from "node:fs";

View File

@@ -1,4 +1,4 @@
// AUTO-GENERATED from docs/reference/openapi.yaml. Do not edit.
// AUTO-GENERATED from docs/openapi.yaml. Do not edit.
import { apiFetch } from "../api.mjs";
import { emit } from "../output.mjs";
import { readFileSync } from "node:fs";

View File

@@ -56,7 +56,7 @@ Lookup material — API surface, environment variables, CLI flags, provider cata
- [API_REFERENCE.md](reference/API_REFERENCE.md) — REST API endpoints and shapes.
- [PROVIDER_REFERENCE.md](reference/PROVIDER_REFERENCE.md) — auto-generated provider catalog.
- [openapi.yaml](reference/openapi.yaml) — OpenAPI 3.1 spec for the public API.
- [openapi.yaml](openapi.yaml) — OpenAPI 3.1 spec for the public API.
- [ENVIRONMENT.md](reference/ENVIRONMENT.md) — environment variables reference.
- [CLI-TOOLS.md](reference/CLI-TOOLS.md) — bundled CLI commands.
- [FREE_TIERS.md](reference/FREE_TIERS.md) — free-tier LLM provider directory.

View File

@@ -755,7 +755,7 @@ See [RESILIENCE_GUIDE.md](./RESILIENCE_GUIDE.md) and the dedicated section in
4. If management-only: add the path to `src/shared/constants/publicApiRoutes.ts`
(denylist for the public API surface).
5. Add tests under `tests/unit/`.
6. Update `docs/reference/API_REFERENCE.md` and `docs/reference/openapi.yaml`.
6. Update `docs/reference/API_REFERENCE.md` and `docs/openapi.yaml`.
### Add a new DB module

View File

@@ -139,7 +139,7 @@ These run on a cron schedule (and `workflow_dispatch`), never on PRs. All are ad
| `nightly-property` | fast-check property tests with a random seed + high run count | **Advisory** |
| `nightly-resilience` | heap-growth gate, chaos fault-injection, k6 load/soak | **Advisory** |
| `nightly-llm-security` | promptfoo injection guard (block mode) + garak probes (skipped without a provider secret) | **Advisory** |
| `nightly-schemathesis` | OpenAPI contract fuzzing (schemathesis) against a live OmniRoute using `docs/reference/openapi.yaml` — surfaces spec violations / unhandled 500s (Fase 8 B.4) | **Advisory** |
| `nightly-schemathesis` | OpenAPI contract fuzzing (schemathesis) against a live OmniRoute using `docs/openapi.yaml` — surfaces spec violations / unhandled 500s (Fase 8 B.4) | **Advisory** |
---

View File

@@ -31,7 +31,7 @@ src/shared/constants/agentSkills.ts — 42-entry curated list (name/desc/cate
src/lib/agentSkills/
catalog.ts — getCatalog(), getSkillById(), filterCatalog(), computeCoverage()
generator.ts — generateAgentSkills() writes SKILL.md to skills/{id}/
openapiParser.ts — extracts REST endpoints from docs/reference/openapi.yaml
openapiParser.ts — extracts REST endpoints from docs/openapi.yaml
cliRegistryParser.ts — extracts CLI subcommands from bin/cli-registry.ts
schemas.ts — Zod schemas: AgentSkillSchema, SkillCoverageSchema, etc.
types.ts — TypeScript interfaces: AgentSkill, SkillCoverage, etc.

View File

@@ -448,7 +448,7 @@ Base path: `/api/tools/agent-bridge/`
| POST | `/api/tools/agent-bridge/upstream-ca/test` | Validate-only (dry-run) an upstream CA path — does not persist |
| GET / POST / DELETE | `/api/tools/agent-bridge/tproxy` | TPROXY transparent-decrypt capture mode — see [`docs/security/MITM-TPROXY-DECRYPT.md`](../security/MITM-TPROXY-DECRYPT.md) |
Full OpenAPI schemas: `docs/reference/openapi.yaml` → tag `AgentBridge`.
Full OpenAPI schemas: `docs/openapi.yaml` → tag `AgentBridge`.
---

View File

@@ -623,7 +623,7 @@ If the embedded service exposes an OpenAI-compatible `/v1/chat/completions` endp
table in §1 and any new endpoints to §4.
2. Add unit tests in `tests/unit/services/` (lifecycle, installer, API shape).
3. Add integration test in `tests/integration/services/` (behind `RUN_SERVICES_INT=1`).
4. Update `docs/reference/openapi.yaml` with the new endpoints.
4. Update `docs/openapi.yaml` with the new endpoints.
---
@@ -791,5 +791,5 @@ the most recent lines within the `tail` limit. Logs are not persisted to disk un
- `docs/security/ROUTE_GUARD_TIERS.md` — LOCAL_ONLY tier details
- `docs/architecture/CODEBASE_DOCUMENTATION.md` — §3.2 Embedded Services module mapping
- `docs/architecture/ARCHITECTURE.md` — system-level context
- `docs/reference/openapi.yaml` — machine-readable endpoint definitions
- `docs/openapi.yaml` — machine-readable endpoint definitions
- `CLAUDE.md` §"Adding a New Embedded Service" — quick-reference checklist

View File

@@ -477,4 +477,4 @@ Base path: `/api/tools/traffic-inspector/`
|--------|------|-------------|
| POST | `/internal/ingest` | Accepts intercepted request from `server.cjs` passthrough path; requires `INSPECTOR_INTERNAL_INGEST_TOKEN` header |
Full OpenAPI schemas: `docs/reference/openapi.yaml` → tag `Traffic Inspector`.
Full OpenAPI schemas: `docs/openapi.yaml` → tag `Traffic Inspector`.

View File

@@ -284,4 +284,4 @@ omniroute contexts remove 192-168-0-15 --yes # drop the local context (even if
| POST | `/api/cli/tokens` | access token | admin |
| DELETE | `/api/cli/tokens/:id` | access token | admin |
See [openapi.yaml](../reference/openapi.yaml) for full schemas.
See [openapi.yaml](../openapi.yaml) for full schemas.

View File

@@ -84,7 +84,7 @@ lastUpdated: 2026-06-13
- **Como funciona:** `docs/<seção>/*.md``source.config.ts` (globs) → `.source/server.ts` (gerado) → `src/lib/source.ts``src/app/docs/layout.tsx` (sidebar = `pageTree` dos `meta.json`) → `[...slug]/page.tsx`. **60 docs em inglês** entram no site.
- **Navegação curada por `meta.json`** → arquivo novo em `/docs` **não aparece** até ser adicionado manualmente ao `meta.json` da seção. Hoje há 4 arquivos importados mas fora da sidebar (acima).
- **i18n no site:** `[...slug]/page.tsx` lê cookie `NEXT_LOCALE`; se ≠ en, tenta `docs/i18n/<locale>/docs/<seção>/<FILE>.md` via `marked.parse()`, com fallback para o MDX inglês. Seletor: `LanguageSelector.tsx` (40 idiomas em `LANGUAGES`).
- **API Explorer:** `openapi.generated.ts` é gerado por `scripts/docs/gen-openapi-module.mjs` a partir de `docs/reference/openapi.yaml` no `prebuild:docs`.
- **API Explorer:** `openapi.generated.ts` é gerado por `scripts/docs/gen-openapi-module.mjs` a partir de `docs/openapi.yaml` no `prebuild:docs`.
- **Riscos de drift:** (a) `meta.json` manual; (b) traduções não atualizam quando o inglês muda; (c) `openapi.yaml` precisa de regen; (d) `LANGUAGES` no app diz 40, config diz 42 → **divergência app vs config**.
### 2.4 Wiki do GitHub (`/wiki`) — **mais defasada de todas**

View File

@@ -52,7 +52,7 @@ npm run test:e2e # optional but recommended
- [ ] Manually review CHANGELOG.md and clean up commit messages if needed
- [ ] Ensure the latest semver section in `CHANGELOG.md` equals `package.json` version
- [ ] Keep `## [Unreleased]` as the first changelog section for upcoming work
- [ ] Update `docs/reference/openapi.yaml``info.version` must equal `package.json` version
- [ ] Update `docs/openapi.yaml``info.version` must equal `package.json` version
### Code Quality
@@ -104,7 +104,7 @@ Breaking changes: add `BREAKING CHANGE:` footer or `!` after the scope (e.g. `fe
- [ ] `docs/guides/TROUBLESHOOTING.md` reviewed for env var and operational drift
- [ ] If `.env.example` changed: `docs/reference/ENVIRONMENT.md` updated
- [ ] If new feature has a UI: `docs/guides/USER_GUIDE.md` mentions it
- [ ] If new feature has API: `docs/reference/API_REFERENCE.md` + `docs/reference/openapi.yaml` updated
- [ ] If new feature has API: `docs/reference/API_REFERENCE.md` + `docs/openapi.yaml` updated
- [ ] If new feature is a module: dedicated `docs/<MODULE>.md` exists
- [ ] If breaking change: `docs/guides/TROUBLESHOOTING.md` has migration note

View File

@@ -136,7 +136,7 @@ expired DB doesn't silently downgrade to "deny".
## Documenting Security Tiers in OpenAPI
When adding a new route to `docs/reference/openapi.yaml`, apply the corresponding
When adding a new route to `docs/openapi.yaml`, apply the corresponding
vendor extension if the route is classified by `routeGuard.ts`:
| routeGuard.ts classification | YAML annotation | Enforcement |

6690
public/openapi.yaml Normal file

File diff suppressed because it is too large Load Diff

View File

@@ -34,7 +34,7 @@ export const APP_STAGING_REMOVAL_PATHS: string[] = [
export const APP_STAGING_ALLOWED_EXACT_PATHS: string[] = [
".env.example",
"BUILD_SHA",
"docs/reference/openapi.yaml",
"docs/openapi.yaml",
"http-method-guard.cjs",
"open-sse/mcp-server/server.js",
// LLMLingua ONNX worker — esbuild'd standalone .js spawned via worker_threads

View File

@@ -5,7 +5,7 @@ import path from "node:path";
const cwd = process.cwd();
const packageJsonPath = path.resolve(cwd, "package.json");
const openApiPath = path.resolve(cwd, "docs/reference/openapi.yaml");
const openApiPath = path.resolve(cwd, "docs/openapi.yaml");
const changelogPath = path.resolve(cwd, "CHANGELOG.md");
const llmPath = path.resolve(cwd, "llm.txt");
const i18nDocsPath = path.resolve(cwd, "docs/i18n");
@@ -209,7 +209,7 @@ try {
const openApiVersion = extractOpenApiVersion(readText(openApiPath));
if (!openApiVersion) {
fail("could not extract docs/reference/openapi.yaml info.version");
fail("could not extract docs/openapi.yaml info.version");
} else if (openApiVersion !== packageVersion) {
fail(`OpenAPI version (${openApiVersion}) differs from package.json (${packageVersion})`);
} else {

View File

@@ -358,7 +358,7 @@ const ENDPOINT_ALLOWLIST = new Set([
/** Doc files to skip (auto-generated, vendored, or third-party). */
const SKIP_DOC_FILES = new Set([
"docs/reference/PROVIDER_REFERENCE.md", // auto-generated from providers.ts
"docs/reference/openapi.yaml",
"docs/openapi.yaml",
"docs/i18n", // translations — separate workflow
// Point-in-time documentation audit (v3.8.24): intentionally references drift,
// counts, and not-yet-existing files as part of documenting them — not living docs.

View File

@@ -2,7 +2,7 @@
// scripts/check/check-openapi-breaking.mjs
// Catraca de breaking-change na API pública (Fase 8 B.4 — backlog opcional).
//
// Diffa a spec do PR (docs/reference/openapi.yaml na working tree = HEAD) contra
// Diffa a spec do PR (docs/openapi.yaml na working tree = HEAD) contra
// a MESMA spec no branch base, via `oasdiff breaking`. Pega regressões de contrato:
// endpoint removido, parâmetro novo obrigatório, campo de resposta removido, enum
// estreitado, etc. — mudanças que quebram clientes existentes.
@@ -32,7 +32,7 @@
// • CI passa BASE_REF=${{ github.base_ref }} (ex.: "release/vX.Y.Z").
// • Local: default derivado da versão do package.json (releaseBranchForVersion),
// ex.: package 3.8.29 → "origin/release/v3.8.29" — nunca fica stale entre ciclos.
// A spec base é extraída com `git show <BASE_REF>:docs/reference/openapi.yaml`.
// A spec base é extraída com `git show <BASE_REF>:docs/openapi.yaml`.
//
// Uso:
// node scripts/check/check-openapi-breaking.mjs
@@ -52,8 +52,8 @@ const QUIET = process.argv.includes("--quiet");
const PRINT_JSON = process.argv.includes("--json");
const RATCHET = process.argv.includes("--ratchet");
const SPEC_REL = "docs/reference/openapi.yaml";
const SPEC_PATH = path.join(ROOT, "docs", "reference", "openapi.yaml");
const SPEC_REL = "docs/openapi.yaml";
const SPEC_PATH = path.join(ROOT, "docs", "openapi.yaml");
/**
* Deriva o branch base de release a partir de uma versão semver

View File

@@ -13,7 +13,7 @@ import * as yaml from "js-yaml";
const ROOT = process.cwd();
const API_ROOT = path.join(ROOT, "src", "app", "api");
const OPENAPI_PATH = path.join(ROOT, "docs", "reference", "openapi.yaml");
const OPENAPI_PATH = path.join(ROOT, "docs", "openapi.yaml");
// Floor recorded on 2026-05-26 for release/v3.8.4: 137/365 routes documented.
// The original ≥99% target tracks the OpenAPI audit follow-up (#2701);
// until the backlog (services, free-proxies, relay-tokens, key-groups,

View File

@@ -1,6 +1,6 @@
#!/usr/bin/env node
// scripts/check/check-openapi-routes.mjs
// Gate anti-alucinação (docs): toda `path` documentada em docs/reference/openapi.yaml
// Gate anti-alucinação (docs): toda `path` documentada em docs/openapi.yaml
// deve resolver para um route.ts real em src/app/api/. Pega endpoint INVENTADO/obsoleto
// na spec (a IA escreve docs descrevendo rota que não existe). Complementa
// check-openapi-coverage.mjs (que mede a direção inversa: % de rotas documentadas).
@@ -14,7 +14,7 @@ import { assertNoStale } from "./lib/allowlist.mjs";
const ROOT = process.cwd();
const API_ROOT = path.join(ROOT, "src", "app", "api");
const OPENAPI_PATH = path.join(ROOT, "docs", "reference", "openapi.yaml");
const OPENAPI_PATH = path.join(ROOT, "docs", "openapi.yaml");
// Entradas da spec sem rota real, congeladas para triagem (catraca: bloqueia NOVAS).
export const KNOWN_STALE_SPEC = new Set([

View File

@@ -11,7 +11,7 @@ import path from "node:path";
import * as yaml from "js-yaml";
const ROOT = process.cwd();
const OPENAPI_PATH = path.join(ROOT, "docs", "reference", "openapi.yaml");
const OPENAPI_PATH = path.join(ROOT, "docs", "openapi.yaml");
const ROUTE_GUARD_PATH = path.join(ROOT, "src", "server", "authz", "routeGuard.ts");
function parseStringArray(match) {

View File

@@ -10,7 +10,7 @@ import * as yaml from "js-yaml";
const __dirname = dirname(fileURLToPath(import.meta.url));
const ROOT = join(__dirname, "..", "..");
const SPEC_PATH = process.env.OPENAPI_SPEC || join(ROOT, "docs/reference/openapi.yaml");
const SPEC_PATH = process.env.OPENAPI_SPEC || join(ROOT, "docs/openapi.yaml");
const OUT_DIR = join(ROOT, "bin/cli/api-commands");
// Operations already covered by hand-crafted commands — skip in generated output.

View File

@@ -1,6 +1,6 @@
#!/usr/bin/env node
/**
* gen-openapi-module.mjs — build helper that reads docs/reference/openapi.yaml,
* gen-openapi-module.mjs — build helper that reads docs/openapi.yaml,
* flattens the path/method matrix, and emits
* src/app/docs/lib/openapi.generated.ts so the Api Explorer client can
* iterate endpoints without parsing YAML at runtime.
@@ -23,7 +23,7 @@ import * as yaml from "js-yaml";
const __filename = fileURLToPath(import.meta.url);
const __dirname = path.dirname(__filename);
const ROOT = path.resolve(__dirname, "..", "..");
const OPENAPI_PATH = path.join(ROOT, "docs", "reference", "openapi.yaml");
const OPENAPI_PATH = path.join(ROOT, "docs", "openapi.yaml");
const OUT_PATH = path.join(ROOT, "src", "app", "docs", "lib", "openapi.generated.ts");
const HTTP_METHODS = ["get", "post", "put", "delete", "patch", "options", "head"];
@@ -108,7 +108,7 @@ async function main() {
const header = `// AUTO-GENERATED by scripts/docs/gen-openapi-module.mjs — DO NOT EDIT MANUALLY
// Regenerate with: node scripts/docs/gen-openapi-module.mjs
//
// Source of truth: docs/reference/openapi.yaml
// Source of truth: docs/openapi.yaml
//
// The Api Explorer consumes \`OPENAPI_ENDPOINTS\`; the spec metadata
// (\`OPENAPI_VERSION\`, \`OPENAPI_TITLE\`) is surfaced in the page header.

View File

@@ -119,7 +119,7 @@ function coverageByModule() {
// 4) OpenAPI coverage: percentage of implemented routes documented in openapi.yaml
function openapiCoverage() {
const API_ROOT = path.join(cwd, "src", "app", "api");
const OPENAPI_PATH = path.join(cwd, "docs", "reference", "openapi.yaml");
const OPENAPI_PATH = path.join(cwd, "docs", "openapi.yaml");
if (!fs.existsSync(API_ROOT) || !fs.existsSync(OPENAPI_PATH)) return;
function collectRoutePaths(dir) {

View File

@@ -17,7 +17,7 @@ All requests require a valid Bearer token or session cookie. Obtain a token via
_No endpoints mapped for this area yet._
## Payloads
See the full OpenAPI specification at `GET /api/openapi/spec` or `docs/reference/openapi.yaml` for detailed request/response schemas.
See the full OpenAPI specification at `GET /api/openapi/spec` or `docs/openapi.yaml` for detailed request/response schemas.
<!-- skill:custom-start -->
<!-- Migrated from skills/omniroute-a2a/SKILL.md (preserved curated content) -->

View File

@@ -45,4 +45,4 @@ curl -X DELETE https://localhost:20128/api/keys/{id} \
## Payloads
See the full OpenAPI specification at `GET /api/openapi/spec` or `docs/reference/openapi.yaml` for detailed request/response schemas.
See the full OpenAPI specification at `GET /api/openapi/spec` or `docs/openapi.yaml` for detailed request/response schemas.

View File

@@ -38,7 +38,7 @@ curl -X POST https://localhost:20128/api/auth/logout \
## Payloads
See the full OpenAPI specification at `GET /api/openapi/spec` or `docs/reference/openapi.yaml` for detailed request/response schemas.
See the full OpenAPI specification at `GET /api/openapi/spec` or `docs/openapi.yaml` for detailed request/response schemas.
<!-- skill:custom-start -->
<!-- Migrated from skills/omniroute/SKILL.md (preserved curated content) -->

View File

@@ -36,4 +36,4 @@ curl -X POST https://localhost:20128/api/rate-limit \
## Payloads
See the full OpenAPI specification at `GET /api/openapi/spec` or `docs/reference/openapi.yaml` for detailed request/response schemas.
See the full OpenAPI specification at `GET /api/openapi/spec` or `docs/openapi.yaml` for detailed request/response schemas.

View File

@@ -54,4 +54,4 @@ curl -X DELETE https://localhost:20128/api/cache/stats \
## Payloads
See the full OpenAPI specification at `GET /api/openapi/spec` or `docs/reference/openapi.yaml` for detailed request/response schemas.
See the full OpenAPI specification at `GET /api/openapi/spec` or `docs/openapi.yaml` for detailed request/response schemas.

View File

@@ -317,4 +317,4 @@ curl -X DELETE https://localhost:20128/api/cli-tools/openclaw-settings \
## Payloads
See the full OpenAPI specification at `GET /api/openapi/spec` or `docs/reference/openapi.yaml` for detailed request/response schemas.
See the full OpenAPI specification at `GET /api/openapi/spec` or `docs/openapi.yaml` for detailed request/response schemas.

View File

@@ -109,7 +109,7 @@ curl -X DELETE https://localhost:20128/api/fallback/chains \
## Payloads
See the full OpenAPI specification at `GET /api/openapi/spec` or `docs/reference/openapi.yaml` for detailed request/response schemas.
See the full OpenAPI specification at `GET /api/openapi/spec` or `docs/openapi.yaml` for detailed request/response schemas.
<!-- skill:custom-start -->
<!-- Migrated from skills/omniroute-routing/SKILL.md (preserved curated content) -->

View File

@@ -45,7 +45,7 @@ curl https://localhost:20128/api/compression/rules \
## Payloads
See the full OpenAPI specification at `GET /api/openapi/spec` or `docs/reference/openapi.yaml` for detailed request/response schemas.
See the full OpenAPI specification at `GET /api/openapi/spec` or `docs/openapi.yaml` for detailed request/response schemas.
<!-- skill:custom-start -->
<!-- Migrated from skills/omniroute-compression/SKILL.md (preserved curated content) -->

View File

@@ -65,4 +65,4 @@ curl https://localhost:20128/api/context/rtk/raw-output/{id} \
## Payloads
See the full OpenAPI specification at `GET /api/openapi/spec` or `docs/reference/openapi.yaml` for detailed request/response schemas.
See the full OpenAPI specification at `GET /api/openapi/spec` or `docs/openapi.yaml` for detailed request/response schemas.

View File

@@ -17,4 +17,4 @@ All requests require a valid Bearer token or session cookie. Obtain a token via
_No endpoints mapped for this area yet._
## Payloads
See the full OpenAPI specification at `GET /api/openapi/spec` or `docs/reference/openapi.yaml` for detailed request/response schemas.
See the full OpenAPI specification at `GET /api/openapi/spec` or `docs/openapi.yaml` for detailed request/response schemas.

View File

@@ -210,7 +210,7 @@ curl https://localhost:20128/api/v1/providers/{provider}/models \
## Payloads
See the full OpenAPI specification at `GET /api/openapi/spec` or `docs/reference/openapi.yaml` for detailed request/response schemas.
See the full OpenAPI specification at `GET /api/openapi/spec` or `docs/openapi.yaml` for detailed request/response schemas.
<!-- skill:custom-start -->
<!-- Aggregated from: omniroute-chat, omniroute-image, omniroute-tts, omniroute-stt, omniroute-embeddings, omniroute-web-search, omniroute-web-fetch -->

View File

@@ -17,7 +17,7 @@ All requests require a valid Bearer token or session cookie. Obtain a token via
_No endpoints mapped for this area yet._
## Payloads
See the full OpenAPI specification at `GET /api/openapi/spec` or `docs/reference/openapi.yaml` for detailed request/response schemas.
See the full OpenAPI specification at `GET /api/openapi/spec` or `docs/openapi.yaml` for detailed request/response schemas.
<!-- skill:custom-start -->
<!-- Migrated from skills/omniroute-mcp/SKILL.md (preserved curated content) -->

View File

@@ -56,4 +56,4 @@ curl https://localhost:20128/api/models/catalog \
## Payloads
See the full OpenAPI specification at `GET /api/openapi/spec` or `docs/reference/openapi.yaml` for detailed request/response schemas.
See the full OpenAPI specification at `GET /api/openapi/spec` or `docs/openapi.yaml` for detailed request/response schemas.

View File

@@ -176,7 +176,7 @@ curl https://localhost:20128/api/provider-models \
## Payloads
See the full OpenAPI specification at `GET /api/openapi/spec` or `docs/reference/openapi.yaml` for detailed request/response schemas.
See the full OpenAPI specification at `GET /api/openapi/spec` or `docs/openapi.yaml` for detailed request/response schemas.
<!-- skill:custom-start -->
## Additional endpoints

View File

@@ -17,4 +17,4 @@ All requests require a valid Bearer token or session cookie. Obtain a token via
_No endpoints mapped for this area yet._
## Payloads
See the full OpenAPI specification at `GET /api/openapi/spec` or `docs/reference/openapi.yaml` for detailed request/response schemas.
See the full OpenAPI specification at `GET /api/openapi/spec` or `docs/openapi.yaml` for detailed request/response schemas.

View File

@@ -27,7 +27,7 @@ curl https://localhost:20128/api/monitoring/health \
## Payloads
See the full OpenAPI specification at `GET /api/openapi/spec` or `docs/reference/openapi.yaml` for detailed request/response schemas.
See the full OpenAPI specification at `GET /api/openapi/spec` or `docs/openapi.yaml` for detailed request/response schemas.
<!-- skill:custom-start -->
<!-- Migrated from skills/omniroute-monitoring/SKILL.md (preserved curated content) -->

View File

@@ -219,4 +219,4 @@ curl https://localhost:20128/api/tags \
## Payloads
See the full OpenAPI specification at `GET /api/openapi/spec` or `docs/reference/openapi.yaml` for detailed request/response schemas.
See the full OpenAPI specification at `GET /api/openapi/spec` or `docs/openapi.yaml` for detailed request/response schemas.

View File

@@ -95,4 +95,4 @@ curl -X POST https://localhost:20128/api/sync/initialize \
## Payloads
See the full OpenAPI specification at `GET /api/openapi/spec` or `docs/reference/openapi.yaml` for detailed request/response schemas.
See the full OpenAPI specification at `GET /api/openapi/spec` or `docs/openapi.yaml` for detailed request/response schemas.

View File

@@ -17,4 +17,4 @@ All requests require a valid Bearer token or session cookie. Obtain a token via
_No endpoints mapped for this area yet._
## Payloads
See the full OpenAPI specification at `GET /api/openapi/spec` or `docs/reference/openapi.yaml` for detailed request/response schemas.
See the full OpenAPI specification at `GET /api/openapi/spec` or `docs/openapi.yaml` for detailed request/response schemas.

View File

@@ -112,4 +112,4 @@ curl -X POST https://localhost:20128/api/usage/budget \
## Payloads
See the full OpenAPI specification at `GET /api/openapi/spec` or `docs/reference/openapi.yaml` for detailed request/response schemas.
See the full OpenAPI specification at `GET /api/openapi/spec` or `docs/openapi.yaml` for detailed request/response schemas.

View File

@@ -218,4 +218,4 @@ curl https://localhost:20128/api/services/{name}/logs \
## Payloads
See the full OpenAPI specification at `GET /api/openapi/spec` or `docs/reference/openapi.yaml` for detailed request/response schemas.
See the full OpenAPI specification at `GET /api/openapi/spec` or `docs/openapi.yaml` for detailed request/response schemas.

View File

@@ -17,4 +17,4 @@ All requests require a valid Bearer token or session cookie. Obtain a token via
_No endpoints mapped for this area yet._
## Payloads
See the full OpenAPI specification at `GET /api/openapi/spec` or `docs/reference/openapi.yaml` for detailed request/response schemas.
See the full OpenAPI specification at `GET /api/openapi/spec` or `docs/openapi.yaml` for detailed request/response schemas.

89
src/app/api/docs/route.ts Normal file
View File

@@ -0,0 +1,89 @@
/**
* GET /api/docs — Rendered API reference (Redoc UI).
*
* Serves an HTML page that loads Redoc from a CDN and points it at
* `/openapi.yaml` (the same canonical spec maintained at
* `docs/openapi.yaml` in the repo). The CDN dependency is documented in
* `docs/architecture/standalone-renderer-strategy.md`; if the deployment
* is air-gapped, mirror the Redoc assets under `public/vendor/redoc/`
* and update the <script src> below.
*
* Auth: PUBLIC tier. Anyone can read the API surface.
*
* Implementation note: we intentionally inline a minimal HTML shell
* (no React, no client bundle) so this route stays cheap to render
* even under cold-start conditions. Redoc itself is loaded from
* `https://cdn.redocly.com/redoc/latest/bundles/redoc.standalone.js`
* which is the SOTA choice for standalone OpenAPI renderers.
*/
export const dynamic = "force-static";
const REDOC_HTML = `<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width, initial-scale=1" />
<title>OmniRoute API Reference</title>
<meta name="description" content="Redoc-rendered OpenAPI 3.0 spec for the OmniRoute v1 API." />
<link rel="icon" href="/favicon.ico" />
<style>
body { margin: 0; padding: 0; font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, sans-serif; }
#redoc-container { min-height: 100vh; }
.or-fallback { padding: 24px; max-width: 800px; margin: 64px auto; line-height: 1.6; color: #1a1a1a; }
.or-fallback h1 { font-size: 24px; margin-bottom: 12px; }
.or-fallback a { color: #0066cc; }
.or-fallback code { background: #f4f4f4; padding: 2px 6px; border-radius: 3px; font-size: 13px; }
</style>
</head>
<body>
<noscript>
<div class="or-fallback">
<h1>JavaScript required</h1>
<p>Redoc needs JavaScript to render the OpenAPI spec. The raw spec is also
<a href="/openapi.yaml">available as YAML</a>.</p>
</div>
</noscript>
<div id="redoc-container"></div>
<script src="https://cdn.redocly.com/redoc/latest/bundles/redoc.standalone.js"></script>
<script>
// Redoc 2.x global API. Falls back gracefully if the CDN is blocked.
if (typeof Redoc !== "undefined") {
Redoc.init(
"/openapi.yaml",
{
scrollYOffset: 0,
hideDownloadButton: false,
expandResponses: "200,201",
jsonSampleExpandLevel: 2,
pathInMiddlePanel: true,
requiredPropsFirst: true,
sortPropsAlphabetically: false,
theme: {
colors: { primary: { main: "#0066cc" } },
typography: { fontSize: "15px", fontFamily: "-apple-system, BlinkMacSystemFont, Segoe UI, Roboto, sans-serif" },
},
},
document.getElementById("redoc-container")
);
} else {
document.getElementById("redoc-container").innerHTML =
'<div class="or-fallback"><h1>Redoc CDN unreachable</h1>' +
'<p>The Redoc bundle at <code>cdn.redocly.com</code> did not load. The raw spec is still ' +
'<a href="/openapi.yaml">available as YAML</a>, and you can render it locally with any ' +
'OpenAPI viewer (e.g. <code>npx @redocly/cli preview-docs docs/openapi.yaml</code>).</p></div>';
}
</script>
</body>
</html>
`;
export function GET() {
return new Response(REDOC_HTML, {
status: 200,
headers: {
"Content-Type": "text/html; charset=utf-8",
"Cache-Control": "public, max-age=300, s-maxage=300",
"X-Robots-Tag": "noindex",
},
});
}

View File

@@ -11,11 +11,12 @@ import { sanitizeErrorMessage } from "@omniroute/open-sse/utils/error";
let cachedSpec: { data: any; mtime: number } | null = null;
const OPENAPI_SPEC_CANDIDATES = [
path.join(/* turbopackIgnore: true */ process.cwd(), "docs", "reference", "openapi.yaml"),
path.join(/* turbopackIgnore: true */ process.cwd(), "app", "docs", "reference", "openapi.yaml"),
// Legacy locations kept as fallback for old standalone bundles.
path.join(/* turbopackIgnore: true */ process.cwd(), "docs", "openapi.yaml"),
path.join(/* turbopackIgnore: true */ process.cwd(), "app", "docs", "openapi.yaml"),
// Legacy locations kept as fallback for old standalone bundles (pre-#4781 move
// from docs/reference/openapi.yaml to the canonical docs/openapi.yaml).
path.join(/* turbopackIgnore: true */ process.cwd(), "docs", "reference", "openapi.yaml"),
path.join(/* turbopackIgnore: true */ process.cwd(), "app", "docs", "reference", "openapi.yaml"),
];
/**

View File

@@ -1,7 +1,7 @@
// AUTO-GENERATED by scripts/docs/gen-openapi-module.mjs — DO NOT EDIT MANUALLY
// Regenerate with: node scripts/docs/gen-openapi-module.mjs
//
// Source of truth: docs/reference/openapi.yaml
// Source of truth: docs/openapi.yaml
//
// The Api Explorer consumes `OPENAPI_ENDPOINTS`; the spec metadata
// (`OPENAPI_VERSION`, `OPENAPI_TITLE`) is surfaced in the page header.
@@ -25,7 +25,7 @@ export interface OpenApiEndpoint {
hasRequestBody: boolean;
}
export const OPENAPI_VERSION = "3.8.24";
export const OPENAPI_VERSION = "3.8.35";
export const OPENAPI_TITLE = "OmniRoute API";
export const OPENAPI_ENDPOINTS: OpenApiEndpoint[] = [
@@ -173,8 +173,7 @@ export const OPENAPI_ENDPOINTS: OpenApiEndpoint[] = [
path: "/api/v1/providers/{provider}/models",
method: "GET",
summary: "List models for a specific provider",
description:
"Returns only models for the selected provider with provider prefix removed from each model id.",
description: "Returns only models for the selected provider with provider prefix removed from each model id.",
tag: "Models",
tags: ["Models"],
requiresAuth: true,
@@ -200,6 +199,16 @@ export const OPENAPI_ENDPOINTS: OpenApiEndpoint[] = [
requiresAuth: true,
hasRequestBody: true,
},
{
path: "/api/v1/ws",
method: "GET",
summary: "Chat completion over WebSocket (handshake + upgrade)",
description: "OpenAI-compatible chat over a WebSocket connection. `GET` with `?handshake=1` returns the connection descriptor (auth path, message protocol and live-event channels) as JSON; a plain `GET` without an Upgrade returns `426 Upgrade Required`. After upgrading, the client exchanges JSON frames — `{type:\"request\", id, payload:{model, messages}}` to start a completion and `{type:\"cancel\", id}` to abort it. A separate live channel (default port `LIVE_WS_PORT=20129`, path `/live`) streams dashboard events on the `requests`, `combo` and `credentials` topics with a 15s heartbeat. Requires an API key.",
tag: "Chat",
tags: ["Chat"],
requiresAuth: true,
hasRequestBody: false,
},
{
path: "/api/v1beta/models",
method: "GET",

View File

@@ -124,7 +124,7 @@ function buildApiBody(skill: AgentSkill, sources: BuildSources): string {
lines.push("## Payloads\n");
lines.push(
"See the full OpenAPI specification at `GET /api/openapi/spec` or " +
"`docs/reference/openapi.yaml` for detailed request/response schemas.",
"`docs/openapi.yaml` for detailed request/response schemas.",
);
lines.push("");

View File

@@ -1,5 +1,5 @@
/**
* openapiParser.ts — parses docs/reference/openapi.yaml to extract endpoint info
* openapiParser.ts — parses docs/openapi.yaml to extract endpoint info
* grouped by SkillArea. Used by the catalog and the generator.
*
* Reads the OpenAPI YAML synchronously at runtime (same pattern as
@@ -139,7 +139,7 @@ function extractOperations(pathsObj: Record<string, any>): OpenapiPath[] {
}
/**
* Parses `docs/reference/openapi.yaml` and returns:
* Parses `docs/openapi.yaml` and returns:
* - `paths`: all operations keyed by `"METHOD /path"`
* - `areas`: operations grouped by SkillArea (api skills only)
*
@@ -147,7 +147,7 @@ function extractOperations(pathsObj: Record<string, any>): OpenapiPath[] {
* and standalone scripts without async machinery.
*/
export function parseOpenapi(): ParsedOpenapi {
const yamlPath = path.resolve(process.cwd(), "docs", "reference", "openapi.yaml");
const yamlPath = path.resolve(process.cwd(), "docs", "openapi.yaml");
let rawContent: string;
try {

View File

@@ -309,7 +309,7 @@ describe("API Routes — dashboard and tool consumers", () => {
it("keeps legacy usage history and raw request-log APIs explicitly classified", () => {
const usageStats = readProjectFile("src/shared/components/UsageStats.tsx");
const apiReference = readProjectFile("docs/reference/API_REFERENCE.md");
const openApi = readProjectFile("docs/reference/openapi.yaml");
const openApi = readProjectFile("docs/openapi.yaml");
assert.ok(usageStats, "UsageStats compatibility component should exist");
assert.ok(apiReference, "API reference should exist");
@@ -359,7 +359,7 @@ describe("Dashboard Wiring — T05 payload rules", () => {
const payloadRulesTabSrc = readProjectFile(
"src/app/(dashboard)/dashboard/settings/components/PayloadRulesTab.tsx"
);
const openapiSrc = readProjectFile("docs/reference/openapi.yaml");
const openapiSrc = readProjectFile("docs/openapi.yaml");
it.skip("settings page should surface payload rules inside advanced settings", () => {
assert.ok(settingsPageSrc, "settings page source should exist");
@@ -379,7 +379,7 @@ describe("Dashboard Wiring — T05 payload rules", () => {
});
it("openapi should document the payload rules management surface", () => {
assert.ok(openapiSrc, "docs/reference/openapi.yaml should exist");
assert.ok(openapiSrc, "docs/openapi.yaml should exist");
assert.match(openapiSrc, /\/api\/settings\/payload-rules:/);
assert.match(openapiSrc, /summary:\s+Get payload rules configuration/);
assert.match(openapiSrc, /ManagementSessionAuth:/);

View File

@@ -0,0 +1,24 @@
import test from "node:test";
import assert from "node:assert/strict";
// GET /api/docs serves the Redoc-rendered API reference (#4781). Static HTML
// shell that loads Redoc from a CDN and points it at /openapi.yaml (the
// canonical spec served from public/openapi.yaml). PUBLIC tier — no auth.
const docsRoute = await import("../../src/app/api/docs/route.ts");
test("GET /api/docs returns a 200 text/html Redoc shell", async () => {
const response = docsRoute.GET();
assert.equal(response.status, 200);
assert.match(response.headers.get("content-type") ?? "", /text\/html/);
const body = await response.text();
// Renders Redoc and points it at the canonical spec.
assert.match(body, /redoc/i);
assert.ok(body.includes("/openapi.yaml"), "Redoc must load the canonical /openapi.yaml spec");
// No stack traces / secrets leaked into the static shell.
assert.ok(!body.includes("at /"), "static shell must not leak stack-trace frames");
});
test("GET /api/docs is statically renderable (no per-request work)", () => {
assert.equal(docsRoute.dynamic, "force-static");
});

View File

@@ -75,7 +75,7 @@ test("raw HTTP guard allows documented methods through", () => {
});
test("OpenAPI documents high-risk route auth and setup responses", () => {
const spec = readFileSync("docs/reference/openapi.yaml", "utf8");
const spec = readFileSync("docs/openapi.yaml", "utf8");
const apiKeyDetailStart = spec.indexOf(" /api/keys/{id}:");
const apiKeyDetailEnd = spec.indexOf("\n /api/combos:", apiKeyDetailStart);
const apiKeyDetail = spec.slice(apiKeyDetailStart, apiKeyDetailEnd);

View File

@@ -6,7 +6,7 @@ import * as yaml from "js-yaml";
const ROOT = process.cwd();
const API_ROOT = path.join(ROOT, "src", "app", "api");
const OPENAPI_PATH = path.join(ROOT, "docs", "reference", "openapi.yaml");
const OPENAPI_PATH = path.join(ROOT, "docs", "openapi.yaml");
function collectRoutePaths(dir: string): string[] {
const entries = fs.readdirSync(dir, { withFileTypes: true });

View File

@@ -5,7 +5,7 @@ import path from "node:path";
import * as yaml from "js-yaml";
const ROOT = process.cwd();
const OPENAPI_PATH = path.join(ROOT, "docs", "reference", "openapi.yaml");
const OPENAPI_PATH = path.join(ROOT, "docs", "openapi.yaml");
const { LOCAL_ONLY_API_PREFIXES, ALWAYS_PROTECTED_API_PATHS } =
await import("../../src/server/authz/routeGuard.ts");

View File

@@ -11,7 +11,7 @@ import * as yaml from "js-yaml";
// in the spec, so it was invisible in the endpoints reference.
const ROOT = fileURLToPath(new URL("../../", import.meta.url));
const spec = yaml.load(readFileSync(ROOT + "docs/reference/openapi.yaml", "utf8")) as {
const spec = yaml.load(readFileSync(ROOT + "docs/openapi.yaml", "utf8")) as {
paths: Record<string, Record<string, { tags?: string[]; security?: unknown[]; responses?: Record<string, unknown> }>>;
};