diff --git a/bun.lockb b/bun.lockb index 1e0161a..6b32bda 100755 Binary files a/bun.lockb and b/bun.lockb differ diff --git a/package.json b/package.json index dd94c6e..9c239f6 100644 --- a/package.json +++ b/package.json @@ -19,8 +19,9 @@ "typescript": "^5.0.0" }, "dependencies": { + "brotli-wasm": "^2.0.1", "exit-hook": "^4.0.0", - "prisma": "^5.8.1", - "firebase-admin": "^11.11.0" + "firebase-admin": "^11.11.0", + "prisma": "^5.8.1" } } \ No newline at end of file diff --git a/pkgs/server/api-ctx.ts b/pkgs/server/api-ctx.ts index c591a5f..ec0e334 100644 --- a/pkgs/server/api-ctx.ts +++ b/pkgs/server/api-ctx.ts @@ -1,4 +1,6 @@ import { gzipSync } from "bun"; +import brotliPromise from "brotli-wasm"; // Import the default export +const brotli = await brotliPromise; const parseQueryParams = (ctx: any) => { const pageHref = ctx.req.url; @@ -36,7 +38,11 @@ export const apiContext = (ctx: any) => { }; }; -const cache = { gz: {} as Record }; +const cache = { + gz: {} as Record, + br: {} as Record, + br_timeout: new Set(), +}; export const createResponse = ( existingRes: any, @@ -48,15 +54,35 @@ export const createResponse = ( let content: any = typeof body === "string" ? body : JSON.stringify(body); const headers = {} as Record; - if (cache_accept && cache_accept.toLowerCase().includes("gz")) { + if (cache_accept) { const content_hash = simpleHash(content); - if (content_hash) { - content = cache.gz[content_hash]; - } else { - cache.gz[content_hash] = gzipSync(content); - content = cache.gz[content_hash]; + if (cache_accept.toLowerCase().includes("br")) { + if (cache.br[content_hash]) { + content = cache.br[content_hash]; + } else { + if (!cache.br_timeout.has(content_hash)) { + cache.br_timeout.add(content_hash); + setTimeout(() => { + cache.br[content_hash] = brotli.compress(Buffer.from(content)); + cache.br_timeout.delete(content_hash); + }); + } + } + headers["content-encoding"] = "br"; + } + + if ( + cache_accept.toLowerCase().includes("gz") && + !headers["content-encoding"] + ) { + if (cache.gz[content_hash]) { + content = cache.gz[content_hash]; + } else { + cache.gz[content_hash] = gzipSync(content); + content = cache.gz[content_hash]; + } + headers["content-encoding"] = "gzip"; } - headers["content-encoding"] = "gz"; } let res = new Response( diff --git a/pkgs/server/load-web.ts b/pkgs/server/load-web.ts index 73d5b1a..db7ae3c 100644 --- a/pkgs/server/load-web.ts +++ b/pkgs/server/load-web.ts @@ -12,48 +12,12 @@ import { gunzipSync } from "zlib"; import { downloadFile } from "../api/_deploy"; import { dir } from "../utils/dir"; import { g } from "../utils/global"; +const decoder = new TextDecoder(); export const loadWeb = async () => { await dirAsync(dir(`app/static`)); - const siteZip = `${ - g.mode === "dev" ? "http://localhost:4550" : "https://prasi.app" - }/site-bundle`; - const zipPath = dir(`app/static/site.zip`); - const md5Path = dir(`app/static/md5`); - - if (!(await file(zipPath).exists()) || !(await file(md5Path).exists())) { - const md5 = await fetch(`${siteZip}/md5`); - await writeAsync(md5Path, await md5.text()); - await new Promise((r) => setTimeout(r, 1000)); - await downloadFile(`${siteZip}/download`, zipPath); - await removeAsync(dir(`app/static/site`)); - await $({ cwd: dir(`app/static`) })`unzip site.zip`; - } else { - const md5 = await fetch(`${siteZip}/md5`); - const md5txt = await md5.text(); - - if (md5txt !== (await readAsync(md5Path))) { - const e = await fetch(`${siteZip}/download`); - await removeAsync(dir(`app/static`)); - await dirAsync(dir(`app/static`)); - await downloadFile(`${siteZip}/download`, zipPath); - await writeAsync(md5Path, md5txt); - await $({ cwd: dir(`app/static`) })`unzip site.zip`; - } - } - - const list = await inspectTreeAsync(dir(`app/web`)); - for (const web of list?.children || []) { - if (web.type === "file") continue; - - const deploy = web.children?.find((e) => e.name === "deploys"); - if (!deploy) { - await dirAsync(dir(`app/web/${web.name}/deploys`)); - } - } }; -const decoder = new TextDecoder(); export const loadWebCache = async (site_id: string, ts: number | string) => { const web = g.web; if (web) {