CipherStash Docs

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).

init.ts
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

OptionTypeRequiredDescription
schemasEncryptedTable[]YesOne or more encrypted table schemas
configEncryptionClientConfigNoExplicit credentials. If omitted, reads CS_* env vars

EncryptionClientConfig

types.ts
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

VariableMaps toDescription
CS_WORKSPACE_CRNworkspaceCrnWorkspace identifier in CRN format
CS_CLIENT_IDclientIdClient identifier
CS_CLIENT_KEYclientKeyClient key material
CS_CLIENT_ACCESS_KEYaccessKeyAPI key for authentication
STASH_STACK_LOGLog 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.

types.ts
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

result-check.ts
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).

encrypt.ts
const result = await client.encrypt(plaintext, {
  column: users.email,
  table: users,
})
// result.data: Encrypted payload
ParameterTypeDescription
plaintextstring | number | boolean | Date | bigint | nullThe value to encrypt
options.columnProtectColumnColumn from your schema (e.g., users.email)
options.tableEncryptedTableTable from your schema (e.g., users)

Returns EncryptOperation — thenable, supports .withLockContext() and .audit().

decrypt

Decrypt a single encrypted payload.

decrypt.ts
const result = await client.decrypt(encryptedData)
// result.data: plaintext value
ParameterTypeDescription
encryptedDataEncryptedThe 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.

encrypt-model.ts
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 }
ParameterTypeDescription
modelTThe object to encrypt
tableEncryptedTableTable 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.

decrypt-model.ts
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.

encrypt-query.ts
// 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)TypeDescription
plaintextstring | number | boolean | object | nullThe search term
options.columnProtectColumnColumn to search
options.tableEncryptedTableTable 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'
returnTypeOutputUse case
'eql' (default)Encrypted objectParameterized queries, ORMs accepting JSON
'composite-literal'stringSupabase .eq(), string-based APIs
'escaped-composite-literal'stringEmbedding 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.

bulk-encrypt.ts
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.

bulk-decrypt.ts
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.

bulk-encrypt-models.ts
const result = await client.bulkEncryptModels(userModels, users)
// result.data: array of encrypted models

Returns BulkEncryptModelsOperation<T> — thenable, supports .withLockContext() and .audit().

bulkDecryptModels

Decrypt multiple encrypted models in a single ZeroKMS call.

bulk-decrypt-models.ts
const result = await client.bulkDecryptModels(encryptedModels)
// result.data: array of decrypted models

Returns BulkDecryptModelsOperation<T> — thenable, supports .withLockContext().

Operation chaining

All operations return thenable objects that support chaining before awaiting:

chaining.ts
const result = await client
  .encrypt(plaintext, { column: users.email, table: users })
  .withLockContext(lockContext)                           // identity-aware encryption
  .audit({ metadata: { action: "create" } })             // audit trail
MethodAvailable onDescription
.withLockContext(lc)All operationsBind operation to an identity lock context
.audit(options)Encrypt operationsAttach metadata to the audit log

Schema builders

schema.ts
import {
  encryptedTable,
  encryptedColumn,
  encryptedField,
} from "@cipherstash/stack/schema"

encryptedTable(name, columns)

Define an encrypted table schema.

ParameterTypeDescription
namestringDatabase table name
columnsRecord<string, ProtectColumn>Map of column names to encrypted column definitions

encryptedColumn(name)

Define an encrypted column with chainable index methods.

MethodDescription
.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

types.ts
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.

lock-context.ts
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 optionTypeDefaultDescription
context.identityClaimstring | string[]"sub"JWT claim(s) to bind encryption to

Requires CS_CTS_ENDPOINT environment variable for the CipherStash Token Service.

Subpath exports

Import pathProvides
@cipherstash/stackEncryption function (main entry point)
@cipherstash/stack/schemaencryptedTable, encryptedColumn, encryptedField, schema types
@cipherstash/stack/identityLockContext class and identity types
@cipherstash/stack/secretsSecrets class and secrets types
@cipherstash/stack/drizzleencryptedType, extractEncryptionSchema, createEncryptionOperators for Drizzle ORM
@cipherstash/stack/supabaseencryptedSupabase wrapper for Supabase
@cipherstash/stack/dynamodbencryptedDynamoDB helper for DynamoDB
@cipherstash/stack/clientClient-safe exports (schema builders and types only — no native FFI)
@cipherstash/stack/typesAll TypeScript types

Validation rules

The SDK validates inputs before making ZeroKMS calls:

RuleWhen it applies
NaN and Infinity are rejectedNumeric values
Only strings are acceptedColumns with .freeTextSearch() index
At least one schema requiredEncryption() initialization
Valid UUID format requiredKeyset id option
JWT must be valid and contain required claimsLockContext.identify()

On this page