@statewalker/webrun-files
v0.7.0
Published
FilesApi interface and utilities for cross-platform filesystem abstraction
Downloads
255
Readme
@statewalker/webrun-files
Core types and utilities for cross-platform file operations. This package defines the FilesApi interface that all storage backends implement, plus utility functions for common file operations.
Installation
npm install @statewalker/webrun-filesFor actual filesystem implementations, install one of these packages:
@statewalker/webrun-files-mem- In-memory storage@statewalker/webrun-files-node- Node.js filesystem@statewalker/webrun-files-browser- Browser File System Access API@statewalker/webrun-files-s3- AWS S3 / S3-compatible storage
The FilesApi Interface
All implementations provide this interface:
interface FilesApi {
// Read file content as async iterable of chunks
read(path: string, options?: ReadOptions): AsyncIterable<Uint8Array>;
// Write content to file (creates parent directories)
write(path: string, content: Iterable<Uint8Array> | AsyncIterable<Uint8Array>): Promise<void>;
// Create directory (and parents)
mkdir(path: string): Promise<void>;
// List directory contents
list(path: string, options?: ListOptions): AsyncIterable<FileInfo>;
// Get file/directory metadata
stats(path: string): Promise<FileStats | undefined>;
// Check if path exists
exists(path: string): Promise<boolean>;
// Remove file or directory (recursively)
remove(path: string): Promise<boolean>;
// Move/rename file or directory
move(source: string, target: string): Promise<boolean>;
// Copy file or directory (recursively)
copy(source: string, target: string): Promise<boolean>;
}Quick Start
import { MemFilesApi } from '@statewalker/webrun-files-mem';
import { readFile, writeText } from '@statewalker/webrun-files';
const files = new MemFilesApi();
// Write a file
await writeText(files, '/documents/notes.txt', 'Remember to water the plants');
// Read it back
const content = await readFile(files, '/documents/notes.txt');
console.log(new TextDecoder().decode(content));Utility Functions
Reading Files
import { readFile, readText, tryReadFile, tryReadText, readRange, readAt } from '@statewalker/webrun-files';
// Read entire file as Uint8Array
const content = await readFile(files, '/data.bin');
// Read as UTF-8 string
const text = await readText(files, '/config.json');
// Read with undefined return for missing files
const maybeContent = await tryReadFile(files, '/optional.txt');
const maybeText = await tryReadText(files, '/optional.txt');
// Read a specific byte range
const chunk = await readRange(files, '/large.bin', 1000, 500); // 500 bytes starting at position 1000
// Read into a buffer at specific offset (like fs.read)
const buffer = new Uint8Array(100);
const bytesRead = await readAt(files, '/data.bin', buffer, 0, 100, 500);Writing Files
import { writeText } from '@statewalker/webrun-files';
// Write string content as UTF-8
await writeText(files, '/greeting.txt', 'Hello, World!');
// Write binary content directly
await files.write('/data.bin', [new Uint8Array([1, 2, 3, 4])]);
// Write from multiple chunks
await files.write('/large.bin', generateChunks());Path Utilities
import { normalizePath, joinPath, dirname, basename, extname } from '@statewalker/webrun-files';
normalizePath('//foo/../bar/./baz/'); // '/bar/baz'
joinPath('/foo', 'bar', 'baz.txt'); // '/foo/bar/baz.txt'
dirname('/foo/bar/baz.txt'); // '/foo/bar'
basename('/foo/bar/baz.txt'); // 'baz.txt'
extname('/foo/bar/baz.txt'); // '.txt'Working with Files
Checking Existence
if (await files.exists('/config.json')) {
// Load configuration
}Getting Metadata
const info = await files.stats('/photo.jpg');
if (info) {
console.log(`Size: ${info.size} bytes`);
console.log(`Modified: ${new Date(info.lastModified)}`);
console.log(`Type: ${info.kind}`); // "file" or "directory"
}Listing Directories
// List direct children
for await (const entry of files.list('/documents')) {
console.log(`${entry.name} (${entry.kind})`);
}
// List recursively
for await (const entry of files.list('/project', { recursive: true })) {
console.log(entry.path);
}File Management
await files.mkdir('/archive/2024');
await files.copy('/report.pdf', '/archive/2024/report.pdf');
await files.move('/temp/draft.txt', '/documents/final.txt');
await files.remove('/old-stuff'); // Recursively deletes directoriesType Reference
import type {
FilesApi, // Core interface for backends
FileInfo, // Metadata from list() - includes name, path, kind, size, lastModified
FileStats, // Metadata from stats() - kind, size, lastModified
FileKind, // "file" | "directory"
ReadOptions, // { start?: number, length?: number, signal?: AbortSignal }
ListOptions, // { recursive?: boolean }
} from '@statewalker/webrun-files';License
MIT
