
Research
6 Malicious Packagist Themes Ship Trojanized jQuery and FUNNULL Redirect Payloads
Six malicious Packagist packages posing as OphimCMS themes contain trojanized jQuery that exfiltrates URLs, injects ads, and loads FUNNULL-linked redirects.
A high-performance ZIP archive library for Bun, built with native C bindings using the miniz compression library and Bun's C compiler.
npm install zip-bun
# or
bun add zip-bun
import { createArchive, CompressionLevel } from "zip-bun";
// Create a new ZIP archive
const writer = createArchive("archive.zip");
// Add files with different compression levels
const textData = new TextEncoder().encode("Hello, World!");
writer.addFile("hello.txt", textData, CompressionLevel.DEFAULT);
const jsonData = new TextEncoder().encode('{"message": "Hello"}');
writer.addFile("data.json", jsonData, CompressionLevel.BEST_COMPRESSION);
// Don't forget to finalize the archive
writer.finalize();
import { createMemoryArchive } from "zip-bun";
// Create a memory-based ZIP archive
const writer = createMemoryArchive();
// Add files
const textData = new TextEncoder().encode("Hello, World!");
writer.addFile("hello.txt", textData, CompressionLevel.DEFAULT);
// Get the ZIP data as a Uint8Array
const zipData = writer.finalizeToMemory();
// Use the data (e.g., save to file, send over network, etc.)
await Bun.write("archive.zip", zipData);
import { openMemoryArchive } from "zip-bun";
// Read a ZIP archive from memory data
const zipData = await Bun.file("archive.zip").arrayBuffer();
const reader = openMemoryArchive(new Uint8Array(zipData));
// Use the reader just like a file-based reader
console.log(`Archive contains ${reader.getFileCount()} files`);
// Extract files
const data = reader.extractFile(0);
const text = new TextDecoder().decode(data);
console.log(text);
reader.close();
import { openArchive } from "zip-bun";
// Open an existing ZIP archive
const reader = openArchive("archive.zip");
// Get information about files
console.log(`Archive contains ${reader.getFileCount()} files`);
// List all files
for (let i = 0; i < reader.getFileCount(); i++) {
const fileInfo = reader.getFileByIndex(i);
console.log(`${fileInfo.filename}: ${fileInfo.uncompressedSize} bytes`);
}
// Extract a specific file
const data = reader.extractFile(0);
const text = new TextDecoder().decode(data);
console.log(text);
// Or extract by filename
const fileData = reader.extractFileByName("hello.txt");
// Don't forget to close the reader
reader.close();
enum CompressionLevel {
NO_COMPRESSION = 0, // No compression
BEST_SPEED = 1, // Fastest compression
DEFAULT = 6, // Default compression
BEST_COMPRESSION = 9 // Best compression ratio
}
A class for creating ZIP archives, supporting both file-based and memory-based operations.
Constructor:
// File-based ZIP
createArchive(filename: string): ZipArchiveWriter
// Memory-based ZIP
createMemoryArchive(): ZipArchiveWriter
// or
createArchive(): ZipArchiveWriter // No filename creates memory-based archive
Methods:
// Add a file to the archive
addFile(
filename: string,
data: Uint8Array | ArrayBuffer | DataView,
compressionLevel?: CompressionLevel
): boolean
// Finalize file-based archive (writes to disk)
finalize(): boolean
// Finalize memory-based archive (returns Uint8Array)
finalizeToMemory(): Uint8Array
A class for reading and extracting from ZIP archives, supporting both file-based and memory-based archives.
Constructor:
// File-based ZIP
openArchive(filename: string): ZipArchiveReader
// Memory-based ZIP
openMemoryArchive(data: Uint8Array | ArrayBuffer | DataView): ZipArchiveReader
Methods:
// Get the number of files in the archive
getFileCount(): number
// Get information about a file by index
getFileByIndex(index: number): ZipFile
// Extract a file by index
extractFile(index: number): Uint8Array
// Extract a file by name
extractFileByName(filename: string): Uint8Array
// Find the index of a file by name (returns -1 if not found)
findFile(filename: string): number
// Close the archive reader
close(): boolean
Information about a file in a ZIP archive.
interface ZipFile {
filename: string; // Name of the file
comment: string; // File comment
uncompressedSize: number; // Original file size
compressedSize: number; // Compressed file size
directory: boolean; // Whether this is a directory
encrypted: boolean; // Whether the file is encrypted
}
Supported data types for adding files to archives.
type FileData = Uint8Array | ArrayBuffer | DataView;
// Create a ZIP archive from a directory
zipDirectory(
sourceDir: string,
outputFile: string,
compressionLevel?: CompressionLevel
): Promise<void>
// Extract all files from a ZIP archive
extractArchive(
zipFile: string,
outputDir: string
): Promise<void>
// Create a ZIP archive from a directory in memory
zipDirectoryToMemory(
sourceDir: string,
compressionLevel?: CompressionLevel
): Promise<Uint8Array>
// Open a ZIP archive from memory data
openMemoryArchive(data: Uint8Array | ArrayBuffer | DataView): ZipArchiveReader
import { createArchive, CompressionLevel } from "zip-bun";
const writer = createArchive("backup.zip");
// Add text files
const readmeData = new TextEncoder().encode("# My Project\n\nThis is a README file.");
writer.addFile("README.md", readmeData, CompressionLevel.DEFAULT);
// Add JSON configuration
const configData = new TextEncoder().encode('{"version": "1.0.0", "debug": false}');
writer.addFile("config.json", configData, CompressionLevel.BEST_COMPRESSION);
// Add binary files
const imageData = await Bun.file("image.png").arrayBuffer();
writer.addFile("image.png", new Uint8Array(imageData), CompressionLevel.BEST_SPEED);
writer.finalize();
import { zipDirectory, CompressionLevel } from "zip-bun";
// Create a ZIP from a directory
await zipDirectory("my-project", "project-backup.zip", CompressionLevel.BEST_COMPRESSION);
import { openArchive } from "zip-bun";
const reader = openArchive("backup.zip");
for (let i = 0; i < reader.getFileCount(); i++) {
const fileInfo = reader.getFileByIndex(i);
if (!fileInfo.directory) {
const data = reader.extractFile(i);
// Save to file system
await Bun.write(fileInfo.filename, data);
console.log(`Extracted: ${fileInfo.filename}`);
}
}
reader.close();
import { extractArchive } from "zip-bun";
// Extract all files from a ZIP to a directory
await extractArchive("backup.zip", "extracted-files");
import { createMemoryArchive, CompressionLevel } from "zip-bun";
const writer = createMemoryArchive();
// Add files to memory-based archive
const textData = new TextEncoder().encode("Hello, World!");
writer.addFile("hello.txt", textData, CompressionLevel.DEFAULT);
const jsonData = new TextEncoder().encode('{"key": "value"}');
writer.addFile("data.json", jsonData, CompressionLevel.BEST_COMPRESSION);
// Get the ZIP data as Uint8Array
const zipData = writer.finalizeToMemory();
// Use the data
await Bun.write("output.zip", zipData);
// or send over network
// await fetch("https://api.example.com/upload", {
// method: "POST",
// body: zipData
// });
import { zipDirectoryToMemory, CompressionLevel } from "zip-bun";
// Create a ZIP from a directory in memory
const zipData = await zipDirectoryToMemory("my-project", CompressionLevel.BEST_COMPRESSION);
// Use the memory-based ZIP data
await Bun.write("project.zip", zipData);
import { openMemoryArchive } from "zip-bun";
// Read a ZIP archive from memory data
const zipData = await Bun.file("archive.zip").arrayBuffer();
const reader = openMemoryArchive(new Uint8Array(zipData));
// Use the reader just like a file-based reader
console.log(`Archive contains ${reader.getFileCount()} files`);
// Extract files
const data = reader.extractFile(0);
const text = new TextDecoder().decode(data);
console.log(text);
reader.close();
import { createMemoryArchive, openMemoryArchive } from "zip-bun";
// Create a memory-based ZIP
const writer = createMemoryArchive();
const textData = new TextEncoder().encode("Hello, World!");
writer.addFile("hello.txt", textData, CompressionLevel.DEFAULT);
// Get the ZIP data
const zipData = writer.finalizeToMemory();
// Read the same ZIP data back from memory
const reader = openMemoryArchive(zipData);
const extractedData = reader.extractFile(0);
const extractedText = new TextDecoder().decode(extractedData);
console.log(extractedText); // "Hello, World!"
reader.close();
import { createMemoryArchive } from "zip-bun";
const writer = createMemoryArchive();
// Uint8Array
const uint8Data = new Uint8Array([1, 2, 3, 4, 5]);
writer.addFile("data.bin", uint8Data);
// ArrayBuffer
const arrayBuffer = new ArrayBuffer(8);
const view = new DataView(arrayBuffer);
view.setInt32(0, 42, true);
writer.addFile("config.bin", arrayBuffer);
// DataView
const dataView = new DataView(new ArrayBuffer(4));
dataView.setFloat32(0, 3.14, true);
writer.addFile("float.bin", dataView);
const zipData = writer.finalizeToMemory();
import { openMemoryArchive } from "zip-bun";
// Read ZIP from different data types
const zipData = await Bun.file("archive.zip").arrayBuffer();
// Using Uint8Array
const reader1 = openMemoryArchive(new Uint8Array(zipData));
// Using ArrayBuffer directly
const reader2 = openMemoryArchive(zipData);
// Using DataView
const dataView = new DataView(zipData);
const reader3 = openMemoryArchive(dataView);
// All readers work the same way
console.log(`Files: ${reader1.getFileCount()}`);
reader1.close();
reader2.close();
reader3.close();
import { openArchive } from "zip-bun";
const reader = openArchive("archive.zip");
// Find a specific file
const index = reader.findFile("config.json");
if (index >= 0) {
const data = reader.extractFile(index);
const config = JSON.parse(new TextDecoder().decode(data));
console.log("Config:", config);
} else {
console.log("config.json not found");
}
// Or extract directly by name
try {
const data = reader.extractFileByName("config.json");
const config = JSON.parse(new TextDecoder().decode(data));
console.log("Config:", config);
} catch (error) {
console.log("config.json not found");
}
reader.close();
import { openArchive } from "zip-bun";
const reader = openArchive("archive.zip");
for (let i = 0; i < reader.getFileCount(); i++) {
const fileInfo = reader.getFileByIndex(i);
console.log(`File: ${fileInfo.filename}`);
console.log(` Size: ${fileInfo.uncompressedSize} bytes`);
console.log(` Compressed: ${fileInfo.compressedSize} bytes`);
console.log(` Compression ratio: ${((1 - fileInfo.compressedSize / fileInfo.uncompressedSize) * 100).toFixed(1)}%`);
console.log(` Directory: ${fileInfo.directory}`);
console.log(` Encrypted: ${fileInfo.encrypted}`);
console.log(` Comment: ${fileInfo.comment}`);
}
reader.close();
import { createArchive, openArchive } from "zip-bun";
// Error handling for file-based operations
try {
const writer = createArchive("output.zip");
writer.addFile("test.txt", new TextEncoder().encode("Hello"));
writer.finalize();
} catch (error) {
console.error("Failed to create ZIP:", error.message);
}
// Error handling for memory-based operations
try {
const writer = createMemoryArchive();
writer.addFile("test.txt", new TextEncoder().encode("Hello"));
const data = writer.finalizeToMemory();
} catch (error) {
console.error("Failed to create memory ZIP:", error.message);
}
// Error handling for reading
try {
const reader = openArchive("nonexistent.zip");
reader.close();
} catch (error) {
console.error("Failed to open ZIP:", error.message);
}
This library provides excellent performance through:
| Operation | File Size | Time |
|---|---|---|
| Create ZIP | 1MB | ~50ms |
| Create Memory ZIP | 1MB | ~45ms |
| Extract ZIP | 1MB | ~30ms |
| Extract Memory ZIP | 1MB | ~25ms |
| Compress (BEST) | 1MB | ~100ms |
| Compress (SPEED) | 1MB | ~20ms |
| Directory to ZIP | 10MB | ~200ms |
| Directory to Memory ZIP | 10MB | ~180ms |
| Round-trip Memory | 1MB | ~70ms |
# Run all tests
bun test
# Run tests with coverage
bun test --coverage
# Run specific test file
bun test zip.test.ts
# Build the project
bun run build
This project is licensed under the MIT License - see the LICENSE file for details.
FAQs
A high-performance zip archive library for Bun with native C bindings
We found that zip-bun demonstrated a healthy version release cadence and project activity because the last version was released less than a year ago. It has 1 open source maintainer collaborating on the project.
Did you know?

Socket for GitHub automatically highlights issues in each pull request and monitors the health of all your open source dependencies. Discover the contents of your packages and block harmful activity before you install or update your dependencies.

Research
Six malicious Packagist packages posing as OphimCMS themes contain trojanized jQuery that exfiltrates URLs, injects ads, and loads FUNNULL-linked redirects.

Security News
The GCVE initiative operated by CIRCL has officially opened its publishing ecosystem, letting organizations issue and share vulnerability identifiers without routing through a central authority.

Security News
The project is retiring its odd/even release model in favor of a simpler annual cadence where every major version becomes LTS.