fix: OpenAPI spec accuracy — hide internal endpoints, mark signup/verify deprecated
All checks were successful
Build & Deploy to Staging / Build & Deploy to Staging (push) Successful in 13m9s
All checks were successful
Build & Deploy to Staging / Build & Deploy to Staging (push) Successful in 13m9s
- Remove @openapi annotations from /v1/billing/webhook (Stripe-internal) - Remove @openapi annotations from /v1/billing/success (browser redirect) - Mark /v1/signup/verify as deprecated (returns 410) - Add 3 TDD tests in openapi-spec.test.ts - Update 2 existing tests in app-routes.test.ts - 530 tests passing (was 527)
This commit is contained in:
parent
1d5d9adf08
commit
6b1b3d584e
15 changed files with 399 additions and 290 deletions
|
|
@ -106,14 +106,12 @@ describe("App-level routes", () => {
|
|||
expect(spec.paths["/v1/signup/verify"].post).toBeDefined();
|
||||
});
|
||||
|
||||
it("includes GET /v1/billing/success", () => {
|
||||
expect(spec.paths["/v1/billing/success"]).toBeDefined();
|
||||
expect(spec.paths["/v1/billing/success"].get).toBeDefined();
|
||||
it("excludes GET /v1/billing/success (browser redirect, not public API)", () => {
|
||||
expect(spec.paths["/v1/billing/success"]).toBeUndefined();
|
||||
});
|
||||
|
||||
it("includes POST /v1/billing/webhook", () => {
|
||||
expect(spec.paths["/v1/billing/webhook"]).toBeDefined();
|
||||
expect(spec.paths["/v1/billing/webhook"].post).toBeDefined();
|
||||
it("excludes POST /v1/billing/webhook (internal Stripe endpoint)", () => {
|
||||
expect(spec.paths["/v1/billing/webhook"]).toBeUndefined();
|
||||
});
|
||||
});
|
||||
|
||||
|
|
|
|||
18
src/__tests__/openapi-spec.test.ts
Normal file
18
src/__tests__/openapi-spec.test.ts
Normal file
|
|
@ -0,0 +1,18 @@
|
|||
import { describe, it, expect } from "vitest";
|
||||
import { swaggerSpec } from "../swagger.js";
|
||||
|
||||
describe("OpenAPI spec accuracy", () => {
|
||||
const spec = swaggerSpec as any;
|
||||
|
||||
it("should NOT include /v1/billing/webhook (internal Stripe endpoint)", () => {
|
||||
expect(spec.paths).not.toHaveProperty("/v1/billing/webhook");
|
||||
});
|
||||
|
||||
it("should NOT include /v1/billing/success (browser redirect page)", () => {
|
||||
expect(spec.paths).not.toHaveProperty("/v1/billing/success");
|
||||
});
|
||||
|
||||
it("should mark /v1/signup/verify as deprecated", () => {
|
||||
expect(spec.paths["/v1/signup/verify"]?.post?.deprecated).toBe(true);
|
||||
});
|
||||
});
|
||||
|
|
@ -139,37 +139,7 @@ router.post("/checkout", checkoutLimiter, async (req: Request, res: Response) =>
|
|||
}
|
||||
});
|
||||
|
||||
/**
|
||||
* @openapi
|
||||
* /v1/billing/success:
|
||||
* get:
|
||||
* tags: [Billing]
|
||||
* summary: Checkout success page
|
||||
* description: |
|
||||
* Provisions a Pro API key after successful Stripe checkout and displays it in an HTML page.
|
||||
* Called by Stripe redirect after payment completion.
|
||||
* parameters:
|
||||
* - in: query
|
||||
* name: session_id
|
||||
* required: true
|
||||
* schema:
|
||||
* type: string
|
||||
* description: Stripe Checkout session ID
|
||||
* responses:
|
||||
* 200:
|
||||
* description: HTML page displaying the new API key
|
||||
* content:
|
||||
* text/html:
|
||||
* schema:
|
||||
* type: string
|
||||
* 400:
|
||||
* description: Missing session_id or no customer found
|
||||
* 409:
|
||||
* description: Checkout session already used
|
||||
* 500:
|
||||
* description: Failed to retrieve session
|
||||
*/
|
||||
// Success page — provision Pro API key after checkout
|
||||
// Success page — provision Pro API key after checkout (browser redirect, not a public API)
|
||||
router.get("/success", async (req: Request, res: Response) => {
|
||||
const sessionId = req.query.session_id as string;
|
||||
if (!sessionId) {
|
||||
|
|
@ -249,48 +219,7 @@ a { color: #4f9; }
|
|||
}
|
||||
});
|
||||
|
||||
/**
|
||||
* @openapi
|
||||
* /v1/billing/webhook:
|
||||
* post:
|
||||
* tags: [Billing]
|
||||
* summary: Stripe webhook endpoint
|
||||
* description: |
|
||||
* Receives Stripe webhook events for subscription lifecycle management.
|
||||
* Requires the raw request body and a valid Stripe-Signature header for verification.
|
||||
* Handles checkout.session.completed, customer.subscription.updated,
|
||||
* customer.subscription.deleted, and customer.updated events.
|
||||
* parameters:
|
||||
* - in: header
|
||||
* name: Stripe-Signature
|
||||
* required: true
|
||||
* schema:
|
||||
* type: string
|
||||
* description: Stripe webhook signature for payload verification
|
||||
* requestBody:
|
||||
* required: true
|
||||
* content:
|
||||
* application/json:
|
||||
* schema:
|
||||
* type: object
|
||||
* description: Raw Stripe event payload
|
||||
* responses:
|
||||
* 200:
|
||||
* description: Webhook received
|
||||
* content:
|
||||
* application/json:
|
||||
* schema:
|
||||
* type: object
|
||||
* properties:
|
||||
* received:
|
||||
* type: boolean
|
||||
* example: true
|
||||
* 400:
|
||||
* description: Missing Stripe-Signature header or invalid signature
|
||||
* 500:
|
||||
* description: Webhook secret not configured
|
||||
*/
|
||||
// Stripe webhook for subscription lifecycle events
|
||||
// Stripe webhook for subscription lifecycle events (internal, not in public API docs)
|
||||
router.post("/webhook", async (req: Request, res: Response) => {
|
||||
const sig = req.headers["stripe-signature"] as string;
|
||||
const webhookSecret = process.env.STRIPE_WEBHOOK_SECRET;
|
||||
|
|
|
|||
|
|
@ -68,9 +68,10 @@ router.post("/free", rejectDuplicateEmail, signupLimiter, async (req: Request, r
|
|||
* /v1/signup/verify:
|
||||
* post:
|
||||
* tags: [Account]
|
||||
* summary: Verify email and get API key
|
||||
* summary: Verify email and get API key (discontinued)
|
||||
* deprecated: true
|
||||
* description: |
|
||||
* Verifies the 6-digit code sent to the user's email and provisions a free API key.
|
||||
* **Discontinued.** Free accounts are no longer available. Try the demo at POST /v1/demo/html or upgrade to Pro at https://docfast.dev.
|
||||
* Rate limited to 15 attempts per 15 minutes.
|
||||
* requestBody:
|
||||
* required: true
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue