FsBrowserSide
FS Browser side Javascript module (server-to-client adaptation)
Install / Use
/learn @WaRtr0/FsBrowserSideREADME
Fs Browser Side
Overview
Fs Browser Side is a TypeScript library that brings Node.js FileSystem (fs) capabilities into the client-side environment, built on top of the File System Access API. It provides a clean, promise-based interface for managing files and directories within the browser.
Features
- Promise-first API — All methods return
Promiseby default, with optional error-first callbacks. - Stateless path resolution — No mutable internal state; concurrent operations are safe.
- Robust path handling — Proper normalization with
.,.., and//support. - Idiomatic errors —
FsErrorextendsErrorwith typed error codes. - AsyncGenerator for recursive reads —
readdirRecursiveyields entries lazily viafor await...of. - Two access modes — User-picked directory (
showDirectoryPicker) or OPFS (navigator.storage).
Installation
pnpm add fs-browser-side
Quick Start
import { FsBrowserSide } from 'fs-browser-side';
const fs = new FsBrowserSide();
// Request access to a user-selected directory
if (await fs.getAccess()) {
// Create nested directories
await fs.mkdir('/project/src', { recursive: true });
// Write a text file
await fs.writeFileText('/project/src/index.ts', 'console.log("hello");');
// Read it back
const content = await fs.readFileText('/project/src/index.ts');
console.log(content); // 'console.log("hello");'
// List directory contents
const entries = await fs.readdir('/project/src');
console.log(entries);
// [{ name: 'index.ts', type: 'file', path: '/project/src/index.ts' }]
}
OPFS Mode (Origin Private File System)
const fs = new FsBrowserSide({ navigatorMode: true });
await fs.getAccess(); // No user prompt needed
API Reference
new FsBrowserSide(options?)
| Option | Type | Default | Description |
|---|---|---|---|
| navigatorMode | boolean | false | Use OPFS instead of showDirectoryPicker |
getAccess(): Promise<boolean>
Request file system access. Returns true on success.
readFile(path): Promise<ArrayBuffer>
Read a file as an ArrayBuffer.
readFileText(path): Promise<string>
Read a file as a UTF-8 string.
writeFile(path, data, options?): Promise<void>
Write binary data to a file. Creates the file and parent directories if needed.
| Option | Type | Default | Description |
|---|---|---|---|
| append | boolean | false | Append to existing content |
writeFileText(path, data, options?): Promise<void>
Write a string to a file. Same options as writeFile.
exists(path): Promise<boolean>
Check if a file or directory exists at the given path.
mkdir(path, options?): Promise<void>
Create a directory.
| Option | Type | Default | Description |
|---|---|---|---|
| recursive | boolean | false | Create parent directories as needed |
rmdir(path, options?): Promise<void>
Remove a directory. Fails if non-empty unless recursive is true.
| Option | Type | Default | Description |
|---|---|---|---|
| recursive | boolean | false | Remove contents recursively |
rm(path, options?): Promise<void>
Remove a file or directory entry.
| Option | Type | Default | Description |
|---|---|---|---|
| recursive | boolean | false | Remove directory contents recursively |
copyFile(src, dest): Promise<void>
Copy a file from src to dest.
rename(src, dest): Promise<void>
Move/rename a file (copy + remove).
readdir(path): Promise<DirEntry[]>
List entries in a directory. Each DirEntry has name, type ('file' | 'directory'), and path.
readdirRecursive(path): AsyncGenerator<DirEntry>
Recursively yield all entries under a directory:
for await (const entry of fs.readdirRecursive('/')) {
console.log(entry.type, entry.path);
}
Callback Style
Every method also accepts an error-first callback as last argument:
fs.readFileText('/file.txt', (err, content) => {
if (err) {
console.error(err.code, err.path);
return;
}
console.log(content);
});
Error Handling
All errors are instances of FsError with a typed code:
import { FsError } from 'fs-browser-side';
try {
await fs.readFile('/missing.txt');
} catch (err) {
if (err instanceof FsError) {
console.log(err.code); // 'NOT_FOUND'
console.log(err.path); // '/missing.txt'
}
}
| Code | Description |
|---|---|
| NO_ACCESS | File system access not granted |
| NOT_FOUND | Path does not exist |
| ALREADY_EXISTS | Path already exists |
| PERMISSION_DENIED | Insufficient permissions |
| INVALID_PATH | Invalid path (e.g. resolves above root) |
| NOT_A_DIRECTORY | Expected a directory |
| NOT_A_FILE | Expected a file |
| UNKNOWN | Unexpected error |
Path Utilities
import { PathUtils } from 'fs-browser-side';
PathUtils.normalize('//a/./b/../c'); // '/a/c'
PathUtils.dirname('/a/b/c'); // '/a/b'
PathUtils.basename('/a/b/c'); // 'c'
PathUtils.join('/a', 'b', '../c'); // '/a/c'
PathUtils.segments('/a/b/c'); // ['a', 'b', 'c']
Compatibility
The library requires browser support for the File System Access API. OPFS mode (navigatorMode: true) has broader compatibility than showDirectoryPicker.
Use Cases
- Browser-Based IDE — Read and write project files directly. Demo Github
- Custom CMS — Manage content files without a server.
- Offline-first apps — Persistent storage via OPFS.
- Client-side scraping — Save processed data to local files.
- Photo/file organizer — Manage user files in the browser.
Contributing
You are completely free to contribute to this project! It would be my pleasure to review and accept your Pull Requests or Issues to improve this package.
License
This project is licensed under the MIT License.
Related Skills
gh-issues
339.5kFetch GitHub issues, spawn sub-agents to implement fixes and open PRs, then monitor and address PR review comments. Usage: /gh-issues [owner/repo] [--label bug] [--limit 5] [--milestone v1.0] [--assignee @me] [--fork user/repo] [--watch] [--interval 5] [--reviews-only] [--cron] [--dry-run] [--model glm-5] [--notify-channel -1002381931352]
node-connect
339.5kDiagnose OpenClaw node connection and pairing failures for Android, iOS, and macOS companion apps
oracle
339.5kBest practices for using the oracle CLI (prompt + file bundling, engines, sessions, and file attachment patterns).
tmux
339.5kRemote-control tmux sessions for interactive CLIs by sending keystrokes and scraping pane output.
