🚧 VeloxKit is pre-release software. APIs may change before v1.0. Get started →
Documentation
Packages
@velox/keychain

@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/keychain

Simple 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?)

ParamTypeDefaultDescription
namespacestringKey prefix, e.g. 'auth', 'payments'
opts.servicestring'velox'OS keychain service name

Returns { set, get, delete, clear }:

MethodSignatureDescription
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?)

ParamTypeDescription
namespacestringKey prefix
schema{ key: defaultValue }All valid keys with default values
opts.servicestringOS keychain service name (default 'velox')

Returns { set, get, getAll, delete, clear }:

MethodSignatureDescription
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()
}