zstd.ts

1.7 KB · raw

1/**2 * Thin wrapper around @bokuweb/zstd-wasm that defers WASM load until the3 * first compress/decompress call and memoises the init promise.4 *5 * The WASM binary lives alongside the package's ESM entrypoint, so Vite's6 * default asset handling picks it up. The extension's CSP already allows7 * `wasm-unsafe-eval` for the existing hash-wasm Argon2id module.8 */910import {11  compress as zstdCompress,12  decompress as zstdDecompress,13  init as zstdInit,14} from "@bokuweb/zstd-wasm";15import { IMPORT_LIMITS, importTooLarge } from "../shared/import-limits";1617let initPromise: Promise<void> | null = null;1819function ensureInit(): Promise<void> {20  if (!initPromise) {21    initPromise = zstdInit().catch((err) => {22      initPromise = null;23      throw err;24    });25  }26  return initPromise;27}2829/** Compress bytes with zstd at the given level (default 19 per spec §4.1). */30export async function compressZstd(bytes: Uint8Array, level = 19): Promise<Uint8Array> {31  await ensureInit();32  return zstdCompress(bytes, level);33}3435/**36 * Decompress a zstd frame. Throws if the frame is malformed or if the37 * output exceeds IMPORT_LIMITS.MAX_DECOMPRESSED_BYTES (MV-4 — @bokuweb/38 * zstd-wasm materialises the whole output, so the post-hoc check is the39 * strongest available here; callers must ALSO bound the declared length40 * before calling).41 */42export async function decompressZstd(bytes: Uint8Array): Promise<Uint8Array> {43  await ensureInit();44  const out = zstdDecompress(bytes);45  if (out.byteLength > IMPORT_LIMITS.MAX_DECOMPRESSED_BYTES) {46    throw importTooLarge(47      `decompressed payload ${out.byteLength} bytes exceeds ${IMPORT_LIMITS.MAX_DECOMPRESSED_BYTES}`,48    );49  }50  return out;51}