wip library to store cold objects in s3, warm objects on disk, and hot objects in memory
nodejs typescript
at main 3.4 kB view raw
1import { gzip, gunzip, createGzip, createGunzip } from 'node:zlib'; 2import { promisify } from 'node:util'; 3import type { Transform } from 'node:stream'; 4 5const gzipAsync = promisify(gzip); 6const gunzipAsync = promisify(gunzip); 7 8/** 9 * Compress data using gzip. 10 * 11 * @param data - Data to compress 12 * @returns Compressed data as Uint8Array 13 * 14 * @remarks 15 * Uses Node.js zlib with default compression level (6). 16 * Compression is transparent to the user - data is automatically decompressed on retrieval. 17 * 18 * @example 19 * ```typescript 20 * const original = new TextEncoder().encode('Hello, world!'); 21 * const compressed = await compress(original); 22 * console.log(`Compressed from ${original.length} to ${compressed.length} bytes`); 23 * ``` 24 */ 25export async function compress(data: Uint8Array): Promise<Uint8Array> { 26 const buffer = Buffer.from(data); 27 const compressed = await gzipAsync(buffer); 28 return new Uint8Array(compressed); 29} 30 31/** 32 * Decompress gzip-compressed data. 33 * 34 * @param data - Compressed data 35 * @returns Decompressed data as Uint8Array 36 * @throws Error if data is not valid gzip format 37 * 38 * @remarks 39 * Automatically validates gzip magic bytes (0x1f 0x8b) before decompression. 40 * 41 * @example 42 * ```typescript 43 * const decompressed = await decompress(compressedData); 44 * const text = new TextDecoder().decode(decompressed); 45 * ``` 46 */ 47export async function decompress(data: Uint8Array): Promise<Uint8Array> { 48 // Validate gzip magic bytes 49 if (data.length < 2 || data[0] !== 0x1f || data[1] !== 0x8b) { 50 throw new Error('Invalid gzip data: missing magic bytes'); 51 } 52 53 const buffer = Buffer.from(data); 54 const decompressed = await gunzipAsync(buffer); 55 return new Uint8Array(decompressed); 56} 57 58/** 59 * Check if data appears to be gzip-compressed by inspecting magic bytes. 60 * 61 * @param data - Data to check 62 * @returns true if data starts with gzip magic bytes (0x1f 0x8b) 63 * 64 * @remarks 65 * This is a quick check that doesn't decompress the data. 66 * Useful for detecting already-compressed data to avoid double compression. 67 * 68 * @example 69 * ```typescript 70 * if (isGzipped(data)) { 71 * console.log('Already compressed, skipping compression'); 72 * } else { 73 * data = await compress(data); 74 * } 75 * ``` 76 */ 77export function isGzipped(data: Uint8Array): boolean { 78 return data.length >= 2 && data[0] === 0x1f && data[1] === 0x8b; 79} 80 81/** 82 * Create a gzip compression transform stream. 83 * 84 * @returns A transform stream that compresses data passing through it 85 * 86 * @remarks 87 * Use this for streaming compression of large files. 88 * Pipe data through this stream to compress it on-the-fly. 89 * 90 * @example 91 * ```typescript 92 * const compressStream = createCompressStream(); 93 * sourceStream.pipe(compressStream).pipe(destinationStream); 94 * ``` 95 */ 96export function createCompressStream(): Transform { 97 return createGzip(); 98} 99 100/** 101 * Create a gzip decompression transform stream. 102 * 103 * @returns A transform stream that decompresses data passing through it 104 * 105 * @remarks 106 * Use this for streaming decompression of large files. 107 * Pipe compressed data through this stream to decompress it on-the-fly. 108 * 109 * @example 110 * ```typescript 111 * const decompressStream = createDecompressStream(); 112 * compressedStream.pipe(decompressStream).pipe(destinationStream); 113 * ``` 114 */ 115export function createDecompressStream(): Transform { 116 return createGunzip(); 117}