99 lines
2.3 KiB
TypeScript
Executable File
99 lines
2.3 KiB
TypeScript
Executable File
#!./run
|
|
// Automated bundle server
|
|
|
|
import {
|
|
Response,
|
|
serve,
|
|
ServerRequest,
|
|
} from "https://deno.land/std@0.103.0/http/server.ts";
|
|
|
|
export async function processRequest(
|
|
req: ServerRequest,
|
|
hostpath: string,
|
|
runner = Deno.run,
|
|
): Promise<Response> {
|
|
if (req.method != "GET") {
|
|
return { status: 405 };
|
|
}
|
|
|
|
const params = req.url.split("/").filter((x) => !!x);
|
|
if (params.length < 2) {
|
|
return { status: 404 };
|
|
}
|
|
|
|
const [lib, version] = params[0].split("@", 2);
|
|
const file = params.slice(1).join("/");
|
|
const branch = version || "master";
|
|
const path = `https://${hostpath}/${lib}/raw/${branch}/${file}`;
|
|
if (!isName(lib) || !isName(branch) || !isPath(file)) {
|
|
return {
|
|
status: 400,
|
|
body: `console.error("bundler error - Invalid path ${path}");`,
|
|
};
|
|
}
|
|
|
|
if (path.endsWith(".js")) {
|
|
return await bundle(path.slice(0, -3) + ".ts", runner);
|
|
} else {
|
|
return {
|
|
status: 301,
|
|
headers: new Headers({ Location: path }),
|
|
};
|
|
}
|
|
}
|
|
|
|
async function bundle(
|
|
path: string,
|
|
runner: typeof Deno.run,
|
|
): Promise<Response> {
|
|
const process = runner({
|
|
cmd: ["deno", "bundle", path],
|
|
stdout: "piped",
|
|
});
|
|
const output = await process.output();
|
|
const status = await process.status();
|
|
if (status.success) {
|
|
return { body: output };
|
|
} else {
|
|
return {
|
|
status: 500,
|
|
body: `console.error("bundler error - Failed to bundle ${path}");`,
|
|
};
|
|
}
|
|
}
|
|
|
|
export async function serveBundles(hostpath: string, port: number) {
|
|
const listen = { hostname: "0.0.0.0", port };
|
|
const server = serve(listen);
|
|
console.log(
|
|
`Serving ${hostpath} bundles on ${listen.hostname}:${listen.port} ...`,
|
|
);
|
|
for await (const req of server) {
|
|
try {
|
|
const response = await processRequest(req, hostpath);
|
|
await req.respond(response);
|
|
} catch (err) {
|
|
// console.error(err);
|
|
await req.respond({ status: 500 });
|
|
}
|
|
}
|
|
}
|
|
|
|
function isName(input: string): boolean {
|
|
return !!input.match(/^[a-zA-Z0-9_\-\.]+$/);
|
|
}
|
|
|
|
function isPath(input: string): boolean {
|
|
return !input.split("/").some((part) => !isName(part));
|
|
}
|
|
|
|
export type { Response };
|
|
|
|
if (import.meta.main) {
|
|
if (Deno.args.length >= 1 && Deno.args.length <= 2) {
|
|
await serveBundles(Deno.args[0], parseInt(Deno.args[1] || "8000"));
|
|
} else {
|
|
console.error("Usage: server.ts yourgithosting.net/namespace [port]");
|
|
}
|
|
}
|