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

@inspiration-particle/win-cred-binding

v0.1.1

Published

Windows Credential Manager native binding with TypeScript credential manager

Readme

@inspiration-particle/win-cred-binding

Windows Credential Manager native binding for Node.js.

Stores private signing keys in the Windows Credential Manager — the same secure OS-managed store that browsers, VPN clients, and Git use on Windows. On macOS and Linux the package installs normally but all methods throw, letting callers fall back to file-based storage.

Why a native binding?

The Windows Credential Manager API is a C API exposed by advapi32.dll. Node.js has no built-in wrapper for it. The alternatives are:

| Approach | Problem | |---|---| | PowerShell subprocess | Secrets transit a process boundary and are briefly visible in ps output | | Third-party keyring library | Pulls in 100+ crates, cross-platform drivers (dbus, libsecret) you don't need, and single-maintainer concentration risk | | This package | ~30 crates total, Windows-only target, no subprocess, secrets never leave the process |

Requirements

  • Runtime: Node.js ≥ 22 on Windows x64, x86, or ARM64
  • Install anywhere: the package installs on macOS and Linux too — it just won't be functional

Installation

pnpm add @inspiration-particle/win-cred-binding

The three platform-specific binary packages (-win32-x64-msvc, -win32-ia32-msvc, -win32-arm64-msvc) are listed as optionalDependencies. pnpm automatically skips the ones that do not match the current OS and CPU, so macOS and Linux developers install no Windows binaries.

Usage

Import the pre-built credential manager singleton:

import { credentialManager } from '@inspiration-particle/win-cred-binding/credential-manager'

// Always check isSupported before using — it is false on non-Windows
if (!credentialManager.isSupported) {
  console.log('Running on non-Windows, use file-based storage instead')
  process.exit(0)
}

// Store a value (overwrites any existing entry for the same account)
credentialManager.store('my-key-id', base64EncodedPrivateKey)

// Retrieve it
const key = credentialManager.read('my-key-id')   // string | null

// List all stored account names in the cognite-flows namespace
const accounts = credentialManager.list()          // string[]

// Remove an entry (no-op if it does not exist)
credentialManager.delete('my-key-id')

Interface

interface CredentialManager {
  readonly isSupported: boolean
  store(account: string, value: string): void
  read(account: string): string | null
  delete(account: string): void
  list(): string[]
}

Credential format in Windows Credential Manager

Credentials appear under Generic Credentials in control /name Microsoft.CredentialManager as:

| Field | Value | |---|---| | TargetName | cognite-flows:<account> | | UserName | cognite-cli | | Credential | The secret string, encoded as UTF-16 LE (native Windows format) |

UTF-16 LE encoding means the stored bytes are interoperable with any native Windows application that reads the same credential.


How it works

Architecture

TypeScript caller
       │  import { credentialManager } from '@inspiration-particle/win-cred-binding/credential-manager'
       ▼
ts/credential-manager.ts        ← platform detection, service prefix, interface
       │  require('..')
       ▼
index.js  (generated)           ← napi-rs platform shim: picks the right .node file
       │  require('@inspiration-particle/win-cred-binding-win32-x64-msvc')
       ▼
win-cred-binding.win32-x64-msvc.node   ← compiled Rust binary
       │  unsafe { CredWriteW(...) }
       ▼
Windows Credential Manager (advapi32.dll)

Why Rust?

  • Direct access to C APIs: The Windows Credential Manager is a C API. Rust can call C functions directly with zero overhead — no subprocess, no COM, no scripting engine.
  • Memory safety: Rust's ownership model prevents common C bugs (use-after-free, double-free) even in code that calls into unsafe C APIs. Every unsafe block in this codebase has an explanatory comment.
  • Small binary: The compiled .node file is a few hundred kilobytes. There is no garbage collector, no runtime, and no framework.

Why windows-sys?

The Windows API is a C API defined in the Windows SDK. To call it from Rust you need bindings — Rust declarations that match the C function signatures and struct layouts so the compiler knows how to generate the right machine code.

We use windows-sys, maintained by Microsoft, which provides these bindings as thin, zero-cost wrappers. We use exactly two feature slices:

Win32_Foundation — basic Windows types used throughout the Win32 API surface:

  • BOOL — Win32's integer-based boolean (0 = false)
  • FILETIME — 64-bit timestamp used in credential metadata
  • GetLastError — retrieves the error code from a failed API call
  • Error constants: ERROR_NOT_FOUND, ERROR_NO_SUCH_LOGON_SESSION

Win32_Security_Credentials — the Credential Manager API itself:

  • CredWriteW — create or update a credential
  • CredReadW — read a credential by target name
  • CredDeleteW — delete a credential
  • CredEnumerateW — list credentials (supports "prefix*" wildcard filtering)
  • CredFree — release memory allocated by the above functions
  • CREDENTIALW — the struct describing a single credential
  • CRED_TYPE_GENERIC, CRED_PERSIST_ENTERPRISE — constants controlling credential type and persistence scope

The W suffix on every function name is a Windows convention meaning the function takes wide (UTF-16) strings rather than ANSI strings. We encode all strings as null-terminated UTF-16 before passing them to the API.


Dependencies

| Crate | Role | |---|---| | napi | Rust runtime for N-API: marshals values between Rust and the Node.js VM | | napi-derive | The #[napi] procedural macro that generates Node.js export boilerplate | | napi-build | Build-script helper that sets the linker flags Node.js requires to load .node files | | windows-sys | Zero-cost Win32 API bindings, maintained by Microsoft |

What is N-API?

N-API (Node API) is a stable C interface that Node.js exposes to native addons. "Stable" means a binary compiled against N-API version 4 (Node 10+) runs on every later version of Node.js without recompilation. This is why you do not need to rebuild when upgrading Node.

napi-rs wraps N-API in idiomatic Rust, eliminating most of the boilerplate. #[napi] on a Rust function automatically generates the code that registers the function with Node's module system and converts arguments and return values between JavaScript types and Rust types.


Building

The native binary can only be built on Windows (it links against Windows SDK libraries). The CI pipeline handles this automatically on every tagged release.

If you need a local Windows build:

# Install Rust: https://rustup.rs
# Then:
pnpm install
pnpm build              # builds for the current Windows architecture
pnpm build:debug        # unoptimised build, faster compile times

This produces a .node file in the repo root, which Node.js will use in preference to the npm sub-package binary.

TypeScript

pnpm compile:ts         # compiles ts/ → dist/ with .d.ts declarations

Publishing

Triggered automatically when a v* tag is pushed. The GitHub Actions workflow:

  1. Builds the .node binary for all three Windows targets in parallel (windows-latest runners)
  2. Publishes the three platform sub-packages (-win32-x64-msvc, -win32-ia32-msvc, -win32-arm64-msvc)
  3. Compiles TypeScript and generates index.js
  4. Publishes the main package

Requires an NPM_TOKEN secret with publish access to the @inspiration-particle npm org.

git tag v1.0.0
git push origin v1.0.0

License

MIT OR Apache-2.0