@mui/internal-docs-infra
Version:
MUI Infra - internal documentation creation tools.
88 lines (86 loc) • 3.06 kB
JavaScript
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();
}
}
}