v0.4.1: Code-driven OpenAPI docs via swagger-jsdoc
Some checks failed
Build & Deploy to Staging / Build & Deploy to Staging (push) Has been cancelled

- Add swagger-jsdoc dependency for auto-generating OpenAPI spec from JSDoc
- Add JSDoc @openapi annotations to all route handlers
- Create scripts/generate-openapi.mjs build step
- OpenAPI spec now auto-generated from code — no manual JSON editing
- All 13 endpoints documented with full parameters
- New demo endpoints documented, signup marked as deprecated
- Updated info description: demo-first, no free tier references
- Dockerfile updated to run openapi generation during build
- Build script updated: npm run build generates spec before compile
This commit is contained in:
DocFast Bot 2026-02-20 07:54:37 +00:00
parent 53755d6093
commit 792e2d9142
12 changed files with 1931 additions and 305 deletions

View file

@ -49,7 +49,55 @@ interface ConvertBody {
filename?: string;
}
// POST /v1/convert/html
/**
* @openapi
* /v1/convert/html:
* post:
* tags: [Conversion]
* summary: Convert HTML to PDF
* description: Converts HTML content to a PDF document. Bare HTML fragments are automatically wrapped in a full HTML document.
* security:
* - BearerAuth: []
* - ApiKeyHeader: []
* requestBody:
* required: true
* content:
* application/json:
* schema:
* allOf:
* - type: object
* required: [html]
* properties:
* html:
* type: string
* description: HTML content to convert. Can be a full document or a fragment.
* example: '<h1>Hello World</h1><p>My first PDF</p>'
* css:
* type: string
* description: Optional CSS to inject (only used when html is a fragment, not a full document)
* example: 'body { font-family: sans-serif; padding: 40px; }'
* - $ref: '#/components/schemas/PdfOptions'
* responses:
* 200:
* description: PDF document
* content:
* application/pdf:
* schema:
* type: string
* format: binary
* 400:
* description: Missing html field
* 401:
* description: Missing API key
* 403:
* description: Invalid API key
* 415:
* description: Unsupported Content-Type (must be application/json)
* 429:
* description: Rate limit or usage limit exceeded
* 500:
* description: PDF generation failed
*/
convertRouter.post("/html", async (req: Request & { acquirePdfSlot?: () => Promise<void>; releasePdfSlot?: () => void }, res: Response) => {
let slotAcquired = false;
try {
@ -103,7 +151,54 @@ convertRouter.post("/html", async (req: Request & { acquirePdfSlot?: () => Promi
}
});
// POST /v1/convert/markdown
/**
* @openapi
* /v1/convert/markdown:
* post:
* tags: [Conversion]
* summary: Convert Markdown to PDF
* description: Converts Markdown content to HTML and then to a PDF document.
* security:
* - BearerAuth: []
* - ApiKeyHeader: []
* requestBody:
* required: true
* content:
* application/json:
* schema:
* allOf:
* - type: object
* required: [markdown]
* properties:
* markdown:
* type: string
* description: Markdown content to convert
* example: '# Hello World\n\nThis is **bold** and *italic*.'
* css:
* type: string
* description: Optional CSS to inject into the rendered HTML
* - $ref: '#/components/schemas/PdfOptions'
* responses:
* 200:
* description: PDF document
* content:
* application/pdf:
* schema:
* type: string
* format: binary
* 400:
* description: Missing markdown field
* 401:
* description: Missing API key
* 403:
* description: Invalid API key
* 415:
* description: Unsupported Content-Type
* 429:
* description: Rate limit or usage limit exceeded
* 500:
* description: PDF generation failed
*/
convertRouter.post("/markdown", async (req: Request & { acquirePdfSlot?: () => Promise<void>; releasePdfSlot?: () => void }, res: Response) => {
let slotAcquired = false;
try {
@ -153,7 +248,59 @@ convertRouter.post("/markdown", async (req: Request & { acquirePdfSlot?: () => P
}
});
// POST /v1/convert/url
/**
* @openapi
* /v1/convert/url:
* post:
* tags: [Conversion]
* summary: Convert URL to PDF
* description: |
* Fetches a URL and converts the rendered page to PDF. JavaScript is disabled for security.
* Private/internal IP addresses are blocked (SSRF protection). DNS is pinned to prevent rebinding.
* security:
* - BearerAuth: []
* - ApiKeyHeader: []
* requestBody:
* required: true
* content:
* application/json:
* schema:
* allOf:
* - type: object
* required: [url]
* properties:
* url:
* type: string
* format: uri
* description: URL to convert (http or https only)
* example: 'https://example.com'
* waitUntil:
* type: string
* enum: [load, domcontentloaded, networkidle0, networkidle2]
* default: domcontentloaded
* description: When to consider navigation finished
* - $ref: '#/components/schemas/PdfOptions'
* responses:
* 200:
* description: PDF document
* content:
* application/pdf:
* schema:
* type: string
* format: binary
* 400:
* description: Missing/invalid URL or URL resolves to private IP
* 401:
* description: Missing API key
* 403:
* description: Invalid API key
* 415:
* description: Unsupported Content-Type
* 429:
* description: Rate limit or usage limit exceeded
* 500:
* description: PDF generation failed
*/
convertRouter.post("/url", async (req: Request & { acquirePdfSlot?: () => Promise<void>; releasePdfSlot?: () => void }, res: Response) => {
let slotAcquired = false;
try {