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

@k13engineering/fsapi-nodefs

v0.0.2

Published

An fsapi file system of a directory on the disk, through the fs promises API of Node.js

Readme

fsapi-nodefs

An fsapi file system of a directory on the disk, through the fs promises API of Node.js. Everything fsapi offers on top of a file system, such as its convenience API, chroot, virtual file systems, or an NFS server like nfs-server, then works on real files.

Note: this project is mostly AI coded. Its code, tests and documentation were largely written by an AI assistant, and reviewed and directed by a human maintainer.

npm install @k13engineering/fsapi-nodefs @k13engineering/fsapi

Example

import { createConvenienceApi } from "@k13engineering/fsapi";
import { createNodeFileSystem } from "@k13engineering/fsapi-nodefs";

const fileSystem = createNodeFileSystem({ root: "/srv/data" });
const files = createConvenienceApi({ fileSystem });

await files.mkdirOrThrow({ filepath: "/docs" });
await files.writeFileOrThrow({ filepath: "/docs/hello.txt", data: new TextEncoder().encode("Hello!") });
// /srv/data/docs/hello.txt is on the disk now

const entries = await files.readdirOrThrow({ filepath: "/docs" });
const data = await files.readFileOrThrow({ filepath: "/docs/hello.txt" });

await fileSystem.close();

examples/serve-a-directory.ts does more in a temporary directory: node examples/serve-a-directory.ts.

API

createNodeFileSystem({ root, nodeFs?, watchIntervalMs?, watchTimers? })

  • root: the directory of the host that is served as /. Symlinks in it are resolved once.
  • nodeFs: the fs promises API to use, node:fs by default. The tests give an in-memory fake.
  • watchIntervalMs: how often watches poll the stat of their inode, 1000 by default.
  • watchTimers: the timers the polling uses, the timers of the platform by default.

Returns a TFilesystem of fsapi. Paths are checked like in every file system of fsapi: paths that are not normalised throw, as programming errors.

Behavior

The file system behaves like Linux, which is what Node.js reports, with what fsapi asks for on top:

  • Errors are values. Errors of Node.js are returned as the errno of their code, and as EIO if fsapi does not know the code. Nothing is thrown for errors of the disk.
  • Symlinks are never followed. Opening a path opens the entry itself, and a path through a symlinked directory fails with ENOTDIR, also where Node.js would follow it. So a symlink in the served directory never leads out of it.
  • File handles find their inode by its path. Node.js cannot open directories and symlinks without following them, so a handle remembers the device, inode number and type it was opened for, and checks them on every use. Once its path is gone or holds another inode, the handle fails with ENOENT, as fsapi has no ESTALE. A renamed node is gone for handles opened before.
  • IO: regular files are opened only for the actions asked for, never through a symlink, and read and written at exact bigint offsets. Directories list their entries with type and inode number, leaving out entries removed while listing. Symlinks fail with ELOOP, fifos with EOPNOTSUPP, sockets and devices with ENXIO, as in ramfs: opening a fifo blocks, and opening a device can have effects of its own.
  • Creating nodes: fsapi creates nodes without a name and names them with link, which Node.js cannot do. A created file handle keeps the mode, owner and times set on it, and creates the node at its first link, exclusively, removing it again if the attributes cannot be set. Until then it cannot be opened for IO (EOPNOTSUPP), and watches start once the node exists. Later links add hard links.
  • Changing nodes: chmod changes the permission bits and fails for symlinks with EOPNOTSUPP. chown and utimens change the node itself, never what a symlink points to. The root cannot be removed or renamed (EBUSY).
  • Watching: Node.js cannot tell what changed, so each watch polls the stat of its inode and reports what differs from the stat before, starting with the stat the handle was opened with. A watch reports the removal once its inode is gone from its path or has no links.
  • stat reports a generation of 0, which Node.js does not know.

Limitations

  • Races: each call checks the directories along its path, and then works on the path. Something that changes the path in between is not noticed, as Node.js has no openat(). Do not serve directories that others can change to attack the process.
  • Nodes Node.js cannot create: fifos, sockets and device nodes cannot be created (ENOSYS), as Node.js has no mknod.
  • Times are set in seconds as a number, which keeps them to about a tenth of a microsecond.
  • Permissions are those of the process. Changing owners needs the privileges for it.
  • ioctl and fcntl are not supported (ENOSYS).

Development

npm ci
npm run build
npm run type-check
npm run lint
npm test

The tests are deterministic. They run against an in-memory fake of the fs promises API (lib/test-helpers/fake-node-fs.ts), and use no real timers or disk. The behavior of the fs API they rely on is written down as a contract in lib/test-helpers/node-fs-contract.ts, which passes against the fake in the tests, and against the real API as well. npm test reports the coverage, which is 100%.

License

LGPL-2.1-only