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

@wy-ai-labs/secure-store

v0.1.0

Published

Named credential sets encrypted at rest — OS keychain (injected Electron safeStorage adapter) when available, AES-256-GCM with a scrypt machine key otherwise; atomic writes, versioned envelope with migration hook, values never logged or listed.

Readme

@wy-ai-labs/secure-store

Named credential sets encrypted at rest — OS keychain (injected safeStorage adapter) when available, AES-256-GCM with a scrypt machine key otherwise — that writes atomically and never puts a value on disk, in a log line, in an error or in a listing.

npm License: MIT Node ≥22 runtime deps: 0

Part of the wy-ai-labs parts monorepo (packages/secure-store) · contract v1 · no Python twin

Install

npm install @wy-ai-labs/secure-store      # Node ≥22.11, ESM only (import — no require)

30-second usage

import { createSecureStore, createKeyProvider, CONTRACT_VERSION } from '@wy-ai-labs/secure-store';
import { homedir } from 'node:os';
import { join } from 'node:path';

const store = createSecureStore({
  dir: join(homedir(), '.my-app'),                                  // the app decides where the file lives
  keyProvider: createKeyProvider({ salt: 'my-app-credentials-v1' }), // app-specific salt (not a secret); add `safeStorage` in Electron
});

store.set('hosted', 'api_key', process.env.LLM_API_KEY ?? 'paste-at-runtime');   // encrypted + written atomically
store.set('gateway', 'client_id', 'my-app');

console.log(CONTRACT_VERSION, store.listSets(), store.listKeys('hosted'));  // 1 [ 'gateway', 'hosted' ] [ 'api_key' ] — names only
console.log(store.get('hosted', 'api_key') !== undefined);                   // true — values come back only through get()

In an Electron main process pass the real keychain adapter: createKeyProvider({ salt, safeStorage }) — the part never imports electron; when safeStorage.isEncryptionAvailable() is false it falls back to the machine key, and a store written with one can be opened with the other.

Recovering from a file that cannot be opened (moved from another machine, modified, keychain gone):

try {
  store.listSets();
} catch (err) {
  if (err.code === 'locked' || err.code === 'integrity' || err.code === 'invalid_envelope') {
    store.clear();                       // preserves the old file once as <path>.unreadable-backup, then starts fresh
    store.set('hosted', 'api_key', askUserAgain());
  } else throw err;
}

Contract

Public API, invariants and error model are fixed in CONTRACT.md; the tests in test/ are the contract suite (one test per numbered invariant). Three invariants to know before depending on this part:

  1. No plaintext on disk, no values in errors or listings — the file holds an envelope (v, kdf, alg, iv, tag, data, …); set names, key names and values all live inside the ciphertext; listSets()/listKeys() return names only and every SecureStoreError message is value-free.
  2. Tamper → integrity, wrong key → locked — a modified payload and a file sealed on another machine / user / salt / keychain fail with stable codes and one-line messages, never with a raw crypto error; an unreadable file is never silently overwritten — only an explicit clear() replaces it, after preserving it once as <path>.unreadable-backup.
  3. Atomic writes, memory-only hot path — temp file + rename (mode 0o600 where supported); a failed write leaves the previous file byte-identical; after the first load, reads never touch the disk and scrypt runs once per key provider.

An incompatible change bumps CONTRACT_VERSION and the major version together (CONTRACT.md → Compatibility).

Mined from

Extracted from two private source repositories (LLM_GATEWAY, module server/credstore.mjs; CodeReviewWar, modules server/llm/vendor/credstore.mjs, server/github-creds.ts; developed 2026-07-13 – 2026-08-08), generalized from a flat per-app credential blob to named credential sets with a pluggable key provider and a versioned JSON envelope, and re-tested for publication. What was kept, generalized and stripped: PROVENANCE.md.

Used by

| Client | Role of this part there | |---|---| | llm-gateway | provider API keys and per-provider connection settings entered in the tray UI, one set per provider | | code-review-war | LLM provider credentials and per-host GitHub tokens (one set per host) without a plaintext .env | | ark | embedding / chat endpoint keys for the local RAG workbench |

Dependencies & budget

  • Runtime dependencies: 0 (budget 0, default 0) — enforced by scripts/check-budget.mjs; imports are node:crypto, node:fs, node:os, node:path only.
  • Allowed: other @wy-ai-labs/* parts, pinned as caret ranges from the registry. Never a client, never file: / link: / git URLs / ../.
  • No private host, model id or key as a default: the part reads no environment variables; the caller chooses dir, name, salt and the key provider.

Gates

| Command | What | When | |---|---|---| | npm test | contract suite (node:test), offline, seconds | every save | | npm run gates:core | dependency budget + independence + engines.node + tests | before every commit / PR | | npm run gates:full | everything above | nightly / before release |

CI only calls these scripts (wy-ai-labs/.githubnode-gates.yml). Releases: Keep a Changelog + npm publish --provenance.

License

MIT © 2026 waneekim

한국어 요약

  • @wy-ai-labs/secure-store — 이름 있는 자격증명 세트를 저장 시 암호화하는 부품. OS 키체인(호출자가 넘긴 Electron safeStorage 어댑터)이 있으면 그걸, 없으면 scrypt 머신 키 + AES-256-GCM을 쓰고, 원자적으로 쓰며, 값은 디스크·로그·오류 메시지·목록 어디에도 평문으로 남기지 않습니다. 공개 API·불변식·오류 모델은 CONTRACT.md에 고정되어 있고, 테스트가 곧 계약 스위트입니다.
  • 설치 npm install @wy-ai-labs/secure-store(Node ≥22, ESM). 런타임 의존성 0, 다른 part에만 핀 버전으로 의존, 사설 호스트 기본값 없음(환경변수도 읽지 않음).
  • 비공개 저장소 LLM_GATEWAY·CodeReviewWar의 credstore 모듈에서 추출·일반화했습니다(PROVENANCE.md). 커밋 전 npm run gates:core.