feat(api): make /api/v1/stats public and point the landing at it

Unify the monitoring stats on the versioned API: /api/v1/stats is now public
(no auth) and CORS-enabled, mirroring the legacy /api/stats. The marketing
landing (docs/index.html) now fetches /api/v1/stats; /api/stats is kept as a
deprecated alias for existing monitors. Feed/email routes remain token-gated.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
This commit is contained in:
Julien Herr
2026-05-23 23:11:13 +02:00
parent 45d2a14a12
commit daa93d8093
5 changed files with 36 additions and 24 deletions
+7 -3
View File
@@ -252,10 +252,11 @@ describe("REST API (/api/v1)", () => {
});
describe("Stats", () => {
it("returns monitoring counters", async () => {
it("returns monitoring counters without a token (public)", async () => {
await createFeed();
const res = await request("/api/v1/stats", { headers: authHeaders });
const res = await request("/api/v1/stats");
expect(res.status).toBe(200);
expect(res.headers.get("Access-Control-Allow-Origin")).toBe("*");
const stats = (await res.json()) as {
feeds_created: number;
active_feeds: number;
@@ -273,12 +274,15 @@ describe("REST API (/api/v1)", () => {
expect(res.status).toBe(200);
const doc = (await res.json()) as {
openapi: string;
paths: Record<string, unknown>;
paths: Record<string, { get?: { security?: unknown[] } }>;
};
expect(doc.openapi).toBe("3.1.0");
expect(doc.paths).toHaveProperty("/v1/feeds");
expect(doc.paths).toHaveProperty("/v1/feeds/{feedId}");
expect(doc.paths).toHaveProperty("/v1/stats");
// Feed routes are secured; stats is public.
expect(doc.paths["/v1/feeds"].get?.security).toBeTruthy();
expect(doc.paths["/v1/stats"].get?.security).toBeUndefined();
});
});
});