fix
This commit is contained in:
parent
5bf02b47d5
commit
102f78b523
|
|
@ -40,15 +40,17 @@ function isAuthorised(page: { id: string; password_hash: string | null }, req: R
|
||||||
return verifyAuthCookie(req.headers.get("cookie"), page.id);
|
return verifyAuthCookie(req.headers.get("cookie"), page.id);
|
||||||
}
|
}
|
||||||
|
|
||||||
const app = new Elysia()
|
// Memoirist (Elysia's router) treats `:slug.json` as a single parameter named
|
||||||
.get("/", () => new Response("PingQL status service", {
|
// "slug.json" and refuses to coexist with `:slug`. Instead, use one `:slug`
|
||||||
headers: { "content-type": "text/plain" },
|
// route and dispatch on the suffix in the handler.
|
||||||
}))
|
function splitSlugAndFormat(raw: string): { slug: string; format: "html" | "json" | "rss" } {
|
||||||
|
if (raw.endsWith(".json")) return { slug: raw.slice(0, -5), format: "json" };
|
||||||
|
if (raw.endsWith(".rss")) return { slug: raw.slice(0, -4), format: "rss" };
|
||||||
|
return { slug: raw, format: "html" };
|
||||||
|
}
|
||||||
|
|
||||||
// Public HTML page
|
async function renderHtml(slug: string, request: Request): Promise<Response> {
|
||||||
.get("/:slug", async ({ params, request, set }) => {
|
const page = await cached(`page:${slug}`, 60, () => loadStatusPage(slug));
|
||||||
if (!allow(params.slug, clientIp(request))) return rateLimited();
|
|
||||||
const page = await cached(`page:${params.slug}`, 60, () => loadStatusPage(params.slug));
|
|
||||||
if (!page) return notFound();
|
if (!page) return notFound();
|
||||||
if (!isAuthorised(page, request)) {
|
if (!isAuthorised(page, request)) {
|
||||||
return new Response(eta.render("password", { title: page.title, slug: page.slug, error: null }), {
|
return new Response(eta.render("password", { title: page.title, slug: page.slug, error: null }), {
|
||||||
|
|
@ -56,9 +58,8 @@ const app = new Elysia()
|
||||||
headers: { "content-type": "text/html; charset=utf-8" },
|
headers: { "content-type": "text/html; charset=utf-8" },
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
const payload = await cached(`payload:${params.slug}`, 60, () => loadPagePayload(params.slug));
|
const payload = await cached(`payload:${slug}`, 60, () => loadPagePayload(slug));
|
||||||
if (!payload) return notFound();
|
if (!payload) return notFound();
|
||||||
|
|
||||||
const html = eta.render("page", payload);
|
const html = eta.render("page", payload);
|
||||||
const headers: Record<string, string> = {
|
const headers: Record<string, string> = {
|
||||||
"content-type": "text/html; charset=utf-8",
|
"content-type": "text/html; charset=utf-8",
|
||||||
|
|
@ -69,19 +70,15 @@ const app = new Elysia()
|
||||||
};
|
};
|
||||||
if (!page.index_search) headers["x-robots-tag"] = "noindex, nofollow";
|
if (!page.index_search) headers["x-robots-tag"] = "noindex, nofollow";
|
||||||
return new Response(html, { headers });
|
return new Response(html, { headers });
|
||||||
})
|
}
|
||||||
|
|
||||||
// Public JSON
|
async function renderJson(slug: string, request: Request, win?: Window): Promise<Response> {
|
||||||
.get("/:slug.json", async ({ params, request, set, query }) => {
|
const page = await cached(`page:${slug}`, 60, () => loadStatusPage(slug));
|
||||||
if (!allow(params.slug, clientIp(request))) return rateLimited();
|
if (!page) return new Response(JSON.stringify({ error: "not found" }), { status: 404, headers: { "content-type": "application/json" } });
|
||||||
const page = await cached(`page:${params.slug}`, 60, () => loadStatusPage(params.slug));
|
if (!isAuthorised(page, request)) return new Response(JSON.stringify({ error: "password required" }), { status: 401, headers: { "content-type": "application/json" } });
|
||||||
if (!page) { set.status = 404; return { error: "not found" }; }
|
const cacheKey = `payload:${slug}:${win ?? page.default_window}`;
|
||||||
if (!isAuthorised(page, request)) { set.status = 401; return { error: "password required" }; }
|
const payload = await cached(cacheKey, 60, () => loadPagePayload(slug, win));
|
||||||
|
if (!payload) return new Response(JSON.stringify({ error: "not found" }), { status: 404, headers: { "content-type": "application/json" } });
|
||||||
const win = (query as any)?.window as Window | undefined;
|
|
||||||
const cacheKey = `payload:${params.slug}:${win ?? page.default_window}`;
|
|
||||||
const payload = await cached(cacheKey, 60, () => loadPagePayload(params.slug, win));
|
|
||||||
if (!payload) { set.status = 404; return { error: "not found" }; }
|
|
||||||
return new Response(JSON.stringify(payload), {
|
return new Response(JSON.stringify(payload), {
|
||||||
headers: {
|
headers: {
|
||||||
"content-type": "application/json",
|
"content-type": "application/json",
|
||||||
|
|
@ -89,20 +86,32 @@ const app = new Elysia()
|
||||||
...(page.index_search ? {} : { "x-robots-tag": "noindex, nofollow" }),
|
...(page.index_search ? {} : { "x-robots-tag": "noindex, nofollow" }),
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
})
|
}
|
||||||
|
|
||||||
// Public RSS
|
async function renderRssResp(slug: string): Promise<Response> {
|
||||||
.get("/:slug.rss", async ({ params, request }) => {
|
const page = await loadStatusPage(slug);
|
||||||
if (!allow(params.slug, clientIp(request))) return rateLimited();
|
|
||||||
const page = await loadStatusPage(params.slug);
|
|
||||||
if (!page) return notFound();
|
if (!page) return notFound();
|
||||||
const xml = await cached(`rss:${params.slug}`, 300, () => renderRss(page, PUBLIC_BASE));
|
const xml = await cached(`rss:${slug}`, 300, () => renderRss(page, PUBLIC_BASE));
|
||||||
return new Response(xml, {
|
return new Response(xml, {
|
||||||
headers: {
|
headers: {
|
||||||
"content-type": "application/rss+xml; charset=utf-8",
|
"content-type": "application/rss+xml; charset=utf-8",
|
||||||
"cache-control": "public, max-age=300, s-maxage=300",
|
"cache-control": "public, max-age=300, s-maxage=300",
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
const app = new Elysia()
|
||||||
|
.get("/", () => new Response("PingQL status service", {
|
||||||
|
headers: { "content-type": "text/plain" },
|
||||||
|
}))
|
||||||
|
|
||||||
|
// Single public route — dispatches HTML / JSON / RSS by extension on the slug.
|
||||||
|
.get("/:slug", async ({ params, request, query }) => {
|
||||||
|
const { slug, format } = splitSlugAndFormat(params.slug);
|
||||||
|
if (!allow(slug, clientIp(request))) return rateLimited();
|
||||||
|
if (format === "json") return renderJson(slug, request, (query as any)?.window as Window | undefined);
|
||||||
|
if (format === "rss") return renderRssResp(slug);
|
||||||
|
return renderHtml(slug, request);
|
||||||
})
|
})
|
||||||
|
|
||||||
// Public SVG badge
|
// Public SVG badge
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue