Skip to content

Commit c2991f4

Browse files
committed
refactor(prisma-next)!: drop Encrypted prefix from v3 PSL constructors; cipherstashFromStackV3 -> cipherstashFromStack
Aligns the EQL v3 authoring surface with the stack / Drizzle types.* catalog (the cipherstash. namespace already disambiguates): - v3 PSL column constructors drop the Encrypted prefix, at the single derivation seam (contract-authoring.ts v3PascalName): EncryptedTextSearch -> TextSearch, EncryptedDoubleOrd -> DoubleOrd, EncryptedBoolean -> Boolean, EncryptedJson -> Json, etc. - v3 one-call setup: cipherstashFromStackV3 -> cipherstashFromStack (v3 is the default); the v2 setup fn becomes cipherstashFromStackV2. Deliberately unchanged: - runtime value envelopes (EncryptedString/Number/BigInt/Date/Boolean/Json) — a separate write-side surface; Dan asked to leave them as-is. - the cipherstash.*V2 legacy column constructors. - generated contract.json + codec ids (they key off codecIds, not constructor names — so no contract regeneration needed, which sidesteps the broken on this branch). - the eql* query operators. - camelCase TS-authoring exports (encryptedTextSearch, …) keep their prefix for now — a follow-up will align them (kept v3CamelName unchanged to avoid desyncing the static exports). Namespace stays cipherstash (not eql): it is the extension's vendor identity (CIPHERSTASH_SPACE_ID, woven through every cipherstash/eql-v3/* codec id and cipherstash:* invariant) — switching it would re-identify the whole extension. Updated: example schema.prisma + db.ts + e2e, both READMEs, the stash-prisma-next skill, and the authoring/psl-interpretation tests. Verified: package builds clean, bundling-isolation 12/12, authoring/psl/column-types/ from-stack suites green, code:check clean. (Pre-existing env failures — live tests, properties, migration-v3 — are missing-devdep/DB issues, not this change.) Stacked on #683. v2 name per Dan; namespace + scope calls documented above. Claude-Session: https://claude.ai/code/session_01MxTTPaPP16m6br7Hoab94w
1 parent 8872d1e commit c2991f4

23 files changed

Lines changed: 181 additions & 143 deletions
Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
---
2+
'@cipherstash/prisma-next': minor
3+
'stash': patch
4+
---
5+
6+
**Breaking (v3 authoring surface):** the EQL v3 PSL column constructors drop
7+
the `Encrypted` prefix to line up with the stack / Drizzle `types.*` catalog —
8+
the `cipherstash.` namespace already disambiguates. So
9+
`cipherstash.EncryptedTextSearch()``cipherstash.TextSearch()`,
10+
`cipherstash.EncryptedDoubleOrd()``cipherstash.DoubleOrd()`,
11+
`cipherstash.EncryptedBoolean()``cipherstash.Boolean()`, etc.
12+
13+
The v3 one-call setup function is renamed `cipherstashFromStackV3`
14+
`cipherstashFromStack` (v3 is the default), and the existing v2 setup function
15+
becomes `cipherstashFromStackV2`.
16+
17+
Unchanged: the runtime value envelopes (`EncryptedString`, `EncryptedNumber`,
18+
`EncryptedBoolean`, …), the `cipherstash.*V2` legacy column constructors, the
19+
generated `contract.json` / codec ids, and the `eql*` query operators. The
20+
camelCase TS-authoring factory exports (`encryptedTextSearch`, …) keep their
21+
prefix for now — a follow-up will align them.
22+
23+
The `stash-prisma-next` skill is updated to the new names (skills ship in the
24+
`stash` tarball).

examples/prisma/README.md

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -6,12 +6,12 @@ A single `User` model with one column per plaintext family, exercised end-to-end
66

77
| Column | Constructor | Domain | Query surface |
88
| --------------- | --------------------------------- | --------------------------- | -------------------------------------- |
9-
| `email` | `cipherstash.EncryptedTextSearch()` | `public.eql_v3_text_search` | equality + order/range + free-text (`eqlMatch`) |
10-
| `salary` | `cipherstash.EncryptedDoubleOrd()` | `public.eql_v3_double_ord` | equality + order/range |
11-
| `accountId` | `cipherstash.EncryptedBigIntOrd()` | `public.eql_v3_bigint_ord` | equality + order/range (true `bigint`) |
12-
| `birthday` | `cipherstash.EncryptedDateOrd()` | `public.eql_v3_date_ord` | equality + order/range |
13-
| `emailVerified` | `cipherstash.EncryptedBoolean()` | `public.eql_v3_boolean` | storage-only (no operators) |
14-
| `preferences` | `cipherstash.EncryptedJson()` | `public.eql_v3_json` | `eqlJsonContains` (`@>`) |
9+
| `email` | `cipherstash.TextSearch()` | `public.eql_v3_text_search` | equality + order/range + free-text (`eqlMatch`) |
10+
| `salary` | `cipherstash.DoubleOrd()` | `public.eql_v3_double_ord` | equality + order/range |
11+
| `accountId` | `cipherstash.BigIntOrd()` | `public.eql_v3_bigint_ord` | equality + order/range (true `bigint`) |
12+
| `birthday` | `cipherstash.DateOrd()` | `public.eql_v3_date_ord` | equality + order/range |
13+
| `emailVerified` | `cipherstash.Boolean()` | `public.eql_v3_boolean` | storage-only (no operators) |
14+
| `preferences` | `cipherstash.Json()` | `public.eql_v3_json` | `eqlJsonContains` (`@>`) |
1515

1616
📖 See the [Prisma Next encryption docs](https://cipherstash.com/docs/stack/cipherstash/encryption/prisma-next) for the full operator reference, security model, and known limitations.
1717

@@ -22,7 +22,7 @@ A single `User` model with one column per plaintext family, exercised end-to-end
2222
| `docker-compose.yml` | Local Postgres 16 on port 54338. |
2323
| `prisma/schema.prisma` | Application schema (one `User` model exercising six cipherstash v3 domains). |
2424
| `prisma-next.config.ts` | Wires `cipherstash` into `extensionPacks`. |
25-
| `src/db.ts` | One-call setup via `cipherstashFromStackV3({ contractJson })`. |
25+
| `src/db.ts` | One-call setup via `cipherstashFromStack({ contractJson })`. |
2626
| `src/index.ts` | The demo flow. |
2727
| `src/prisma/contract.*` | Emitted by `pnpm emit`. |
2828
| `migrations/` | Emitted by `pnpm migration:plan` (app space + the cipherstash EQL bundle baselines). |

examples/prisma/prisma/schema.prisma

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -36,12 +36,12 @@
3636

3737
model User {
3838
id String @id
39-
email cipherstash.EncryptedTextSearch()
40-
salary cipherstash.EncryptedDoubleOrd()
41-
accountId cipherstash.EncryptedBigIntOrd() @map("accountid")
42-
birthday cipherstash.EncryptedDateOrd()
43-
emailVerified cipherstash.EncryptedBoolean() @map("emailverified")
44-
preferences cipherstash.EncryptedJson()
39+
email cipherstash.TextSearch()
40+
salary cipherstash.DoubleOrd()
41+
accountId cipherstash.BigIntOrd() @map("accountid")
42+
birthday cipherstash.DateOrd()
43+
emailVerified cipherstash.Boolean() @map("emailverified")
44+
preferences cipherstash.Json()
4545
4646
@@map("users")
4747
}

examples/prisma/src/db.ts

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22
* Wire the Prisma Next Postgres runtime with the cipherstash EQL v3
33
* extension in one call.
44
*
5-
* `cipherstashFromStackV3({ contractJson })` derives the v3 encryption
5+
* `cipherstashFromStack({ contractJson })` derives the v3 encryption
66
* schemas from the contract (one `public.eql_v3_*` domain per column),
77
* constructs the `@cipherstash/stack` `EncryptionV3` client against
88
* your `CS_*` env vars or local profile, builds the SDK adapter, and
@@ -11,19 +11,19 @@
1111
* does not model.
1212
*
1313
* A v3 client is v3-only: a contract carrying v2 cipherstash codec ids
14-
* is rejected at setup (use `cipherstashFromStack` from
14+
* is rejected at setup (use `cipherstashFromStackV2` from
1515
* `@cipherstash/prisma-next/stack` for a v2 contract).
1616
*/
1717

1818
import 'dotenv/config'
1919

20-
import { cipherstashFromStackV3 } from '@cipherstash/prisma-next/v3'
20+
import { cipherstashFromStack } from '@cipherstash/prisma-next/v3'
2121
import postgres from '@prisma-next/postgres/runtime'
2222

2323
import type { Contract } from './prisma/contract.d'
2424
import contractJson from './prisma/contract.json' with { type: 'json' }
2525

26-
const cipherstash = await cipherstashFromStackV3({ contractJson })
26+
const cipherstash = await cipherstashFromStack({ contractJson })
2727

2828
export const db = postgres<Contract>({
2929
contractJson,

examples/prisma/test/e2e/mixed.e2e.test.ts

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@
1313
* middleware controls and what this suite observes.)
1414
*
1515
* Crossing counts are observed by wrapping a fresh `CipherstashSdk`
16-
* (built from `cipherstashFromStackV3({ contractJson }).encryptionClient`
16+
* (built from `cipherstashFromStack({ contractJson }).encryptionClient`
1717
* via `createCipherstashV3Sdk`) with a counting decorator and threading
1818
* the wrapped instance into a private `db` runtime. Concretely:
1919
*
@@ -40,7 +40,7 @@ import {
4040
eqlAsc,
4141
} from '@cipherstash/prisma-next/runtime'
4242
import {
43-
cipherstashFromStackV3,
43+
cipherstashFromStack,
4444
createCipherstashV3Sdk,
4545
deriveStackSchemasV3,
4646
} from '@cipherstash/prisma-next/v3'
@@ -141,12 +141,12 @@ describe('Mixed-domain e2e (live PG + EQL v3 + ZeroKMS)', () => {
141141
let runtime: { close(): Promise<void> } | undefined
142142

143143
beforeAll(async () => {
144-
// Reuse the encryption client from `cipherstashFromStackV3` so the
144+
// Reuse the encryption client from `cipherstashFromStack` so the
145145
// counting wrapper observes the same ZeroKMS workspace + schema
146146
// surface the example app would in production. Re-derive the v3
147147
// stack schemas from `contractJson` to satisfy
148148
// `createCipherstashV3Sdk`'s `(client, schemas)` contract.
149-
const { encryptionClient } = await cipherstashFromStackV3({ contractJson })
149+
const { encryptionClient } = await cipherstashFromStack({ contractJson })
150150
const schemas = deriveStackSchemasV3(contractJson)
151151
const baseSdk = createCipherstashV3Sdk(encryptionClient, schemas)
152152
counting = wrapWithCounting(baseSdk)

examples/prisma/test/e2e/str-range.e2e.test.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22
* End-to-end coverage for the `eql_v3_text_search` domain against
33
* live Postgres + EQL v3 + ZeroKMS.
44
*
5-
* `cipherstash.EncryptedTextSearch()` is the maximal text domain:
5+
* `cipherstash.TextSearch()` is the maximal text domain:
66
* equality + order/range (OPE) + free-text search (bloom match) on one
77
* column. Pins:
88
* - Round-trip decrypt recovers the source strings.

packages/prisma-next/README.md

Lines changed: 9 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@ Declare encrypted columns directly in `schema.prisma`, and the framework's migra
1212
- 🔍 Searchable encryption — equality, free-text search, range, order, JSON path and containment
1313
- 🎯 Type-safe query operators — EQL v3 uses the EQL-derived `eql*` vocabulary (`eqlEq`, `eqlMatch`, `eqlGt`, `eqlAsc`, …); the legacy v2 surface keeps its `cipherstash*` names
1414
- ⚡ Bulk encrypt / bulk decrypt coalescing — one SDK round-trip per `(table, column)` group per query
15-
- 🧩 One-call setup via `cipherstashFromStackV3({ contractJson })` (v2: `cipherstashFromStack`) — no duplicate stack schema to maintain
15+
- 🧩 One-call setup via `cipherstashFromStack({ contractJson })` (v2: `cipherstashFromStackV2`) — no duplicate stack schema to maintain
1616
- 🛡️ Plaintext redaction on every implicit serialisation path (`toJSON`, `toString`, `util.inspect`, …)
1717

1818
## Installation
@@ -27,10 +27,10 @@ npm install @cipherstash/stack @cipherstash/prisma-next
2727
// prisma/schema.prisma
2828
model User {
2929
id String @id
30-
email cipherstash.EncryptedString()
31-
salary cipherstash.EncryptedDouble()
32-
birthday cipherstash.EncryptedDate()
33-
preferences cipherstash.EncryptedJson()
30+
email cipherstash.TextSearch()
31+
salary cipherstash.DoubleOrd()
32+
birthday cipherstash.DateOrd()
33+
preferences cipherstash.Json()
3434
}
3535
```
3636

@@ -47,12 +47,12 @@ export default defineConfig({
4747
```typescript
4848
// src/db.ts
4949
import "dotenv/config"
50-
import { cipherstashFromStack } from "@cipherstash/prisma-next/stack"
50+
import { cipherstashFromStackV2 } from "@cipherstash/prisma-next/stack"
5151
import postgres from "@prisma-next/postgres/runtime"
5252
import type { Contract } from "./prisma/contract.d"
5353
import contractJson from "./prisma/contract.json" with { type: "json" }
5454

55-
const cipherstash = await cipherstashFromStack({ contractJson })
55+
const cipherstash = await cipherstashFromStackV2({ contractJson })
5656

5757
export const db = postgres<Contract>({
5858
contractJson,
@@ -91,8 +91,8 @@ See the [full documentation](https://cipherstash.com/docs/stack/cipherstash/encr
9191

9292
| Subpath | Purpose |
9393
| ---------------- | ------------------------------------------------------------------------------------------------------ |
94-
| `./v3` | The complete EQL v3 surface: `cipherstashFromStackV3`, the `eql*` query operations, `eqlAsc`/`eqlDesc`, envelopes, middleware, SDK adapter |
95-
| `./stack` | One-call setup against `@cipherstash/stack` (EQL v2): `cipherstashFromStack`, `deriveStackSchemas`, `createCipherstashSdk` |
94+
| `./v3` | The complete EQL v3 surface: `cipherstashFromStack`, the `eql*` query operations, `eqlAsc`/`eqlDesc`, envelopes, middleware, SDK adapter |
95+
| `./stack` | One-call setup against `@cipherstash/stack` (EQL v2): `cipherstashFromStackV2`, `deriveStackSchemas`, `createCipherstashSdk` |
9696
| `./control` | `SqlControlExtensionDescriptor` (contract space + pack meta + codec lifecycle hooks) |
9797
| `./runtime` | Six envelope classes + `CipherstashSdk` + codec runtime + `decryptAll` + four free-standing helpers |
9898
| `./middleware` | `bulkEncryptMiddleware(sdk)` |

packages/prisma-next/src/contract-authoring.ts

Lines changed: 19 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -7,14 +7,14 @@
77
* `*_ord_ore` variants) gets exactly one argument-less PSL constructor,
88
* derived 1:1 from `EXPOSED_DOMAIN_ENTRIES`:
99
*
10-
* `cipherstash.EncryptedTextSearch` → codec
10+
* `cipherstash.TextSearch` → codec
1111
* `cipherstash/eql-v3/eql_v3_text_search@1`, native type
1212
* `public.eql_v3_text_search`, static
1313
* `typeParams: { castAs, capabilities }`.
1414
*
1515
* There are NO options: the constructor IS the capability set. The name is
1616
* the mechanical `Encrypted<Stem><Suffix>` transform of the bare domain with
17-
* its `eql_v3_` prefix stripped (`eql_v3_bigint_ord` → `EncryptedBigIntOrd`);
17+
* its `eql_v3_` prefix stripped (`eql_v3_bigint_ord` → `BigIntOrd`);
1818
* the codec id keeps the registry key VERBATIM (never name-transformed).
1919
*
2020
* ### Static typeParams — confirmed framework shape (Step 0)
@@ -107,11 +107,25 @@ function coreName(bareDomain: string): string {
107107
return `${stemLabel}${suffixLabel}`
108108
}
109109

110-
/** `eql_v3_text_search` → `EncryptedTextSearch`, `eql_v3_bigint_ord` → `EncryptedBigIntOrd`. */
110+
/**
111+
* `eql_v3_text_search` → `TextSearch`, `eql_v3_bigint_ord` → `BigIntOrd`.
112+
*
113+
* The `cipherstash.` PSL namespace already disambiguates, so the constructor
114+
* names drop the `Encrypted` prefix to line up with the stack / Drizzle
115+
* `types.*` catalog (`types.TextSearch`, `types.BigintOrd`, …). The v2
116+
* constructors keep their `*V2` names; the runtime envelope classes
117+
* (`EncryptedString`, `EncryptedBoolean`, …) are a separate surface and are
118+
* unchanged.
119+
*/
111120
export function v3PascalName(bareDomain: string): string {
112-
return `Encrypted${coreName(bareDomain)}`
121+
return coreName(bareDomain)
113122
}
114-
/** `eql_v3_text_search` → `encryptedTextSearch`, `eql_v3_bigint_ord` → `encryptedBigIntOrd`. */
123+
/**
124+
* `eql_v3_text_search` → `encryptedTextSearch`. The camelCase TS-authoring
125+
* factory names keep their `encrypted` prefix for now — only the PSL
126+
* constructor names (`v3PascalName`) drop it in this pass; aligning the
127+
* camelCase exports is a follow-up.
128+
*/
115129
export function v3CamelName(bareDomain: string): string {
116130
return `encrypted${coreName(bareDomain)}`
117131
}

packages/prisma-next/src/exports/stack.ts

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@
33
* `@cipherstash/stack` SDK against a Prisma Next contract.
44
*
55
* The three exports here form a layered API. Most consumers want
6-
* {@link cipherstashFromStack}; the two primitives are exposed for
6+
* {@link cipherstashFromStackV2}; the two primitives are exposed for
77
* advanced users who need to interpose custom logic.
88
*
99
* - {@link deriveStackSchemas} — pure function, contract.json →
@@ -15,7 +15,7 @@
1515
* shape. Use when you've constructed the client yourself (custom
1616
* keyset, multi-tenant routing).
1717
*
18-
* - {@link cipherstashFromStack} — the all-in-one factory.
18+
* - {@link cipherstashFromStackV2} — the all-in-one factory.
1919
* Returns ready-to-spread arrays for `postgres<Contract>({...})`.
2020
*
2121
* This subpath imports `@cipherstash/stack` directly. Consumers who
@@ -31,17 +31,17 @@ export type {
3131
CipherstashFromStackOptions,
3232
CipherstashFromStackResult,
3333
} from '../stack/from-stack'
34-
export { cipherstashFromStack } from '../stack/from-stack'
34+
export { cipherstashFromStackV2 } from '../stack/from-stack'
3535
// ---------------------------------------------------------------------------
3636
// EQL v3 (decision 1b: a SEPARATE entry point — a client is v2 or v3,
37-
// never both; `cipherstashFromStackV3` rejects contracts carrying v2
37+
// never both; `cipherstashFromStack` rejects contracts carrying v2
3838
// cipherstash codec ids).
3939
// ---------------------------------------------------------------------------
4040
export type {
4141
CipherstashFromStackV3Options,
4242
CipherstashFromStackV3Result,
4343
} from '../stack/from-stack-v3'
44-
export { cipherstashFromStackV3 } from '../stack/from-stack-v3'
44+
export { cipherstashFromStack } from '../stack/from-stack-v3'
4545
export { createCipherstashSdk } from '../stack/sdk-adapter'
4646
export type {
4747
V3ContractColumnEntry,

packages/prisma-next/src/exports/v3.ts

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -6,15 +6,15 @@
66
*
77
* Most consumers want exactly one symbol from here:
88
*
9-
* const cipherstash = await cipherstashFromStackV3({ contractJson })
9+
* const cipherstash = await cipherstashFromStack({ contractJson })
1010
*
1111
* The remaining exports are the primitives that factory composes —
1212
* schema derivation, the SDK adapter, the runtime descriptor, the
1313
* bulk-encrypt middleware, envelopes, and the query-term seam — for
1414
* advanced users interposing custom logic (multi-tenant SDK routing,
1515
* a non-stack `CipherstashSdk` implementation, …).
1616
*
17-
* Bundle note: this entry re-exports `cipherstashFromStackV3`, which
17+
* Bundle note: this entry re-exports `cipherstashFromStack`, which
1818
* imports `@cipherstash/stack`. Consumers who need an SDK-free runtime
1919
* plane (custom `CipherstashSdk`) should import from `./runtime`
2020
* instead — its v3 exports carry no `@cipherstash/stack` client
@@ -34,7 +34,7 @@ export type {
3434
CipherstashFromStackV3Options,
3535
CipherstashFromStackV3Result,
3636
} from '../stack/from-stack-v3'
37-
export { cipherstashFromStackV3 } from '../stack/from-stack-v3'
37+
export { cipherstashFromStack } from '../stack/from-stack-v3'
3838
// User-facing value envelopes (version-neutral classes + the v3-only
3939
// EncryptedNumber).
4040
export * from '../v3/barrel'

0 commit comments

Comments
 (0)