Skip to content

Commit b2f9d7a

Browse files
committed
docs(skills,meta): correct the naming the v2 removal inverted
PRs 3-5 froze the API names but the prose describing them was not swept, so the shipped guidance told users the opposite of what the code does. The worst of it is in skills/, which ship inside the stash tarball and get copied into customer repos: stash-encryption and stash-cli both described `encryptedSupabase` as the legacy EQL v2 wrapper. It is the EQL v3 factory — the v2 wrapper was deleted in #769. stash-drizzle taught `EncryptionV3` as the canonical client, contradicting stash-encryption, which correctly calls it deprecated. Also corrects the @cipherstash/stack README, the npm landing page, which claimed DynamoDB "still requires v2" and pointed at #657 — #768 removed the v2 write overloads and #657 is closed. The root README quickstart still taught the v2 chainable builders as the primary example. Reframes the "Legacy: EQL v2" sections to say what is actually true now: v2 is a read path, not an authoring surface. Left alone deliberately: the v2 CLI/database sections in supabase-sdk.md and the v2 read path in stash-dynamodb — both accurate today, and the CLI text moves with the SQL teardown. `export { Encryption }` in v3.ts is ordered after the `export *` so Biome's organizeImports is satisfied without detaching the comment from its subject.
1 parent ccc7fbc commit b2f9d7a

14 files changed

Lines changed: 102 additions & 74 deletions

File tree

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
---
2+
'stash': patch
3+
'@cipherstash/stack': patch
4+
---
5+
6+
De-suffix the v3 client name in generated code and shipped guidance.
7+
8+
`stash init` scaffolded `import { EncryptionV3 } from '@cipherstash/stack/v3'`
9+
into the client file it writes. `EncryptionV3` is a deprecated alias of
10+
`Encryption`, so new projects were started on the deprecated name. The
11+
scaffold now emits `Encryption`.
12+
13+
`@cipherstash/stack/v3` now re-exports `Encryption` alongside the deprecated
14+
`EncryptionV3` alias, so a v3 schema and its client come from one import
15+
specifier — the deprecation notice already documented this import, but it did
16+
not resolve.
17+
18+
Corrects the bundled agent skills and package docs, which described
19+
`encryptedSupabase` as the legacy EQL v2 wrapper. It is the EQL v3 factory;
20+
the v2 wrapper was removed. Also drops the stale "DynamoDB still requires v2"
21+
note from the `@cipherstash/stack` README — DynamoDB writes EQL v3 and reads
22+
existing v2 items.

‎AGENTS.md‎

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -78,7 +78,7 @@ If these variables are missing, tests that require live encryption will fail or
7878
- `packages/migrate`: Plaintext-to-encrypted column migration (`@cipherstash/migrate`) — resumable backfill, per-column state
7979
- `packages/prisma-next`: Prisma Next integration (`@cipherstash/prisma-next`) — searchable field-level encryption for Postgres. **EQL v3 only**: per-domain constructors (`cipherstash.TextSearch()` / `text()` / `bigIntOrd()` / …) and `cipherstashFromStack` (the `./v3` and `./stack` entries). The EQL v2 surface was removed — the adapter's baseline migration installs the EQL v3 bundle only (works on Supabase as a non-superuser)
8080
- `packages/stack-drizzle`: Drizzle ORM integration (`@cipherstash/stack-drizzle`), depends on `@cipherstash/stack` — **EQL v3 only**, on the package root (the v2 surface was removed and the old `./v3` subpath collapsed into `.`). Split out of `@cipherstash/stack`.
81-
- `packages/stack-supabase`: Supabase integration (`@cipherstash/stack-supabase`), depends on `@cipherstash/stack` — `encryptedSupabase` (v2) and `encryptedSupabaseV3` (v3). Split out of `@cipherstash/stack`.
81+
- `packages/stack-supabase`: Supabase integration (`@cipherstash/stack-supabase`), depends on `@cipherstash/stack` — **EQL v3 only**: `encryptedSupabase` is the v3 factory (`encryptedSupabaseV3` remains as a `@deprecated` alias). Split out of `@cipherstash/stack`.
8282
- `packages/nextjs`: Next.js helpers and Clerk integration (`./clerk` export)
8383
- `packages/utils`: Shared config (`utils/config`) and logger (`utils/logger`)
8484
- `packages/bench`: Performance / index-engagement benchmarks (private, not published)
@@ -155,7 +155,7 @@ Three rules to remember when editing CI or pnpm config:
155155
- **Identity-aware encryption**: Authenticate the client as the end user with `OidcFederationStrategy` (`config.authStrategy`, re-exported from `@cipherstash/stack`), then chain `.withLockContext({ identityClaim })` on operations to bind the data key to a claim. The same claim must be used for encrypt and decrypt. (`LockContext.identify()` from `@cipherstash/stack/identity` is deprecated — the strategy now handles token acquisition; `.withLockContext()` also accepts a `LockContext`.)
156156
- **Integrations**:
157157
- **Drizzle ORM**: `types.*` column factories, `extractEncryptionSchema`, `createEncryptionOperators` from `@cipherstash/stack-drizzle`
158-
- **Supabase**: `encryptedSupabase` (v2) / `encryptedSupabaseV3` (v3) from `@cipherstash/stack-supabase`
158+
- **Supabase**: `encryptedSupabase` from `@cipherstash/stack-supabase` (EQL v3; `encryptedSupabaseV3` is a `@deprecated` alias)
159159
- **DynamoDB**: `encryptedDynamoDB` from `@cipherstash/stack/dynamodb`
160160

161161
## Critical Gotchas (read before coding)

‎README.md‎

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -20,11 +20,11 @@
2020
**Encryption**
2121

2222
```typescript
23-
import { Encryption, encryptedTable, encryptedColumn } from "@cipherstash/stack";
23+
import { Encryption, encryptedTable, types } from "@cipherstash/stack/v3";
2424

25-
// 1. Define your schema
25+
// 1. Define your schema — the column type fixes its query capabilities
2626
const users = encryptedTable("users", {
27-
email: encryptedColumn("email").equality().freeTextSearch(),
27+
email: types.TextSearch("email"), // equality + order/range + free-text search
2828
});
2929

3030
// 2. Initialize the client
@@ -67,7 +67,7 @@ bun add @cipherstash/stack
6767
## Features
6868

6969
- **[Searchable encryption](https://cipherstash.com/docs/stack/cipherstash/encryption/searchable-encryption)**: query encrypted data with equality, free text search, range, and [JSONB queries](https://cipherstash.com/docs/stack/cipherstash/encryption/searchable-encryption#jsonb-queries-with-searchablejson).
70-
- **[Type-safe schema](https://cipherstash.com/docs/stack/cipherstash/encryption/schema)**: define encrypted tables and columns with `encryptedTable` / `encryptedColumn`
70+
- **[Type-safe schema](https://cipherstash.com/docs/stack/cipherstash/encryption/schema)**: define encrypted tables and columns with `encryptedTable` and the `types.*` concrete-domain factories
7171
- **[Model & bulk operations](https://cipherstash.com/docs/stack/cipherstash/encryption/encrypt-decrypt#model-operations)**: encrypt and decrypt entire objects or batches with `encryptModel` / `bulkEncryptModels`.
7272
- **[Identity-aware encryption](https://cipherstash.com/docs/stack/cipherstash/encryption/identity)**: authenticate as the end user with `OidcFederationStrategy` and bind the data key to their identity with `.withLockContext({ identityClaim })` for policy-based access control.
7373

‎SECURITY.md‎

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -14,8 +14,8 @@ This repository is the CipherStash Stack monorepo for JavaScript/TypeScript. It
1414
| `@cipherstash/nextjs` | Next.js helpers |
1515
| `@cipherstash/migrate` | Plaintext-to-encrypted column migration tooling |
1616
| `@cipherstash/prisma-next` | Prisma Next integration (searchable field-level encryption for Postgres) |
17-
| `@cipherstash/stack-drizzle` | Drizzle ORM integration for `@cipherstash/stack` (EQL v2 + v3) |
18-
| `@cipherstash/stack-supabase` | Supabase integration for `@cipherstash/stack` (EQL v2 + v3) |
17+
| `@cipherstash/stack-drizzle` | Drizzle ORM integration for `@cipherstash/stack` (EQL v3) |
18+
| `@cipherstash/stack-supabase` | Supabase integration for `@cipherstash/stack` (EQL v3) |
1919
| `@cipherstash/wizard` | AI-powered encryption setup |
2020

2121
**Security fixes are released for the latest release line of each package.** Security reports are welcome for any version, but fixes land in the latest release — if you are running an older major version, plan to upgrade to receive them.

‎docs/reference/supabase-sdk.md‎

Lines changed: 20 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -4,37 +4,41 @@
44
are transparently encrypted on mutations, `::jsonb`-cast on selects, encrypted
55
in filter terms, and decrypted in results.
66

7-
Two entry points, one query mechanism:
7+
One entry point, EQL v3 only:
88

99
| Entry point | Schema DSL | Column storage |
1010
|---|---|---|
11-
| `encryptedSupabase` | `@cipherstash/stack/schema` (EQL v2) | `eql_v2_encrypted` composite |
12-
| `encryptedSupabaseV3` | `@cipherstash/stack/eql/v3` (EQL v3) | native `public.eql_v3_*` domains |
11+
| `encryptedSupabase` | `@cipherstash/stack/eql/v3` (EQL v3) | native `public.eql_v3_*` domains |
1312

14-
Both filter via **direct EQL operators over PostgREST**: the wrapper encrypts
13+
`encryptedSupabaseV3` remains as a `@deprecated`, type-identical alias. The old
14+
EQL v2 authoring wrapper — `encryptedSupabase({ encryptionClient,
15+
supabaseClient })` — has been removed; the name now binds to the v3 factory
16+
below.
17+
18+
It filters via **direct EQL operators over PostgREST**: the wrapper encrypts
1519
the filter term and emits an ordinary `col <op> term` filter, which resolves
1620
to the custom operator defined on the encrypted type (equality by HMAC, range
1721
by the ordering term — CLLW-OPE on `_ord` domains, block-ORE on `_ord_ore` —
1822
free-text by bloom-filter containment).
1923

2024
## Quick start (EQL v3)
2125

22-
`encryptedSupabaseV3` is an async factory that **introspects the database at
26+
`encryptedSupabase` is an async factory that **introspects the database at
2327
connect time**: it detects EQL v3 columns by their Postgres domain, derives
2428
each column's encryption config from the domain, and builds the encryption
2529
client internally. Introspection needs a direct Postgres connection
2630
(`options.databaseUrl`, defaulting to `DATABASE_URL`), so the factory cannot
2731
run in a Worker or the browser.
2832

2933
```typescript
30-
import { encryptedSupabaseV3 } from '@cipherstash/stack-supabase'
34+
import { encryptedSupabase } from '@cipherstash/stack-supabase'
3135

3236
// Introspects the database via options.databaseUrl or DATABASE_URL
33-
const es = await encryptedSupabaseV3(
37+
const es = await encryptedSupabase(
3438
process.env.SUPABASE_URL!,
3539
process.env.SUPABASE_ANON_KEY!,
3640
)
37-
// or wrap an existing client: await encryptedSupabaseV3(supabaseClient, options)
41+
// or wrap an existing client: await encryptedSupabase(supabaseClient, options)
3842

3943
await es.from('users').insert({ email: 'a@b.com', amount: 30 })
4044

@@ -49,16 +53,14 @@ await es.from('users').select('id, amount').gte('amount', 10).lte('amount', 100)
4953
`from(tableName)` takes only the table name — no schema argument; column
5054
capabilities come from the introspected domains.
5155

52-
The builder surface is shared across v2 and v3:
53-
`.select/.insert/.update/.upsert/.delete`,
56+
The builder surface is `.select/.insert/.update/.upsert/.delete`,
5457
`.eq/.neq/.in/.is/.gt/.gte/.lt/.lte/.match/.or/.not/.filter`,
5558
transforms (`.order/.limit/.range/.single/.maybeSingle/.csv/.abortSignal/.throwOnError`),
56-
plus `.withLockContext(lockContext)` and `.audit(config)` — with one fork:
57-
free-text search. v2 exposes `.like/.ilike` (SQL wildcard matching); v3
58-
exposes `.matches()` (fuzzy bloom token search) on encrypted columns, keeps
59-
`.contains()` for native (exact) containment on plaintext columns, and treats
60-
`like`/`ilike` on an encrypted column as an approximate shim that delegates to
61-
`.matches()` (see "v3 encoding details" below).
59+
plus `.withLockContext(lockContext)` and `.audit(config)`. For free-text
60+
search it exposes `.matches()` (fuzzy bloom token search) on encrypted
61+
columns, keeps `.contains()` for native (exact) containment on plaintext
62+
columns, and treats `like`/`ilike` on an encrypted column as an approximate
63+
shim that delegates to `.matches()` (see "v3 encoding details" below).
6264

6365
### Typing (v3)
6466

@@ -68,14 +70,14 @@ tables against the database at construction:
6870

6971
```typescript
7072
import { encryptedTable, types } from '@cipherstash/stack/eql/v3'
71-
import { encryptedSupabaseV3 } from '@cipherstash/stack-supabase'
73+
import { encryptedSupabase } from '@cipherstash/stack-supabase'
7274

7375
const users = encryptedTable('users', {
7476
email: types.TextSearch('email'), // public.eql_v3_text_search
7577
amount: types.IntegerOrd('amount'), // public.eql_v3_integer_ord
7678
})
7779

78-
const es = await encryptedSupabaseV3(
80+
const es = await encryptedSupabase(
7981
process.env.SUPABASE_URL!,
8082
process.env.SUPABASE_ANON_KEY!,
8183
{ schemas: { users } },

‎packages/bench/README.md‎

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3,8 +3,9 @@
33
Performance / index-engagement benchmarks for stack integrations.
44

55
This package validates that each integration emits SQL that engages the canonical
6-
EQL functional indexes (`eql_v2.hmac_256`, `eql_v2.bloom_filter`, `eql_v2.ste_vec`)
7-
on a Supabase-shaped install (no operator classes). It runs in two layers:
6+
EQL functional indexes (`eql_v3.eq_term`, `eql_v3.match_term`,
7+
`eql_v3.to_ste_vec_query`) on a Supabase-shaped install (no operator classes).
8+
It runs in two layers:
89

910
1. **EXPLAIN-shape tests** (`__tests__/`) — vitest tests that assert on
1011
`EXPLAIN (ANALYZE, BUFFERS, FORMAT JSON)` output. Pass/fail. Cheap.

‎packages/migrate/README.md‎

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -43,7 +43,7 @@ Creates `cipherstash.cs_migrations` idempotently. Normally called by `stash eql
4343
Chunked, resumable, idempotent backfill of plaintext → encrypted. Per chunk, in a single transaction: select next page → encrypt via `client.bulkEncryptModels` → `UPDATE … FROM (VALUES …)` → `INSERT` a `backfill_checkpoint` event. Guards with `encrypted IS NULL` so re-runs never double-write.
4444

4545
- `db`: a `pg.PoolClient` (the runner drives transactions on it).
46-
- `encryptionClient`: your initialised `@cipherstash/stack` client (or anything that exposes `bulkEncryptModels(models, table)` returning `{ data } | { failure }`). For an EQL v3 column pass an `EncryptionV3` client (from `@cipherstash/stack/v3`) — it pins the v3 wire format; the engine itself is version-agnostic and writes whatever envelope the client produces.
46+
- `encryptionClient`: your initialised `@cipherstash/stack` client (or anything that exposes `bulkEncryptModels(models, table)` returning `{ data } | { failure }`). For an EQL v3 column pass an `Encryption` client (from `@cipherstash/stack/v3`) — it pins the v3 wire format; the engine itself is version-agnostic and writes whatever envelope the client produces.
4747
- `tableSchema`: the `EncryptedTable` for the target table from your encryption client file.
4848
- `signal`: optional `AbortSignal`. If aborted between chunks, the backfill exits cleanly and leaves a resumable checkpoint.
4949

‎packages/stack-drizzle/README.md‎

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -78,7 +78,7 @@ are fixed by the `types.*` factory you choose — no per-column config object:
7878

7979
```ts
8080
import { pgTable, integer } from 'drizzle-orm/pg-core'
81-
import { EncryptionV3 } from '@cipherstash/stack/v3'
81+
import { Encryption } from '@cipherstash/stack/v3'
8282
import {
8383
types,
8484
extractEncryptionSchema,
@@ -92,7 +92,7 @@ const users = pgTable('users', {
9292
})
9393

9494
const schema = extractEncryptionSchema(users)
95-
const client = await EncryptionV3({ schemas: [schema] })
95+
const client = await Encryption({ schemas: [schema] })
9696
const ops = createEncryptionOperators(client)
9797

9898
// Insert — encrypt models first (bulk helpers batch key operations

0 commit comments

Comments
 (0)