UNPKG

@mui/internal-docs-infra

Version:

MUI Infra - internal documentation creation tools.

88 lines (86 loc) 3.06 kB
import { inflateSync, inflate, strFromU8 } from 'fflate'; import { decode } from 'uint8-to-base64'; import { buildDictionary, computeDictionaryChecksum, CHECKSUM_BYTES, HastDictionaryMismatchError } from "./hastDictionary.mjs"; /** * Decompress a base64-encoded DEFLATE payload that was compressed with * `compressHast`. Returns the original JSON string. * * When `textContent` is provided, the first 4 bytes of the decoded payload * are treated as a dictionary checksum. If the checksum does not match the * dictionary built from `textContent`, a `HastDictionaryMismatchError` is * thrown — this prevents silently rendering corrupted data. * * When `textContent` is omitted, only the static dictionary is used for * decompression and no checksum verification is performed. */ export function decompressHast(base64, textContent) { const raw = decode(base64); const dictionary = buildDictionary(textContent); if (textContent != null) { verifyChecksum(raw, dictionary); } try { const deflated = textContent != null ? raw.subarray(CHECKSUM_BYTES) : raw; return strFromU8(inflateSync(deflated, { dictionary })); } catch (error) { // A raw inflate failure (e.g. fflate's "unexpected EOF") is almost always a // payload that was compressed with a fallback dictionary being decoded // without one — the checksum prefix is then read as deflate data. Surface // that cause instead of the cryptic `{code:0}` the raw error stringifies to. throw new Error(`Failed to decompress payload${textContent == null ? ' — if it was compressed with a fallback dictionary, that dictionary must be provided' : ''}: ${error instanceof Error ? error.message : String(error)}`); } } /** * Decompress a base64-encoded DEFLATE payload asynchronously. * Returns the original JSON string. * * See `decompressHast` for `textContent` semantics. */ export function decompressHastAsync(base64, textContent) { const raw = decode(base64); const dictionary = buildDictionary(textContent); if (textContent != null) { try { verifyChecksum(raw, dictionary); } catch (checksumError) { return Promise.reject(checksumError); } return new Promise((resolve, reject) => { inflate(raw.subarray(CHECKSUM_BYTES), { consume: true, dictionary }, (err, output) => { if (err) { reject(err); } else { resolve(strFromU8(output)); } }); }); } return new Promise((resolve, reject) => { inflate(raw, { consume: true, dictionary }, (err, output) => { if (err) { reject(err); } else { resolve(strFromU8(output)); } }); }); } function verifyChecksum(raw, dictionary) { if (raw.byteLength < CHECKSUM_BYTES) { throw new HastDictionaryMismatchError(); } const expected = computeDictionaryChecksum(dictionary); for (let i = 0; i < CHECKSUM_BYTES; i += 1) { if (raw[i] !== expected[i]) { throw new HastDictionaryMismatchError(); } } }