-
Notifications
You must be signed in to change notification settings - Fork 0
/
main.ts
121 lines (114 loc) · 3.52 KB
/
main.ts
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
import { serve } from "std/http/server.ts";
import { build, initialize } from "esbuild";
import { denoPlugins } from "esbuild-deno-loader";
await initialize({ worker: false });
const solverCode = await (async () => {
const { outputFiles: [{ contents }] = [] } = await build({
entryPoints: [new URL("./www/solver.ts", import.meta.url).href],
bundle: true,
minify: true,
format: "esm",
write: false,
external: ["esm.sh/*"],
plugins: [
...denoPlugins({
importMapURL: new URL("./importMap.json", import.meta.url).href,
loader: "portable",
}),
],
});
return contents;
// const { code } = await bundle("./www/solver.ts", bundleOptions);
// return code.replace(/^const\s+importMeta\s*=\s*\{$[\s\S]*?^\};$\s*?^/m, "")
// .replaceAll(/\bimportMeta\b/g, "import.meta");
})();
const unimplementedSolveCode = /* JavaScript */ `\
export default function solve() { throw new Error("unimplemented"); }
`;
const urlPatterns = new Map<
URLPattern,
(result: URLPatternResult) => Promise<
| Record<string, (result: URLPatternResult) => Promise<BodyInit>>
| null
>
>()
.set(
new URLPattern({ pathname: "/solver.js" }),
// deno-lint-ignore require-await
async () => ({ GET: async () => solverCode }),
)
.set(
new URLPattern({ pathname: "/:year/day/:day/part/:part/solve.js" }),
async ({ pathname: { groups: { year, day, part } } }) => {
const root = `./${year}/day/${day}/part/${part}/solve.ts`;
try {
await Deno.lstat(root);
} catch {
return null;
}
return {
GET: async () => {
const { outputFiles: [{ contents }] = [] } = await build({
entryPoints: [new URL(root, import.meta.url).href],
bundle: true,
minify: false,
format: "esm",
write: false,
external: ["esm.sh/*"],
plugins: [
...denoPlugins({
importMapURL: new URL("./importMap.json", import.meta.url).href,
loader: "portable",
}),
],
});
return contents;
},
};
},
);
serve(async (request) => {
try {
for (const [urlPattern, createResource] of urlPatterns) {
const result = urlPattern.exec(request.url);
if (result === null) continue;
const resource = await createResource(result);
const headers = {
"Access-Control-Allow-Origin": "*",
"Access-Control-Allow-Methods": resource
? Object.keys(resource).join()
: "GET,OPTIONS",
"Content-Type": "text/javascript",
};
if (resource === null) {
return new Response(unimplementedSolveCode, { headers });
}
if (request.method === "OPTIONS") {
return new Response(null, {
status: 204,
statusText: "No Content",
headers,
});
}
if (!Object.hasOwn(resource, request.method)) {
return new Response(null, {
status: 405,
statusText: "Method Not Allowed",
});
}
const { [request.method]: handler } = resource;
return new Response(await handler(result), { headers });
}
return new Response(null, { status: 404, statusText: "Not Found" });
} catch (e) {
try {
console.error("failed to handle request", e);
} finally {
console.error("failed to handle request and failed to log exception");
}
return new Response(null, {
status: 500,
statusText: "Internal Server Error",
});
}
});