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

@george43g/secret-store

v0.2.2

Published

Vendor-neutral secret mechanism for local tools: resolve from process env, .env files, and the OS keychain, with an optional external-command fallback — plus keychain save/delete for setup flows. No vault-vendor logic.

Readme

@george43g/secret-store

Vendor-neutral secret mechanism for local tools.

env  →  .env files  →  OS keychain  →  external command (opt-in)

It reads the places a secret may already have been put, and gives tools a keychain read/write surface so each one doesn't reinvent it.

What it deliberately does NOT do

It never talks to a secret vault — no 1Password, Vault, AWS Secrets Manager. Pulling secrets out of a vault, keeping a cache warm, and exporting them into your environment is a secret manager's job (mise, direnv, a systemd unit, your own CLI). A tool should do what you'd expect a tool to do: read its config from the environment, from a .env file, or from the OS keychain if it knowingly put it there.

That boundary is the whole point. It keeps this package portable, keeps vault credentials out of every tool's dependency tree, and means one manager change doesn't ripple through N tools.

If you do run a manager, the opt-in exec layer lets a tool ask it directly — without this package knowing which one you use.

Install

pnpm add @george43g/secret-store

Resolve

import { resolveSecret } from "@george43g/secret-store";

const secret = await resolveSecret({ toolPrefix: "up-bank", name: "token" });
// → { value: "...", source: "env" | "env-file" | "keychain" | "exec" } | null

{ toolPrefix: "up-bank", name: "token" } maps to the canonical name UP_BANK_TOKEN, which is used as the env var, the .env key, and the keychain account. Pass { required: true } to throw MissingSecretError instead of returning null.

| Layer | Looks at | Notes | |---|---|---| | env | UP_BANK_TOKEN, UP_BANK_TOKEN_JSON | Most explicit, so it wins | | env-file | .env.env.local.env.[mode].env.[mode].local | Vite precedence; never overrides real env | | keychain | service up-bank, account UP_BANK_TOKEN | macOS only; null elsewhere | | exec | your manager's stdout | Opt-in; see below |

Values are returned raw. _JSON is accepted as an alias for convenience, but parsing (and deciding which field is the token) is the caller's policy.

Store (setup flows)

import { saveSecret, deleteSecret } from "@george43g/secret-store";

await saveSecret({ toolPrefix: "up-bank", name: "token" }, value);
await deleteSecret({ toolPrefix: "up-bank", name: "token" });

Reads degrade silently (there's a fallback); writes throw on a platform with no keychain backend, because a silently-dropped write is data loss.

saveSecret passes -U (update in place). -A (allow any application to read without a prompt) is opt-in via { allowAnyApp: true } — it's what lets a GUI- or launchd-spawned process read without a dialog, but it is a real widening of access. Note the value is passed as an argv element and is therefore visible in the process table for the duration of the call; that's inherent to the security CLI.

Override the item with UP_BANK_TOKEN_KEYCHAIN=service[/account].

The exec layer

Point it at whatever manager you run. This package names none.

SECRET_STORE_EXEC_BIN=/absolute/path/to/your-manager
SECRET_STORE_EXEC_ARGS="get {VAR} --cached-only"

…or programmatically:

await resolveSecret(ref, { exec: { bin: "/abs/mgr", args: ["get", "{VAR}"] } });

{VAR} is replaced with the canonical name. Not in the chain unless configured.

Two rules for whatever you point it at, both learned the hard way:

  1. It must be non-interactive and fail closed. A manager that falls back to an interactive or biometric unlock will hang, then get killed by the timeout — a GUI/launchd-spawned process has no TTY to prompt on. Prefer an explicit cache-only flag.
  2. Use an absolute path. A GUI-launched process doesn't inherit your shell's PATH, so a bare command name works in your terminal and silently fails everywhere else.

Portability

The keychain backend is macOS (/usr/bin/security, absolute path so a stripped PATH can't break it). Elsewhere, keychain reads return null and the chain falls through; env and env-file work everywhere. Adding Linux (libsecret) or Windows (DPAPI) means implementing keychain.ts for that platform — nothing else changes.

Also exported

loadEnv() / parseEnvFile() — the Vite-style .env precedence loader, for reading env before spawning a subprocess with introspection of what loaded.

License

MIT