@velox/keychain Stable
Namespace-scoped OS keychain with automatic JSON serialization. Wraps the credentials API with key collision prevention and typed schemas.
Requires capability: "credentials"
Backed by: Windows Credential Manager, macOS Keychain, Linux Secret Service (libsecret)
Install
npm install @velox/keychainSimple keychain
import { createKeychain } from '@velox/keychain'
const authChain = createKeychain('auth')
// Store
await authChain.set('accessToken', 'Bearer abc123')
await authChain.set('userId', 42) // any JSON-serializable value
// Read
const token = await authChain.get('accessToken') // 'Bearer abc123'
const id = await authChain.get('userId') // 42
// Delete
await authChain.delete('accessToken')
// Clear specific keys
await authChain.clear(['accessToken', 'userId'])Keys are stored as namespace:key in the OS keychain, preventing collisions between different logical stores that share the same service.
Typed keychain
For compile-time key safety and automatic defaults:
import { createTypedKeychain } from '@velox/keychain'
const secrets = createTypedKeychain('auth', {
accessToken: null as string | null,
refreshToken: null as string | null,
userId: null as number | null,
})
await secrets.set('accessToken', 'Bearer xyz')
const token = await secrets.get('accessToken') // 'Bearer xyz' | null — default is null
const all = await secrets.getAll() // { accessToken, refreshToken, userId }
await secrets.clear() // clears all keys in the schema (no list needed)Unknown keys throw at runtime: @velox/keychain: unknown key "foo" in namespace "auth".
API
createKeychain(namespace, opts?)
| Param | Type | Default | Description |
|---|---|---|---|
namespace | string | — | Key prefix, e.g. 'auth', 'payments' |
opts.service | string | 'velox' | OS keychain service name |
Returns { set, get, delete, clear }:
| Method | Signature | Description |
|---|---|---|
set | (key, value) => Promise<void> | Store any JSON-serializable value |
get | (key) => Promise<any | null> | Read value, or null if absent |
delete | (key) => Promise<void> | Delete one key |
clear | (keys: string[]) => Promise<void> | Delete a list of keys |
createTypedKeychain(namespace, schema, opts?)
| Param | Type | Description |
|---|---|---|
namespace | string | Key prefix |
schema | { key: defaultValue } | All valid keys with default values |
opts.service | string | OS keychain service name (default 'velox') |
Returns { set, get, getAll, delete, clear }:
| Method | Signature | Description |
|---|---|---|
set | (key, value) => Promise<void> | Set a schema key |
get | (key) => Promise<value | default> | Returns schema default if absent |
getAll | () => Promise<schema> | Resolve all keys at once |
delete | (key) => Promise<void> | Delete one key (resets to default) |
clear | () => Promise<void> | Delete all schema keys |
Values are JSON-serialized before storage. get returns the original value type after deserialization — strings stay strings, numbers stay numbers, objects stay objects.
Auth token example
// src/auth.ts
import { createTypedKeychain } from '@velox/keychain'
export const authSecrets = createTypedKeychain('auth', {
accessToken: null,
refreshToken: null,
expiresAt: 0,
})
export async function saveTokens(access: string, refresh: string, expiresAt: number) {
await authSecrets.set('accessToken', access)
await authSecrets.set('refreshToken', refresh)
await authSecrets.set('expiresAt', expiresAt)
}
export async function loadTokens() {
return authSecrets.getAll()
}
export async function clearTokens() {
await authSecrets.clear()
}