feat: wire up swagger-jsdoc dynamic spec, delete static openapi.json
Some checks failed
Build & Deploy to Staging / Build & Deploy to Staging (push) Has been cancelled

- Create src/swagger.ts config module for swagger-jsdoc
- Add GET /openapi.json dynamic route (generated from @openapi annotations)
- Delete static public/openapi.json (was drifting from code)
- Add @openapi annotation for deprecated /v1/signup/free in index.ts
- Import swaggerSpec into index.ts
- All 12 endpoints now code-driven: demo/html, demo/markdown, convert/html,
  convert/markdown, convert/url, templates, templates/{id}/render,
  recover, recover/verify, billing/checkout, signup/free, health
This commit is contained in:
OpenClaw 2026-02-20 07:56:56 +00:00
parent 792e2d9142
commit 825c6562ba
11 changed files with 624 additions and 1070 deletions

92
src/swagger.ts Normal file
View file

@ -0,0 +1,92 @@
import swaggerJsdoc from "swagger-jsdoc";
import { createRequire } from "module";
const _require = createRequire(import.meta.url);
const { version } = _require("../package.json");
const options: swaggerJsdoc.Options = {
definition: {
openapi: "3.0.3",
info: {
title: "DocFast API",
version,
description:
"Convert HTML, Markdown, and URLs to pixel-perfect PDFs. Built-in invoice & receipt templates.\n\n## Authentication\nAll conversion and template endpoints require an API key via `Authorization: Bearer <key>` or `X-API-Key: <key>` header.\n\n## Rate Limits\n- Free tier: 100 PDFs/month, 10 req/min\n- Pro tier: 5,000 PDFs/month, 30 req/min\n\n## Getting Started\n1. Try the demo endpoints (no auth required, 5/hour limit)\n2. Upgrade to Pro at [docfast.dev](https://docfast.dev)\n3. Use your API key to convert documents",
contact: {
name: "DocFast",
url: "https://docfast.dev",
email: "support@docfast.dev",
},
},
servers: [{ url: "https://docfast.dev", description: "Production" }],
tags: [
{ name: "Demo", description: "Try the API without authentication (watermarked, 5/hour)" },
{ name: "Conversion", description: "Convert HTML, Markdown, or URLs to PDF" },
{ name: "Templates", description: "Built-in document templates" },
{ name: "Account", description: "Signup and key recovery" },
{ name: "Billing", description: "Stripe-powered subscription management" },
{ name: "System", description: "Health checks and usage stats" },
],
components: {
securitySchemes: {
BearerAuth: {
type: "http",
scheme: "bearer",
description: "API key as Bearer token",
},
ApiKeyHeader: {
type: "apiKey",
in: "header",
name: "X-API-Key",
description: "API key via X-API-Key header",
},
},
schemas: {
PdfOptions: {
type: "object",
properties: {
format: {
type: "string",
enum: ["A4", "Letter", "Legal", "A3", "A5", "Tabloid"],
default: "A4",
description: "Page size",
},
landscape: {
type: "boolean",
default: false,
description: "Landscape orientation",
},
margin: {
type: "object",
properties: {
top: { type: "string", example: "20mm" },
bottom: { type: "string", example: "20mm" },
left: { type: "string", example: "15mm" },
right: { type: "string", example: "15mm" },
},
},
printBackground: {
type: "boolean",
default: true,
description: "Print background graphics",
},
filename: {
type: "string",
default: "document.pdf",
description: "Suggested filename for the PDF",
},
},
},
Error: {
type: "object",
properties: {
error: { type: "string", description: "Error message" },
},
},
},
},
},
apis: ["./dist/routes/*.js", "./dist/index.js"],
};
export const swaggerSpec = swaggerJsdoc(options);