From c16a8e9f4ded36c4237899049c2db7d687636ba2 Mon Sep 17 00:00:00 2001 From: cc Date: Tue, 14 Apr 2026 16:58:11 +0200 Subject: [PATCH] Remove WASM SQLite engine and skip database download KV backend is now the only data source - no need for SQLite. --- .github/workflows/build.yml | 12 -- package.json | 1 - src/lib/engine/wasm.ts | 219 ------------------------------------ 3 files changed, 232 deletions(-) delete mode 100644 src/lib/engine/wasm.ts diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 219f85d..13844a6 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -68,18 +68,6 @@ jobs: curl -fL "$data_url" -o data.tar.gz tar -xzf data.tar.gz -C out/data - - name: Download SQLite database - env: - GH_TOKEN: ${{ github.token }} - run: | - release_json=$(curl -fsSL \ - -H "Accept: application/vnd.github+json" \ - -H "Authorization: Bearer $GH_TOKEN" \ - https://api.github.com/repos/ChiChou/entdb-data/releases/latest) - - db_url=$(echo "$release_json" | jq -er '.assets[] | select(.name == "ent.db") | .browser_download_url') - curl -fL "$db_url" -o out/data/ent.db - - name: Upload artifact if: steps.configure-pages.outcome == 'success' uses: actions/upload-pages-artifact@v3 diff --git a/package.json b/package.json index 0b01b62..39a14d1 100644 --- a/package.json +++ b/package.json @@ -18,7 +18,6 @@ "@radix-ui/react-slot": "^1.2.3", "@radix-ui/react-tabs": "^1.1.13", "@radix-ui/react-tooltip": "^1.2.8", - "@sqlite.org/sqlite-wasm": "^3.49.1-build3", "class-variance-authority": "^0.7.1", "clsx": "^2.1.1", "cmdk": "^1.1.1", diff --git a/src/lib/engine/wasm.ts b/src/lib/engine/wasm.ts deleted file mode 100644 index c00a2a9..0000000 --- a/src/lib/engine/wasm.ts +++ /dev/null @@ -1,219 +0,0 @@ -import type { Engine, PathHistory } from "./types"; -import type { OS } from "@/lib/types"; -import { dataBaseURL } from "@/lib/env"; - -type SQLite3Database = { - exec: (options: { - sql: string; - bind?: unknown[]; - rowMode: "array"; - returnValue: "resultRows"; - }) => unknown[][]; - close: () => void; -}; - -type SQLite3API = { - oo1: { - DB: new (filename?: string, flags?: string, vfs?: string) => SQLite3Database; - }; - capi: { - sqlite3_js_posix_create_file: ( - filename: string, - data: Uint8Array | ArrayBuffer, - dataLen?: number - ) => void; - }; -}; - -let sqlite3Module: SQLite3API | null = null; -let dbInstance: SQLite3Database | null = null; -let dbReady = false; - -const RANGE_CHUNK_SIZE = 8 * 1024 * 1024; -const RANGE_CONCURRENCY = 6; - -async function loadSQLite(): Promise { - if (sqlite3Module) return sqlite3Module; - - const sqliteModule = await import("@sqlite.org/sqlite-wasm"); - const initSQLite = sqliteModule.default; - sqlite3Module = (await initSQLite()) as unknown as SQLite3API; - return sqlite3Module; -} - -export async function checkWASMSupport(): Promise { - try { - if (typeof WebAssembly === "undefined") { - return false; - } - - await WebAssembly.instantiate( - Uint8Array.of(0x0, 0x61, 0x73, 0x6d, 0x01, 0x00, 0x00, 0x00) - ); - await loadSQLite(); - return true; - } catch { - return false; - } -} - -async function fetchRangeChunk( - url: string, - start: number, - end: number -): Promise { - const res = await fetch(url, { - headers: { - Range: `bytes=${start}-${end}`, - }, - }); - - if (res.status !== 206) { - throw new Error(`Range request not honored: ${res.status}`); - } - - return new Uint8Array(await res.arrayBuffer()); -} - -async function fetchDatabaseBytes(url: string): Promise { - const head = await fetch(url, { method: "HEAD" }); - if (!head.ok) { - throw new Error( - `Failed to fetch SQLite database: ${head.status} ${head.statusText}` - ); - } - - const contentLengthRaw = head.headers.get("content-length"); - const contentLength = contentLengthRaw ? Number(contentLengthRaw) : Number.NaN; - if (!Number.isFinite(contentLength) || contentLength <= 0) { - throw new Error("Missing or invalid Content-Length header"); - } - - const out = new Uint8Array(contentLength); - const ranges: Array<[number, number]> = []; - for (let start = 0; start < contentLength; start += RANGE_CHUNK_SIZE) { - const end = Math.min(start + RANGE_CHUNK_SIZE - 1, contentLength - 1); - ranges.push([start, end]); - } - - let next = 0; - const workers = Array.from( - { length: Math.min(RANGE_CONCURRENCY, ranges.length || 1) }, - async () => { - while (next < ranges.length) { - const idx = next; - next += 1; - - const [start, end] = ranges[idx]; - const chunk = await fetchRangeChunk(url, start, end); - out.set(chunk, start); - } - } - ); - - await Promise.all(workers); - return out; -} - -async function getDB(): Promise { - if (dbReady && dbInstance) return dbInstance; - - const sqlite3 = await loadSQLite(); - - const bytes = await fetchDatabaseBytes(`${dataBaseURL()}/ent.db`); - const filename = "/ent.db"; - - try { - sqlite3.capi.sqlite3_js_posix_create_file(filename, bytes, bytes.byteLength); - } catch { - // Ignore duplicate file creation in hot-reload or repeated initialization cases. - } - - dbInstance = new sqlite3.oo1.DB(filename, "r"); - dbReady = true; - return dbInstance; -} - -export class WASMEngine implements Engine { - async listOS(): Promise { - const db = await getDB(); - const rows = db.exec({ - sql: "SELECT name, version, build, devices FROM os ORDER BY version DESC", - rowMode: "array", - returnValue: "resultRows", - }); - - return rows.map((row) => ({ - name: row[0] as string, - version: row[1] as string, - build: row[2] as string, - devices: JSON.parse(row[3] as string), - })); - } - - async getPaths(build: string): Promise { - const db = await getDB(); - const rows = db.exec({ - sql: `SELECT path FROM bin JOIN os ON bin.osid=os.id WHERE os.build=?`, - bind: [build], - rowMode: "array", - returnValue: "resultRows", - }); - return rows.map((row) => row[0] as string); - } - - async getBinaryXML(build: string, path: string): Promise { - const db = await getDB(); - const rows = db.exec({ - sql: `SELECT xml FROM bin JOIN os ON bin.osid=os.id WHERE os.build=? AND bin.path=?`, - bind: [build, path], - rowMode: "array", - returnValue: "resultRows", - }); - if (!rows.length) { - throw new Error(`Binary not found: ${path}`); - } - return rows[0][0] as string; - } - - async getKeys(build: string): Promise { - const db = await getDB(); - const rows = db.exec({ - sql: `SELECT DISTINCT key FROM pair JOIN bin ON pair.binid=bin.id JOIN os ON bin.osid=os.id WHERE os.build=?`, - bind: [build], - rowMode: "array", - returnValue: "resultRows", - }); - return rows.map((row) => row[0] as string); - } - - async getPathsForKey(build: string, key: string): Promise { - const db = await getDB(); - const rows = db.exec({ - sql: `SELECT path FROM bin JOIN pair ON bin.id=pair.binid JOIN os ON bin.osid=os.id WHERE os.build=? AND pair.key=?`, - bind: [build, key], - rowMode: "array", - returnValue: "resultRows", - }); - return rows.map((row) => row[0] as string); - } - - async getPathHistory(path: string): Promise { - const db = await getDB(); - const osList = await this.listOS(); - - const rows = db.exec({ - sql: `SELECT DISTINCT os.build FROM bin JOIN os ON bin.osid=os.id WHERE bin.path=?`, - bind: [path], - rowMode: "array", - returnValue: "resultRows", - }); - - const availableBuilds = new Set(rows.map((row) => row[0] as string)); - - return osList.map((os) => ({ - os, - available: availableBuilds.has(os.build), - })); - } -}