diff --git a/actions/swagger.ts b/actions/swagger.ts index 9d5dbfc..17bda30 100644 --- a/actions/swagger.ts +++ b/actions/swagger.ts @@ -47,7 +47,10 @@ export class Swagger implements Action { }, host: `${config.server.web.host}:${config.server.web.port}`, basePath: `${config.server.web.apiRoute}/`, - schemes: ["https", "http"], + schemes: + ["0.0.0.0", "localhost"].indexOf(config.server.web.host) >= 0 + ? ["http"] + : ["https", "http"], paths: swaggerPaths, securityDefinitions: { @@ -76,12 +79,37 @@ function buildSwaggerPaths() { if (!swaggerPaths[formattedPath]) swaggerPaths[formattedPath] = {}; swaggerPaths[formattedPath][method] = { - summary: action.description || "no description", + summary: action.description || action.name, consumes: ["application/json"], produces: ["application/json"], responses: swaggerResponses, security: [], - parameters: [], //TODO + parameters: Object.keys(action.inputs) + .sort() + .map((inputName) => { + return { + // in: action?.web?.route.toString().includes(`:${inputName}`) + // ? "path" + // : "query", + in: "query", + name: inputName, + type: "string", // not really true, but helps the swagger validator + required: action.inputs[inputName].required ?? false, + // || + // route.path.includes(`:${inputName}`) + // ? true + // : false + default: + action.inputs[inputName].default !== null && + action.inputs[inputName].default !== undefined + ? typeof action.inputs[inputName].default === "object" + ? JSON.stringify(action.inputs[inputName].default) + : typeof action.inputs[inputName].default === "function" + ? action.inputs[inputName].default() + : `${action.inputs[inputName].default}` + : undefined, + }; + }), }; } diff --git a/bun.lockb b/bun.lockb index a17ac04..5305a79 100755 Binary files a/bun.lockb and b/bun.lockb differ diff --git a/components/SwaggerCard.tsx b/components/SwaggerCard.tsx index bce9d24..1a4d73f 100644 --- a/components/SwaggerCard.tsx +++ b/components/SwaggerCard.tsx @@ -1,10 +1,21 @@ -import { Card } from "react-bootstrap"; +import { useEffect } from "react"; + +declare var SwaggerUIBundle: any; // imported via the layout export const SwaggerCard = () => { - return ( - - API Endpoints - - - ); + useEffect(() => { + SwaggerUIBundle({ + dom_id: "#swaggerContainer", + url: `/api/swagger`, + presets: [ + SwaggerUIBundle.presets.apis, + SwaggerUIBundle.SwaggerUIStandalonePreset, + ], + deepLinking: true, + docExpansion: "none", + filter: true, + }); + }, []); + + return
; }; diff --git a/initializers/react.ts b/initializers/react.ts index 45ba565..0af7bc9 100644 --- a/initializers/react.ts +++ b/initializers/react.ts @@ -93,8 +93,13 @@ const transpileAllPages = async (pages: string[]) => { await unlink(path.join(transpiledPagesDir, f)); } - await Bun.build({ + const result = await Bun.build({ ...{ entrypoints: pages }, ...transpilerOptions, }); + + if (!result.success) { + logger.fatal("Build failed"); + for (const message of result.logs) console.error(message); + } }; diff --git a/layouts/swagger.tsx b/layouts/swagger.tsx new file mode 100644 index 0000000..0741f70 --- /dev/null +++ b/layouts/swagger.tsx @@ -0,0 +1,34 @@ +import React from "react"; + +export type LayoutProps = { + title: string; +}; + +const swaggerVersion = "5.13.0"; + +export const SwaggerLayout = (props: React.PropsWithChildren) => { + return ( + + + + + + + + + + {props.title} + + {props.children} + + + ); +}; diff --git a/pages/index.tsx b/pages/index.tsx index 51aa409..a7450b4 100644 --- a/pages/index.tsx +++ b/pages/index.tsx @@ -4,14 +4,15 @@ import { mount } from "../util/browser"; import { StatusCard } from "../components/StatusCard"; import { MainLayout } from "../layouts/main"; import { HelloCard } from "../components/HelloCard"; -import { SwaggerCard } from "../components/SwaggerCard"; export default function Page() { return (

Hello World

-

sups.

+

+ View API Endpoints +


@@ -21,12 +22,6 @@ export default function Page() { -
- - - - -
); diff --git a/pages/swagger.tsx b/pages/swagger.tsx new file mode 100644 index 0000000..f09eac1 --- /dev/null +++ b/pages/swagger.tsx @@ -0,0 +1,20 @@ +import { Container, Row, Col } from "react-bootstrap"; +import { mount } from "../util/browser"; +import { SwaggerLayout } from "../layouts/swagger"; +import { SwaggerCard } from "../components/SwaggerCard"; + +export default function Page() { + return ( + + + + + + + + + + ); +} + +mount(Page); diff --git a/servers/web.ts b/servers/web.ts index c6f9836..9b7d4ee 100644 --- a/servers/web.ts +++ b/servers/web.ts @@ -100,6 +100,10 @@ export class WebServer extends Server> { } catch {} } + for (const [key, value] of url.searchParams) { + params.set(key, value); + } + const { response, error } = await connection.act( actionName, params,