fix: code-driven OpenAPI docs — replace static JSON with swagger-jsdoc
Some checks failed
Deploy to Staging / build-and-deploy (push) Failing after 10m13s
Some checks failed
Deploy to Staging / build-and-deploy (push) Failing after 10m13s
BREAKING: OpenAPI spec is now generated from JSDoc annotations on route handlers at startup, eliminating drift between code and documentation. What was wrong: - Static public/openapi.json was manually maintained and could drift - Missing endpoints: signup, billing (checkout/success/webhook) - Signup route was imported but never mounted (dead code) What was fixed: - Added swagger-jsdoc to generate OpenAPI spec from JSDoc on route files - Every route handler now has @openapi JSDoc annotation as source of truth - Spec served dynamically at GET /openapi.json (no static file) - Deleted public/openapi.json - Documented all missing endpoints (signup, billing x3) - Mounted /v1/signup route - All 9 screenshot params documented with types, ranges, defaults
This commit is contained in:
parent
a70157d0ae
commit
713cc30ac7
10 changed files with 700 additions and 124 deletions
|
|
@ -4,6 +4,123 @@ import logger from "../services/logger.js";
|
|||
|
||||
export const screenshotRouter = Router();
|
||||
|
||||
/**
|
||||
* @openapi
|
||||
* /v1/screenshot:
|
||||
* post:
|
||||
* tags: [Screenshots]
|
||||
* summary: Take a screenshot (authenticated)
|
||||
* description: Capture a pixel-perfect, unwatermarked screenshot. Requires an API key.
|
||||
* operationId: takeScreenshot
|
||||
* security:
|
||||
* - BearerAuth: []
|
||||
* - ApiKeyAuth: []
|
||||
* requestBody:
|
||||
* required: true
|
||||
* content:
|
||||
* application/json:
|
||||
* schema:
|
||||
* type: object
|
||||
* required: [url]
|
||||
* properties:
|
||||
* url:
|
||||
* type: string
|
||||
* format: uri
|
||||
* description: URL to capture
|
||||
* example: "https://example.com"
|
||||
* format:
|
||||
* type: string
|
||||
* enum: [png, jpeg, webp]
|
||||
* default: png
|
||||
* description: Output image format
|
||||
* width:
|
||||
* type: integer
|
||||
* minimum: 320
|
||||
* maximum: 3840
|
||||
* default: 1280
|
||||
* description: Viewport width in pixels
|
||||
* height:
|
||||
* type: integer
|
||||
* minimum: 200
|
||||
* maximum: 2160
|
||||
* default: 800
|
||||
* description: Viewport height in pixels
|
||||
* fullPage:
|
||||
* type: boolean
|
||||
* default: false
|
||||
* description: Capture full scrollable page instead of viewport only
|
||||
* quality:
|
||||
* type: integer
|
||||
* minimum: 1
|
||||
* maximum: 100
|
||||
* default: 80
|
||||
* description: JPEG/WebP quality (ignored for PNG)
|
||||
* waitForSelector:
|
||||
* type: string
|
||||
* description: CSS selector to wait for before capturing (e.g. "#main-content")
|
||||
* deviceScale:
|
||||
* type: number
|
||||
* minimum: 1
|
||||
* maximum: 3
|
||||
* default: 1
|
||||
* description: Device scale factor (2 = Retina)
|
||||
* delay:
|
||||
* type: integer
|
||||
* minimum: 0
|
||||
* maximum: 5000
|
||||
* default: 0
|
||||
* description: Extra delay in ms after page load before capturing
|
||||
* examples:
|
||||
* simple:
|
||||
* summary: Simple screenshot
|
||||
* value: { "url": "https://example.com" }
|
||||
* hd_jpeg:
|
||||
* summary: HD JPEG
|
||||
* value: { "url": "https://github.com", "format": "jpeg", "width": 1920, "height": 1080, "quality": 90 }
|
||||
* mobile:
|
||||
* summary: Mobile viewport
|
||||
* value: { "url": "https://example.com", "width": 375, "height": 812, "deviceScale": 2 }
|
||||
* responses:
|
||||
* 200:
|
||||
* description: Screenshot image binary
|
||||
* content:
|
||||
* image/png:
|
||||
* schema: { type: string, format: binary }
|
||||
* image/jpeg:
|
||||
* schema: { type: string, format: binary }
|
||||
* image/webp:
|
||||
* schema: { type: string, format: binary }
|
||||
* 400:
|
||||
* description: Invalid request (bad URL, blocked domain, etc.)
|
||||
* content:
|
||||
* application/json:
|
||||
* schema: { $ref: "#/components/schemas/Error" }
|
||||
* 401:
|
||||
* description: Missing API key
|
||||
* content:
|
||||
* application/json:
|
||||
* schema: { $ref: "#/components/schemas/Error" }
|
||||
* 403:
|
||||
* description: Invalid API key
|
||||
* content:
|
||||
* application/json:
|
||||
* schema: { $ref: "#/components/schemas/Error" }
|
||||
* 429:
|
||||
* description: Rate or usage limit exceeded
|
||||
* content:
|
||||
* application/json:
|
||||
* schema: { $ref: "#/components/schemas/Error" }
|
||||
* 503:
|
||||
* description: Service busy (queue full)
|
||||
* content:
|
||||
* application/json:
|
||||
* schema: { $ref: "#/components/schemas/Error" }
|
||||
* 504:
|
||||
* description: Screenshot timed out
|
||||
* content:
|
||||
* application/json:
|
||||
* schema: { $ref: "#/components/schemas/Error" }
|
||||
*/
|
||||
screenshotRouter.post("/", async (req: any, res) => {
|
||||
const { url, format, width, height, fullPage, quality, waitForSelector, deviceScale, delay } = req.body;
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue