stash-encryption
Compare original and translation side by side
🇺🇸
Original
English🇨🇳
Translation
ChineseCipherStash Stack - Encryption
CipherStash Stack - 加密
Comprehensive guide for implementing field-level encryption with . 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提供支持)使用专属密钥进行加密。加密操作在数据离开应用前于客户端完成。
@cipherstash/stackWhen 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 to
@cipherstash/protect@cipherstash/stack
- 为TypeScript/Node.js项目添加字段级加密
- 定义加密表模式
- 加密和解密单个值或整个模型
- 实现可搜索加密(等值、全文、范围、JSON查询)
- 批量加密/解密大型数据集
- 基于JWT锁上下文实现身份感知加密
- 配置多租户加密密钥集
- 从迁移到
@cipherstash/protect@cipherstash/stack
Installation
安装
bash
npm install @cipherstash/stackThe package includes a native FFI module (). You must opt out of bundling it in tools like Webpack, esbuild, or Next.js ().
@cipherstash/protect-ffiserverExternalPackagesbash
npm install @cipherstash/stack该包包含一个原生FFI模块()。在Webpack、esbuild或Next.js等工具中,你必须将其排除在打包范围外(通过配置)。
@cipherstash/protect-ffiserverExternalPackagesConfiguration
配置
Environment Variables
环境变量
Set these in or your hosting platform:
.envbash
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-keySign up at cipherstash.com/signup to generate credentials.
在文件或你的托管平台中设置以下环境变量:
.envbash
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 is omitted, the client reads environment variables automatically.
configCS_*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" }, // 可选:多租户隔离
},
})如果省略,客户端会自动读取环境变量。
configCS_*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 Path | Provides |
|---|---|
| |
| |
| |
| |
| |
| |
| |
| Client-safe exports (schema builders + types only, no native FFI) |
| All TypeScript types |
| 导入路径 | 提供内容 |
|---|---|
| |
| |
| |
| |
| 用于Drizzle ORM的 |
| 用于Supabase的 |
| 用于DynamoDB的 |
| 客户端安全导出(仅模式构建器和类型,无原生FFI) |
| 所有TypeScript类型 |
Schema Definition
模式定义
Define which tables and columns to encrypt using and :
encryptedTableencryptedColumntypescript
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)
})使用和定义要加密的表和列:
encryptedTableencryptedColumntypescript
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
索引类型
| Method | Purpose | Query Type |
|---|---|---|
| Exact match lookups | |
| Full-text / fuzzy search | |
| Sorting, comparison, range queries | |
| Encrypted JSONB path and containment queries (auto-sets | |
| Set plaintext data type | N/A |
Supported data types: (default), , , , ,
'string''number''boolean''date''bigint''json'Methods are chainable - call as many as you need on a single column.
| 方法 | 用途 | 查询类型 |
|---|---|---|
| 精确匹配查找 | |
| 全文/模糊搜索 | |
| 排序、比较、范围查询 | |
| 加密JSONB路径和包含查询(自动将 | |
| 设置明文数据类型 | 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 function returns and throws on error (e.g., bad credentials, missing config, invalid keyset UUID). At least one schema is required.
Encryption()Promise<EncryptionClient>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>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 returns .
nullnulltypescript
// 加密
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"
}空值会被保留:加密会返回。
nullnullModel 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 , while other fields retain their original types. For best results, let TypeScript infer the type parameters from the arguments rather than providing an explicit .
Encrypted<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 type maps encrypted fields back to their plaintext types.
Decrypted<T>Passing an explicit type parameter (e.g., ) still works for backward compatibility — the return type degrades to in that case.
client.encryptModel<User>(...)User加密或解密整个对象。只有与模式匹配的字段会被加密;其他字段保持不变。
返回类型是模式感知的:与表模式匹配的字段类型为,其他字段保留原类型。为获得最佳效果,让TypeScript从参数中推断类型参数,而非显式提供。
Encrypted<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>(...)UserBulk 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 is omitted, it's auto-inferred from the column's configured indexes (priority: unique > match > ore > ste_vec).
queryTypetypescript
// 等值查询
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",
})如果省略,会从列的配置索引中自动推断(优先级:唯一 > 匹配 > ore > ste_vec)。
queryTypeQuery Result Formatting (returnType
)
returnType查询结果格式(returnType
)
returnTypeBy default returns an object (the raw EQL JSON payload). Use to change the output format:
encryptQueryEncryptedreturnType | Output | Use case |
|---|---|---|
| | Parameterized queries, ORMs accepting JSON |
| | Supabase |
| | 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 stringEach term in a batch can have its own .
returnType默认情况下返回对象(原始EQL JSON载荷)。使用可更改输出格式:
encryptQueryEncryptedreturnType | 输出 | 适用场景 |
|---|---|---|
| | 参数化查询、接受JSON的ORM |
| | Supabase |
| | 嵌入到另一个字符串或JSON值中 |
typescript
// 获取复合字面量字符串用于Supabase
const term = await client.encryptQuery("alice@example.com", {
column: users.email,
table: users,
queryType: "equality",
returnType: "composite-literal",
})
// term.data 是一个字符串批量中的每个条件都可以有自己的。
returnTypeSearchable JSON
可搜索JSON
For columns using , the query type is auto-inferred from the plaintext:
.searchableJson()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: , , , , , , , , .
encryptdecryptencryptModeldecryptModelbulkEncryptbulkDecryptbulkEncryptModelsbulkDecryptModelsencryptQuery通过要求有效的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)锁上下文适用于所有操作:、、、、、、、、。
encryptdecryptencryptModeldecryptModelbulkEncryptbulkDecryptbulkEncryptModelsbulkDecryptModelsencryptQueryCTS 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.netMulti-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 object - a discriminated union with either (success) or (error), never both.
Resultdatafailuretypescript
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)
}所有异步方法都会返回对象 - 一个区分联合类型,包含(成功)或(错误),不会同时存在两者。
Resultdatafailuretypescript
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
错误类型
| Type | When |
|---|---|
| Client initialization fails (bad credentials, missing config) |
| An encrypt operation fails |
| A decrypt operation fails |
| Lock context creation or usage fails |
| Identity token exchange fails |
| 类型 | 触发场景 |
|---|---|
| 客户端初始化失败(无效凭证、缺失配置) |
| 加密操作失败 |
| 解密操作失败 |
| 锁上下文创建或使用失败 |
| 身份令牌交换失败 |
Validation Rules
验证规则
- NaN and Infinity are rejected for numeric values
- index only supports string values
freeTextSearch - At least one schema must be provided
encryptedTable - 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迁移
| | Import Path |
|---|---|---|
| | |
| | |
| | |
| | |
All method signatures on the encryption client remain the same. The pattern is unchanged.
Result | | 导入路径 |
|---|---|---|
| | |
| | |
| | |
| | |
加密客户端上的所有方法签名保持不变。模式也未更改。
ResultComplete API Reference
完整API参考
EncryptionClient Methods
EncryptionClient方法
| Method | Signature | Returns |
|---|---|---|
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
All operations are thenable (awaitable) and support and chaining.
.withLockContext().audit()| 方法 | 签名 | 返回值 |
|---|---|---|
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
所有操作都支持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()