filepulse
v1.0.0
Published
A powerful Node.js utility library for PDF compression, image optimization, file validation, file hashing, and streaming support
Maintainers
Readme
filepulse
A powerful, zero-bloat Node.js utility library for Advanced PDF compression, Image optimization, File validation, File hashing, and Streaming support.
Table of Contents
Installation
npm install filepulsePeer requirements
- Node.js ≥ 18
sharpnative bindings are installed automatically via npm
Features
📄 Advanced PDF Compression
A highly simplified native PDF parser that scans a buffer for Image XObjects, uses Sharp to compress/downscale them, and reconstructs the PDF XREF table.
Note: This targets simple PDFs specifically to optimize embedded images (e.g. JPEG and FlateDecode types) while bypassing full tree parsing overhead.
import { compressPdfAdvanced } from 'filepulse';
import { readFileSync, writeFileSync } from 'fs';
// ── Compress a PDF buffer directly ─────────────────────────────────────────
const pdfBuffer = readFileSync('scan.pdf');
const result = await compressPdfAdvanced(pdfBuffer, {
maxDimension: 1500, // Max width/height for embedded images
scale: 0.5, // Uniformly shrink images (mocking DPI reduction)
imageQuality: 60 // Re-encode quality for JPEG
});
console.log(`Original : ${result.originalSize} bytes`);
console.log(`Compressed : ${result.compressedSize} bytes`);
console.log(`Ratio : ${(result.ratio * 100).toFixed(1)}% smaller`);
if (result.buffer) {
writeFileSync('scan-compressed.pdf', result.buffer);
}🖼️ Image Optimization
Resize, reformat (JPEG / PNG / WebP / AVIF), and compress images. Uses the battle-tested sharp library under the hood.
import { optimizeImage, optimizeImageFile, getImageMetadata } from 'filepulse';
// ── Optimize a buffer ─────────────────────────────────────────────────────
const result = await optimizeImage(readFileSync('photo.jpg'), {
width: 800,
format: 'webp',
quality: 75,
fit: 'inside',
});
console.log(`${result.width}x${result.height} ${result.format}`);
console.log(`Saved ${(result.ratio * 100).toFixed(1)}%`);
// ── Optimize a file and save ──────────────────────────────────────────────
await optimizeImageFile('hero.png', 'hero.webp', {
width: 1920,
quality: 85,
});
// ── Read metadata only ────────────────────────────────────────────────────
const meta = await getImageMetadata('photo.jpg');
console.log(meta.width, meta.height, meta.format);✅ File Validation
Validate files by real MIME type (magic bytes, not just extension), file size, and allowed extensions.
import { validateFile, getFileInfo, matchesMime } from 'filepulse';
// ── Validate an upload ────────────────────────────────────────────────────
const result = await validateFile('uploadBuffer', {
allowedMimeTypes: ['image/jpeg', 'image/png', 'image/webp'],
allowedExtensions: ['jpg', 'jpeg', 'png', 'webp'],
maxSizeBytes: 5 * 1024 * 1024, // 5 MB
minSizeBytes: 1024, // 1 KB
});
if (!result.valid) {
console.error('Invalid file:', result.errors);
} else {
console.log(`Detected: ${result.detectedMimeType} (${result.detectedExtension})`);
}
// ── Get file info ─────────────────────────────────────────────────────────
const info = await getFileInfo('/path/to/unknown.bin');
console.log(info.mimeType); // 'image/jpeg' (from magic bytes)
console.log(info.size); // 204800
// ── Wildcard MIME matching ────────────────────────────────────────────────
matchesMime('image/jpeg', 'image/*'); // true🔒 File Hashing
Compute MD5, SHA-1, SHA-256, or SHA-512 hashes for buffers, files, or streams.
import { hashFile, hashStream, hashMany, filesAreEqual } from 'filepulse';
import { createReadStream } from 'fs';
const result = await hashFile('document.pdf', 'sha256');
console.log(result.hex);
const streamResult = await hashStream(createReadStream('video.mp4'), 'sha512');
console.log(streamResult.hex);
const identical = await filesAreEqual('original.pdf', 'copy.pdf');
console.log(identical ? 'Files match ✅' : 'Files differ ❌');🔄 Streaming Support
Purpose-built Transform streams for large-file processing: live progress tracking, in-flight hashing, and a simple pipeline builder.
import {
ProgressTransform,
HashTransform,
buildPipeline,
createGzipStream,
createGunzipStream,
} from 'filepulse';
import { createReadStream, createWriteStream, statSync } from 'fs';
// ── Track progress while copying ──────────────────────────────────────────
const size = statSync('large-video.mp4').size;
const progress = new ProgressTransform({ totalBytes: size });
progress.on('progress', ({ percent, bytesProcessed }) => {
process.stdout.write(`\r${percent?.toFixed(1)}% (${bytesProcessed} bytes)`);
});
await buildPipeline(
createReadStream('large-video.mp4'),
progress,
createWriteStream('large-video.copy.mp4')
);API Reference
PDF Advanced Compression
| Function | Description |
|---|---|
| compressPdfAdvanced(input, options?) | Compress PDF embedded images using Sharp and rebuild XREF |
Image
| Function | Description |
|---|---|
| optimizeImage(input, options?) | Optimize a buffer |
| optimizeImageFile(src, dest, options?) | Optimize and write to disk |
| getImageMetadata(input) | Read image dimensions/format without processing |
Validation
| Function | Description |
|---|---|
| validateFile(input, rules?) | Validate MIME, extension, size |
| getFileInfo(input) | Get size, MIME type, and extension |
| matchesMime(mime, pattern) | Wildcard MIME matching |
Hashing
| Function | Description |
|---|---|
| hashFile(input, algorithm?) | Hash a buffer or file |
| hashStream(stream, algorithm?) | Hash a readable stream |
| hashMany(inputs, algorithm?) | Hash multiple inputs in parallel |
| filesAreEqual(a, b, algorithm?) | Compare two files by hash |
Streaming
| Export | Description |
|---|---|
| ProgressTransform | Passthrough stream that emits progress events |
| HashTransform | Passthrough stream that computes a hash digest |
| buildPipeline(source, ...stages) | Chain multiple streams into a Promise-based pipeline |
| createGzipStream(options?) | Create a gzip Transform stream |
| createGunzipStream() | Create a gunzip Transform stream |
TypeScript Support
filepulse is written in TypeScript and ships full .d.ts type declarations.
import type {
CompressionResult,
AdvancedPdfCompressionOptions,
ImageOptimizationOptions,
ImageOptimizationResult,
ValidationRule,
ValidationResult,
HashAlgorithm,
HashResult,
FileInfo,
} from 'filepulse';Contributing
- Fork the repo
- Run
npm install - Implement your change under
src/ - Run
npm test - Submit a PR 🎉
License
MIT © 2026
