| |
| |
| |
| |
| |
| |
| |
|
|
|
|
| import fs from "node:fs";
|
| import path from "node:path";
|
| import yaml from "js-yaml";
|
| import type { SkillArea } from "./types";
|
|
|
|
|
|
|
| export interface OpenapiPath {
|
|
|
| method: string;
|
|
|
| path: string;
|
|
|
| summary: string;
|
|
|
| description?: string;
|
|
|
| tags: string[];
|
| }
|
|
|
| export interface ParsedOpenapi {
|
|
|
| paths: Map<string, OpenapiPath>;
|
|
|
| areas: Map<SkillArea, OpenapiPath[]>;
|
| }
|
|
|
|
|
|
|
| |
| |
| |
|
|
| const PATH_AREA_MAP: Array<[string, SkillArea]> = [
|
|
|
| ["/api/auth", "auth"],
|
| ["/api/session", "auth"],
|
|
|
| ["/api/providers", "providers"],
|
| ["/api/provider-nodes", "providers"],
|
| ["/api/provider-models", "providers"],
|
|
|
| ["/api/v1/models", "models"],
|
| ["/api/models", "models"],
|
|
|
| ["/api/combos", "combos-routing"],
|
| ["/api/fallback", "combos-routing"],
|
|
|
| ["/api/keys", "api-keys"],
|
|
|
| ["/api/usage", "usage-logs"],
|
|
|
| ["/api/rate-limit", "budget"],
|
| ["/api/budget", "budget"],
|
|
|
| ["/api/settings", "settings"],
|
| ["/api/tags", "settings"],
|
|
|
| ["/api/settings/proxy", "proxies"],
|
|
|
| ["/api/cache", "cache"],
|
|
|
| ["/api/settings/compression", "compression"],
|
| ["/api/compression", "compression"],
|
| ["/api/context/rtk", "context-rtk"],
|
|
|
| ["/api/monitoring", "resilience"],
|
| ["/api/provider-metrics", "resilience"],
|
| ["/api/circuit-breakers", "resilience"],
|
|
|
| ["/api/cli-tools", "cli-tools"],
|
|
|
| ["/api/tunnel", "tunnels"],
|
|
|
| ["/api/cloud", "sync-cloud"],
|
| ["/api/sync", "sync-cloud"],
|
|
|
| ["/api/system", "db-backups"],
|
| ["/api/backup", "db-backups"],
|
|
|
| ["/api/webhooks", "webhooks"],
|
|
|
| ["/api/mcp", "mcp"],
|
|
|
| ["/a2a", "agents-a2a"],
|
|
|
| ["/api/services", "version-manager"],
|
| ["/api/version", "version-manager"],
|
|
|
| ["/api/v1", "inference"],
|
| ];
|
|
|
|
|
|
|
| const HTTP_METHODS = ["get", "post", "put", "patch", "delete", "head", "options"] as const;
|
|
|
|
|
|
|
| function resolveArea(urlPath: string): SkillArea | null {
|
| for (const [prefix, area] of PATH_AREA_MAP) {
|
| if (urlPath === prefix || urlPath.startsWith(prefix + "/") || urlPath.startsWith(prefix + "{")) {
|
| return area;
|
| }
|
| }
|
| return null;
|
| }
|
|
|
|
|
| function extractOperations(pathsObj: Record<string, any>): OpenapiPath[] {
|
| const ops: OpenapiPath[] = [];
|
|
|
| for (const [urlPath, pathItem] of Object.entries(pathsObj)) {
|
| if (!pathItem || typeof pathItem !== "object") continue;
|
|
|
| for (const method of HTTP_METHODS) {
|
| const operation = pathItem[method];
|
| if (!operation || typeof operation !== "object") continue;
|
|
|
| ops.push({
|
| method: method.toUpperCase(),
|
| path: urlPath,
|
| summary: String(operation.summary ?? ""),
|
| description: operation.description ? String(operation.description) : undefined,
|
| tags: Array.isArray(operation.tags) ? operation.tags.map(String) : [],
|
| });
|
| }
|
| }
|
|
|
| return ops;
|
| }
|
|
|
| |
| |
| |
| |
| |
| |
| |
|
|
| export function parseOpenapi(): ParsedOpenapi {
|
| const yamlPath = path.resolve(process.cwd(), "docs", "reference", "openapi.yaml");
|
| let rawContent: string;
|
|
|
| try {
|
| rawContent = fs.readFileSync(yamlPath, "utf-8");
|
| } catch (err) {
|
| throw new Error(
|
| `openapiParser: could not read ${yamlPath}. ` +
|
| `Run from project root. Underlying error: ${err instanceof Error ? err.message : String(err)}`,
|
| );
|
| }
|
|
|
|
|
| const doc = yaml.load(rawContent) as Record<string, any>;
|
|
|
| if (!doc || typeof doc !== "object") {
|
| throw new Error("openapiParser: parsed YAML is not an object");
|
| }
|
|
|
| const pathsObj = doc.paths ?? {};
|
| const operations = extractOperations(pathsObj);
|
|
|
| const paths = new Map<string, OpenapiPath>();
|
| const areas = new Map<SkillArea, OpenapiPath[]>();
|
|
|
| for (const op of operations) {
|
| const key = `${op.method} ${op.path}`;
|
| paths.set(key, op);
|
|
|
| const area = resolveArea(op.path);
|
| if (area) {
|
| if (!areas.has(area)) {
|
| areas.set(area, []);
|
| }
|
| areas.get(area)!.push(op);
|
| }
|
| }
|
|
|
| return { paths, areas };
|
| }
|
|
|
| |
| |
| |
|
|
| export function getEndpointsForArea(area: SkillArea): string[] {
|
| const { areas } = parseOpenapi();
|
| const ops = areas.get(area) ?? [];
|
| return ops.map((op) => `${op.method} ${op.path}`);
|
| }
|
|
|