API reference
Complete API reference for the CipherStash Encryption SDK
API reference
For auto-generated TypeDoc reference with full type signatures, see the generated API reference.
Encryption(config)
Initialize the encryption client. Returns Promise<EncryptionClient> and throws on error (e.g., bad credentials, missing config, invalid keyset UUID).
import { Encryption } from "@cipherstash/stack"
import { users } from "./schema"
try {
const client = await Encryption({
schemas: [users],
config: { /* optional — reads CS_* env vars by default */ },
})
} catch (error) {
console.error("Init failed:", error.message)
}Config options
| Option | Type | Required | Description |
|---|---|---|---|
schemas | EncryptedTable[] | Yes | One or more encrypted table schemas |
config | EncryptionClientConfig | No | Explicit credentials. If omitted, reads CS_* env vars |
EncryptionClientConfig
type EncryptionClientConfig = {
workspaceCrn: string // CRN format: "crn:<region>:<workspace-id>"
clientId: string // Client identifier
clientKey: string // Client key material for ZeroKMS
accessKey: string // API key for CipherStash API
keyset?: {
name?: string // Keyset name (multi-tenant isolation)
id?: string // Keyset UUID (alternative to name)
}
}Environment variables
| Variable | Maps to | Description |
|---|---|---|
CS_WORKSPACE_CRN | workspaceCrn | Workspace identifier in CRN format |
CS_CLIENT_ID | clientId | Client identifier |
CS_CLIENT_KEY | clientKey | Client key material |
CS_CLIENT_ACCESS_KEY | accessKey | API key for authentication |
STASH_STACK_LOG | — | Log verbosity: debug, info, error (default: error) |
The Result type
All async methods return a Result — a discriminated union with either data (success) or failure (error), never both.
type Result<T, E = EncryptionError> =
| { data: T; failure?: never }
| { failure: E; data?: never }
type EncryptionError = {
type: "ClientInitError" | "EncryptionError" | "DecryptionError"
| "LockContextError" | "CtsTokenError"
message: string
}Checking results
const result = await client.encrypt("hello", { column: users.email, table: users })
if (result.failure) {
// result.failure.type: string
// result.failure.message: string
console.error(result.failure.type, result.failure.message)
} else {
// result.data: the encrypted payload
console.log(result.data)
}Client methods
encrypt
Encrypt a single plaintext value. Null values are preserved (encrypting null returns null).
const result = await client.encrypt(plaintext, {
column: users.email,
table: users,
})
// result.data: Encrypted payload| Parameter | Type | Description |
|---|---|---|
plaintext | string | number | boolean | Date | bigint | null | The value to encrypt |
options.column | ProtectColumn | Column from your schema (e.g., users.email) |
options.table | EncryptedTable | Table from your schema (e.g., users) |
Returns EncryptOperation — thenable, supports .withLockContext() and .audit().
decrypt
Decrypt a single encrypted payload.
const result = await client.decrypt(encryptedData)
// result.data: plaintext value| Parameter | Type | Description |
|---|---|---|
encryptedData | Encrypted | The encrypted payload from a previous encrypt call |
Returns DecryptOperation — thenable, supports .withLockContext().
encryptModel
Encrypt all schema-defined fields on an object. Fields not in the schema pass through unchanged.
type User = { id: string; email: string; createdAt: Date }
const result = await client.encryptModel<User>(
{ id: "user_123", email: "alice@example.com", createdAt: new Date() },
users
)
// result.data: { id: "user_123", email: Encrypted, createdAt: Date }| Parameter | Type | Description |
|---|---|---|
model | T | The object to encrypt |
table | EncryptedTable | Table schema defining which fields to encrypt |
Returns EncryptModelOperation<T> — thenable, supports .withLockContext() and .audit().
decryptModel
Decrypt all encrypted fields on a model back to plaintext.
const result = await client.decryptModel<User>(encryptedModel)
// result.data: { id: "user_123", email: "alice@example.com", createdAt: Date }Returns DecryptModelOperation<T> — thenable, supports .withLockContext().
encryptQuery
Encrypt a query term for searching encrypted data in PostgreSQL.
// Single query
const result = await client.encryptQuery("alice@example.com", {
column: users.email,
table: users,
queryType: "equality", // optional — auto-inferred from column indexes
})
// Batch query (multiple terms in one ZeroKMS call)
const results = await client.encryptQuery([
{ value: "alice@example.com", column: users.email, table: users, queryType: "equality" as const },
{ value: "bob", column: users.email, table: users, queryType: "freeTextSearch" as const },
])| Parameter (single) | Type | Description |
|---|---|---|
plaintext | string | number | boolean | object | null | The search term |
options.column | ProtectColumn | Column to search |
options.table | EncryptedTable | Table schema |
options.queryType | 'equality' | 'freeTextSearch' | 'orderAndRange' | 'searchableJson' | Index type. Auto-inferred if omitted |
options.returnType | 'eql' | 'composite-literal' | 'escaped-composite-literal' | Output format. Default: 'eql' |
returnType | Output | Use case |
|---|---|---|
'eql' (default) | Encrypted object | Parameterized queries, ORMs accepting JSON |
'composite-literal' | string | Supabase .eq(), string-based APIs |
'escaped-composite-literal' | string | Embedding inside another string or JSON value |
Returns EncryptQueryOperation or BatchEncryptQueryOperation — thenable, supports .withLockContext().
bulkEncrypt
Encrypt multiple values in a single ZeroKMS call. Each value still gets a unique key.
const result = await client.bulkEncrypt(
[
{ id: "u1", plaintext: "alice@example.com" },
{ id: "u2", plaintext: "bob@example.com" },
{ id: "u3", plaintext: null },
],
{ column: users.email, table: users }
)
// result.data: [{ id: "u1", data: Encrypted }, ...]Returns BulkEncryptOperation — thenable, supports .withLockContext() and .audit().
bulkDecrypt
Decrypt multiple encrypted payloads in a single ZeroKMS call. Supports per-item error handling.
const result = await client.bulkDecrypt(encryptedPayloads)
for (const item of result.data) {
if ("data" in item) {
console.log(`${item.id}: ${item.data}`)
} else {
console.error(`${item.id} failed: ${item.error}`)
}
}Returns BulkDecryptOperation — thenable, supports .withLockContext().
bulkEncryptModels
Encrypt multiple model objects in a single ZeroKMS call.
const result = await client.bulkEncryptModels(userModels, users)
// result.data: array of encrypted modelsReturns BulkEncryptModelsOperation<T> — thenable, supports .withLockContext() and .audit().
bulkDecryptModels
Decrypt multiple encrypted models in a single ZeroKMS call.
const result = await client.bulkDecryptModels(encryptedModels)
// result.data: array of decrypted modelsReturns BulkDecryptModelsOperation<T> — thenable, supports .withLockContext().
Operation chaining
All operations return thenable objects that support chaining before awaiting:
const result = await client
.encrypt(plaintext, { column: users.email, table: users })
.withLockContext(lockContext) // identity-aware encryption
.audit({ metadata: { action: "create" } }) // audit trail| Method | Available on | Description |
|---|---|---|
.withLockContext(lc) | All operations | Bind operation to an identity lock context |
.audit(options) | Encrypt operations | Attach metadata to the audit log |
Schema builders
import {
encryptedTable,
encryptedColumn,
encryptedField,
} from "@cipherstash/stack/schema"encryptedTable(name, columns)
Define an encrypted table schema.
| Parameter | Type | Description |
|---|---|---|
name | string | Database table name |
columns | Record<string, ProtectColumn> | Map of column names to encrypted column definitions |
encryptedColumn(name)
Define an encrypted column with chainable index methods.
| Method | Description |
|---|---|
.equality() | Enable exact-match queries (HMAC-SHA-256) |
.freeTextSearch(opts?) | Enable full-text / fuzzy search (Bloom filters) |
.orderAndRange() | Enable sorting and range queries (Block ORE) |
.searchableJson() | Enable encrypted JSONB queries (JSONPath + containment) |
.dataType(cast) | Set the plaintext data type: 'string', 'number', 'boolean', 'date', 'bigint', 'json' |
Methods are chainable — call as many as needed on a single column.
encryptedField(name)
Define an encrypted field for nested objects. Not searchable. Supports .dataType() chaining.
Type inference
import type { InferPlaintext, InferEncrypted } from "@cipherstash/stack/schema"
type UserPlaintext = InferPlaintext<typeof users>
// { email: string; age: string; address: string }
type UserEncrypted = InferEncrypted<typeof users>
// { email: Encrypted; age: Encrypted; address: Encrypted }LockContext
Identity-aware encryption using JWT-based lock contexts.
import { LockContext } from "@cipherstash/stack/identity"
// Default: uses the "sub" claim
const lc = new LockContext()
// Custom claims
const lc = new LockContext({
context: { identityClaim: ["sub", "org_id"] }
})
// Identify user
const result = await lc.identify(jwtToken)
if (result.failure) {
console.error(result.failure.message)
} else {
const lockContext = result.data
// Use with .withLockContext(lockContext)
}| Constructor option | Type | Default | Description |
|---|---|---|---|
context.identityClaim | string | string[] | "sub" | JWT claim(s) to bind encryption to |
Requires CS_CTS_ENDPOINT environment variable for the CipherStash Token Service.
Subpath exports
| Import path | Provides |
|---|---|
@cipherstash/stack | Encryption function (main entry point) |
@cipherstash/stack/schema | encryptedTable, encryptedColumn, encryptedField, schema types |
@cipherstash/stack/identity | LockContext class and identity types |
@cipherstash/stack/secrets | Secrets class and secrets types |
@cipherstash/stack/drizzle | encryptedType, extractEncryptionSchema, createEncryptionOperators for Drizzle ORM |
@cipherstash/stack/supabase | encryptedSupabase wrapper for Supabase |
@cipherstash/stack/dynamodb | encryptedDynamoDB helper for DynamoDB |
@cipherstash/stack/client | Client-safe exports (schema builders and types only — no native FFI) |
@cipherstash/stack/types | All TypeScript types |
Validation rules
The SDK validates inputs before making ZeroKMS calls:
| Rule | When it applies |
|---|---|
| NaN and Infinity are rejected | Numeric values |
| Only strings are accepted | Columns with .freeTextSearch() index |
| At least one schema required | Encryption() initialization |
| Valid UUID format required | Keyset id option |
| JWT must be valid and contain required claims | LockContext.identify() |