import load from "better-sqlite3"; import { createReadStream } from "node:fs"; import { readFile, readdir, rm, stat } from "node:fs/promises"; import { extname, join } from "node:path"; import { Writable } from "node:stream"; import { pipeline } from "node:stream/promises"; import { promisify } from "node:util"; // import * as brotli from "brotli"; import { brotliCompress, constants, createBrotliCompress } from "node:zlib"; const compress = promisify(brotliCompress); const name = process.argv[2] || "./archive.sqlite3"; await rm(name, { force: true }); const db = load(name); db.pragma("journal_mode = WAL"); db.exec("create table files(path string, content blob, compressed bool)"); db.exec("create unique index path on files(path)"); const insertStmt = db.prepare( "insert into files(path, content, compressed) values(?, ?, ?)" ); /** * @param {string} parent * @param {string} strip */ async function recurse(parent, strip) { const dir = await readdir(parent, { withFileTypes: true }); await Promise.all( dir.map(async (entry) => { const realPath = join(parent, entry.name); if (entry.name === "pack.js") { debugger; } if (entry.isFile()) { if (!realPath.startsWith(strip)) throw new Error("wtf"); const virtualPath = realPath.slice(strip.length); const file = createReadStream(realPath); const ext = extname(entry.name).toLowerCase(); if ([".html", ".css", ".js", ".svg", ".json"].includes(ext)) { try { const brotli = createBrotliCompress({ params: { [constants.BROTLI_PARAM_MODE]: constants.BROTLI_MODE_TEXT, [constants.BROTLI_PARAM_QUALITY]: 11, [constants.BROTLI_PARAM_SIZE_HINT]: (await stat(realPath)).size, }, }); pipeline(file, brotli); const buffers = []; for await (const data of brotli) { buffers.push(data); } const finalBuffer = Buffer.concat(buffers); insertStmt.run(virtualPath, finalBuffer, 1); } catch (error) { console.error(error); } } else if ([".gz", ".br"].includes(ext)) { // nada } else { file.close(); insertStmt.run(virtualPath, await readFile(realPath), 0); } } else { await recurse(realPath, strip); } }) ); } await recurse("input/", "input");