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

stash

v1.0.0

Published

CipherStash CLI — the one stash command for auth, init, encryption schema, database setup, and secrets.

Readme

stash

npm version License: MIT

The single CLI for CipherStash. It handles authentication, project initialization, EQL v3 installation/upgrades, validation, migration rollout, and schema building.


Quickstart

npm install -D stash
npx stash auth login    # authenticate with CipherStash
npx stash init          # scaffold, introspect, install EQL

stash init authenticates, resolves DATABASE_URL, introspects the database, scaffolds an encryption client, installs dependencies and EQL v3, and writes .cipherstash/context.json.

The agent handoff belongs to the next two commands — stash plan drafts a reviewable .cipherstash/plan.md, and stash impl executes it. Both present the same four targets:

  • Hand off to Claude Code — copies the per-integration set of skills (stash-encryption, stash-<integration>, stash-cli) into .claude/skills/, writes .cipherstash/context.json and setup-prompt.md, then launches claude interactively.
  • Hand off to Codex — copies the same skills into .codex/skills/, writes a sentinel-managed AGENTS.md (durable doctrine), plus .cipherstash/ context files, then launches codex.
  • Use the CipherStash Agent — runs the in-house wizard (@cipherstash/wizard).
  • Write AGENTS.md — for editor agents (Cursor / Windsurf / Cline) that don't auto-load skill directories. Writes a single AGENTS.md with the doctrine plus the relevant skill content inlined under a sentinel block, and stops.

Pass --target <claude-code|codex|agents-md|wizard> to skip the picker. It is required when running plan or impl non-interactively (CI, pipes, an agent's shell) — the picker reads from /dev/tty, so without it the command prints a hint and exits without handing off.

A project-specific action plan is written to .cipherstash/setup-prompt.md regardless of which target you pick — it tells the agent exactly what's already done and what's left, with the right commands for your package manager and ORM. The matching context (selected columns, env keys, paths, versions) is at .cipherstash/context.json.

If neither claude nor codex is on PATH, the handoff still writes the rules files and prints install instructions — your progress is never wasted.


Recommended flow

npx stash auth login
    └── npx stash init      ← introspects DB, installs EQL, writes context.json
            └── npx stash plan   ← drafts .cipherstash/plan.md for review
                    └── npx stash impl   ← agent edits schema files / generates migrations
                            └── npx stash status   ← where am I?

stash covers authentication, initialization, EQL install/upgrade/status, schema introspection, and the staged EQL v3 encryption rollout.


Configuration

stash.config.ts is the single source of truth for database-touching commands. Create it in your project root:

import { defineConfig } from 'stash'

export default defineConfig({
  databaseUrl: process.env.DATABASE_URL!,
  client: './src/encryption/index.ts',
})

| Option | Required | Default | Description | |--------|----------|---------|-------------| | databaseUrl | Yes | — | PostgreSQL connection string | | client | No | ./src/encryption/index.ts | Path to your encryption client file |

The CLI loads .env files automatically before reading the config, so process.env references work without extra setup. The config file is resolved by walking up from the current working directory.

Commands that consume stash.config.ts: eql install, eql upgrade, db validate, eql status, db test-connection, schema build, and encrypt *.


Commands reference

npx stash init

Set up CipherStash end-to-end: authenticate, introspect your database, install dependencies, install EQL, and hand off the rest to your local coding agent.

npx stash init [--supabase] [--drizzle] [--region <slug>]

| Flag | Description | |------|-------------| | --supabase | Use the Supabase-specific setup flow | | --drizzle | Use the Drizzle-specific setup flow | | --region <slug> | Region to authenticate against (e.g. us-east-1). Skips the interactive region picker. Also settable via STASH_REGION. |

What init does, in order:

  1. Authenticate — re-uses an existing token if found, otherwise opens the browser device-code flow.
  2. Resolve DATABASE_URL — flag → env → supabase status → interactive prompt → hard-fail. The same resolver eql install uses.
  3. Generate the encryption client placeholder — detects the integration and writes ./src/encryption/index.ts without selecting columns or replacing the project's authoritative schema files. The subsequent stash plan / stash impl workflow edits the real schema.
  4. Install dependencies@cipherstash/stack (runtime) and stash (dev), with a confirmation prompt.
  5. Install EQL — runs stash eql install against the resolved URL after a y/N confirm.
  6. Checkpoint — writes .cipherstash/context.json and exits. Continue with stash plan, then stash impl, as described in Quickstart.

The full pipeline state — integration, columns, env-key names, paths, versions — is captured in .cipherstash/context.json. The action plan at .cipherstash/setup-prompt.md records what's already done and what stash plan / stash impl should do next.

CIPHERSTASH_WIZARD_URL overrides the gateway endpoint for the rulebook fetch. Useful for local-dev against a wizard gateway running on localhost.

Running init non-interactively (CI, agents, pipes): every prompt has an escape hatch, so init never blocks waiting on a TTY. Provide the region up front (--region / STASH_REGION) if you aren't already logged in and set DATABASE_URL. Init exits at a clean checkpoint and points you at stash plan --target …; run stash impl after planning. When a required value is missing in a non-TTY context the command exits non-zero with an actionable message rather than hanging.

STASH_REGION=us-east-1 DATABASE_URL=postgres://… npx stash init

npx stash auth login

Authenticate with CipherStash using a browser-based device code flow.

npx stash auth login [--region <slug>] [--json] [--no-open]

| Flag | Description | |------|-------------| | --region <slug> | Region to authenticate against (e.g. us-east-1). Skips the interactive region picker. Also settable via STASH_REGION. | | --json | Emit newline-delimited JSON events instead of prose (see below). Implies non-interactive — never renders the region picker, and never auto-opens a browser (the human opens the URL you hand them). | | --no-open | Don't auto-open the verification URL in a browser (already implied by --json). | | --supabase / --drizzle | Track the integration as the referrer. |

Saves the token to ~/.cipherstash/auth.json. Database-touching commands check for this file before running.

Triggering auth from an agent (device-code flow)

The device-code flow is designed so an agent can trigger authentication but only a human completes it in the browser. Run auth login --json in the background and read the first line — authorization_required carries the verification URL to hand to the user:

npx stash auth login --region us-east-1 --json
// stdout is newline-delimited JSON, one event per line:
{"status":"authorization_required","userCode":"ABCD-1234","verificationUri":"https://…/activate","verificationUriComplete":"https://…/activate?user_code=ABCD-1234","expiresIn":899}
// … the process then blocks polling until the human authorizes in the browser …
{"status":"authorized","expiresAt":1751990400,"expiresAtIso":"2025-07-08T12:00:00.000Z"}
{"status":"device_bound"}

Errors are emitted as {"status":"error","code":"…","message":"…"} and exit non-zero. In a non-TTY context without --region/STASH_REGION the command exits immediately with code: "region_required" instead of hanging on the picker.


npx stash auth regions

List the regions you can authenticate against — a first-contact affordance so you (or an agent) can discover valid --region / STASH_REGION values up front instead of learning them from an error.

npx stash auth regions          # human-readable list
npx stash auth regions --json   # machine-readable [{ "slug": "…", "label": "…" }]
// --json output:
[{"slug":"us-east-1","label":"us-east-1 (Virginia, USA)"}, {"slug":"us-east-2","label":"us-east-2 (Ohio, USA)"}, …]

The region list is currently maintained in the CLI. The intended long-term source of truth is the CipherStash region API (tracked by a TODO in src/commands/auth/region.ts); when that lands, this command and the runtime SDK should both read from it.


npx stash wizard

Launch the CipherStash AI wizard. Thin wrapper around @cipherstash/wizard — the wizard ships as a separate npm package so the agent SDK stays out of the stash bundle, but you don't need to remember a second tool name.

npx stash wizard [...flags]

Any flags after wizard are forwarded verbatim to the wizard package. On the first run the package manager downloads the wizard (~5s); subsequent runs are instant.


npx stash eql install

Configure your database and install CipherStash EQL extensions in a single command. Run this after npx stash init. (npx stash db install is a deprecated alias — it still works but prints a warning.)

When stash.config.ts is missing, the command offers to scaffold it. Installation is direct and EQL v3 only, using the bundle pinned by @cipherstash/eql.

npx stash eql install [options]

| Flag | Description | |------|-------------| | --force | Reinstall even if EQL is already installed | | --dry-run | Show what would happen without making changes | | --supabase | Supabase-compatible install with grants for built-in roles | | --database-url <url> | One-shot target; leaves project files untouched |

--supabase grants the built-in roles access to both eql_v3 and eql_v3_internal. Removed v2 options fail explicitly; --eql-version 2 points dump-recovery users to the upstream EQL 2.3.1 SQL release.

Good to know: The pinned EQL v3 bundle self-adapts when the install role cannot create its optional ORE operator family. In that case it disables the *OrdOre domains; use the ordinary *Ord domains for ordering.


npx stash eql upgrade

Upgrade an existing EQL v3 installation to the package-pinned version.

npx stash eql upgrade [options]

| Flag | Description | |------|-------------| | --dry-run | Show what would happen without making changes | | --supabase | Use Supabase-compatible upgrade |

The install SQL is idempotent and safe to re-run. If EQL is not installed, the command suggests running npx stash eql install instead.


npx stash db validate

Validate your encryption schema for common misconfigurations.

npx stash db validate [--supabase] [--exclude-operator-family]

| Rule | Severity | |------|----------| | freeTextSearch on a non-string column | Warning | | orderAndRange without operator families | Warning | | No indexes on an encrypted column | Info | | searchableJson without dataType("json") | Error |

The command exits with code 1 on errors (not on warnings or info).


npx stash db migrate

Run pending encrypt config migrations.

npx stash db migrate

Good to know: This command is not yet implemented.


npx stash eql status

Show the current state of EQL in your database.

npx stash eql status

Reports EQL installation status and version, database permission status, and read-only diagnostics for legacy EQL v2/Proxy configuration state.


npx stash db test-connection

Verify that the database URL in your config is valid and the database is reachable.

npx stash db test-connection

Reports the database name, connected role, and PostgreSQL server version.


npx stash schema build

Build an encryption client file from your database schema using DB introspection.

npx stash schema build [--supabase]

Connects to your database, lets you select tables and columns to encrypt, asks about searchable indexes, and generates a typed encryption client file.

Reads databaseUrl from stash.config.ts.


Drizzle migration mode

Use eql migration --drizzle to add EQL v3 installation to Drizzle migration history instead of applying it directly.

npx stash eql migration --drizzle
npx drizzle-kit migrate

How it works:

  1. Runs npx drizzle-kit generate --custom --name=<name> to create an empty migration.
  2. Loads the pinned EQL v3 SQL.
  3. Writes the EQL SQL into the generated migration file.

With a custom name or output directory:

npx stash eql migration --drizzle --name setup-eql --out ./migrations
npx drizzle-kit migrate

drizzle-kit must be installed in your project (npm install -D drizzle-kit). The --out directory must match your drizzle.config.ts.


npx stash eql repair --drizzle

Repairs migrations drizzle-kit generate emitted with an in-place ALTER COLUMN … SET DATA TYPE <eql_v3_*>, which Postgres cannot run (there is no cast from text/numeric to an EQL domain). Each is rewritten into an additive ADD COLUMN "<column>_encrypted" that preserves the source column.

npx stash eql repair --drizzle
npx drizzle-kit migrate

| Flag | Description | |------|-------------| | --drizzle | Required. Repair a Drizzle migration directory | | --out <path> | Directory to sweep. Default drizzle | | --dry-run | Report what would be rewritten without writing anything | | --database-url <url> | Leave migrations the database has already applied untouched |

This is the same sweep eql migration --drizzle performs, without generating an install migration you do not need. With --database-url it reads drizzle.__drizzle_migrations and refuses to rewrite an already-applied migration — doing so would leave the file describing a shape that database never got from it, and a fresh CI or staging database replaying it would silently diverge. Without a URL it proceeds and warns that applied state could not be verified.


Required database permissions

Before installing EQL, the CLI verifies that the connected role has:

  • CREATE on the database (for CREATE SCHEMA and CREATE EXTENSION).
  • CREATE on the public schema (for the public.eql_v3_* domains).
  • SUPERUSER or extension owner privileges (for CREATE EXTENSION pgcrypto, if not already installed).

If permissions are insufficient, the CLI exits with a message listing what is missing.


Programmatic API

import {
  defineConfig,
  loadStashConfig,
  EQLInstaller,
  loadBundledEqlSql,
} from 'stash'

defineConfig

Type-safe identity function for stash.config.ts:

import { defineConfig } from 'stash'

export default defineConfig({
  databaseUrl: process.env.DATABASE_URL!,
  client: './src/encryption/index.ts',
})

loadStashConfig

Finds and loads the nearest stash.config.ts, validates it with Zod, applies defaults, and returns the typed config:

import { loadStashConfig } from 'stash'

const config = await loadStashConfig()
// config.databaseUrl — validated non-empty string
// config.client — defaults to './src/encryption/index.ts'

EQLInstaller

Programmatic access to EQL installation:

import { EQLInstaller } from 'stash'

const installer = new EQLInstaller({ databaseUrl: process.env.DATABASE_URL! })

const permissions = await installer.checkPermissions()
if (!permissions.ok) {
  console.error('Missing permissions:', permissions.missing)
  process.exit(1)
}

if (!(await installer.isInstalled())) {
  await installer.install({ supabase: true })
}

| Method | Returns | Description | |--------|---------|-------------| | checkPermissions() | Promise<PermissionCheckResult> | Check required database permissions | | isInstalled() | Promise<boolean> | Check if the EQL v3 schemas exist | | getInstalledVersion() | Promise<string \| null> | Get the installed EQL version | | install(options?) | Promise<void> | Execute the EQL install SQL in a transaction |

Install options: supabase.

loadBundledEqlSql

Load the bundled EQL install SQL as a string:

import { loadBundledEqlSql } from 'stash'

const sql = loadBundledEqlSql()

Relationship to @cipherstash/stack

@cipherstash/stack is the runtime SDK. It stays lean with no heavy dependencies like pg and ships in your production bundle. stash is a devDependency: it handles database tooling and schema lifecycle at development time. Think of it like Drizzle Kit — a companion tool that prepares the database while the runtime SDK handles queries.


Links