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

@just-be/automerge-fs

v0.0.1

Published

A virtual filesystem backed by Automerge CRDTs — character-level merging for text files, pluggable blob store for binary, optional Effect FileSystem provider.

Readme

@just-be/automerge-fs

A virtual filesystem backed by Automerge CRDTs. Text files get character-level CRDT merging via Automerge.updateText(), binary files are stored in a pluggable blob store, and the directory tree lives in a single root Automerge document.

Architecture

  • One Automerge document per text file — enables fine-grained merging of concurrent edits
  • Root document — maintains the full directory tree structure (paths, metadata, pointers to file docs / blob hashes)
  • BlobStore — pluggable interface for binary file storage (ships with InMemoryBlobStore)

Install

bun add @just-be/automerge-fs

Usage

Direct API

import { Repo } from "@automerge/automerge-repo"
import { AutomergeFs, InMemoryBlobStore } from "@just-be/automerge-fs"

const repo = new Repo({ network: [] })
const fs = AutomergeFs.create({
  repo,
  blobStore: new InMemoryBlobStore(),
})

await fs.writeFile("/hello.txt", "world")
const content = await fs.readFile("/hello.txt") // Uint8Array

await fs.mkdir("/src/components", { recursive: true })
await fs.rename("/hello.txt", "/src/hello.txt")

const entries = fs.readdir("/src") // [{ name, isFile, isDirectory }]
const info = fs.stat("/src/hello.txt") // { size, isFile, isDirectory, mode, mtime, ctime }

Effect FileSystem provider

The @just-be/automerge-fs/effect export implements Effect's FileSystem interface, so any Effect program that uses FileSystem can be backed by Automerge with zero code changes.

import { Effect } from "effect"
import { FileSystem } from "effect/FileSystem"
import { Repo } from "@automerge/automerge-repo"
import { makeFs } from "@just-be/automerge-fs/effect"

const layer = makeFs({ repo: new Repo({ network: [] }) })

const program = Effect.gen(function* () {
  const fs = yield* FileSystem
  yield* fs.writeFileString("/hello.txt", "world")
  return yield* fs.readFileString("/hello.txt")
})

await Effect.runPromise(Effect.provide(program, layer))

For more control, compose the layer manually:

import { Layer } from "effect"
import { AutomergeFsFileSystem, AutomergeFsInstance } from "@just-be/automerge-fs/effect"

const layer = AutomergeFsFileSystem.pipe(
  Layer.provide(Layer.succeed(AutomergeFsInstance, myFsInstance))
)

API

AutomergeFs

| Method | Description | |---|---| | create({ repo, blobStore }) | Create a new filesystem | | load({ repo, blobStore, rootDocUrl }) | Load an existing filesystem by its root document URL | | readFile(path) | Read file contents as Uint8Array | | writeFile(path, content) | Write a string or Uint8Array — auto-detects binary vs text | | stat(path) | Get file/directory metadata | | readdir(path) | List directory entries | | mkdir(path, options?) | Create a directory (supports { recursive: true }) | | remove(path, options?) | Remove a file or directory (supports { recursive, force }) | | rename(oldPath, newPath) | Move/rename a file or directory | | copy(src, dest, options?) | Copy a file or directory tree | | exists(path) | Check if a path exists | | chmod(path, mode) | Change file mode | | utimes(path, atime, mtime) | Update modification time | | truncate(path, length?) | Truncate a file |

Version control

Each text file is its own Automerge document, so you get built-in version history:

const heads = await fs.getFileHeads("/hello.txt")
const history = await fs.getFileHistory("/hello.txt")
const oldContent = await fs.getFileAt("/hello.txt", someOlderHeads)
const patches = await fs.diff("/hello.txt", fromHeads, toHeads)

BlobStore

Implement the BlobStore interface to use your own storage backend for binary files:

interface BlobStore {
  get(hash: string): Promise<Uint8Array | null>
  set(hash: string, data: Uint8Array): Promise<void>
  has(hash: string): Promise<boolean>
  delete(hash: string): Promise<void>
  list(): Promise<string[]>
}