npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

fs-browser-side

v2.0.1

Published

NodeJS-like FileSystem API for the browser, built on the File System Access API

Readme

GitHub GitHub top language GitHub repo size GitHub contributors GitHub repo directory count GitHub last commit (branch) GitHub Repo stars GitHub watchers GitHub followers View counter

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 Promise by 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 errorsFsError extends Error with typed error codes.
  • AsyncGenerator for recursive readsreaddirRecursive yields entries lazily via for 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. Sample
  • 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.

License

MIT