stash-encryption

Compare original and translation side by side

🇺🇸

Original

English
🇨🇳

Translation

Chinese

CipherStash Stack - Encryption

CipherStash Stack - 加密

Comprehensive guide for implementing field-level encryption with
@cipherstash/stack
. Every value is encrypted with its own unique key via ZeroKMS (backed by AWS KMS). Encryption happens client-side before data leaves the application.
这是一份使用
@cipherstash/stack
实现字段级加密的综合指南。每个值都会通过ZeroKMS(由AWS KMS提供支持)使用专属密钥进行加密。加密操作在数据离开应用前于客户端完成。

When to Use This Skill

适用场景

  • Adding field-level encryption to a TypeScript/Node.js project
  • Defining encrypted table schemas
  • Encrypting and decrypting individual values or entire models
  • Implementing searchable encryption (equality, free-text, range, JSON queries)
  • Bulk encrypting/decrypting large datasets
  • Implementing identity-aware encryption with JWT-based lock contexts
  • Setting up multi-tenant encryption with keysets
  • Migrating from
    @cipherstash/protect
    to
    @cipherstash/stack
  • 为TypeScript/Node.js项目添加字段级加密
  • 定义加密表模式
  • 加密和解密单个值或整个模型
  • 实现可搜索加密(等值、全文、范围、JSON查询)
  • 批量加密/解密大型数据集
  • 基于JWT锁上下文实现身份感知加密
  • 配置多租户加密密钥集
  • @cipherstash/protect
    迁移到
    @cipherstash/stack

Installation

安装

bash
npm install @cipherstash/stack
The package includes a native FFI module (
@cipherstash/protect-ffi
). You must opt out of bundling it in tools like Webpack, esbuild, or Next.js (
serverExternalPackages
).
bash
npm install @cipherstash/stack
该包包含一个原生FFI模块(
@cipherstash/protect-ffi
)。在Webpack、esbuild或Next.js等工具中,你必须将其排除在打包范围外(通过
serverExternalPackages
配置)。

Configuration

配置

Environment Variables

环境变量

Set these in
.env
or your hosting platform:
bash
CS_WORKSPACE_CRN=crn:ap-southeast-2.aws:your-workspace-id
CS_CLIENT_ID=your-client-id
CS_CLIENT_KEY=your-client-key
CS_CLIENT_ACCESS_KEY=your-access-key
Sign up at cipherstash.com/signup to generate credentials.
.env
文件或你的托管平台中设置以下环境变量:
bash
CS_WORKSPACE_CRN=crn:ap-southeast-2.aws:your-workspace-id
CS_CLIENT_ID=your-client-id
CS_CLIENT_KEY=your-client-key
CS_CLIENT_ACCESS_KEY=your-access-key
访问cipherstash.com/signup注册以生成凭证。

Programmatic Config

程序化配置

typescript
const client = await Encryption({
  schemas: [users],
  config: {
    workspaceCrn: "crn:ap-southeast-2.aws:your-workspace-id",
    clientId: "your-client-id",
    clientKey: "your-client-key",
    accessKey: "your-access-key",
    keyset: { name: "my-keyset" }, // optional: multi-tenant isolation
  },
})
If
config
is omitted, the client reads
CS_*
environment variables automatically.
typescript
const client = await Encryption({
  schemas: [users],
  config: {
    workspaceCrn: "crn:ap-southeast-2.aws:your-workspace-id",
    clientId: "your-client-id",
    clientKey: "your-client-key",
    accessKey: "your-access-key",
    keyset: { name: "my-keyset" }, // 可选:多租户隔离
  },
})
如果省略
config
,客户端会自动读取
CS_*
环境变量。

Logging

日志

Logging is disabled by default. Enable it via environment variable or programmatically:
bash
STASH_LOG_LEVEL=debug  # debug | info | warn | error (enables logging automatically)
默认情况下日志是禁用的。可通过环境变量或程序化方式启用:
bash
STASH_LOG_LEVEL=debug  # debug | info | warn | error(自动启用日志)

Programmatic Logging Configuration

程序化日志配置

typescript
const client = await Encryption({
  schemas: [users],
  logging: {
    enabled: true,     // toggle logging on/off (default: false, auto-enabled by STASH_LOG_LEVEL)
    pretty: true,      // pretty-print in development (default: auto-detected)
  },
})
typescript
const client = await Encryption({
  schemas: [users],
  logging: {
    enabled: true,     // 开启/关闭日志(默认:false,由STASH_LOG_LEVEL自动启用)
    pretty: true,      // 开发环境下格式化输出(默认:自动检测)
  },
})

Log Draining

日志导出

Send structured logs to an external observability platform:
typescript
const client = await Encryption({
  schemas: [users],
  logging: {
    drain: (ctx) => {
      // Forward to Axiom, Datadog, OTLP, etc.
      fetch("https://your-service.com/logs", {
        method: "POST",
        body: JSON.stringify(ctx.event),
      })
    },
  },
})
The SDK never logs plaintext data.
将结构化日志发送到外部可观测性平台:
typescript
const client = await Encryption({
  schemas: [users],
  logging: {
    drain: (ctx) => {
      // 转发到Axiom、Datadog、OTLP等平台
      fetch("https://your-service.com/logs", {
        method: "POST",
        body: JSON.stringify(ctx.event),
      })
    },
  },
})
SDK绝不会记录明文数据。

Subpath Exports

子路径导出

Import PathProvides
@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 + types only, no native FFI)
@cipherstash/stack/types
All TypeScript types
导入路径提供内容
@cipherstash/stack
Encryption
函数(主入口)
@cipherstash/stack/schema
encryptedTable
encryptedColumn
encryptedField
及模式类型
@cipherstash/stack/identity
LockContext
类及身份类型
@cipherstash/stack/secrets
Secrets
类及密钥类型
@cipherstash/stack/drizzle
用于Drizzle ORM的
encryptedType
extractEncryptionSchema
createEncryptionOperators
@cipherstash/stack/supabase
用于Supabase的
encryptedSupabase
包装器
@cipherstash/stack/dynamodb
用于DynamoDB的
encryptedDynamoDB
助手
@cipherstash/stack/client
客户端安全导出(仅模式构建器和类型,无原生FFI)
@cipherstash/stack/types
所有TypeScript类型

Schema Definition

模式定义

Define which tables and columns to encrypt using
encryptedTable
and
encryptedColumn
:
typescript
import { encryptedTable, encryptedColumn } from "@cipherstash/stack/schema"

const users = encryptedTable("users", {
  email: encryptedColumn("email")
    .equality()         // exact-match queries
    .freeTextSearch()   // full-text / fuzzy search
    .orderAndRange(),   // sorting and range queries

  age: encryptedColumn("age")
    .dataType("number")
    .equality()
    .orderAndRange(),

  address: encryptedColumn("address"), // encrypt-only, no search indexes
})

const documents = encryptedTable("documents", {
  metadata: encryptedColumn("metadata")
    .searchableJson(), // encrypted JSONB queries (JSONPath + containment)
})
使用
encryptedTable
encryptedColumn
定义要加密的表和列:
typescript
import { encryptedTable, encryptedColumn } from "@cipherstash/stack/schema"

const users = encryptedTable("users", {
  email: encryptedColumn("email")
    .equality()         // 精确匹配查询
    .freeTextSearch()   // 全文/模糊搜索
    .orderAndRange(),   // 排序和范围查询

  age: encryptedColumn("age")
    .dataType("number")
    .equality()
    .orderAndRange(),

  address: encryptedColumn("address"), // 仅加密,无搜索索引
})

const documents = encryptedTable("documents", {
  metadata: encryptedColumn("metadata")
    .searchableJson(), // 加密JSONB查询(JSONPath + 包含查询)
})

Index Types

索引类型

MethodPurposeQuery Type
.equality()
Exact match lookups
'equality'
.freeTextSearch(opts?)
Full-text / fuzzy search
'freeTextSearch'
.orderAndRange()
Sorting, comparison, range queries
'orderAndRange'
.searchableJson()
Encrypted JSONB path and containment queries (auto-sets
dataType
to
'json'
)
'searchableJson'
.dataType(cast)
Set plaintext data typeN/A
Supported data types:
'string'
(default),
'number'
,
'boolean'
,
'date'
,
'bigint'
,
'json'
Methods are chainable - call as many as you need on a single column.
方法用途查询类型
.equality()
精确匹配查找
'equality'
.freeTextSearch(opts?)
全文/模糊搜索
'freeTextSearch'
.orderAndRange()
排序、比较、范围查询
'orderAndRange'
.searchableJson()
加密JSONB路径和包含查询(自动将
dataType
设置为
'json'
'searchableJson'
.dataType(cast)
设置明文数据类型N/A
支持的数据类型:
'string'
(默认)、
'number'
'boolean'
'date'
'bigint'
'json'
方法支持链式调用 - 可在单个列上调用多个方法。

Free-Text Search Options

全文搜索选项

typescript
encryptedColumn("bio").freeTextSearch({
  tokenizer: { kind: "ngram", token_length: 3 },  // or { kind: "standard" }
  token_filters: [{ kind: "downcase" }],
  k: 6,
  m: 2048,
  include_original: false,
})
typescript
encryptedColumn("bio").freeTextSearch({
  tokenizer: { kind: "ngram", token_length: 3 },  // 或 { kind: "standard" }
  token_filters: [{ kind: "downcase" }],
  k: 6,
  m: 2048,
  include_original: false,
})

Type Inference

类型推断

typescript
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 }
typescript
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 }

Client Initialization

客户端初始化

typescript
import { Encryption } from "@cipherstash/stack"

const client = await Encryption({ schemas: [users, documents] })
The
Encryption()
function returns
Promise<EncryptionClient>
and throws on error (e.g., bad credentials, missing config, invalid keyset UUID). At least one schema is required.
typescript
// Error handling
try {
  const client = await Encryption({ schemas: [users] })
} catch (error) {
  console.error("Init failed:", error.message)
}
typescript
import { Encryption } from "@cipherstash/stack"

const client = await Encryption({ schemas: [users, documents] })
Encryption()
函数返回
Promise<EncryptionClient>
,出错时会抛出异常(例如无效凭证、缺失配置、无效密钥集UUID)。至少需要提供一个模式。
typescript
// 错误处理
try {
  const client = await Encryption({ schemas: [users] })
} catch (error) {
  console.error("初始化失败:", error.message)
}

Encrypt and Decrypt Single Values

单值加解密

typescript
// Encrypt
const encrypted = await client.encrypt("hello@example.com", {
  column: users.email,
  table: users,
})

if (encrypted.failure) {
  console.error(encrypted.failure.message)
} else {
  console.log(encrypted.data) // Encrypted payload (opaque object)
}

// Decrypt
const decrypted = await client.decrypt(encrypted.data)

if (!decrypted.failure) {
  console.log(decrypted.data) // "hello@example.com"
}
Null values are preserved: encrypting
null
returns
null
.
typescript
// 加密
const encrypted = await client.encrypt("hello@example.com", {
  column: users.email,
  table: users,
})

if (encrypted.failure) {
  console.error(encrypted.failure.message)
} else {
  console.log(encrypted.data) // 加密载荷(不透明对象)
}

// 解密
const decrypted = await client.decrypt(encrypted.data)

if (!decrypted.failure) {
  console.log(decrypted.data) // "hello@example.com"
}
空值会被保留:加密
null
会返回
null

Model Operations

模型操作

Encrypt or decrypt an entire object. Only fields matching your schema are encrypted; other fields pass through unchanged.
The return type is schema-aware: fields matching the table schema are typed as
Encrypted
, while other fields retain their original types. For best results, let TypeScript infer the type parameters from the arguments rather than providing an explicit
<User>
.
typescript
type User = { id: string; email: string; createdAt: Date }

const user = {
  id: "user_123",
  email: "alice@example.com",  // defined in schema -> encrypted
  createdAt: new Date(),       // not in schema -> unchanged
}

// Encrypt model — let TypeScript infer the return type from the schema
const encResult = await client.encryptModel(user, users)
if (!encResult.failure) {
  // encResult.data.email is typed as Encrypted
  // encResult.data.id is typed as string
  // encResult.data.createdAt is typed as Date
}

// Decrypt model
const decResult = await client.decryptModel(encResult.data)
if (!decResult.failure) {
  console.log(decResult.data.email) // "alice@example.com"
}
The
Decrypted<T>
type maps encrypted fields back to their plaintext types.
Passing an explicit type parameter (e.g.,
client.encryptModel<User>(...)
) still works for backward compatibility — the return type degrades to
User
in that case.
加密或解密整个对象。只有与模式匹配的字段会被加密;其他字段保持不变。
返回类型是模式感知的:与表模式匹配的字段类型为
Encrypted
,其他字段保留原类型。为获得最佳效果,让TypeScript从参数中推断类型参数,而非显式提供
<User>
typescript
type User = { id: string; email: string; createdAt: Date }

const user = {
  id: "user_123",
  email: "alice@example.com",  // 已在模式中定义 -> 会被加密
  createdAt: new Date(),       // 未在模式中定义 -> 保持不变
}

// 加密模型 — 让TypeScript从模式中推断返回类型
const encResult = await client.encryptModel(user, users)
if (!encResult.failure) {
  // encResult.data.email 类型为 Encrypted
  // encResult.data.id 类型为 string
  // encResult.data.createdAt 类型为 Date
}

// 解密模型
const decResult = await client.decryptModel(encResult.data)
if (!decResult.failure) {
  console.log(decResult.data.email) // "alice@example.com"
}
Decrypted<T>
类型会将加密字段映射回其明文类型。
显式传递类型参数(例如
client.encryptModel<User>(...)
)仍可向后兼容 — 此时返回类型会降级为
User

Bulk Operations

批量操作

All bulk methods make a single call to ZeroKMS regardless of record count, while still using a unique key per value.
所有批量方法无论记录数量多少,都只会调用一次ZeroKMS,同时仍为每个值使用专属密钥。

Bulk Encrypt / Decrypt (Raw Values)

批量加解密(原始值)

typescript
const plaintexts = [
  { id: "u1", plaintext: "alice@example.com" },
  { id: "u2", plaintext: "bob@example.com" },
  { id: "u3", plaintext: null }, // null values preserved
]

const encrypted = await client.bulkEncrypt(plaintexts, {
  column: users.email,
  table: users,
})
// encrypted.data = [{ id: "u1", data: EncryptedPayload }, ...]

const decrypted = await client.bulkDecrypt(encrypted.data)
// Per-item error handling:
for (const item of decrypted.data) {
  if ("data" in item) {
    console.log(`${item.id}: ${item.data}`)
  } else {
    console.error(`${item.id} failed: ${item.error}`)
  }
}
typescript
const plaintexts = [
  { id: "u1", plaintext: "alice@example.com" },
  { id: "u2", plaintext: "bob@example.com" },
  { id: "u3", plaintext: null }, // 空值会被保留
]

const encrypted = await client.bulkEncrypt(plaintexts, {
  column: users.email,
  table: users,
})
// encrypted.data = [{ id: "u1", data: EncryptedPayload }, ...]

const decrypted = await client.bulkDecrypt(encrypted.data)
// 逐项错误处理:
for (const item of decrypted.data) {
  if ("data" in item) {
    console.log(`${item.id}: ${item.data}`)
  } else {
    console.error(`${item.id} 失败: ${item.error}`)
  }
}

Bulk Encrypt / Decrypt Models

批量加解密模型

typescript
const userModels = [
  { id: "1", email: "alice@example.com" },
  { id: "2", email: "bob@example.com" },
]

const encrypted = await client.bulkEncryptModels(userModels, users)
const decrypted = await client.bulkDecryptModels(encrypted.data)
typescript
const userModels = [
  { id: "1", email: "alice@example.com" },
  { id: "2", email: "bob@example.com" },
]

const encrypted = await client.bulkEncryptModels(userModels, users)
const decrypted = await client.bulkDecryptModels(encrypted.data)

Searchable Encryption

可搜索加密

Encrypt query terms so you can search encrypted data in PostgreSQL.
加密查询条件,以便在PostgreSQL中搜索加密数据。

Single Query Encryption

单查询加密

typescript
// Equality query
const eqQuery = await client.encryptQuery("alice@example.com", {
  column: users.email,
  table: users,
  queryType: "equality",
})

// Free-text search
const matchQuery = await client.encryptQuery("alice", {
  column: users.email,
  table: users,
  queryType: "freeTextSearch",
})

// Order and range
const rangeQuery = await client.encryptQuery(25, {
  column: users.age,
  table: users,
  queryType: "orderAndRange",
})
If
queryType
is omitted, it's auto-inferred from the column's configured indexes (priority: unique > match > ore > ste_vec).
typescript
// 等值查询
const eqQuery = await client.encryptQuery("alice@example.com", {
  column: users.email,
  table: users,
  queryType: "equality",
})

// 全文搜索
const matchQuery = await client.encryptQuery("alice", {
  column: users.email,
  table: users,
  queryType: "freeTextSearch",
})

// 范围查询
const rangeQuery = await client.encryptQuery(25, {
  column: users.age,
  table: users,
  queryType: "orderAndRange",
})
如果省略
queryType
,会从列的配置索引中自动推断(优先级:唯一 > 匹配 > ore > ste_vec)。

Query Result Formatting (
returnType
)

查询结果格式(
returnType

By default
encryptQuery
returns an
Encrypted
object (the raw EQL JSON payload). Use
returnType
to change the output format:
returnType
OutputUse 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
typescript
// Get a composite literal string for use with Supabase
const term = await client.encryptQuery("alice@example.com", {
  column: users.email,
  table: users,
  queryType: "equality",
  returnType: "composite-literal",
})
// term.data is a string
Each term in a batch can have its own
returnType
.
默认情况下
encryptQuery
返回
Encrypted
对象(原始EQL JSON载荷)。使用
returnType
可更改输出格式:
returnType
输出适用场景
'eql'
(默认)
Encrypted
对象
参数化查询、接受JSON的ORM
'composite-literal'
string
Supabase
.eq()
、基于字符串的API
'escaped-composite-literal'
string
嵌入到另一个字符串或JSON值中
typescript
// 获取复合字面量字符串用于Supabase
const term = await client.encryptQuery("alice@example.com", {
  column: users.email,
  table: users,
  queryType: "equality",
  returnType: "composite-literal",
})
// term.data 是一个字符串
批量中的每个条件都可以有自己的
returnType

Searchable JSON

可搜索JSON

For columns using
.searchableJson()
, the query type is auto-inferred from the plaintext:
typescript
// String -> JSONPath selector query
const pathQuery = await client.encryptQuery("$.user.email", {
  column: documents.metadata,
  table: documents,
})

// Object/Array -> containment query
const containsQuery = await client.encryptQuery({ role: "admin" }, {
  column: documents.metadata,
  table: documents,
})
对于使用
.searchableJson()
的列,查询类型会从明文中自动推断:
typescript
// 字符串 -> JSONPath选择器查询
const pathQuery = await client.encryptQuery("$.user.email", {
  column: documents.metadata,
  table: documents,
})

// 对象/数组 -> 包含查询
const containsQuery = await client.encryptQuery({ role: "admin" }, {
  column: documents.metadata,
  table: documents,
})

Batch Query Encryption

批量查询加密

Encrypt multiple query terms in one ZeroKMS call:
typescript
const terms = [
  { value: "alice@example.com", column: users.email, table: users, queryType: "equality" as const },
  { value: "bob", column: users.email, table: users, queryType: "freeTextSearch" as const },
]

const results = await client.encryptQuery(terms)
// results.data = [EncryptedPayload, EncryptedPayload]
Null values in the array are skipped and returned as null.
在一次ZeroKMS调用中加密多个查询条件:
typescript
const terms = [
  { value: "alice@example.com", column: users.email, table: users, queryType: "equality" as const },
  { value: "bob", column: users.email, table: users, queryType: "freeTextSearch" as const },
]

const results = await client.encryptQuery(terms)
// results.data = [EncryptedPayload, EncryptedPayload]
数组中的空值会被跳过并返回null。

Identity-Aware Encryption (Lock Contexts)

身份感知加密(锁上下文)

Lock encryption to a specific user by requiring a valid JWT for decryption.
typescript
import { LockContext } from "@cipherstash/stack/identity"

// 1. Create a lock context (defaults to the "sub" claim)
const lc = new LockContext()
// Or with custom claims: new LockContext({ context: { identityClaim: ["sub", "org_id"] } })

// 2. Identify the user with their JWT
const identifyResult = await lc.identify(userJwt)
if (identifyResult.failure) {
  throw new Error(identifyResult.failure.message)
}
const lockContext = identifyResult.data

// 3. Encrypt with lock context
const encrypted = await client
  .encrypt("sensitive data", { column: users.email, table: users })
  .withLockContext(lockContext)

// 4. Decrypt with the same lock context
const decrypted = await client
  .decrypt(encrypted.data)
  .withLockContext(lockContext)
Lock contexts work with ALL operations:
encrypt
,
decrypt
,
encryptModel
,
decryptModel
,
bulkEncrypt
,
bulkDecrypt
,
bulkEncryptModels
,
bulkDecryptModels
,
encryptQuery
.
通过要求有效的JWT才能解密,将加密与特定用户绑定。
typescript
import { LockContext } from "@cipherstash/stack/identity"

// 1. 创建锁上下文(默认使用"sub"声明)
const lc = new LockContext()
// 或使用自定义声明: new LockContext({ context: { identityClaim: ["sub", "org_id"] } })

// 2. 使用用户JWT识别用户
const identifyResult = await lc.identify(userJwt)
if (identifyResult.failure) {
  throw new Error(identifyResult.failure.message)
}
const lockContext = identifyResult.data

// 3. 使用锁上下文加密
const encrypted = await client
  .encrypt("敏感数据", { column: users.email, table: users })
  .withLockContext(lockContext)

// 4. 使用相同的锁上下文解密
const decrypted = await client
  .decrypt(encrypted.data)
  .withLockContext(lockContext)
锁上下文适用于所有操作:
encrypt
decrypt
encryptModel
decryptModel
bulkEncrypt
bulkDecrypt
bulkEncryptModels
bulkDecryptModels
encryptQuery

CTS Token Service

CTS令牌服务

The lock context exchanges the JWT for a CTS (CipherStash Token Service) token. Set the endpoint:
bash
CS_CTS_ENDPOINT=https://ap-southeast-2.aws.auth.viturhosted.net
锁上下文会将JWT交换为CTS(CipherStash令牌服务)令牌。设置端点:
bash
CS_CTS_ENDPOINT=https://ap-southeast-2.aws.auth.viturhosted.net

Multi-Tenant Encryption (Keysets)

多租户加密(密钥集)

Isolate encryption keys per tenant:
typescript
// By name
const client = await Encryption({
  schemas: [users],
  config: { keyset: { name: "Company A" } },
})

// By UUID
const client = await Encryption({
  schemas: [users],
  config: { keyset: { id: "123e4567-e89b-12d3-a456-426614174000" } },
})
Each keyset provides full cryptographic isolation between tenants.
按租户隔离加密密钥:
typescript
// 按名称
const client = await Encryption({
  schemas: [users],
  config: { keyset: { name: "Company A" } },
})

// 按UUID
const client = await Encryption({
  schemas: [users],
  config: { keyset: { id: "123e4567-e89b-12d3-a456-426614174000" } },
})
每个密钥集在租户之间提供完整的加密隔离。

Operation Chaining

操作链式调用

All operations return thenable objects that support chaining:
typescript
const result = await client
  .encrypt(plaintext, { column: users.email, table: users })
  .withLockContext(lockContext)         // optional: identity-aware
  .audit({ metadata: { action: "create" } }) // optional: audit trail
所有操作都返回支持链式调用的thenable对象:
typescript
const result = await client
  .encrypt(明文, { column: users.email, table: users })
  .withLockContext(lockContext)         // 可选:身份感知
  .audit({ metadata: { action: "create" } }) // 可选:审计追踪

Error Handling

错误处理

All async methods return a
Result
object - a discriminated union with either
data
(success) or
failure
(error), never both.
typescript
const result = await client.encrypt("hello", { column: users.email, table: users })

if (result.failure) {
  console.error(result.failure.type, result.failure.message)
  // type is one of: "ClientInitError" | "EncryptionError" | "DecryptionError"
  //                  | "LockContextError" | "CtsTokenError"
} else {
  console.log(result.data)
}
所有异步方法都会返回
Result
对象 - 一个区分联合类型,包含
data
(成功)或
failure
(错误),不会同时存在两者。
typescript
const result = await client.encrypt("hello", { column: users.email, table: users })

if (result.failure) {
  console.error(result.failure.type, result.failure.message)
  // type 可选值: "ClientInitError" | "EncryptionError" | "DecryptionError"
  //                  | "LockContextError" | "CtsTokenError"
} else {
  console.log(result.data)
}

Error Types

错误类型

TypeWhen
ClientInitError
Client initialization fails (bad credentials, missing config)
EncryptionError
An encrypt operation fails
DecryptionError
A decrypt operation fails
LockContextError
Lock context creation or usage fails
CtsTokenError
Identity token exchange fails
类型触发场景
ClientInitError
客户端初始化失败(无效凭证、缺失配置)
EncryptionError
加密操作失败
DecryptionError
解密操作失败
LockContextError
锁上下文创建或使用失败
CtsTokenError
身份令牌交换失败

Validation Rules

验证规则

  • NaN and Infinity are rejected for numeric values
  • freeTextSearch
    index only supports string values
  • At least one
    encryptedTable
    schema must be provided
  • Keyset UUIDs must be valid format
  • 数值类型的NaN和Infinity会被拒绝
  • freeTextSearch
    索引仅支持字符串值
  • 必须至少提供一个
    encryptedTable
    模式
  • 密钥集UUID必须格式有效

PostgreSQL Storage

PostgreSQL存储

Encrypted data is stored as EQL (Encrypt Query Language) JSON payloads. Install the EQL extension in PostgreSQL:
sql
CREATE EXTENSION IF NOT EXISTS eql_v2;

CREATE TABLE users (
  id BIGINT GENERATED ALWAYS AS IDENTITY PRIMARY KEY,
  email eql_v2_encrypted
);
Or store as JSONB if not using the EQL extension directly:
sql
CREATE TABLE users (
  id SERIAL PRIMARY KEY,
  email jsonb NOT NULL
);
加密数据以EQL(加密查询语言)JSON载荷的形式存储。在PostgreSQL中安装EQL扩展:
sql
CREATE EXTENSION IF NOT EXISTS eql_v2;

CREATE TABLE users (
  id BIGINT GENERATED ALWAYS AS IDENTITY PRIMARY KEY,
  email eql_v2_encrypted
);
如果不直接使用EQL扩展,也可以存储为JSONB:
sql
CREATE TABLE users (
  id SERIAL PRIMARY KEY,
  email jsonb NOT NULL
);

Migration from @cipherstash/protect

从@cipherstash/protect迁移

@cipherstash/protect
@cipherstash/stack
Import Path
protect(config)
Encryption(config)
@cipherstash/stack
csTable(name, cols)
encryptedTable(name, cols)
@cipherstash/stack/schema
csColumn(name)
encryptedColumn(name)
@cipherstash/stack/schema
LockContext
from
/identify
LockContext
from
/identity
@cipherstash/stack/identity
All method signatures on the encryption client remain the same. The
Result
pattern is unchanged.
@cipherstash/protect
@cipherstash/stack
导入路径
protect(config)
Encryption(config)
@cipherstash/stack
csTable(name, cols)
encryptedTable(name, cols)
@cipherstash/stack/schema
csColumn(name)
encryptedColumn(name)
@cipherstash/stack/schema
LockContext
from
/identify
LockContext
from
/identity
@cipherstash/stack/identity
加密客户端上的所有方法签名保持不变。
Result
模式也未更改。

Complete API Reference

完整API参考

EncryptionClient Methods

EncryptionClient方法

MethodSignatureReturns
encrypt
(plaintext, { column, table })
EncryptOperation
decrypt
(encryptedData)
DecryptOperation
encryptQuery
(plaintext, { column, table, queryType?, returnType? })
EncryptQueryOperation
encryptQuery
(terms: readonly ScalarQueryTerm[])
BatchEncryptQueryOperation
encryptModel
(model, table)
EncryptModelOperation<EncryptedFromSchema<T, S>>
decryptModel
(encryptedModel)
DecryptModelOperation<T>
bulkEncrypt
(plaintexts, { column, table })
BulkEncryptOperation
bulkDecrypt
(encryptedPayloads)
BulkDecryptOperation
bulkEncryptModels
(models, table)
BulkEncryptModelsOperation<EncryptedFromSchema<T, S>>
bulkDecryptModels
(encryptedModels)
BulkDecryptModelsOperation<T>
All operations are thenable (awaitable) and support
.withLockContext()
and
.audit()
chaining.
方法签名返回值
encrypt
(plaintext, { column, table })
EncryptOperation
decrypt
(encryptedData)
DecryptOperation
encryptQuery
(plaintext, { column, table, queryType?, returnType? })
EncryptQueryOperation
encryptQuery
(terms: readonly ScalarQueryTerm[])
BatchEncryptQueryOperation
encryptModel
(model, table)
EncryptModelOperation<EncryptedFromSchema<T, S>>
decryptModel
(encryptedModel)
DecryptModelOperation<T>
bulkEncrypt
(plaintexts, { column, table })
BulkEncryptOperation
bulkDecrypt
(encryptedPayloads)
BulkDecryptOperation
bulkEncryptModels
(models, table)
BulkEncryptModelsOperation<EncryptedFromSchema<T, S>>
bulkDecryptModels
(encryptedModels)
BulkDecryptModelsOperation<T>
所有操作都支持thenable(可await),并支持
.withLockContext()
.audit()
链式调用。

Schema Builders

模式构建器

typescript
encryptedTable(tableName: string, columns: Record<string, EncryptedColumn | EncryptedField | nested>)
encryptedColumn(columnName: string) // chainable: .equality(), .freeTextSearch(), .orderAndRange(), .searchableJson(), .dataType()
encryptedField(valueName: string)   // for nested encrypted fields (not searchable), chainable: .dataType()
typescript
encryptedTable(tableName: string, columns: Record<string, EncryptedColumn | EncryptedField | nested>)
encryptedColumn(columnName: string)   // 支持链式调用: .equality(), .freeTextSearch(), .orderAndRange(), .searchableJson(), .dataType()
encryptedField(valueName: string)     // 用于嵌套加密字段(不可搜索),支持链式调用: .dataType()