mirror of
https://github.com/diegosouzapw/OmniRoute.git
synced 2026-07-31 04:12:10 +03:00
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:
4
.github/workflows/ci.yml
vendored
4
.github/workflows/ci.yml
vendored
@@ -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
|
||||
|
||||
2
.github/workflows/dast-smoke.yml
vendored
2
.github/workflows/dast-smoke.yml
vendored
@@ -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
|
||||
|
||||
2
.github/workflows/nightly-schemathesis.yml
vendored
2
.github/workflows/nightly-schemathesis.yml
vendored
@@ -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 \
|
||||
|
||||
@@ -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) |
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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` |
|
||||
|
||||
@@ -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 |
|
||||
|
||||
@@ -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";
|
||||
|
||||
@@ -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";
|
||||
|
||||
@@ -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";
|
||||
|
||||
@@ -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";
|
||||
|
||||
@@ -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";
|
||||
|
||||
@@ -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";
|
||||
|
||||
@@ -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";
|
||||
|
||||
@@ -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";
|
||||
|
||||
@@ -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";
|
||||
|
||||
@@ -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";
|
||||
|
||||
@@ -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";
|
||||
|
||||
@@ -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";
|
||||
|
||||
@@ -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";
|
||||
|
||||
@@ -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";
|
||||
|
||||
@@ -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";
|
||||
|
||||
@@ -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";
|
||||
|
||||
@@ -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";
|
||||
|
||||
@@ -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";
|
||||
|
||||
@@ -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";
|
||||
|
||||
@@ -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";
|
||||
|
||||
@@ -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";
|
||||
|
||||
@@ -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";
|
||||
|
||||
@@ -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";
|
||||
|
||||
@@ -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";
|
||||
|
||||
@@ -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";
|
||||
|
||||
@@ -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";
|
||||
|
||||
@@ -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";
|
||||
|
||||
@@ -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";
|
||||
|
||||
@@ -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";
|
||||
|
||||
@@ -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";
|
||||
|
||||
@@ -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";
|
||||
|
||||
@@ -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.
|
||||
|
||||
@@ -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
|
||||
|
||||
|
||||
@@ -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** |
|
||||
|
||||
---
|
||||
|
||||
|
||||
@@ -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.
|
||||
|
||||
@@ -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`.
|
||||
|
||||
---
|
||||
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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`.
|
||||
|
||||
@@ -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.
|
||||
|
||||
@@ -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**
|
||||
|
||||
@@ -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
|
||||
|
||||
|
||||
@@ -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
6690
public/openapi.yaml
Normal file
File diff suppressed because it is too large
Load Diff
@@ -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
|
||||
|
||||
@@ -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 {
|
||||
|
||||
@@ -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.
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -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([
|
||||
|
||||
@@ -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) {
|
||||
|
||||
@@ -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.
|
||||
|
||||
@@ -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.
|
||||
|
||||
@@ -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) {
|
||||
|
||||
@@ -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) -->
|
||||
|
||||
@@ -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.
|
||||
|
||||
@@ -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) -->
|
||||
|
||||
@@ -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.
|
||||
|
||||
@@ -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.
|
||||
|
||||
@@ -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.
|
||||
|
||||
@@ -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) -->
|
||||
|
||||
@@ -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) -->
|
||||
|
||||
@@ -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.
|
||||
|
||||
@@ -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.
|
||||
|
||||
@@ -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 -->
|
||||
|
||||
@@ -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) -->
|
||||
|
||||
@@ -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.
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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.
|
||||
|
||||
@@ -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) -->
|
||||
|
||||
@@ -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.
|
||||
|
||||
@@ -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.
|
||||
|
||||
@@ -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.
|
||||
|
||||
@@ -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.
|
||||
|
||||
@@ -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.
|
||||
|
||||
@@ -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
89
src/app/api/docs/route.ts
Normal 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",
|
||||
},
|
||||
});
|
||||
}
|
||||
@@ -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"),
|
||||
];
|
||||
|
||||
/**
|
||||
|
||||
@@ -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",
|
||||
|
||||
@@ -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("");
|
||||
|
||||
|
||||
@@ -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 {
|
||||
|
||||
@@ -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:/);
|
||||
|
||||
24
tests/unit/api-docs-route.test.ts
Normal file
24
tests/unit/api-docs-route.test.ts
Normal 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");
|
||||
});
|
||||
@@ -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);
|
||||
|
||||
@@ -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 });
|
||||
|
||||
@@ -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");
|
||||
|
||||
@@ -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> }>>;
|
||||
};
|
||||
|
||||
|
||||
Reference in New Issue
Block a user