Move to Deno+Bunny.net, add a way to test webring locally.

This commit is contained in:
DS 2025-02-23 23:47:07 -08:00
parent 9f66f0b37b
commit 8670aa3412
33 changed files with 599 additions and 3360 deletions

10
scripts/build_index.ts Normal file
View file

@ -0,0 +1,10 @@
import { join } from 'node:path';
import { generateIndex } from '../src/render_templates.ts';
if (import.meta.main) {
const encoder = new TextEncoder();
Deno.writeFileSync(
join(import.meta.dirname ?? '', '../build/index.html'),
encoder.encode(generateIndex())
);
}

46
scripts/bundle_bunny.ts Normal file
View file

@ -0,0 +1,46 @@
import * as esbuild from 'esbuild';
import { denoPlugins } from '@luca/esbuild-deno-loader';
import { join } from '@std/path';
if (import.meta.main) {
for (const dirEntry of Deno.readDirSync(
join(import.meta.dirname ?? '', '../bunny')
)) {
if (dirEntry.isFile && dirEntry.name.endsWith('.ts')) {
const outFilename =
dirEntry.name.substring(0, dirEntry.name.length - 3) + '.js';
const res = await esbuild.build({
plugins: [
...denoPlugins({
loader: 'native',
}),
],
entryPoints: [
join(import.meta.dirname ?? '', '../bunny', dirEntry.name),
],
outfile: join(import.meta.dirname ?? '', '../build/bunny', outFilename),
bundle: true,
format: 'esm',
});
await esbuild.stop();
if (res.errors.length > 0) {
console.error(
`Got errors when trying to bundle ${dirEntry.name}: ${JSON.stringify(
res.errors
)}`
);
}
if (res.warnings.length > 0) {
console.warn(
`Got warnings when trying to bundle ${
dirEntry.name
}: ${JSON.stringify(res.warnings)}`
);
}
}
}
}

130
scripts/bunny_api/main.ts Normal file
View file

@ -0,0 +1,130 @@
export async function deployScript(scriptName: string, contents: string) {
const scriptIdEnvName = `SCRIPT_ID_${scriptName.toUpperCase()}`;
const scriptId = Deno.env.get(scriptIdEnvName);
const deployKeyEnvName = `SCRIPT_KEY_${scriptName.toUpperCase()}`;
const deployKey = Deno.env.get(deployKeyEnvName);
if (scriptId === undefined) {
throw new Error(
`Can't deploy script '${scriptName}' because we don't know its id on bunny. Please set it by setting the environment variable '${scriptIdEnvName}'.`
);
}
if (deployKey === undefined) {
throw new Error(
`Can't deploy script '${scriptName}' because we don't know its deploy key on bunny. Please set it by setting the environment variable '${scriptIdEnvName}'.`
);
}
const headers = {
accept: 'application/json',
'content-type': 'application/json',
deploymentkey: deployKey,
};
const setCodeResp = await fetch(
`https://api.bunny.net/compute/script/${scriptId}/code`,
{
method: 'POST',
headers,
body: JSON.stringify({ Code: contents }),
}
);
if (!setCodeResp.ok) {
console.error(await setCodeResp.text());
throw new Error(
`Failed to upload new script code: ${setCodeResp.statusText}`
);
}
const publishResp = await fetch(
`https://api.bunny.net/compute/script/${scriptId}/publish`,
{
method: 'POST',
headers,
}
);
if (!publishResp.ok) {
console.error(await setCodeResp.text());
throw new Error(`Failed to publish script: ${setCodeResp.statusText}`);
}
}
export async function uploadFile(filepath: string, contents: Uint8Array) {
const storageZoneNameEnvName = 'STORAGE_ZONE_NAME';
const storageZoneName = Deno.env.get(storageZoneNameEnvName);
const storageApiKeyEnvName = 'STORAGE_API_KEY';
const apiKey = Deno.env.get(storageApiKeyEnvName);
if (storageZoneName === undefined) {
throw new Error(
`Can't upload file '${filepath}' because we don't know which storage zone to upload to. Please set it by setting the environment variable '${storageZoneNameEnvName}'.`
);
}
if (apiKey === undefined) {
throw new Error(
`Can't upload file '${filepath}' because we don't have an API key. Please set it by setting the environment variable '${storageApiKeyEnvName}'.`
);
}
const headers = {
accept: 'application/json',
'content-type': 'application/octet-stream',
accesskey: apiKey,
};
const res = await fetch(
`https://storage.bunnycdn.com/${storageZoneName}/${filepath}`,
{
method: 'PUT',
headers,
body: contents,
}
);
if (!res.ok) {
console.error(await res.text());
throw new Error(`Failed to upload file: ${res.statusText}`);
}
}
export async function purgePath(filepath: string) {
const cdnBaseUrlEnvName = 'BUNNY_CDN_BASE_URL';
const cdnBaseUrl = Deno.env.get(cdnBaseUrlEnvName);
const accessKeyEnvName = 'BUNNY_ACCESS_KEY';
const accessKey = Deno.env.get(accessKeyEnvName);
if (cdnBaseUrl === undefined) {
throw new Error(
`Can't purge cache for '${filepath}' because we don't know the CDN base URL. Please set it by setting the environment variable '${cdnBaseUrlEnvName}'.`
);
}
if (accessKey === undefined) {
throw new Error(
`Can't purge cache for '${filepath}' because we don't have an API key. Please set it by setting the environment variable '${accessKeyEnvName}'.`
);
}
const headers = {
accept: 'application/json',
'content-type': 'application/json',
accesskey: accessKey,
};
const fetchUrl = new URL(`https://api.bunny.net/purge`);
fetchUrl.searchParams.append('async', 'false');
fetchUrl.searchParams.append('url', `${cdnBaseUrl}/${filepath}`);
const res = await fetch(fetchUrl.toString(), {
method: 'POST',
headers,
});
if (!res.ok) {
console.error(await res.text());
throw new Error(`Failed to purge cache: ${res.statusText}`);
}
}

32
scripts/deploy_bunny.ts Normal file
View file

@ -0,0 +1,32 @@
import { join } from '@std/path';
import { deployScript, purgePath, uploadFile } from './bunny_api/main.ts';
if (import.meta.main) {
console.log(`Attempting to upload index.html`);
const localFilepath = join(import.meta.dirname ?? '', '../build/index.html');
const indexContents = Deno.readFileSync(localFilepath);
await uploadFile('index.html', indexContents);
console.log(`Done!`);
console.log(`Attempting to purge the cache for index.html`);
await purgePath('index.html');
console.log(`Done!`);
for (const dirEntry of Deno.readDirSync(
join(import.meta.dirname ?? '', '../build/bunny')
)) {
if (dirEntry.isFile && dirEntry.name.endsWith('.js')) {
const scriptName = dirEntry.name.substring(0, dirEntry.name.length - 3);
const decoder = new TextDecoder('utf-8');
const contents = decoder.decode(
Deno.readFileSync(
join(import.meta.dirname ?? '', '../build/bunny', dirEntry.name)
)
);
console.log(`Attempting to deploy script '${scriptName}'`);
await deployScript(scriptName, contents);
console.log(`Done!`);
}
}
}