| |
| |
| |
|
|
|
|
| import { NextResponse } from "next/server";
|
| import fs from "fs";
|
| import path from "path";
|
| import yaml from "js-yaml";
|
| import { sanitizeErrorMessage } from "@omniroute/open-sse/utils/error";
|
|
|
| let cachedSpec: { data: any; mtime: number } | null = null;
|
| const OPENAPI_SPEC_CANDIDATES = [
|
| path.join( process.cwd(), "docs", "reference", "openapi.yaml"),
|
| path.join( process.cwd(), "app", "docs", "reference", "openapi.yaml"),
|
|
|
| path.join( process.cwd(), "docs", "openapi.yaml"),
|
| path.join( process.cwd(), "app", "docs", "openapi.yaml"),
|
| ];
|
|
|
| export async function GET() {
|
| try {
|
| let specPath = "";
|
| for (const p of OPENAPI_SPEC_CANDIDATES) {
|
| if (fs.existsSync(p)) {
|
| specPath = p;
|
| break;
|
| }
|
| }
|
|
|
| if (!specPath) {
|
| return NextResponse.json({ error: "openapi.yaml not found" }, { status: 404 });
|
| }
|
|
|
| const stat = fs.statSync(specPath);
|
| const mtime = stat.mtimeMs;
|
|
|
|
|
| if (cachedSpec && cachedSpec.mtime === mtime) {
|
| return NextResponse.json(cachedSpec.data);
|
| }
|
|
|
| const content = fs.readFileSync(specPath, "utf-8");
|
| const raw: any = yaml.load(content);
|
|
|
|
|
| const catalog: any = {
|
| info: raw.info || {},
|
| servers: raw.servers || [],
|
| tags: Array.isArray(raw.tags) ? raw.tags : [],
|
| endpoints: [] as any[],
|
| schemas: Object.keys(raw.components?.schemas || {}),
|
| };
|
|
|
|
|
| const paths = raw.paths || {};
|
| for (const [pathStr, methods] of Object.entries(paths as Record<string, any>)) {
|
| if (!methods || typeof methods !== "object") continue;
|
| for (const [method, spec] of Object.entries(methods as Record<string, any>)) {
|
| if (["get", "post", "put", "patch", "delete"].includes(method) && spec) {
|
| catalog.endpoints.push({
|
| method: method.toUpperCase(),
|
| path: pathStr,
|
| tags: Array.isArray(spec.tags) ? spec.tags : [],
|
| summary: spec.summary || "",
|
| description: spec.description || "",
|
| security: spec.security ? true : false,
|
| parameters: spec.parameters || [],
|
| requestBody: spec.requestBody ? true : false,
|
| responses: Object.keys(spec.responses || {}),
|
| loopbackOnly: spec["x-loopback-only"] === true,
|
| alwaysProtected: spec["x-always-protected"] === true,
|
| internal: spec["x-internal"] === true,
|
| });
|
| }
|
| }
|
| }
|
|
|
| cachedSpec = { data: catalog, mtime };
|
|
|
| return NextResponse.json(catalog);
|
| } catch (error: any) {
|
| return NextResponse.json(
|
| { error: sanitizeErrorMessage(error) || "Failed to parse OpenAPI spec" },
|
| { status: 500 }
|
| );
|
| }
|
| }
|
|
|