Press n or j to go to the next uncovered block, b, p or k for the previous block.
| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 | 85x 76x 28x 28x 34x 9x 5x 20x 18x 17x 17x 1x 14x 14x 14x 14x 14x | /**
* Application-level compression for large text fields in the messages table.
*
* Compresses html_body, raw_headers (not in FTS5 index) and attachment blob
* data using Node.js zlib (deflate). text_body is left uncompressed because
* the FTS5 content=messages triggers read it directly from the messages table.
*
* The decompress helpers are type-aware: SQLite returns TEXT columns as strings
* and BLOB columns as Buffers via better-sqlite3. Legacy uncompressed data
* (string) passes through unchanged; compressed data (Buffer) is inflated.
*/
import { deflateSync, inflateSync } from "node:zlib";
/** Compress a string into a deflated Buffer. Returns null for null/undefined input. */
export function compressText(text: string | null | undefined): Buffer | null {
if (text == null) return null;
return deflateSync(Buffer.from(text, "utf-8"), { level: 6 });
}
/** Compress a Buffer (e.g. attachment data). Returns null for null/undefined input. */
export function compressBuffer(data: Buffer | null | undefined): Buffer | null {
Iif (data == null) return null;
return deflateSync(data, { level: 6 });
}
/**
* Decompress a field that may be either a string (legacy uncompressed) or
* a Buffer (compressed). Returns null for null/undefined input.
*/
export function decompressText(value: Buffer | string | null | undefined): string | null {
if (value == null) return null;
if (typeof value === "string") return value; // legacy uncompressed
return inflateSync(value).toString("utf-8");
}
/**
* Decompress a Buffer field that may be either uncompressed or compressed.
* For attachment blobs: compressed data starts with zlib header (0x78).
* Legacy uncompressed data is returned as-is.
*/
export function decompressBuffer(data: Buffer | null | undefined): Buffer | null {
if (data == null) return null;
// zlib deflate streams start with 0x78 (CMF byte: CM=8 deflate, CINFO varies)
// Raw data that happens to start with 0x78 would fail inflate, so we try/catch
if (data.length >= 2 && data[0] === 0x78) {
try {
return inflateSync(data);
} catch {
return data; // not actually compressed
}
}
return data;
}
/**
* Decompress html_body and raw_headers on a message row object.
* Mutates and returns the same object for convenience.
*/
export function decompressMessageRow<T extends Record<string, unknown>>(row: T): T {
Eif ("html_body" in row) {
(row as Record<string, unknown>).html_body = decompressText(
row.html_body as Buffer | string | null,
);
}
Eif ("raw_headers" in row) {
(row as Record<string, unknown>).raw_headers = decompressText(
row.raw_headers as Buffer | string | null,
);
}
return row;
}
|