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

@cipherstash/stack-forge

v0.1.0

Published

CipherStash Stack Forge

Downloads

30

Readme

@cipherstash/stack-forge

Dev-time CLI and library for managing CipherStash EQL (Encrypted Query Language) in your PostgreSQL database.

npm version License: MIT TypeScript


Why stack-forge?

@cipherstash/stack is the runtime encryption SDK — it should stay lean and free of heavy dependencies like pg. @cipherstash/stack-forge is a devDependency that handles database tooling: installing EQL extensions, checking permissions, and managing schema lifecycle.

Think of it like Prisma or Drizzle Kit — a companion CLI that sets up the database while the main SDK handles runtime operations.

Install

npm install -D @cipherstash/stack-forge

Or with your preferred package manager:

pnpm add -D @cipherstash/stack-forge
yarn add -D @cipherstash/stack-forge
bun add -D @cipherstash/stack-forge

Quick Start

You can install EQL in two ways: direct install (connects to the DB and runs the SQL) or Drizzle migration (generates a migration file; you run drizzle-kit migrate yourself). The steps below use the direct install path.

1. Create a config file

Create stash.config.ts in your project root:

import { defineConfig } from '@cipherstash/stack-forge'

export default defineConfig({
  databaseUrl: process.env.DATABASE_URL!,
})

2. Add a .env file

DATABASE_URL=postgresql://user:password@localhost:5432/mydb

3. Install EQL

npx stash-forge install

That's it. EQL is now installed in your database.

If your encryption client lives elsewhere, set client in stash.config.ts (e.g. client: './lib/encryption.ts'). That path is used by stash-forge push.

Using Drizzle? To install EQL via your migration pipeline instead, run npx stash-forge install --drizzle, then npx drizzle-kit migrate. See install --drizzle below.


Configuration

The stash.config.ts file is the single source of truth for stack-forge. It uses the defineConfig helper for type safety.

import { defineConfig } from '@cipherstash/stack-forge'

export default defineConfig({
  // Required: PostgreSQL connection string
  databaseUrl: process.env.DATABASE_URL!,

  // Optional: path to your encryption client (default: './src/encryption/index.ts')
  // Used by `stash-forge push` to load the encryption schema
  client: './src/encryption/index.ts',

  // Optional: CipherStash workspace and credentials (for future schema sync)
  workspaceId: process.env.CS_WORKSPACE_ID,
  clientAccessKey: process.env.CS_CLIENT_ACCESS_KEY,
})

| Option | Required | Description | |--------|----------|-------------| | databaseUrl | Yes | PostgreSQL connection string | | client | No | Path to encryption client file (default: './src/encryption/index.ts'). Used by push to load the encryption schema. | | workspaceId | No | CipherStash workspace ID | | clientAccessKey | No | CipherStash client access key |

The CLI automatically loads .env files before evaluating the config, so process.env references work out of the box.

The config file is resolved by walking up from the current working directory, similar to how tsconfig.json resolution works.


CLI Reference

stash-forge <command> [options]

install

Install the CipherStash EQL extensions into your database.

npx stash-forge install [options]

| Option | Description | |--------|-------------| | --dry-run | Show what would happen without making changes | | --force | Reinstall even if EQL is already installed | | --supabase | Use Supabase-compatible install (excludes operator families + grants Supabase roles) | | --exclude-operator-family | Skip operator family creation (for non-superuser database roles) | | --drizzle | Generate a Drizzle migration instead of direct install | | --name <value> | Migration name when using --drizzle (default: install-eql) | | --out <value> | Drizzle output directory when using --drizzle (default: drizzle) |

Standard install:

npx stash-forge install

Supabase install:

npx stash-forge install --supabase

The --supabase flag:

  • Downloads the Supabase-specific SQL variant (no CREATE OPERATOR FAMILY)
  • Grants USAGE, table, routine, and sequence permissions on the eql_v2 schema to anon, authenticated, and service_role

Preview changes first:

npx stash-forge install --dry-run

install --drizzle

If you use Drizzle ORM and want EQL installation as part of your migration history, use the --drizzle flag. It creates a Drizzle migration file containing the EQL install SQL, then you run your normal Drizzle migrations to apply it.

npx stash-forge install --drizzle
npx drizzle-kit migrate

How it works:

  1. Runs drizzle-kit generate --custom --name=<name> to create an empty migration.
  2. Downloads the EQL install script from the EQL GitHub releases.
  3. Writes the EQL SQL into the generated migration file.

With a custom migration name or output directory:

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

You need drizzle-kit installed in your project (npm install -D drizzle-kit). The --out directory must match your Drizzle config (e.g. drizzle.config.ts).

push

Load your encryption schema from the file specified by client in stash.config.ts and apply it to the database (or preview with --dry-run).

npx stash-forge push [options]

| Option | Description | |--------|-------------| | --dry-run | Load and validate the schema, then print it as JSON. No database changes. |

Push schema to the database:

npx stash-forge push

This connects to Postgres, marks any existing rows in eql_v2_configuration as inactive, and inserts the current encrypt config as a new row with state active. Your runtime encryption (e.g. @cipherstash/stack) reads the active configuration from this table.

Preview your encryption schema without writing to the database:

npx stash-forge push --dry-run

Permission Pre-checks (install)

Before installing, stash-forge verifies that the connected database role has the required permissions:

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

If permissions are insufficient, the CLI exits with a clear message listing what's missing.

Planned Commands

The following commands are defined but not yet implemented:

| Command | Description | |---------|-------------| | init | Initialize CipherStash Forge in your project | | migrate | Run pending encrypt config migrations | | status | Show EQL installation status |


Programmatic API

You can also use stack-forge as a library:

import { EQLInstaller, loadStashConfig } from '@cipherstash/stack-forge'

// Load config from stash.config.ts
const config = await loadStashConfig()

// Create an installer
const installer = new EQLInstaller({
  databaseUrl: config.databaseUrl,
})

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

// Check if already installed
if (await installer.isInstalled()) {
  console.log('EQL is already installed')
} else {
  await installer.install()
}

EQLInstaller

| Method | Returns | Description | |--------|---------|-------------| | checkPermissions() | Promise<PermissionCheckResult> | Check if the database role has required permissions | | isInstalled() | Promise<boolean> | Check if the eql_v2 schema exists | | getInstalledVersion() | Promise<string \| null> | Get the installed EQL version (or null) | | install(options?) | Promise<void> | Download and execute the EQL install SQL in a transaction |

Install Options

await installer.install({
  excludeOperatorFamily: true, // Skip CREATE OPERATOR FAMILY
  supabase: true,              // Supabase mode (implies excludeOperatorFamily + grants roles)
})

defineConfig

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

import { defineConfig } from '@cipherstash/stack-forge'

export default defineConfig({
  databaseUrl: process.env.DATABASE_URL!,
})

loadStashConfig

Finds and loads the nearest stash.config.ts, validates it with Zod, applies defaults (e.g. client), and returns the typed config:

import { loadStashConfig } from '@cipherstash/stack-forge'

const config = await loadStashConfig()
// config.databaseUrl — guaranteed to be a non-empty string
// config.client — path to encryption client (default: './src/encryption/index.ts')