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

@axfab/pocket-shell

v0.1.0

Published

Interactive mongosh-style REPL for pocket-db — zero server, zero friction (npx @axfab/pocket-shell ./data.pdb)

Downloads

118

Readme

npx @axfab/pocket-shell ./data.pdb
pocket-shell — connected to ./data.pdb
"db" is ready. Try: db.getCollections(), db.<collection>.find(), db.stats(), .help, .exit

pocket-shell> db.users.insertOne({ name: "Ada", role: "admin" })
{ acknowledged: true, insertedId: '...' }

pocket-shell> db.users.find({ role: "admin" })
┌─────────┬──────────────────────────┬────────┬─────────┐
│ (index) │ _id                      │ name   │ role    │
├─────────┼──────────────────────────┼────────┼─────────┤
│ 0       │ '...'                    │ 'Ada'  │ 'admin' │
└─────────┴──────────────────────────┴────────┴─────────┘

pocket-shell> .exit

That's a real pocket-db database — a single-file, zero-native-dependency, MongoDB-style embedded store for Node.js and Electron — created, queried, and closed with nothing installed beforehand. No daemon to start (unlike mongosh, which needs a running mongod), no config, no schema. npx, a path, and you're querying data.


Why pocket-db

pocket-db is built for apps that need real persistence without a server: Electron & desktop apps, CLI tools, local servers, plugins, structured caches, offline-first prototypes.

  • 🪶 Zero native dependencies — pure TypeScript, no node-gyp, no rebuild-per-Electron-version dance
  • 📄 Single file — back up your whole database by copying one .pdb file
  • 🍃 MongoDB-style APIfind / insert / update with the query and update operators you already know
  • Append-only writes — every mutation is a fast sequential append, crash-safe, no full-file reserialisation
  • 🛡️ Safe reads — every query returns an independent copy, so mutating a result never corrupts stored data
  • 🚀 Fast, durable writes — 40–700× faster than other file-backed stores in its own benchmarks, within ~12% of in-memory SQLite (which isn't even durable)

Full details, the benchmark methodology, and the complete API live in pocket-db's own README — this shell is just the fastest way to kick the tires before you commit to reading it.

Using pocket-db in your own project

Once you're sold, it's a two-line integration — no shell involved:

npm install @axfab/pocket-db
import { pocketDb } from "@axfab/pocket-db";

const db = pocketDb("./data.pdb");
const users = db.collection("users");

users.insertOne({ name: "Ada", role: "admin" });
const admins = users.find({ role: "admin" }).toArray();

db.close();

Anything you just tried at the pocket-shell> prompt is the exact same API, called from your own code.


Why a separate package

pocket-db stays strictly zero-dependency and minimal. pocket-shell depends on it as a normal dependency (not a peer) specifically so npx @axfab/pocket-shell works without a prior npm install — that's the friction it exists to remove. It also means the shell can iterate and release independently of the storage engine.

Install

Nothing to install for occasional use — npx @axfab/pocket-shell ./data.pdb fetches and runs it. For repeated use:

npm install -g @axfab/pocket-shell

Installing (globally, or as a project dependency) also links two extra commands, pocket-shell-import and pocket-shell-export — identical to pocket-shell import/pocket-shell export (see below), just without the leading subcommand, for scripts that want a dedicated executable:

pocket-shell-import ./data.pdb ./seed.json
pocket-shell-export ./data.pdb --collection users > users.json

Usage

pocket-shell [path] [options]
pocket-shell import <path> <file.json> [--collection <name>]
pocket-shell export <path> [--collection <name>]

Arguments:
  path                  Path to the .pdb file (default: pocket.pdb). Created automatically if it doesn't exist yet.

Options:
  --eval <code>         Run JS non-interactively against the opened db, print the result, then exit.
  -h, --help             Show help and exit.
  -v, --version          Show the installed version and exit.

db in scope

The REPL is a real Node repl with a db object injected into its context — there is no custom query language to learn. db.collection("users") is pocket-db's actual API; db.users is mongosh-style shorthand for the same thing, implemented with a plain Proxy (no dependency needed):

db.users.insertOne({ name: "Bob" });
db.users.find({ role: "admin" }).sort({ name: 1 }).limit(10).toArray();
db.users.updateOne({ name: "Bob" }, { $set: { role: "admin" } });
db.users.deleteOne({ name: "Bob" });
db.getCollections();

.sort() / .limit() / .skip() / .toArray() are inherited as-is from pocket-db's cursor — nothing here reimplements them. A bare cursor (e.g. db.users.find(...) with no .toArray()) is materialized automatically for display, mongosh-style, so you rarely need to call .toArray() yourself at the prompt.

Results print through a custom writer: arrays of documents render as a table, stats() results print with human-readable byte sizes next to the raw numbers (see below), everything else through util.inspect with colors — no chalk, no extra dependency. Long strings are truncated so one bloated field can't flood the terminal.

Command history persists across sessions in ~/.pocket_shell_history (Node's built-in repl history, nothing custom).

Index management, compact(), drop(), stats()

pocket-db's full Collection/Database API is available through db and db.<collection> — pocket-shell doesn't gate any of it — including the management surface beyond plain CRUD:

db.users.createIndex("email", { type: "string", unique: true });
db.users.getIndexes();
db.users.dropIndex("email");

db.users.drop();       // drops the collection; re-inserting recreates it, same as pocket-db itself
db.compact();          // rewrites the file, discarding dead (deleted/updated) records

db.stats();            // database-wide: file size, live/dead byte counts, document & collection counts
db.users.stats();      // same, scoped to one collection, plus its index count

db.stats() and db.<collection>.stats() print mongosh-style, with a human-readable size next to every byte count:

pocket-shell> db.stats()
{
  path: '/path/to/data.pdb',
  sizeOnDisk: 292 (292 B),
  collectionCount: 1,
  documentCount: 2,
  operationCount: 5,
  tombstoneCount: 2,
  liveBytes: 232 (232 B),
  deadBytes: 48 (48 B)
}

One thing db.stats() does not report: the file's serialization format (JSON/BSON/AMF3). pocket-db's public API doesn't expose it outside of opening the file, so pocket-shell doesn't fabricate it — reading the raw file header ourselves would duplicate storage-layer logic that belongs to pocket-db, and would be one file-format change away from silently going stale.

Import / export

# One collection, from/to a flat array of documents:
npx @axfab/pocket-shell import ./data.pdb ./users.json --collection users
npx @axfab/pocket-shell export ./data.pdb --collection users > users.json

# The whole database at once, keyed by collection name — the two commands round-trip:
npx @axfab/pocket-shell export ./data.pdb > full-backup.json
npx @axfab/pocket-shell import ./restored.pdb ./full-backup.json

export prints JSON to stdout; redirect it with your shell. It never creates <path> — exporting is read-only by nature, so a typo'd path fails loudly instead of silently producing an empty export.

import loads <file.json> into <path>, creating <path> if it doesn't exist yet (same as the REPL). Two shapes are accepted, matching what export produces on each side:

  • --collection <name>: <file.json> is a JSON array of documents (a bare object is also accepted, as a single document) — all loaded into that one collection.
  • no --collection: <file.json> is a JSON object mapping collection name to an array of documents, e.g. { "users": [...], "posts": [...] } — each key is imported into the matching collection.

Each collection is loaded with a single insertMany, which pocket-db validates as a whole batch (document ids, unique indexes) before writing anything — so a failing collection leaves nothing partially inserted for itself. Collections already imported earlier in the same run stay committed, though, since each is its own transaction; a multi-collection import isn't atomic across the whole file.

Run pocket-shell import --help / pocket-shell export --help for the full rundown. Both are also available as their own commands once installed — see Install.

Non-interactive mode

npx @axfab/pocket-shell ./data.pdb --eval "db.users.find({ role: 'admin' })"

Runs the given code, prints its result the same way the REPL would, and exits — closing the database cleanly either way. Useful in CI, and for generating reproducible demo captures without replaying an interactive session by hand for every recording.

Missing file

pocket-db creates a .pdb file that doesn't exist yet rather than erroring. pocket-shell keeps that behavior (so it stays a true zero-friction npx ./data.pdb tool, including non-interactively) but prints a line telling you a new file was created, so it's never a silent surprise.

Clean shutdown

.exit, Ctrl+D, Ctrl+C, and SIGTERM all close the database before the process exits, so an interrupted session doesn't leave a stale lock file behind.

A real JS REPL — accepted risk

There is deliberately no custom command language here: pocket-shell hands you a genuine repl with db in scope, exactly like the standard Node REPL (or mongosh) does. That means it evaluates arbitrary JavaScript — the same trust model as running node interactively. This is a local, single-user, single-process tool with no server exposure, so that's an accepted trade-off, not an oversight: don't pipe untrusted input into it.

Scope

Covers all three SPECS.md milestones: open a file, the core CRUD + query surface (insertOne/insertMany/find/findOne/updateOne/updateMany/deleteOne/deleteMany/getCollections), pretty-printing, history and --eval ("Lot 1"); advanced management (createIndex/dropIndex/getIndexes, drop(), compact(), stats(), "Lot 2"); and import/export ("Lot 3").

Also out of scope by design: multiple database files in one session (pocket-db is single-file, so there's no use <db> the way mongosh has across a multi-database server), and any kind of admin/multi-user tooling — pocket-db is single-process, single-file, and this shell inherits that philosophy.

Development

npm install
npm run build   # tsc -> dist/
npm test        # node's built-in test runner via tsx

docs/pocket-db.svg and docs/pocket-db-dk.svg (the logo at the top of this README, light and dark variants) are copied from pocket-db's own docs/ — update them from there if that logo ever changes.

License

MIT