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

@c9up/sigil

v0.1.5

Published

Multi-driver password hashing — argon2, bcrypt, scrypt

Readme

@c9up/sigil

Canonical password hashing for the Ream ecosystem.

Multi-driver password hashing service backed by Rust NAPI. Built on the same model as @adonisjs/hash (v9): pluggable drivers, a single Hash class, fluent verification.

Drivers

| Driver key | Algorithm | When to use | |---|---|---| | argon2 (default) | argon2id | New applications. Memory-hard, side-channel resistant, OWASP-recommended for password storage. The Rust binding uses Argon2::default() from the argon2 crate, which selects the argon2id variant. Tunable parameters land in a future story; today the recommended Rust defaults are used. | | bcrypt | bcrypt | Interoperating with legacy systems (Rails, PHP, Java) that already store bcrypt hashes. rounds is configurable (default 12, OWASP minimum 10). | | scrypt | scrypt | Memory-hardness with a different parameter space than argon2. Useful when migrating from Node's stdlib crypto.scrypt. keyLength and saltLength are configurable; the cost parameters use scrypt::Params::recommended() from the Rust scrypt crate. |

All drivers run through the dedicated sigil-engine Rust crate (the native half of @c9up/sigil) — no JavaScript or TypeScript fallback. This is intentional: password hashing must hit a vetted, constant-time native implementation.

NAPI binding requirement

Sigil requires its native binding to be present at runtime. If the .node artifact is missing, the first call to make() / verify() throws:

[SIGIL_NAPI_REQUIRED] The argon2 Rust engine is required but not loaded.
  Fix: cd packages/sigil && pnpm build:napi

The argon2 token in the message is interpolated with the failing driver name (argon2 / bcrypt / scrypt).

The pnpm build:napi script is wired in story 40.4. Until then, build the native binding manually with cargo build --release -p sigil-engine from the package root.

Story 40.4 will harden runtime detection and ship prebuilt binaries via the same CI matrix as Ream and Atlas (linux-x64-gnu, linux-arm64-gnu, darwin-x64, darwin-arm64, win32-x64-msvc), so a fresh pnpm install will resolve the binding without a local Rust toolchain.

Quick start

Hash is a class — instantiate it with a config:

import { Hash } from '@c9up/sigil'

const hash = new Hash({
  default: 'argon2',
  drivers: {
    argon2: { driver: 'argon2' },
  },
})

const hashed = await hash.make('correct horse battery staple')
const ok = await hash.verify('correct horse battery staple', hashed)
// ok === true

In a Ream application, register SigilProvider and resolve Hash from the container instead of constructing it manually:

// providers.ts
import { SigilProvider } from '@c9up/sigil/provider'
export default [SigilProvider]
// in a controller / handler
import type { AppContext } from '@c9up/ream'
import { Hash } from '@c9up/sigil'

async function register(app: AppContext) {
  const hash = app.container.resolve<Hash>(Hash)
  const stored = await hash.make(password)
}

Switch driver per call:

const bcryptDriver = hash.use('bcrypt')
const bcryptHashed = await bcryptDriver.make('password')

const scryptHashed = await hash.use('scrypt').make('password')

hash.use(name) returns a HashDriver whose make / verify methods run against the named driver.

Configuration

The default driver and per-driver options are declared via defineConfig:

// config/hash.ts
import { defineConfig } from '@c9up/sigil'

export default defineConfig({
  default: 'argon2',
  drivers: {
    argon2: { driver: 'argon2' },
    bcrypt: { driver: 'bcrypt', rounds: 12 },
    scrypt: { driver: 'scrypt', keyLength: 64, saltLength: 32 },
  },
})

Honored config keys (anything else is silently ignored today):

  • argon2no per-driver options; the Rust binding uses Argon2::default(). Tunable cost (memory, iterations, parallelism) is a future story.
  • bcryptrounds: number (default 12, minimum 10).
  • scryptkeyLength: number (default 64), saltLength: number (default 32). Cost parameters fixed at scrypt::Params::recommended().

When SigilProvider boots without a config/hash.ts, the fallback is argon2 with the recommended defaults — see Story 40.1's SigilProvider fix.

Why Sigil and not @c9up/ream?

Epic 40 declares Sigil the canonical password-hashing package for Ream:

  • Adonis-pattern parity. Adonis isolates hashing in @adonisjs/hash, separate from the framework core. Sigil mirrors that boundary.
  • Single implementation. Before Sigil, password hashing existed in @c9up/ream/security/crypto and (later) in @c9up/warden's internal binding. Two NAPI argon2 implementations in one workspace was duplication waiting for divergence. Sigil consolidates.
  • Cleaner dependency graph. Apps that need only password hashing (e.g., a CLI tool) can depend on @c9up/sigil alone, without pulling in the full Ream framework.

Migration from @c9up/ream/security/crypto

@c9up/ream/security/crypto no longer exports password hashing. Earlier in development it carried throwing stubs (argon2Hash, argon2Verify, bcryptHash, bcryptVerify); story 40.1 removed them since they were never publicly available. The single canonical import is now Sigil:

- import { argon2Hash, argon2Verify } from '@c9up/ream/security/crypto'
+ import { Hash } from '@c9up/sigil'

- const hashed = await argon2Hash(password)
- const ok = await argon2Verify(password, hashed)
+ const hash = new Hash({ default: 'argon2', drivers: { argon2: { driver: 'argon2' } } })
+ const hashed = await hash.make(password)
+ const ok = await hash.verify(password, hashed)

In a Ream application, prefer the container-resolved Hash (see Quick start) over constructing one inline.

Migration from @c9up/warden's internal hash

@c9up/warden historically exposed hashPasswordArgon2 / verifyPasswordArgon2 / hashPasswordBcrypt / verifyPasswordBcrypt on its NativeWarden interface — they were never wired into SessionStrategy (which delegates password verification to the caller; see SessionStrategy.ts:33-37) and had zero TS callers in the workspace. Story 40.3 removed them from the TS surface. The underlying Rust crate still ships those functions in the prebuilt .node artefact (a follow-up hardening story tracks their removal). If your application ever called them directly, switch to Sigil's Hash class.

Public API

| Export | Type | Purpose | |---|---|---| | Hash | class | new Hash(config). Instance methods: make(value), verify(value, hash), use(name?). | | HashDriver | interface | Implement to plug a custom driver. Required: make, verify. Returned by Hash.prototype.use(name). | | HashConfig | type | { default: string; drivers: Record<string, { driver: string; ...}> }. | | defineConfig | helper | Type-safe config authoring. | | SigilProvider | provider | Registers Hash (and the 'hash' token) in the Ream container. Imported via @c9up/sigil/provider. |

Status

  • argon2id, bcrypt, scrypt drivers — shipping.
  • README + module docs (this story 40.1).
  • Warden integration — story 40.3.
  • NAPI binary CI matrix — story 40.4.

Story 40.2 (originally scoped as "ream/crypto delegates to Sigil") is being re-evaluated: 40.1 deleted the throwing stubs in @c9up/ream/security/crypto.ts outright since they were never deployed, so there is no facade to wire. Note this is independent from @c9up/warden's duplicate argon2 path, which story 40.3 still addresses.

License

MIT