diff --git a/docs/index.html b/docs/index.html index a1cc075..c4e53bd 100644 --- a/docs/index.html +++ b/docs/index.html @@ -446,6 +446,35 @@ .demo-note { text-align: left; } } + /* ── Live stats ── */ + .stats-section { padding: 4rem 2rem; } + .stats-inner { max-width: 1100px; margin: 0 auto; text-align: center; } + .stats-live { + display: inline-flex; align-items: center; gap: 0.5rem; + font-size: 0.78rem; color: var(--muted); + text-transform: uppercase; letter-spacing: 0.08em; margin-bottom: 2rem; + } + .stats-dot { + width: 8px; height: 8px; border-radius: 50%; background: var(--accent); + animation: stats-pulse 2s infinite; + } + @keyframes stats-pulse { + 0% { box-shadow: 0 0 0 0 rgba(246,130,31,0.5); } + 70% { box-shadow: 0 0 0 8px rgba(246,130,31,0); } + 100% { box-shadow: 0 0 0 0 rgba(246,130,31,0); } + } + .stats-grid { + display: grid; grid-template-columns: repeat(2, 1fr); + gap: 2rem; max-width: 600px; margin: 0 auto; + } + .stat-num { + font-size: clamp(2.5rem, 6vw, 4rem); font-weight: 700; + color: var(--accent); letter-spacing: -0.03em; + font-variant-numeric: tabular-nums; line-height: 1; + } + .stat-label { font-size: 0.9rem; color: var(--muted); margin-top: 0.6rem; } + @media (max-width: 600px) { .stats-grid { gap: 1.5rem; } } + /* ── Nav links ── */ nav-links { display: flex; @@ -661,6 +690,23 @@ + + +
@@ -1064,5 +1110,41 @@ bucket_name = "kill-the-news-attachments"

+ + diff --git a/src/index.test.ts b/src/index.test.ts index 3aea94c..c6d0ff9 100644 --- a/src/index.test.ts +++ b/src/index.test.ts @@ -12,11 +12,11 @@ function req(path: string, init: RequestInit = {}): Request { describe("CORS middleware", () => { it("adds CORS headers for an allowed origin", async () => { const res = await worker.fetch( - req("/rss/some-feed", { headers: { Origin: "https://getmynews.app" } }), + req("/rss/some-feed", { headers: { Origin: "https://kill-the.news" } }), env as unknown as Env, ); expect(res.headers.get("Access-Control-Allow-Origin")).toBe( - "https://getmynews.app", + "https://kill-the.news", ); }); @@ -33,7 +33,7 @@ describe("CORS middleware", () => { req("/rss/some-feed", { method: "OPTIONS", headers: { - Origin: "https://getmynews.app", + Origin: "https://kill-the.news", "Access-Control-Request-Method": "GET", }, }), @@ -41,7 +41,16 @@ describe("CORS middleware", () => { ); expect(res.status).toBe(204); expect(res.headers.get("Access-Control-Allow-Origin")).toBe( - "https://getmynews.app", + "https://kill-the.news", ); }); + + it("makes /api/stats readable from any origin", async () => { + const res = await worker.fetch( + req("/api/stats", { headers: { Origin: "https://example.com" } }), + env as unknown as Env, + ); + expect(res.status).toBe(200); + expect(res.headers.get("Access-Control-Allow-Origin")).toBe("*"); + }); }); diff --git a/src/index.ts b/src/index.ts index 50d2e49..99e73fb 100644 --- a/src/index.ts +++ b/src/index.ts @@ -22,7 +22,7 @@ import { FORWARD_EMAIL_IPS_CACHE_TTL_MS } from "./config/constants"; type AppEnv = { Bindings: Env }; -const ALLOWED_ORIGINS = ["https://getmynews.app", "https://www.getmynews.app"]; +const ALLOWED_ORIGINS = ["https://kill-the.news", "https://www.kill-the.news"]; // Fallback ForwardEmail.net IP addresses in case API fetch fails const FALLBACK_FORWARD_EMAIL_IPS = [ @@ -140,7 +140,8 @@ api.use("/inbound", async (c, next) => { // API routes (inbound webhook) api.post("/inbound", handleInbound); -// Public monitoring stats (JSON) +// Public monitoring stats (JSON) — readable from any origin (landing page, embeds) +api.use("/stats", cors({ origin: "*" })); api.get("/stats", handleStats); // RSS feed routes (public)