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

@layerbase/secrets

v0.1.1

Published

Official TypeScript SDK for the Layerbase secret-store: fetch and decrypt project/environment secrets, plus an admin client.

Downloads

26

Readme

@layerbase/secrets

Official TypeScript SDK for the Layerbase secret-store: fetch and decrypt project and environment secrets, and (optionally) drive the admin API.

Secrets are encrypted at rest with age. The server only ever returns ciphertext; this SDK decrypts locally with the identity you hold, so a secret value never leaves your process.

The server itself lives in the private secret-store repo; this is the public client package (its source is public so npm can attach provenance to each publish).

Install

npm install @layerbase/secrets

Runtime: Node.js 20 or newer. ESM only.

Consume: fetch and decrypt

A credential is a single string of the form st_v1.<token>.<identity>, minted once when an environment is created. Pass it to the client and pull your secrets:

import { SecretStoreClient } from '@layerbase/secrets'

const client = new SecretStoreClient({
  host: 'https://secrets.layerbase.dev',
  credential: process.env.SECRET_STORE_CREDENTIAL!,
})

const secrets = await client.pull('layerbase', 'production')
// { DATABASE_URL: '...', API_KEY: '...' }

You can also construct the client from the token and identity separately:

const client = new SecretStoreClient({
  host: 'https://secrets.layerbase.dev',
  token: process.env.SECRET_STORE_TOKEN!,
  identity: process.env.SECRET_STORE_IDENTITY!, // optional; see below
})

Load straight into process.env

loadEnv pulls an environment and assigns each value into process.env. Existing keys are left untouched unless you pass override: true. It returns the keys it set.

const applied = await client.loadEnv('layerbase', 'production')
// applied: ['DATABASE_URL', 'API_KEY']
// with override: overwrite keys already present in process.env
await client.loadEnv('layerbase', 'production', { override: true })

Other consume methods

// A single secret with its version.
const { value, version } = await client.get('layerbase', 'production', 'API_KEY')

// A subset of keys.
const some = await client.pull('layerbase', 'production', { keys: ['API_KEY'] })

// Raw armored ciphertext, no identity required (decrypt it yourself, later, elsewhere).
const ciphertext = await client.pullCiphertext('layerbase', 'production')

The identity is optional. Without it, pullCiphertext still works (it returns armored ciphertext), but pull, get, and loadEnv throw a clear error because they cannot decrypt.

Admin

The admin client maps 1:1 onto the admin API behind the ADMIN_TOKEN bearer. Import it from the /admin subpath so the consume half stays out of your bundle when you do not use it:

import { SecretStoreAdmin } from '@layerbase/secrets/admin'

const admin = new SecretStoreAdmin({
  host: 'https://secrets.layerbase.dev',
  adminToken: process.env.SECRET_STORE_ADMIN_TOKEN!,
})

const { project, masterIdentity } = await admin.createProject({
  name: 'Layerbase',
  slug: 'layerbase',
})
// Persist masterIdentity NOW: it decrypts everything in the project and is never shown again.

const env = await admin.createEnvironment(project.id, { slug: 'production' })
// env.credential / env.token / env.identity are shown ONCE. Persist them now.

await admin.setSecret(env.environment.id, 'API_KEY', 'sk-live-...')
await admin.setSecrets(env.environment.id, { A: '1', B: '2' })
await admin.importDotenv(env.environment.id, 'A=1\nB="two words"')

Other admin methods: listProjects, deleteProject, getEnvironment, deleteEnvironment, deleteSecret, createToken, revokeToken, audit.

Shown once

Several responses reveal a secret exactly once. The server never returns them again, so persist them at the call site:

  • createProject -> masterIdentity (decrypts the whole project).
  • createEnvironment -> credential, token, identity.
  • createToken -> token.

Errors

Every failure throws a SecretStoreError with a numeric status and a stable machine-readable code:

import { SecretStoreError } from '@layerbase/secrets'

try {
  await client.pull('layerbase', 'production')
} catch (error) {
  if (error instanceof SecretStoreError && error.code === 'unauthorized') {
    // rotate the credential
  }
}

code is one of 'unauthorized' | 'forbidden' | 'not_found' | 'invalid_request' | 'server_error' | 'network'. Error messages never contain a secret value, a token, an identity, or a raw response body.

Subpaths and tree-shaking

Two entry points resolve to separate files, each with its own types:

  • @layerbase/secrets -> the consume client (SecretStoreClient, parseCredential, SecretStoreError).
  • @layerbase/secrets/admin -> the admin client (SecretStoreAdmin).

The package is sideEffects: false and ESM only, so a bundler drops the half you do not import.

Supported runtimes

Node.js 20+ (uses the built-in global fetch and process.env). ESM only; there is no CommonJS build.

Development

The package is self-contained: it has its own devDependencies pinned by package-lock.json, so its scripts never depend on globals.

npm ci                # deps (typescript, tsx, @types/node, age-encryption)
npm run check         # tsc --noEmit
npm run build         # tsc -> dist/

Some tests boot the real secret-store server, which lives in the private Layerbase-LLC/secret-store repo, from a sibling checkout. For the full end-to-end run, clone that repo next to this one (so it sits at ../secret-store) and install its dependencies, or point SECRET_STORE_DIR at any checkout:

# ../secret-store, with `pnpm install` already run there
npm test              # node:test via tsx; boots the real server and runs every test

# or an explicit path
SECRET_STORE_DIR=/path/to/secret-store npm test

When no server checkout is resolvable, the server-dependent tests (the full lifecycle suite and the live-decrypt step of the pack test) report as SKIPPED with a message naming SECRET_STORE_DIR, and npm test still exits 0. The server-independent checks always run: npm pack, installing the tarball into a throwaway project, importing both subpaths, and the consumer-side tsc types check.

CI (.github/workflows/publish.yml) does not check out the private server: it runs the build, types, and pack/install checks, and the server tests skip. The full end-to-end suite runs locally against a sibling checkout by design.

License

This SDK package (@layerbase/secrets) is released under the MIT license (see LICENSE). The MIT license applies to this SDK package only. The secret-store server itself remains proprietary and is not covered by this license.