Skip to content

Commit 4399cb5

Browse files
caiopizzolcaio-pizzol
authored andcommitted
fix(api): support HEAD requests
1 parent d899b79 commit 4399cb5

2 files changed

Lines changed: 42 additions & 19 deletions

File tree

.github/workflows/deploy-site.yml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ on:
55
push:
66
branches: [main]
77
paths:
8+
- ".github/workflows/deploy-site.yml"
89
- "apps/web/**"
910
- "!apps/web/worker/**"
1011

apps/web/worker/src/index.ts

Lines changed: 41 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -41,20 +41,24 @@ const LANG_NAMES: Record<string, string> = {
4141
function corsHeaders(origin: string): Record<string, string> {
4242
return {
4343
"Access-Control-Allow-Origin": origin,
44-
"Access-Control-Allow-Methods": "GET, OPTIONS",
44+
"Access-Control-Allow-Methods": "GET, HEAD, OPTIONS",
4545
"Access-Control-Allow-Headers": "Content-Type",
4646
};
4747
}
4848

49-
function json(data: unknown, status: number, origin: string, cacheSeconds = 0): Response {
49+
function jsonHeaders(origin: string, cacheSeconds = 0): HeadersInit {
5050
const headers: Record<string, string> = {
5151
"Content-Type": "application/json",
5252
...corsHeaders(origin),
5353
};
5454
if (cacheSeconds > 0) {
5555
headers["Cache-Control"] = `public, max-age=${cacheSeconds}`;
5656
}
57-
return new Response(JSON.stringify(data), { status, headers });
57+
return headers;
58+
}
59+
60+
function json(data: unknown, status: number, origin: string, cacheSeconds = 0): Response {
61+
return new Response(JSON.stringify(data), { status, headers: jsonHeaders(origin, cacheSeconds) });
5862
}
5963

6064
export default {
@@ -67,18 +71,24 @@ export default {
6771
return new Response(null, { status: 204, headers: corsHeaders(origin) });
6872
}
6973

70-
if (request.method !== "GET") {
74+
const isHead = request.method === "HEAD";
75+
76+
if (request.method !== "GET" && !isHead) {
7177
return json({ error: "Method not allowed" }, 405, origin);
7278
}
7379

7480
switch (url.pathname) {
7581
case "/stats":
82+
if (isHead) return new Response(null, { status: 200, headers: jsonHeaders(origin, 300) });
7683
return handleStats(env, origin);
7784
case "/documents":
85+
if (isHead) return new Response(null, { status: 200, headers: jsonHeaders(origin) });
7886
return handleDocuments(url, env, origin);
7987
case "/manifest":
88+
if (isHead) return headManifest(url, origin);
8089
return handleManifest(url, env, origin);
8190
default:
91+
if (isHead) return new Response(null, { status: 404, headers: jsonHeaders(origin) });
8292
return json({ error: "Not found" }, 404, origin);
8393
}
8494
},
@@ -296,6 +306,32 @@ async function handleDocuments(url: URL, env: Env, origin: string): Promise<Resp
296306

297307
const R2_BASE = "https://docxcorp.us/documents/";
298308

309+
function manifestFilename(url: URL): string {
310+
const parts = ["docx-corpus"];
311+
const type = url.searchParams.get("type");
312+
const topic = url.searchParams.get("topic");
313+
const lang = url.searchParams.get("lang");
314+
if (type) parts.push(type);
315+
if (topic) parts.push(topic);
316+
if (lang) parts.push(lang);
317+
return `${parts.join("-")}-manifest.txt`;
318+
}
319+
320+
function manifestHeaders(url: URL, origin: string): HeadersInit {
321+
return {
322+
"Content-Type": "text/plain; charset=utf-8",
323+
"Content-Disposition": `attachment; filename="${manifestFilename(url)}"`,
324+
...corsHeaders(origin),
325+
};
326+
}
327+
328+
function headManifest(url: URL, origin: string): Response {
329+
return new Response(null, {
330+
status: 200,
331+
headers: manifestHeaders(url, origin),
332+
});
333+
}
334+
299335
async function handleManifest(url: URL, env: Env, origin: string): Promise<Response> {
300336
try {
301337
const sql = neon(env.DATABASE_URL);
@@ -307,23 +343,9 @@ async function handleManifest(url: URL, env: Env, origin: string): Promise<Respo
307343

308344
const body = rows.map((r) => `${R2_BASE}${r.id}.docx`).join("\n") + "\n";
309345

310-
// Build a descriptive filename
311-
const parts = ["docx-corpus"];
312-
const type = url.searchParams.get("type");
313-
const topic = url.searchParams.get("topic");
314-
const lang = url.searchParams.get("lang");
315-
if (type) parts.push(type);
316-
if (topic) parts.push(topic);
317-
if (lang) parts.push(lang);
318-
const filename = `${parts.join("-")}-manifest.txt`;
319-
320346
return new Response(body, {
321347
status: 200,
322-
headers: {
323-
"Content-Type": "text/plain; charset=utf-8",
324-
"Content-Disposition": `attachment; filename="${filename}"`,
325-
...corsHeaders(origin),
326-
},
348+
headers: manifestHeaders(url, origin),
327349
});
328350
} catch (err) {
329351
const message = err instanceof Error ? err.message : String(err);

0 commit comments

Comments
 (0)