This document provides comprehensive documentation for all TypeScript types and interfaces used in zip-json.
The primary archive format that represents a compressed collection of files in JSON format.
interface ZipJsonData {
meta: ArchiveMetadata
blob: string
}Properties:
meta- Archive metadata containing file information and statisticsblob- Base64-encoded compressed binary data containing the actual file contents
Example:
const archive: ZipJsonData = {
meta: {
version: "1.0.0",
createdAt: "2024-01-15T10:30:00.000Z",
files: [...],
totalSize: 1048576,
fileCount: 25
},
blob: "H4sIAAAAAAAA..."
}Metadata about the archive and its contents.
interface ArchiveMetadata {
version: string
createdAt: string
files: FileEntry[]
totalSize: number
fileCount: number
}Properties:
version- Archive format version (currently "1.0.0")createdAt- ISO 8601 timestamp of when the archive was createdfiles- Array of file entries describing each file in the archivetotalSize- Total uncompressed size of all files in bytesfileCount- Number of files in the archive
Represents a single file or directory in the archive.
interface FileEntry {
path: string
size: number
mode: number
isDirectory: boolean
modifiedAt: string
}Properties:
path- Relative path of the file from the base directorysize- File size in bytes (0 for directories)mode- Unix file permissions as a number (e.g., 33188 for -rw-r--r--)isDirectory- Boolean indicating if this entry is a directorymodifiedAt- ISO 8601 timestamp of when the file was last modified
Example:
const fileEntry: FileEntry = {
path: "src/utils/format.ts",
size: 2048,
mode: 33188,
isDirectory: false,
modifiedAt: "2024-01-15T10:25:00.000Z"
}
const directoryEntry: FileEntry = {
path: "src/core",
size: 0,
mode: 16877,
isDirectory: true,
modifiedAt: "2024-01-15T10:20:00.000Z"
}Configuration options for creating archives.
interface ZipOptions {
baseDir?: string
ignore?: string[]
onProgress?: (progress: ProgressInfo) => void
}Properties:
baseDir- Base directory for calculating relative paths (default: current working directory)ignore- Array of glob patterns to exclude from archivingonProgress- Callback function called during archiving to report progress
Example:
const options: ZipOptions = {
baseDir: "/home/user/project",
ignore: ["node_modules/**", "*.log", ".git/**"],
onProgress: (info) => {
console.log(`Progress: ${info.percentage}%`)
}
}Configuration options for extracting archives.
interface UnzipOptions {
outputDir?: string
overwrite?: boolean
preservePermissions?: boolean
onProgress?: (progress: ProgressInfo) => void
}Properties:
outputDir- Directory to extract files to (default: current working directory)overwrite- Whether to overwrite existing files (default: true)preservePermissions- Whether to preserve original file permissions (default: false)onProgress- Callback function called during extraction to report progress
Example:
const options: UnzipOptions = {
outputDir: "./extracted",
overwrite: false,
preservePermissions: true,
onProgress: (info) => {
const percent = Math.round(info.percentage)
console.log(`Extracting: ${percent}% (${info.processedFiles}/${info.totalFiles})`)
}
}All error types extend the base Error class and include additional context.
Thrown when a specified file or directory cannot be found.
class FileNotFoundError extends Error {
readonly filePath: string
constructor(filePath: string)
}Properties:
filePath- The path that could not be foundmessage- Human-readable error message
Example:
try {
const content = await readFileContent('/nonexistent/file.txt')
} catch (error) {
if (error instanceof FileNotFoundError) {
console.error(`File not found: ${error.filePath}`)
}
}Thrown when there are insufficient permissions to access a file or directory.
class PermissionError extends Error {
readonly filePath: string
readonly operation: string
constructor(filePath: string, operation: string)
}Properties:
filePath- The path that couldn't be accessedoperation- The operation that failed (e.g., "read", "write", "change permissions for")message- Human-readable error message
Example:
try {
await writeFileContent('/root/restricted.txt', buffer)
} catch (error) {
if (error instanceof PermissionError) {
console.error(`Permission denied: Cannot ${error.operation} ${error.filePath}`)
}
}Thrown when an archive is malformed, corrupted, or has an unsupported format.
class InvalidArchiveError extends Error {
readonly reason: string
constructor(reason: string)
}Properties:
reason- Specific reason why the archive is invalidmessage- Human-readable error message
Example:
try {
const files = await unzip(corruptedArchive)
} catch (error) {
if (error instanceof InvalidArchiveError) {
console.error(`Invalid archive: ${error.reason}`)
}
}Thrown when attempting to overwrite an existing file without permission.
class OverwriteError extends Error {
readonly filePath: string
constructor(filePath: string)
}Properties:
filePath- The path that would be overwrittenmessage- Human-readable error message
Example:
try {
await unzip(archive, { overwrite: false })
} catch (error) {
if (error instanceof OverwriteError) {
console.error(`File already exists: ${error.filePath}`)
}
}Thrown when compression or decompression operations fail.
class CompressionError extends Error {
readonly operation: 'compress' | 'decompress'
constructor(operation: 'compress' | 'decompress', originalError: Error)
}Properties:
operation- Whether the error occurred during compression or decompressionmessage- Human-readable error message including the original error
Example:
try {
const compressed = await compressor.compress(data)
} catch (error) {
if (error instanceof CompressionError) {
console.error(`${error.operation} failed: ${error.message}`)
}
}Information provided to progress callback functions.
interface ProgressInfo {
processedFiles: number
totalFiles: number
percentage: number
currentFile?: string
}Properties:
processedFiles- Number of files processed so fartotalFiles- Total number of files to processpercentage- Completion percentage (0-100)currentFile- Currently processing file path (when available)
Example:
const progressCallback = (info: ProgressInfo) => {
const { processedFiles, totalFiles, percentage, currentFile } = info
console.log(`[${percentage}%] ${processedFiles}/${totalFiles}`)
if (currentFile) {
console.log(`Processing: ${currentFile}`)
}
}Helper functions to check types at runtime:
// Check if an object is a valid ZipJsonData
function isZipJsonData(obj: unknown): obj is ZipJsonData {
return (
typeof obj === 'object' &&
obj !== null &&
'meta' in obj &&
'blob' in obj &&
typeof (obj as any).blob === 'string'
)
}
// Check if an object is a valid FileEntry
function isFileEntry(obj: unknown): obj is FileEntry {
return (
typeof obj === 'object' &&
obj !== null &&
'path' in obj &&
'size' in obj &&
'isDirectory' in obj &&
typeof (obj as any).path === 'string' &&
typeof (obj as any).size === 'number' &&
typeof (obj as any).isDirectory === 'boolean'
)
}Types that can be extended or customized:
// Custom progress callback type
type ProgressCallback<T = void> = (info: ProgressInfo) => T
// File filter predicate
type FileFilter = (file: FileEntry) => boolean
// Archive validation result
type ValidationResult = {
valid: boolean
errors: string[]
warnings: string[]
}Common union types for specific use cases:
// Supported file operations
type FileOperation = 'read' | 'write' | 'delete' | 'change permissions for'
// Archive format versions
type ArchiveVersion = '1.0.0'
// Compression levels (for future use)
type CompressionLevel = 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9
// File modes (common Unix permissions)
type CommonFileMode =
| 0o644 // -rw-r--r-- (regular file)
| 0o755 // -rwxr-xr-x (executable file)
| 0o666 // -rw-rw-rw- (world writable)
| 0o777 // -rwxrwxrwx (world executable)import { ZipJsonData, ZipOptions, FileEntry } from 'zip-json'
async function createProjectBackup(
projectPath: string,
options: Partial<ZipOptions> = {}
): Promise<ZipJsonData> {
const defaultOptions: ZipOptions = {
baseDir: projectPath,
ignore: ['node_modules/**', '.git/**', 'dist/**'],
onProgress: (info) => {
console.log(`Backing up: ${info.percentage}%`)
}
}
const finalOptions = { ...defaultOptions, ...options }
return await zip(['**/*'], finalOptions)
}function validateArchive(data: unknown): data is ZipJsonData {
if (!isZipJsonData(data)) {
throw new InvalidArchiveError('Invalid archive format')
}
if (!data.meta.version || data.meta.version !== '1.0.0') {
throw new InvalidArchiveError(`Unsupported version: ${data.meta.version}`)
}
if (!Array.isArray(data.meta.files)) {
throw new InvalidArchiveError('Files list is not an array')
}
return true
}function analyzeArchive(archive: ZipJsonData): {
directories: FileEntry[]
files: FileEntry[]
totalSize: number
largestFile: FileEntry | null
} {
const directories = archive.meta.files.filter(f => f.isDirectory)
const files = archive.meta.files.filter(f => !f.isDirectory)
const largestFile = files.reduce<FileEntry | null>((largest, current) => {
if (!largest || current.size > largest.size) {
return current
}
return largest
}, null)
return {
directories,
files,
totalSize: archive.meta.totalSize,
largestFile
}
}