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

thumbdrive

v0.3.0

Published

An OPFS wrapper offering sync access and multi-tab support

Downloads

170

Readme

thumbdrive

Browser infrastructure for reducing memory usage in web-based code editors and language servers.

Problem

If you want to store a lot of files client side, say to power a language service or SQLite database or similar, storing all your files in memory occupies a lot of memory! We have disks for just this purpose and OPFS is a helpful Web API for doing just that.

If you have a synchronous client side use case however, like say a TypeScript language service or a VFS for SQLite, OPFS doesn't quite fit the bill, as it's access patterns are all async. You can do synchronous reads and writes once you have a file handle open, but you can't open new files synchronously.

Worse yet, once you have that file handle open in one tab, you can't open it in any other tabs due to OPFS' locking semantics!

Solution

Two primitives that work together to allow sync FS usage among many tabs:

SyncOPFSFileSystem

A synchronous virtual filesystem backed by OPFS (Origin Private File System) that stores files on disk instead of in memory.

Why it's needed: TypeScript's language server assumes fully synchronous filesystem access (fs.readFileSync). OPFS only provides sync access through FileSystemSyncAccessHandle, which requires async file handle acquisition. This VFS solves the problem by maintaining a single pre-opened binary arena file (arena.bin) with an in-memory index of file locations, providing sync read/write to any file without opening handles.

import { SyncOPFSFileSystem } from "thumbdrive";

const fs = new SyncOPFSFileSystem("my-project");
await fs.init();

// Fully synchronous filesystem operations backed by OPFS
fs.writeFileSync("/src/index.ts", "export const x = 1;");
const content = fs.readFileSync("/src/index.ts");
fs.existsSync("/src/index.ts"); // true

MultiTabWorkerBroker

Coordinates multiple browser tabs to share a single web worker that owns the FS. Instead of each tab opening its own filesystem (and using the hunk of memory per tab), we instead elect one tab as the leader tab, and have it's Worker be the exclusive way in or out of the FS. The main thread that owns that worker can talk directly to it, and any other tabs can talk to the leader worker via a BroadcastChannel. When the leader tab closes, one of the other tabs gets promoted to leader, and starts its own Worker that then becomes the single owner.

import { MultiTabWorkerBroker } from "thumbdrive";
import { createMessageConnection } from "vscode-jsonrpc/browser";

const broker = new MultiTabWorkerBroker("typescript-lsp-lock", () => new Worker(new URL("./lsp-worker.js", import.meta.url)));

await broker.start();

// Create a JSON-RPC connection to the worker (or proxied through leader tab)
const { reader, writer } = broker.createConnection();
const connection = createMessageConnection(reader, writer);

// All tabs communicate with the same underlying worker
connection.sendRequest("initialize", { rootUri: "/project" });

Credits

  • Roy Hashimoto pioneered a lot of this approach when working to get SQLite running in the browser. See https://github.com/rhashimoto/wa-sqlite/discussions/81 for the seed of this idea
  • Notion documented their similar approach here: https://www.notion.com/blog/how-we-sped-up-notion-in-the-browser-with-wasm-sqlite -- this is an open-source implementation of the same one-worker-among-many tabs approach!

License

MIT