From d53328b27dbfb43453e34c39f1fa7bc3fc73f3a0 Mon Sep 17 00:00:00 2001 From: Dan Draper Date: Thu, 30 Jul 2026 12:11:04 +1000 Subject: [PATCH 1/6] =?UTF-8?q?chore(release):=20exit=20changesets=20pre?= =?UTF-8?q?=20mode=20=E2=80=94=20next=20release=20is=201.0.0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The 1.0 line has been publishing `1.0.0-rc.*` under the `rc` dist-tag since `pre enter rc`. Exiting pre mode graduates the release train to stable: the next "Version Packages" PR opens as 1.0.0 and publishes under `latest`. - `.changeset/pre.json` moves to `mode: "exit"`. The next `changeset version` run graduates every package, consumes the ~140 accumulated changesets into `CHANGELOG.md`, and deletes the file. Verified by running `changeset version` in an isolated copy of the tree: stash, @cipherstash/stack, stack-drizzle, stack-supabase, prisma-next, wizard and migrate all land on 1.0.0. - The Stack 1.0 changeset headline no longer says "(release candidate)" — that line becomes the top of the 1.0.0 changelog. - CONTRIBUTE.md documents the stable flow as the default and keeps the pre-mode recipe as an explicitly exceptional path, including the trap that pre mode retains consumed changeset markdown until exit. --- .changeset/pre.json | 2 +- .changeset/stack-1-0-0-rc.md | 2 +- CONTRIBUTE.md | 37 ++++++++++++++++++++++++------------ 3 files changed, 27 insertions(+), 14 deletions(-) diff --git a/.changeset/pre.json b/.changeset/pre.json index b874a8b82..fb831f506 100644 --- a/.changeset/pre.json +++ b/.changeset/pre.json @@ -1,5 +1,5 @@ { - "mode": "pre", + "mode": "exit", "tag": "rc", "initialVersions": { "@cipherstash/e2e": "0.0.2", diff --git a/.changeset/stack-1-0-0-rc.md b/.changeset/stack-1-0-0-rc.md index 555ae5c8e..aba65318a 100644 --- a/.changeset/stack-1-0-0-rc.md +++ b/.changeset/stack-1-0-0-rc.md @@ -5,7 +5,7 @@ 'stash': major --- -CipherStash Stack 1.0 (release candidate). +CipherStash Stack 1.0. This is the first 1.0-line release of `@cipherstash/stack`, the first published release of the split-out EQL v3 adapters `@cipherstash/stack-drizzle` and diff --git a/CONTRIBUTE.md b/CONTRIBUTE.md index 04c61a87f..456ab9883 100644 --- a/CONTRIBUTE.md +++ b/CONTRIBUTE.md @@ -104,24 +104,37 @@ We use [**Changesets**](https://github.com/changesets/changesets) to manage vers - Follow the prompts to indicate the type of version bump (patch, minor, major). - The [GitHub Actions workflows](./.github/workflows/) handle the **publish** step to npm once your PR is merged and the changeset is committed to `main`. -## Pre release process +Releases are **stable** — Changesets is not in pre mode. Merging a changeset to +`main` opens (or updates) a "Version Packages" PR with plain semver versions, and +merging that PR publishes to npm under the `latest` dist-tag. + +The `stash` / `@cipherstash/stack` / `@cipherstash/stack-drizzle` / +`@cipherstash/stack-supabase` / `@cipherstash/prisma-next` / `@cipherstash/wizard` +packages are a `fixed` group in [`.changeset/config.json`](./.changeset/config.json): +they always version together, so a bump to any one of them bumps all six. -We currently use [changesets to manage pre-releasing](https://github.com/changesets/changesets/blob/main/docs/prereleases.md) the `next` version of the package, and the process is executed manually. +## Pre release process -To do so, you need to: +The 1.0 line published its `1.0.0-rc.*` series through +[changesets pre mode](https://github.com/changesets/changesets/blob/main/docs/prereleases.md). +That mode is **exited** — do not re-enter it for ordinary work; a stable release +is the default. -1. Check out the `next` branch -2. Run `pnpm changeset pre enter next` -3. Run `pnpm changeset version` -4. Run `git add .` -5. Run `git commit -m "Enter prerelease mode and version packages"` -6. Run `pnpm changeset publish --tag next` -7. Run `git push --follow-tags` +If a future line genuinely needs a prerelease series: -When you are ready to release, you can run `pnpm changeset pre exit` to exit prerelease mode and commit the changes. -When you merge the PR, the `next` branch will be merged into `main`, and the package will be published to npm without the prerelease tag. +1. Run `pnpm changeset pre enter rc` (this writes `.changeset/pre.json`) +2. Commit that file — from then on, every "Version Packages" PR produces + `x.y.z-rc.N` versions and publishes under the `rc` dist-tag +3. When the line is ready to go stable, run `pnpm changeset pre exit` and commit + the change. The next `changeset version` graduates every package to its final + version, consumes the accumulated changesets into `CHANGELOG.md`, and deletes + `.changeset/pre.json` > [!IMPORTANT] +> Pre mode retains every consumed changeset until exit, so its markdown is what +> lands in the stable changelog — an entry that a later change made wrong stays +> wrong until someone edits it. Review `.changeset/*.md` as a set before exiting. +> > This process can be dangerous, so please be careful when using it as it's difficult to undo mistakes. > If you are unfamiliar with the process, please reach out to the maintainers for help. From 88f8e589ba95bf599f6fa90bf37fb3cd6f2ef174 Mon Sep 17 00:00:00 2001 From: Dan Draper Date: Thu, 30 Jul 2026 12:29:52 +1000 Subject: [PATCH 2/6] fix(changesets,skills): reconcile the retained 1.0.0 notes; pin skills at 1.0.0 (#791) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Pre mode retains consumed changeset markdown until exit, so the aggregated 1.0.0 changelog was the union of every rc entry — including ones that later changes made wrong. Reconciled against the surface main actually ships. Changesets: - Re-homed adapter entries onto the packages that own the code (`@cipherstash/stack-drizzle` / `@cipherstash/stack-supabase` instead of `@cipherstash/stack`), so the details land in the changelog of the package that exposes the behaviour, and split the drizzle-root collapse from its one-line `stash` / `@cipherstash/stack` follow-on. - Rewrote entries naming removed APIs to their final names: the `@cipherstash/stack/eql/v3/drizzle` and `@cipherstash/stack-drizzle/v3` subpaths, `createEncryptionOperatorsV3` / `extractEncryptionSchemaV3`, the encrypted `contains()` operator (now `matches()`), and the alpha-era bare domain names (now `public.eql_v3_*`). - Dropped the "Superseded later in this release" footers. Where the entry was wholly about an rc-only surface 1.0.0 removed (`--eql-version`, `db push`, `encrypt cutover`), the entry is deleted — the rc changelog sections still record it; where the substance survives, the stale paragraph is gone and the body describes 1.0.0. - Removed the blanket "order() on any encrypted column is rejected" claim that the OPE ord_term entry contradicts. Skills (#791): - `skills/stash-edge` and `skills/stash-cli` pinned `1.0.0-rc.4` in four places. Nothing rewrites those literals — tsup copies `skills/` verbatim and the runtime-versions embed only reaches compiled CLI code — so the published skill would have told Deno and Supabase Edge users to pin a release candidate in production. They now pin `1.0.0`, and the paragraph explaining why `@^1.0.0` misses `1.0.0-rc.4` is gone with the rc pin. - The `supabase-worker` example pins `1.0.0` too. - `release-train.test.ts` now sweeps every `skills/*/SKILL.md`: an exact pin of a release-train package must be a stable version on the current major. Verified it fails on a reintroduced rc pin. --- .changeset/adapter-split-skills.md | 2 +- .changeset/cli-eql-v3-single-bundle.md | 2 +- .../cli-v2-cutover-prompt-correction.md | 15 -- .changeset/decrypt-chaining-docs.md | 14 +- .changeset/encrypt-client-guard-parity.md | 4 +- .changeset/encrypt-lifecycle-mixed-table.md | 61 ------- .changeset/eql-v3-adapter-type-robustness.md | 37 ++-- .changeset/eql-v3-cli-install.md | 15 -- .changeset/eql-v3-drizzle-encrypt-query.md | 4 +- .changeset/eql-v3-drizzle-fail-open-guards.md | 15 +- .changeset/eql-v3-drizzle.md | 27 +-- .changeset/eql-v3-ga-rebaseline.md | 2 +- .../eql-v3-rename-contains-to-matches.md | 2 +- .changeset/eql-v3-sole-docs.md | 13 +- .changeset/eql-v3-supabase-adapter.md | 89 ++++------ .changeset/eql-v3-wasm-inline.md | 2 +- .changeset/init-drizzle-eql-v3.md | 22 +-- .changeset/init-placeholder-eql-v3.md | 9 +- .changeset/init-scaffold-compiles.md | 11 +- .changeset/migrate-column-exists.md | 4 +- .changeset/migrate-eql-v3.md | 25 +-- .../remove-eql-v2-drizzle-root-consumers.md | 13 ++ .changeset/remove-eql-v2-drizzle-root.md | 9 - .changeset/rewriter-never-drops-ciphertext.md | 7 +- .changeset/skills-eql-v3-accuracy.md | 19 +-- .changeset/skills-pin-stable-1-0.md | 21 +++ .changeset/skills-v3-lifecycle-honesty.md | 29 ---- .changeset/stash-cli-eql-v3-default.md | 14 -- .changeset/stash-cli-skill-refresh.md | 13 +- .../stash-supabase-contains-substrings.md | 4 +- .changeset/supabase-in-list-operands.md | 18 +- .changeset/supabase-is-null-operands.md | 9 +- .changeset/supabase-or-string-parser.md | 6 +- .changeset/supabase-v3-order-by-ope-term.md | 45 +++-- DIFFERENTIAL_REVIEW_REPORT.md | 161 ++++++++++++++++++ .../functions/cipherstash-roundtrip/index.ts | 2 +- .../cli/src/__tests__/release-train.test.ts | 79 ++++++++- skills/stash-cli/SKILL.md | 2 +- skills/stash-edge/SKILL.md | 11 +- 39 files changed, 441 insertions(+), 396 deletions(-) delete mode 100644 .changeset/cli-v2-cutover-prompt-correction.md delete mode 100644 .changeset/encrypt-lifecycle-mixed-table.md delete mode 100644 .changeset/eql-v3-cli-install.md create mode 100644 .changeset/remove-eql-v2-drizzle-root-consumers.md create mode 100644 .changeset/skills-pin-stable-1-0.md delete mode 100644 .changeset/skills-v3-lifecycle-honesty.md delete mode 100644 .changeset/stash-cli-eql-v3-default.md create mode 100644 DIFFERENTIAL_REVIEW_REPORT.md diff --git a/.changeset/adapter-split-skills.md b/.changeset/adapter-split-skills.md index 772eeb21d..06806839d 100644 --- a/.changeset/adapter-split-skills.md +++ b/.changeset/adapter-split-skills.md @@ -5,7 +5,7 @@ Update the bundled `stash-drizzle`, `stash-supabase`, and `stash-encryption` agent skills (and the stack README / Supabase reference doc) for the adapter package split: the Drizzle and Supabase integrations import from `@cipherstash/stack-drizzle` -(+ `/v3`) and `@cipherstash/stack-supabase` respectively, installed alongside +and `@cipherstash/stack-supabase` respectively, installed alongside `@cipherstash/stack`, rather than from `@cipherstash/stack/{drizzle,supabase,eql/v3/drizzle}` subpaths. Skills ship inside the `stash` tarball, so the stale import paths would otherwise become wrong guidance in a user's project. diff --git a/.changeset/cli-eql-v3-single-bundle.md b/.changeset/cli-eql-v3-single-bundle.md index 25db56023..438b5e91c 100644 --- a/.changeset/cli-eql-v3-single-bundle.md +++ b/.changeset/cli-eql-v3-single-bundle.md @@ -2,7 +2,7 @@ 'stash': minor --- -`stash eql install --eql-version 3` now installs the eql-3.0.0 GA bundle, +`stash eql install` now installs the eql-3.0.0 GA bundle, vendored from the pinned `@cipherstash/eql` package (sha256-verified). Since eql-3.0.0 one artifact installs everywhere: the operator-class diff --git a/.changeset/cli-v2-cutover-prompt-correction.md b/.changeset/cli-v2-cutover-prompt-correction.md deleted file mode 100644 index 4a90e2f6b..000000000 --- a/.changeset/cli-v2-cutover-prompt-correction.md +++ /dev/null @@ -1,15 +0,0 @@ ---- -'stash': patch ---- - -`stash init`'s setup prompt no longer tells agents to declare an EQL v2 cutover -column with a `types.*` domain. - -The `types.*` factories are EQL v3 only — a v2 column is an `eql_v2_encrypted` -composite — so an agent following the old step-4 guidance would author a schema -that cannot describe the column it just cut over to. The prompt now says -explicitly not to use `types.*` for a v2 column, and points at the deprecated -`@cipherstash/stack/schema` builders with decryption through -`@cipherstash/stack`, which is the actual read path for legacy v2 rows. - -Superseded later in this release: `stash encrypt cutover` and all v2 mutation guidance are removed; legacy v2 remains read-only. diff --git a/.changeset/decrypt-chaining-docs.md b/.changeset/decrypt-chaining-docs.md index 36afc506b..2b7d6a230 100644 --- a/.changeset/decrypt-chaining-docs.md +++ b/.changeset/decrypt-chaining-docs.md @@ -49,15 +49,11 @@ other two to guess: object-shorthand that read as three required strings — `queryType` is inferred from the column's configured indexes. -The cutover and complete-rollout **plan templates** now split EQL v3 from v2. -Both described the v2 rename swap (`` → `_plaintext`, twin → ``) -as the only cutover path, so on the default v3 install `stash plan` drafted a -plan built around `stash encrypt cutover` — a command that refuses v3 columns -outright ("there is no rename step") and refuses entirely on a v3-only -database, where `eql_v2_configuration` does not exist. The implement prompt -already carried this split; the plan templates did not. The version is -per-column, so the templates tell the agent to establish it per column rather -than deciding once for the whole plan. +The cutover and complete-rollout **plan templates** now describe the EQL v3 +rollout. Both described a rename swap (`` → `_plaintext`, twin → +``) as the only cutover path, which EQL v3 does not have — the application +switches to the encrypted column by name. The implement prompt already carried +the v3 story; the plan templates did not. The "already encrypted" stop-and-ask now recognises `eql_v3_*` domains alongside the legacy `eql_v2_encrypted` udt, so it can fire on the default diff --git a/.changeset/encrypt-client-guard-parity.md b/.changeset/encrypt-client-guard-parity.md index 63c3a2664..68578a39b 100644 --- a/.changeset/encrypt-client-guard-parity.md +++ b/.changeset/encrypt-client-guard-parity.md @@ -6,9 +6,9 @@ initialized encrypt config, instead of reporting a missing table. The guard that refuses an unusable client file existed twice — once in -`loadEncryptConfig` (`stash db push` / `db validate`) and once, hand-copied, in +`loadEncryptConfig` (`stash db validate`) and once, hand-copied, in `loadEncryptionContext` (`stash encrypt backfill`). The copies had already -drifted: for a client whose `getEncryptConfig()` returns nothing, `db push` +drifted: for a client whose `getEncryptConfig()` returns nothing, `db validate` exited 1 with `Encryption client in has no initialized encrypt config`, while `encrypt backfill` fell through to `Table "users" was not found in the encryption client exports. Available: (none)` — naming the symptom rather than diff --git a/.changeset/encrypt-lifecycle-mixed-table.md b/.changeset/encrypt-lifecycle-mixed-table.md deleted file mode 100644 index f6b6273bd..000000000 --- a/.changeset/encrypt-lifecycle-mixed-table.md +++ /dev/null @@ -1,61 +0,0 @@ ---- -'stash': patch ---- - -`stash encrypt cutover` and `stash encrypt drop` no longer act on — or report -success for — an encrypted column they only guessed at. - -On a table holding both a legacy EQL v2 pair (`ssn` / `ssn_encrypted`) and one -unrelated EQL v3 column, the v2 ciphertext column is not classified as an EQL -column at all, so column resolution fell through to the "this is the table's -only EQL column" rule and claimed the unrelated v3 column. Three consequences, -all now fixed: - -- **`cutover` reported success for work it never did.** Its EQL v3 branch had no - guard on how the column was resolved, and returned without setting an exit - code — so it printed "point your application at `email_enc`" and exited 0 - while the v2 rename never ran. A scripted rollout read that as complete. It - now refuses, and exits 1, exactly as `drop` already did. - -- **The recorded pairing was discarded.** `encrypt backfill` writes the true - `encryptedColumn` to `.cipherstash/migrations.json`, so the answer was already - on disk — but a hint that failed to resolve was dropped entirely and the - re-resolution reached the guess. A hint naming a column that still exists but - is not an EQL v3 column is now reported as what it is (most often a legacy - `eql_v2_encrypted` counterpart) instead of being replaced by a guess. A - genuinely stale hint — one naming a column that is gone — still falls back to - the naming convention as before. - -- **`drop`'s refusal message prescribed the guess.** It told the user to re-run - `backfill --encrypted-column `. Following it recorded the - guess as fact, so the next run resolved "by hint", walked past the refusal, - and passed the coverage check vacuously — an unrelated but legitimately - backfilled column is non-NULL on every row — then generated a live - `DROP COLUMN` on the plaintext and exited 0. The message now asks for the - column that actually encrypts the named one, and says explicitly not to record - the guess. - -The `unresolvedHint` refusal is scoped to tables that actually hold EQL v3 -columns a guess could wrongly claim. A **pure-v2** table has none, so it still -falls through to the EQL v2 lifecycle exactly as before — including when -`encrypt backfill` recorded an `encryptedColumn` for it, which it does for v2 -columns too. - -Two cases DO newly exit 1, both deliberately: - -- Any table with at least one EQL v3 column where the manifest records an - `encryptedColumn` that exists but is not one of them — not only the - v2-pair-plus-one-v3 shape. The recorded pairing is authoritative and - disagrees with every candidate, so guessing past it is the bug. - -- A column whose encrypted counterpart could only be identified **by - elimination** — no recorded `encryptedColumn`, no `_encrypted` name - match, one EQL column left once the plaintext column itself is excluded. - `cutover` now refuses this as `drop` already did. Note `.cipherstash/` is - gitignored, so `migrations.json` is machine-local: a fresh clone or CI runner - can hit this on a **pure-v3** table whose encrypted column is named - unconventionally, where `cutover` previously exited 0 with "not applicable". - Re-run `stash encrypt backfill --table T --column C --encrypted-column ` - to record the pairing. - -Superseded later in this release: no v2 lifecycle can be driven by `stash encrypt`; mixed and pure-v2 state now fail with migration/recovery guidance. diff --git a/.changeset/eql-v3-adapter-type-robustness.md b/.changeset/eql-v3-adapter-type-robustness.md index f7cddd986..e2954a322 100644 --- a/.changeset/eql-v3-adapter-type-robustness.md +++ b/.changeset/eql-v3-adapter-type-robustness.md @@ -1,38 +1,35 @@ --- -'@cipherstash/stack': minor +'@cipherstash/stack-drizzle': minor +'@cipherstash/stack-supabase': minor --- Restore the EQL v3 envelope and `Result` types the adapters were erasing. -Both v3 adapters typed their operand-encryption paths as `unknown` and dropped -the `Result` wrapper, so the query-type encoding and the failure channel were +Both adapters typed their operand-encryption paths as `unknown` and dropped the +`Result` wrapper, so the query-type encoding and the failure channel were invisible to the type system: -- `eql/v3/drizzle/operators.ts` typed the client's `encrypt`/`bulkEncrypt` as +- The Drizzle operator module typed the client's `encrypt`/`bulkEncrypt` as returning `unknown`, collapsed the operation's `Result` to `{ data?: unknown; failure?: { message } }`, and cast the bulk response to `Array<{ data: unknown }>`. -- `supabase/query-builder-v3.ts` returned `Promise` from - `encryptCollectedTerms`, `bulkEncryptGroup` and `encryptGroupPerTerm`, and the - base `query-builder.ts` did the same. +- The Supabase query builder returned `Promise` from + `encryptCollectedTerms`, `bulkEncryptGroup` and `encryptGroupPerTerm`. These now carry the SDK's real types — `Encrypted` (the storage envelope union, which includes every v3 per-domain payload), `BulkEncryptedData`, and `EncryptedQueryResult` — threaded through a properly-typed operation surface that -resolves `Result`. The Supabase divergence the erasure hid is -now explicit: the v2 path yields `encryptQuery` composite literals and the v3 -path yields `JSON.stringify`'d envelope strings, and both are `EncryptedQueryResult`. +resolves `Result`. -Bumped `minor`, not `patch`: `createEncryptionOperatorsV3` is a public export -(`@cipherstash/stack/eql/v3/drizzle`), and tightening its client contract from -`unknown` to a typed operation surface is a compile-time breaking change — a -downstream consumer passing a loosely-typed (`unknown`-returning) client double -will now fail `tsc`. That tightening has teeth: `operators.test-d.ts` pins it -with a negative type-test asserting an `unknown`-returning `{ encrypt }` double -is rejected (a positive "correctly-typed double is accepted" assertion cannot -catch a re-erasure, since a correct value is assignable to `unknown`). +Tightening `createEncryptionOperators`' client contract from `unknown` to a typed +operation surface is a compile-time breaking change for a downstream consumer +passing a loosely-typed (`unknown`-returning) client double: it will now fail +`tsc`. That tightening has teeth — `operators.test-d.ts` pins it with a negative +type-test asserting an `unknown`-returning `{ encrypt }` double is rejected (a +positive "correctly-typed double is accepted" assertion cannot catch a +re-erasure, since a correct value is assignable to `unknown`). -Behaviour is otherwise unchanged, with one addition: the Supabase v3 bulk path -now rejects a `null` envelope returned by `bulkEncrypt` (the restored +Behaviour is otherwise unchanged, with one addition: the Supabase bulk path now +rejects a `null` envelope returned by `bulkEncrypt` (the restored `Encrypted | null` type makes that arm reachable, and a `null` would otherwise be `JSON.stringify`'d to the literal `"null"` and sent as a filter operand). diff --git a/.changeset/eql-v3-cli-install.md b/.changeset/eql-v3-cli-install.md deleted file mode 100644 index 264f449d9..000000000 --- a/.changeset/eql-v3-cli-install.md +++ /dev/null @@ -1,15 +0,0 @@ ---- -"stash": minor ---- - -Add an EQL v3 install path to `stash eql install` via a new `--eql-version <2|3>` -flag (default `2`). v3 installs the native concrete-domain schema (`public.*` -type domains, `eql_v3` operators, `eql_v3_internal` constructors) from bundles -vendored into `packages/cli/src/sql` by `scripts/build-eql-v3-sql.mjs` (full -bundle + a Supabase variant with the two superuser-only operator-class chunks -stripped). v3 currently supports the direct install path only — -`--drizzle`/`--migration`/`--migrations-dir`/`--latest` are rejected — and the -installer keys `isInstalled`/version checks and Supabase grants to the `eql_v3` -schema. - -Superseded later in this release: `--eql-version` and the v2 installer are removed; installs and upgrades are v3-only. diff --git a/.changeset/eql-v3-drizzle-encrypt-query.md b/.changeset/eql-v3-drizzle-encrypt-query.md index 9fb894b91..075e6d887 100644 --- a/.changeset/eql-v3-drizzle-encrypt-query.md +++ b/.changeset/eql-v3-drizzle-encrypt-query.md @@ -5,8 +5,8 @@ EQL v3 Drizzle: encrypt every query operand with `encryptQuery`, not `encrypt` (#622). -The v3 Drizzle operators (`eq`/`ne`/`gt`/`gte`/`lt`/`lte`/`between`/`notBetween`/ -`inArray`/`notInArray`/`contains`) previously encrypted their operands with +The Drizzle operators (`eq`/`ne`/`gt`/`gte`/`lt`/`lte`/`between`/`notBetween`/ +`inArray`/`notInArray`/`matches`/`contains`) previously encrypted their operands with `client.encrypt`, producing a full storage envelope (including the ciphertext `c`) cast to `::jsonb`. A WHERE-clause operand should be a query *term*, not a value to store. Every operator now uses `client.encryptQuery`, which yields a diff --git a/.changeset/eql-v3-drizzle-fail-open-guards.md b/.changeset/eql-v3-drizzle-fail-open-guards.md index 990508580..d40c95869 100644 --- a/.changeset/eql-v3-drizzle-fail-open-guards.md +++ b/.changeset/eql-v3-drizzle-fail-open-guards.md @@ -1,10 +1,10 @@ --- -'@cipherstash/stack': minor +'@cipherstash/stack-drizzle': minor --- -Close two fail-open paths in the EQL v3 Drizzle adapter. +Close two fail-open paths in the Drizzle adapter. -`ops.contains()` now throws `EncryptionOperatorError` for a search term that +`ops.matches()` now throws `EncryptionOperatorError` for a search term that tokenizes to nothing: the empty string, or a term shorter than the match index tokenizer's `token_length` (3 by default). Such a term produces an empty bloom filter, and `stored_bf @> '{}'` is true for every row — so a user searching @@ -16,7 +16,7 @@ The floor counts Unicode codepoints, matching the tokenizer. A UTF-16 length check would wave through an astral-plane term — `"👍👍"` is 4 code units but only 2 codepoints, yields no trigram, and matched every row. -**Breaking for callers passing short terms:** `contains()` calls that previously +**Breaking for callers passing short terms:** free-text calls that previously returned every row now throw. Terms of 3+ codepoints are unaffected. `v3FromDriver()` now throws the new `EqlV3CodecError` on a payload that is not @@ -27,12 +27,7 @@ accepts both scalar envelopes (ciphertext at `c`) and SteVec documents (ciphertext at `sv[0].c`). A SteVec's `sv` must be a non-empty array: `sv[0]` is the decryption root, so `sv: []` carries a ciphertext key but no ciphertext, and is now rejected rather than passed to `decrypt`. `EqlV3CodecError` is exported -from `@cipherstash/stack/eql/v3/drizzle` so callers can catch it. +from the `@cipherstash/stack-drizzle` package root so callers can catch it. Also removes an unreachable branch in `inArray`/`notInArray`, whose empty-list guard already throws before it. - -Note: the v2 Drizzle adapter's `like`/`ilike` path builds the same bloom filters -and has the same short-term fail-open. It is **not** fixed here — v2 terms carry -SQL wildcards, so the floor must be measured against what its tokenizer actually -receives before the shared guard can be reused. Tracked separately. diff --git a/.changeset/eql-v3-drizzle.md b/.changeset/eql-v3-drizzle.md index 0ec9d099a..7b1c8a8f0 100644 --- a/.changeset/eql-v3-drizzle.md +++ b/.changeset/eql-v3-drizzle.md @@ -1,17 +1,18 @@ --- -"@cipherstash/stack": minor +'@cipherstash/stack-drizzle': minor --- -Add EQL v3 Drizzle support at `@cipherstash/stack/eql/v3/drizzle`. A Drizzle-native -`types` namespace (same PascalCase names as `@cipherstash/stack/eql/v3`) declares -encrypted columns whose Postgres type is the semantic `public.`; the concrete -type drives the legal query operators. `createEncryptionOperatorsV3` provides -capability-checked `eq`/`ne`/`gt`/`gte`/`lt`/`lte`/`between`/`contains`/`inArray`/ -`asc`/`desc`/`and`/`or` that emit the latest two-argument `eql_v3` SQL functions with -full-envelope operands, and `extractEncryptionSchemaV3` rebuilds the schema for -`Encryption`. This surface was subsequently consolidated at the -`@cipherstash/stack-drizzle` package root. +EQL v3 Drizzle support on the `@cipherstash/stack-drizzle` package root. A +Drizzle-native `types` namespace (same PascalCase names as +`@cipherstash/stack/eql/v3`) declares encrypted columns whose Postgres type is +the semantic `public.eql_v3_`; the concrete type drives the legal query +operators. `createEncryptionOperators` provides capability-checked +`eq`/`ne`/`gt`/`gte`/`lt`/`lte`/`between`/`matches`/`contains`/`inArray`/ +`asc`/`desc`/`and`/`or` that emit the two-argument `eql_v3` SQL functions with +full-envelope operands, and `extractEncryptionSchema` rebuilds the schema for +`Encryption`. -The v3 text-search helper is `contains`; obsolete `like`/`ilike` helpers are not -exposed because v3 free-text search is token containment rather than SQL wildcard -matching. +The encrypted free-text helper is `matches`; obsolete `like`/`ilike` helpers are +not exposed, because encrypted free-text search is bloom-filter token matching +rather than SQL wildcard matching. `contains` is genuine encrypted-JSON +containment (`@>` against a `types.Json` column), not free-text. diff --git a/.changeset/eql-v3-ga-rebaseline.md b/.changeset/eql-v3-ga-rebaseline.md index b394d1741..68a6c1022 100644 --- a/.changeset/eql-v3-ga-rebaseline.md +++ b/.changeset/eql-v3-ga-rebaseline.md @@ -8,7 +8,7 @@ Re-baseline EQL v3 on the eql-3.0.0 GA release and protect-ffi 0.29. eql-3.0.0 naming convention — flat, prefixed names in `public` (`public.eql_v3_text_search`, `public.eql_v3_integer_ord`, …) instead of the alpha-era bare names. Databases installed from an alpha bundle must be - re-installed (`stash eql install --eql-version 3` replaces the schema). + re-installed (`stash eql install` replaces the schema). - `encryptQuery` on the EQL v3 client now returns EQL v3 query operands (protect-ffi 0.29): term-only scalar operands for the `eql_v3.query_` domains, the `eql_v3.query_jsonb` containment needle, and bare selector diff --git a/.changeset/eql-v3-rename-contains-to-matches.md b/.changeset/eql-v3-rename-contains-to-matches.md index 2e576b464..119a8214d 100644 --- a/.changeset/eql-v3-rename-contains-to-matches.md +++ b/.changeset/eql-v3-rename-contains-to-matches.md @@ -11,7 +11,7 @@ containment. The name `contains()` promised substring/containment semantics it never had. It is renamed to `matches()` on the encrypted surface; `contains()` is kept for genuine, exact containment: -- **Drizzle** (`@cipherstash/stack-drizzle/v3`): `matches()` = bloom free-text on +- **Drizzle** (`@cipherstash/stack-drizzle`): `matches()` = bloom free-text on `text_match`/`text_search` columns; `contains()` = exact encrypted-JSON `@>` on `types.Json` (ste_vec) columns. - **Supabase** (`@cipherstash/stack-supabase`): `.matches()` = encrypted free-text; diff --git a/.changeset/eql-v3-sole-docs.md b/.changeset/eql-v3-sole-docs.md index baa9edf10..4b3b14019 100644 --- a/.changeset/eql-v3-sole-docs.md +++ b/.changeset/eql-v3-sole-docs.md @@ -15,14 +15,13 @@ stored EQL v2 data is still reachable there: corresponding v3 table and `{ storedEqlVersion: 2 }`, so the `stash-dynamodb` skill documents that explicit compatibility path (#657). - **The encrypt rollout lifecycle.** `stash encrypt *` and `@cipherstash/migrate` - detect a column's generation from its Postgres domain type, with EQL v3 as the - recognised and default generation; a legacy `eql_v2_encrypted` column does not - classify and falls through to the v2 lifecycle, which ends in - `stash encrypt cutover` rather than the v3 `stash encrypt drop`. That - difference is kept under a version callout (#648). + classify a column from its Postgres domain type: a `public.eql_v3_*` domain is + recognised as v3, and anything else — including a legacy `eql_v2_encrypted` + column — does not classify. The documented lifecycle is the v3 one + (backfill → switch the application to the encrypted column → drop the + plaintext); legacy v2 columns are read-only, covered under a version callout + (#648). Also corrects the legacy `@cipherstash/drizzle` README's pointer to the removed `@cipherstash/stack/drizzle` subpath (now the separate `@cipherstash/stack-drizzle` package). - -Superseded later in this release: CLI/migrate v2 mutation guidance is removed; only legacy ciphertext reads and status diagnostics remain. diff --git a/.changeset/eql-v3-supabase-adapter.md b/.changeset/eql-v3-supabase-adapter.md index 418d410f0..a4ac8bbf7 100644 --- a/.changeset/eql-v3-supabase-adapter.md +++ b/.changeset/eql-v3-supabase-adapter.md @@ -1,68 +1,45 @@ --- -'@cipherstash/stack': minor +'@cipherstash/stack-supabase': minor --- -Add `encryptedSupabaseV3` — the EQL v3 dialect of the Supabase adapter. It is -now a connect-time-async factory: `await encryptedSupabaseV3(url, key)` (or -`(client)`) introspects the database over `DATABASE_URL`, detects EQL v3 columns -by their Postgres domain (`information_schema.columns.domain_name`), and derives -each column's encryption config from its domain — callers no longer pass a -schema to `from()`. `select('*')` is supported (expanded from the introspected -column list, and aliased back to each declared column's JS property name so a -property→DB rename round-trips). A column using an EQL v3 domain this SDK version does not model -(e.g. `public.json`, `*_ord_ope`) throws at construction rather than silently -passing through. Supplying `schemas` remains optional and adds compile-time -types plus startup verification of the declared tables against the database. -Requires a Postgres connection for introspection (`pg` is a new optional peer), -so it cannot run in a Worker or the browser. +`encryptedSupabase` is a connect-time-async, introspecting EQL v3 factory: +`await encryptedSupabase(url, key)` (or `(client)`) introspects the database over +`DATABASE_URL`, detects EQL v3 columns by their Postgres domain +(`information_schema.columns.domain_name`), and derives each column's encryption +config from its domain — callers no longer pass a schema to `from()`. +`select('*')` is supported (expanded from the introspected column list, and +aliased back to each declared column's JS property name so a property→DB rename +round-trips). A column using a `public.eql_v3_*` domain this SDK version does not +model throws at construction rather than silently passing through. Supplying +`schemas` remains optional and adds compile-time types plus startup verification +of the declared tables against the database. Requires a Postgres connection for +introspection (`pg` is an optional peer), so it cannot run in a Worker or the +browser. Every column name a query carries — filters, `match`, `not`, raw `filter`, -`or()`, `order()`, and the `onConflict` option — is now resolved from its JS -property name to its DB column name in a single pass before the query is built, -so a declared rename round-trips everywhere rather than only on the paths that +`or()`, `order()`, and the `onConflict` option — is resolved from its JS property +name to its DB column name in a single pass before the query is built, so a +declared rename round-trips everywhere rather than only on the paths that remembered to translate. -`order()` on ANY encrypted v3 column is now rejected — at compile time when -`schemas` is supplied, and at runtime otherwise. The EQL v3 domains are -`DOMAIN … AS jsonb` and the bundle declares no btree operator class on them, so -`ORDER BY col` resolves through jsonb's default `jsonb_cmp` and sorts by the -envelope's byte structure: a stable, plausible-looking, meaningless row order, -with no error. Correct ordering is `ORDER BY eql_v3.ord_term(col)`, which -PostgREST's `order=` cannot express. Order by a plaintext column, expose -`eql_v3.ord_term()` as a generated column or view, or use the EQL v3 Drizzle -integration, which emits `ord_term` directly. Note `gte`/`lte` filters remain -correct: the comparison operators *are* declared on the ord domains, and only -sorting resolves through the missing operator class. - -`.or()` now understands PostgREST's `column.not..` negation. It was +`.or()` understands PostgREST's `column.not..` negation. It was previously parsed as `{ op: 'not', value: '.' }`, so on an encrypted column `or('nickname.not.in.(ada,grace)')` encrypted the literal string `in.(ada,grace)` as a single plaintext and produced a filter that silently matched nothing. -Free-text search on the v3 builder is `contains(column, value)`. `like`/`ilike` -are not exposed, because EQL v3 free-text search is token containment over a -bloom filter (`@>`, backed by `eql_v3.contains`) rather than SQL wildcard -matching — `%` is tokenized like any other character, so a `like` pattern is a -category error. This matches the v3 Drizzle integration, which omits them for -the same reason. On an encrypted column `like`/`ilike` now throw and name -`contains`; on a plaintext column they remain ordinary PostgREST filters. - -`contains` is narrowed at compile time to columns whose domain carries the -`freeTextSearch` capability (`public.text_match`, `public.text_search`), and -guarded at runtime for the untyped surface. A raw `filter(column, operator, …)` -on an encrypted v3 column now derives its query type from the operator instead -of always encrypting an equality term, so `filter('bio', 'cs', …)` on a -`public.text_match` column works rather than being rejected, and an unsupported -operator throws instead of silently encrypting the wrong term. - -Substring `contains` matches any needle whose trigrams are all present in the -stored value; needles shorter than the tokenizer's window (3 characters) bloom to -nothing and are rejected rather than silently matching every row. The v3 match -index now emits `include_original: false` — the flag is inert in protect-ffi (the -bloom is trigram-only either way), so this moves no ciphertext and only pins the -value a substring-search domain wants. - -This surface was subsequently consolidated as the unsuffixed -`encryptedSupabase` EQL v3 factory. The legacy v2 Supabase authoring wrapper has -been removed; core native decrypt remains compatible with stored v2 payloads. +Encrypted free-text search is `matches(column, value)`, narrowed at compile time +to columns whose domain carries the `freeTextSearch` capability +(`public.eql_v3_text_match`, `public.eql_v3_text_search`) and guarded at runtime +for the untyped surface. It matches any needle whose trigrams are all present in +the stored value; needles shorter than the tokenizer's window (3 characters) +bloom to nothing and are rejected rather than silently matching every row. A raw +`filter(column, operator, …)` on an encrypted column derives its query type from +the operator instead of always encrypting an equality term, so +`filter('bio', 'cs', …)` on a `public.eql_v3_text_match` column works rather than +being rejected, and an unsupported operator throws instead of silently encrypting +the wrong term. + +The v3 match index emits `include_original: false` — the flag is inert in +protect-ffi (the bloom is trigram-only either way), so this moves no ciphertext +and only pins the value a substring-search domain wants. diff --git a/.changeset/eql-v3-wasm-inline.md b/.changeset/eql-v3-wasm-inline.md index c67e659cc..9b1e2c88f 100644 --- a/.changeset/eql-v3-wasm-inline.md +++ b/.changeset/eql-v3-wasm-inline.md @@ -9,7 +9,7 @@ created a client pinned to the FFI's EQL v2 wire format, so a v3 schema (concrete `eql_v3_*` domains) failed every encrypt on the edge. It now targets EQL v3 exclusively: -- The factory constructs the WASM client with `eqlVersion: 3`, so v3 schemas +- The factory builds an EQL v3 WASM client, so v3 schemas encrypt/decrypt correctly on the edge. - The entry re-exports the **v3** authoring surface (`types`, `encryptedTable`, the column classes, `buildEncryptConfig`, and the inference helpers) — the diff --git a/.changeset/init-drizzle-eql-v3.md b/.changeset/init-drizzle-eql-v3.md index 5e54b75e2..184409944 100644 --- a/.changeset/init-drizzle-eql-v3.md +++ b/.changeset/init-drizzle-eql-v3.md @@ -2,16 +2,13 @@ 'stash': patch --- -`stash init --drizzle` now installs EQL v3 instead of v2. +`stash init --drizzle` installs EQL v3. -The Drizzle init flow pinned `--eql-version 2`, because `stash eql install ---drizzle` (the only migration-generating install path at the time) was -v2-only. That made `stash init --drizzle` the single flow that provisioned a v2 -database — a bare `stash eql install`, and init for every other integration, -already defaulted to v3. It also contradicted the `stash-drizzle` skill init -copies into the same project, which documents the v3 `@cipherstash/stack-drizzle` -surface (`types.*` domains, `Encryption`) and would have the user's agent -author v3 code against a v2 database. +The Drizzle init flow used to provision a v2 database — the only +migration-generating install path at the time was v2-only — while the +`stash-drizzle` skill init copies into the same project documents the v3 +`@cipherstash/stack-drizzle` surface (`types.*` domains, `Encryption`). The +user's agent would have authored v3 code against a v2 database. Init's Drizzle flow now routes through `stash eql migration --drizzle`, so it stays migration-first (the install lands in your Drizzle migration history and @@ -21,7 +18,6 @@ The generated migration also carries the `cs_migrations` tracking schema, so one isn't installed or configured, init now reports EQL as not installed and points at `stash eql migration --drizzle` rather than aborting the run. -The final CLI installation and mutation surface is v3-only: the explicit v2 -Drizzle install path is removed. Legacy v2 remains readable and visible in -diagnostics. Generate a checked-in install migration with `stash eql migration ---drizzle`. +The CLI installation and mutation surface is v3-only. Legacy v2 remains readable +and visible in diagnostics. Generate a checked-in install migration with +`stash eql migration --drizzle`. diff --git a/.changeset/init-placeholder-eql-v3.md b/.changeset/init-placeholder-eql-v3.md index 6c75a89c1..28e4bcf3d 100644 --- a/.changeset/init-placeholder-eql-v3.md +++ b/.changeset/init-placeholder-eql-v3.md @@ -13,9 +13,6 @@ customer's coding agent v2 guidance against a v3 schema (follow-up to #732 / Scaffolds now teach the v3 surface: `Encryption` from `@cipherstash/stack/v3`, the concrete-domain `types.*` factories (`types.TextSearch`, `types.IntegerOrd`, -`types.Text`, `types.Json`, …), and the `@cipherstash/stack-drizzle/v3` entry -(`extractEncryptionSchemaV3`) for Drizzle. The `encryptionClient` export shape -and the empty-schema "no schemas yet" error path are unchanged. - -The scaffolds emit `extractEncryptionSchema` from the collapsed -`@cipherstash/stack-drizzle` root. +`types.Text`, `types.Json`, …), and `extractEncryptionSchema` from the +`@cipherstash/stack-drizzle` package root for Drizzle. The `encryptionClient` +export shape and the empty-schema "no schemas yet" error path are unchanged. diff --git a/.changeset/init-scaffold-compiles.md b/.changeset/init-scaffold-compiles.md index 3de825aea..cf6b76338 100644 --- a/.changeset/init-scaffold-compiles.md +++ b/.changeset/init-scaffold-compiles.md @@ -13,16 +13,13 @@ the non-empty schema requirement. The scaffold now declares a single sentinel table, `__stash_placeholder__`, so the file typechecks as written. Every command that reads the encryption client -— `stash db push`, `stash db validate`, and `stash encrypt backfill` — refuses -to run while that table is still the only one declared, and names it, rather -than failing later with a confusing "table not found". (`stash encrypt cutover` -and `stash encrypt drop` do not read the client file at all; they resolve -against the database.) +— `stash db validate` and `stash encrypt backfill` — refuses to run while that +table is still the only one declared, and names it, rather than failing later +with a confusing "table not found". (`stash encrypt drop` does not read the +client file at all; it resolves against the database.) Nothing in the repo compiled this output before: `packages/cli` has no typecheck step, the codegen tests only string-match fragments of the template, and the step test stubs the generator out entirely. Both templates are now committed as fixtures that CI typechecks, pinned byte-for-byte to the generator so they cannot drift. - -Superseded later in this release: the generated guidance no longer references removed `db push` or `encrypt cutover` commands. diff --git a/.changeset/migrate-column-exists.md b/.changeset/migrate-column-exists.md index d88867430..33870eaae 100644 --- a/.changeset/migrate-column-exists.md +++ b/.changeset/migrate-column-exists.md @@ -11,11 +11,11 @@ Callers need that difference to tell a STALE column reference (it is gone) from a live one the domain classifier simply does not recognise — most often a legacy `eql_v2_encrypted` counterpart. -`stash encrypt cutover` / `drop` had a private copy of this probe built on a bare +`stash encrypt drop` had a private copy of this probe built on a bare `to_regclass($1)`. That form *parses* its argument and case-folds unquoted identifiers, so on a Prisma-style `"User"` table it resolved `user`, reported the column missing, and treated a valid recorded pairing as stale — silently skipping -the fail-closed that stops those commands acting on a guessed encrypted column. +the fail-closed that stops the command acting on a guessed encrypted column. The shared implementation quotes with `format('%I')` first, like every other catalog probe in this package, so the lookup is case-exact while still honouring `search_path` for unqualified names. diff --git a/.changeset/migrate-eql-v3.md b/.changeset/migrate-eql-v3.md index e43ea380e..97afadbba 100644 --- a/.changeset/migrate-eql-v3.md +++ b/.changeset/migrate-eql-v3.md @@ -16,17 +16,11 @@ right lifecycle, no new flags: database, including the domain CHECK and a decrypt round-trip). The manifest records the detected version, the encrypted column's name, and the v3 target phase, and the command prints v3-appropriate next steps. -- **`encrypt cutover`** on a backfilled v3 column reports "not applicable" - (exit 0) with guidance: v3 has no rename cut-over — the application - switches to the encrypted column by name. Before backfill completes it - exits 1 and says to finish the backfill instead of instructing the switch. - On a database with no `eql_v2_configuration` table (a v3-only install) the - v2 path now explains that instead of surfacing a raw Postgres error. - **`encrypt drop`** is version-aware: v3 runs from the `backfilled` phase, **verifies live coverage** (refuses to generate the migration while any row still has the plaintext set and the encrypted column NULL — the `countUnencrypted` check), and drops the ORIGINAL plaintext column (there - is no `_plaintext` under v3); v2 behaviour is unchanged. The generated + is no `_plaintext` under v3). The generated v3 migration **re-verifies coverage at apply time** — it locks the table, re-counts, and aborts without dropping if plaintext-only rows appeared after generation. And because dropping is the one irreversible step, it @@ -34,7 +28,7 @@ right lifecycle, no new flags: manifest's recorded `encryptedColumn` or the naming convention): a match found only by being the table's sole EQL column is refused with instructions, and an ambiguous table (several EQL columns, none - identifiable) fails closed listing the candidates — as does `cutover`. + identifiable) fails closed listing the candidates. - **`encrypt status`** classifies each column from the observed domain type (manifest as fallback), shows `v3` in the EQL column, and no longer raises the v2-only `not-registered` / `plaintext-col-missing` drift flags for v3 @@ -49,14 +43,11 @@ right lifecycle, no new flags: matching the manifest and the installer. Resolved columns carry `via: 'hint' | 'convention' | 'sole'` so callers can tell a positively asserted pairing from a by-elimination guess. -- Fixed: `encrypt cutover`/`encrypt drop` precondition failures now actually - exit 1 — the early-return guards previously skipped the exit-code path - entirely, so failed preconditions exited 0. (This also applies to v2 - preconditions: scripted pipelines that relied on the erroneous exit 0 will - now see the documented exit 1.) +- Fixed: `encrypt drop` precondition failures now actually exit 1 — the + early-return guards previously skipped the exit-code path entirely, so failed + preconditions exited 0. Scripted pipelines that relied on the erroneous exit 0 + will now see the documented exit 1. The `stash-cli` and `stash-encryption` skills and the `@cipherstash/migrate` -README document the two lifecycles (v2: backfill → cutover → drop; -v3: backfill → switch-by-name → drop). - -Superseded later in this release: `@cipherstash/migrate` and the CLI now author and mutate v3 only; legacy v2 manifest fields remain readable. +README document the v3 lifecycle: backfill → switch the application to the +encrypted column by name → drop the plaintext column. diff --git a/.changeset/remove-eql-v2-drizzle-root-consumers.md b/.changeset/remove-eql-v2-drizzle-root-consumers.md new file mode 100644 index 000000000..a9001d0a7 --- /dev/null +++ b/.changeset/remove-eql-v2-drizzle-root-consumers.md @@ -0,0 +1,13 @@ +--- +'stash': patch +'@cipherstash/stack': patch +--- + +Follow the `@cipherstash/stack-drizzle` package-root collapse in the packages that +document it. + +- **`stash`:** `stash init --drizzle` emits the package-root + `extractEncryptionSchema` import, and the bundled `stash-drizzle` and + `stash-encryption` skills match. +- **`@cipherstash/stack`:** README only — its Drizzle section documents the + package-root exports. diff --git a/.changeset/remove-eql-v2-drizzle-root.md b/.changeset/remove-eql-v2-drizzle-root.md index eb06bd693..c713ad68a 100644 --- a/.changeset/remove-eql-v2-drizzle-root.md +++ b/.changeset/remove-eql-v2-drizzle-root.md @@ -1,7 +1,5 @@ --- '@cipherstash/stack-drizzle': major -'@cipherstash/stack': patch -'stash': patch --- Remove the EQL v2 authoring surface from `@cipherstash/stack-drizzle` and collapse the EQL v3 `./v3` subpath into the package root. @@ -17,10 +15,3 @@ Remove the EQL v2 authoring surface from `@cipherstash/stack-drizzle` and collap The `types.*` column factories, `makeEqlV3Column` / `getEqlV3Column` / `isEqlV3Column`, the codec helpers (`v3ToDriver` / `v3FromDriver` / `EqlV3CodecError`), and `EncryptionOperatorError` are unchanged apart from moving to the root. Existing EQL v2 ciphertext remains decryptable via `@cipherstash/stack` — only the Drizzle-side v2 authoring and query-building is removed. - -**`stash` (patch):** `stash init --drizzle` now emits the package-root -`extractEncryptionSchema` import. The bundled `stash-drizzle` and -`stash-encryption` skills are updated to match. - -**`@cipherstash/stack` (patch):** README only — its Drizzle section now -documents the final package-root exports. diff --git a/.changeset/rewriter-never-drops-ciphertext.md b/.changeset/rewriter-never-drops-ciphertext.md index e32890e4c..25bbee069 100644 --- a/.changeset/rewriter-never-drops-ciphertext.md +++ b/.changeset/rewriter-never-drops-ciphertext.md @@ -36,11 +36,8 @@ rather than rewritten, so the ADD+DROP+RENAME no longer drops a column that the migration corpus itself shows already holds ciphertext. That is a guarantee about what the corpus says, not about the database: the sweep reasons entirely from migration files, and a database that has drifted from its migration -history is outside what it can see. `stash encrypt cutover` is the sharpest -example — it renames columns directly in the database and never writes drizzle -SQL, so the corpus can still describe a column as plaintext after cutover has -made it ciphertext; the same is true of any change made by hand via psql or the -Supabase dashboard. If your migration history is squashed, the column's +history is outside what it can see: a column encrypted by hand via psql or the +Supabase dashboard is still described as plaintext by the corpus. If your migration history is squashed, the column's `CREATE TABLE` lives outside the directory being swept, or the database has simply drifted from what the migrations describe, you will see the statement flagged instead of repaired: check the column's current type in the database diff --git a/.changeset/skills-eql-v3-accuracy.md b/.changeset/skills-eql-v3-accuracy.md index 75c9f55de..b892b60a0 100644 --- a/.changeset/skills-eql-v3-accuracy.md +++ b/.changeset/skills-eql-v3-accuracy.md @@ -10,16 +10,15 @@ rollout tooling was v2-only. Since these skills are copied into customer repos, stale text steered users away from v3 and toward workarounds they no longer need. - **`stash-drizzle`, `stash-supabase`** — replaced the "v3 not supported end-to-end" - callouts with an accurate EQL version note: the tooling auto-detects a column's - generation from its Postgres domain type, and the two lifecycles differ at the end. - v3 is `backfill → switch the app to the encrypted column by name → drop` with no - cut-over rename; v2 keeps the `stash encrypt cutover` rename plus config promotion. + callouts with an accurate EQL version note: the tooling classifies a column from + its Postgres domain type, and the documented lifecycle is + `backfill → switch the app to the encrypted column by name → drop` — there is no + cut-over rename. - **`stash-supabase`** — removed the "Interim path until #648: the v2 encrypted twin" section; a v2 twin is no longer needed to get CLI-managed backfill. - **`stash-drizzle`, `stash-supabase`** — the drop step now documents that - `stash encrypt drop` targets the *original* column under v3 (there is no - `_plaintext`, since nothing was renamed) and `_plaintext` under v2. -- **`stash-cli`** — corrected the documented `EQLInstaller` default: `eqlVersion` - defaults to `3`, not `2`, matching the `--eql-version` CLI default. Also reworded - the v2 cut-over known-gap note, which cited cipherstash/stack#585 as open tracking - when it was resolved by making v3 the default. + `stash encrypt drop` targets the *original* column (there is no + `_plaintext`, since nothing is renamed). +- **`stash-cli`** — corrected the documented `EQLInstaller` default (EQL v3) and + removed the v2 cut-over known-gap note, which cited cipherstash/stack#585 as open + tracking when it was resolved by making v3 the default. diff --git a/.changeset/skills-pin-stable-1-0.md b/.changeset/skills-pin-stable-1-0.md new file mode 100644 index 000000000..cfe7a9c6a --- /dev/null +++ b/.changeset/skills-pin-stable-1-0.md @@ -0,0 +1,21 @@ +--- +'stash': patch +--- + +The bundled skills pin `1.0.0`, not a release candidate (#791). + +`skills/stash-edge` hardcoded `@cipherstash/stack@1.0.0-rc.4` in its Deno `npm:` +import and its `deno.json` import map, and `skills/stash-cli` pinned the +bare-project `npx --package=stash@…` one-shot the same way. Nothing in the build +rewrites those literals — `tsup.config.ts` copies `skills/` verbatim, and the +`__STASH_RUNTIME_VERSIONS__` embed only reaches compiled CLI code — so the +published skill would have told Deno and Supabase Edge Function users to pin a +release candidate in production, in their own repo, indefinitely. + +The prerelease-semver paragraph that explained why `@^1.0.0` does not match +`1.0.0-rc.4` is gone with the rc pin; "pin exactly, Deno caches by specifier" +stands on its own. The `supabase-worker` example pins the same way. + +A test now guards every `skills/*/SKILL.md`: an exact pin of a release-train +package must name a stable version on the current major, so a stale rc pin fails +on the version-bump PR instead of shipping. diff --git a/.changeset/skills-v3-lifecycle-honesty.md b/.changeset/skills-v3-lifecycle-honesty.md deleted file mode 100644 index 2c29c1d0e..000000000 --- a/.changeset/skills-v3-lifecycle-honesty.md +++ /dev/null @@ -1,29 +0,0 @@ ---- -'stash': patch ---- - -Correct the EQL v2/v3 rollout lifecycle in the bundled `stash-encryption`, -`stash-supabase` and `stash-drizzle` agent skills. Each described the **v2** -lifecycle as the unqualified default even though v3 is the default generation, -so an agent following the prose would run steps that do not apply — and, in one -case, expect the wrong column to be dropped. - -- `stash encrypt drop` was documented as removing `_plaintext`. That is the - **v2** target. On a v3 column there is no `_plaintext`: the command drops - the **original ``**, guarded by a `DO` block that takes `ACCESS EXCLUSIVE` - and re-counts unencrypted rows at apply time, raising instead of dropping if - any remain. Each step in the cutover table is now marked v2-only or v3, and the - drop preconditions (`cut-over` for v2, `backfilled` for v3) are stated. -- "The pending row will be promoted to active by `stash encrypt cutover`" was - false for v3, where cutover short-circuits before touching any configuration. - `stash db activate` is the only promotion path there. -- The CipherStash Proxy call-outs told every reader to run `stash db push`. - `db push`/`db activate` manage `eql_v2_configuration`, which EQL v3 does not - ship — on a v3-only database `db push` reports "Nothing to do." and exits 0, - and `db activate` errors. The call-outs are now scoped to the EQL v2 + Proxy - path. - -Skills ship inside the `stash` tarball and are copied into user projects at -`stash init`, so this guidance was being installed into customer repos. - -Superseded later in this release: the bundled skills no longer document v2/Proxy mutation commands because those CLI paths are removed. diff --git a/.changeset/stash-cli-eql-v3-default.md b/.changeset/stash-cli-eql-v3-default.md deleted file mode 100644 index b6eb6da19..000000000 --- a/.changeset/stash-cli-eql-v3-default.md +++ /dev/null @@ -1,14 +0,0 @@ ---- -"stash": minor ---- - -Default EQL to v3 and stop the CLI recommending `stash db push` (#585). - -- **EQL v3 is now the default.** `stash eql install` and `stash eql upgrade` target v3 (the native `eql_v3.*` domain schema) without `--eql-version 3`. The v2-only paths — `--drizzle`, `--migration`, `--migrations-dir`, and `--latest` — now require an explicit `--eql-version 2` and error with clear guidance otherwise (v3 installs via the direct path only). `stash init` pins v2 automatically when it drives the Drizzle migration flow. **Note:** for a Supabase project, `stash init` now runs a v3 direct install rather than offering the v2 migration-file flow; run `stash eql install --supabase --migration --eql-version 2` if you want a checked-in migration file. -- **`stash db push` is no longer recommended in CLI output.** `db push` writes the `public.eql_v2_configuration` table, which is a v2 + CipherStash Proxy artifact — EQL v3 has no configuration table (config lives in each column's `eql_v3.*` type) and nothing in the v3 stack reads it. The push recommendations are removed from `eql status`, the help banner, and the init/plan/cutover guidance. `db push` (and `db activate`) remain available for EQL v2 + Proxy users; they're now labelled as such. -- **`eql status` is v3-aware.** On a v3-only database it reports that encrypt config lives in the column types instead of hitting a "table not found" dead-end that told users to run `db push` (which neither creates that table nor applies to v3). -- **`stash db push` guards a v3-only database** with a clear "not needed under EQL v3" message instead of a raw `relation "public.eql_v2_configuration" does not exist` error. - -**Superseded later in this release:** the CLI no longer installs or mutates EQL -v2 state; `db push`, `db activate`, the Proxy choice, and the v2 install flags -described above are removed. Legacy state remains visible through status only. diff --git a/.changeset/stash-cli-skill-refresh.md b/.changeset/stash-cli-skill-refresh.md index a2e62330b..7d524448f 100644 --- a/.changeset/stash-cli-skill-refresh.md +++ b/.changeset/stash-cli-skill-refresh.md @@ -20,14 +20,9 @@ handoff time, so a stale skill becomes stale guidance in the user's project. entirely, plus the non-interactive interface (per-command escape hatches, exit codes, the `DATABASE_URL` resolution order, the `auth login --json` NDJSON event contract). - **Corrects the `db` → `eql` move.** `db install`, `db upgrade`, and `db status` are - deprecated aliases that warn and forward; `db push`, `db activate`, `db validate`, - `db test-connection`, and `db migrate` remain in the `db` group. -- **Scopes `db push` / `db activate` as EQL v2 + CipherStash Proxy only**, in both the skill - and the README's recommended flow. SDK users hold their encryption config in application - code and don't need them. -- Adds the missing `--database-url`, `--eql-version`, `--prisma-next`, `--proxy`/`--no-proxy`, - and `--region` flags; corrects six programmatic API signatures; fixes the README's claim + deprecated aliases that warn and forward; `db validate`, `db test-connection`, and + `db migrate` remain in the `db` group. +- Adds the missing `--database-url`, `--prisma-next`, and `--region` flags; corrects + six programmatic API signatures; fixes the README's claim that `stash init` ends in an agent-handoff menu (that belongs to `stash plan` / `stash impl`); and marks `stash env` as the non-functional stub it currently is. - -Superseded later in this release: the v2/Proxy commands and flags listed above are removed from both the CLI and bundled skill. diff --git a/.changeset/stash-supabase-contains-substrings.md b/.changeset/stash-supabase-contains-substrings.md index ca0df909a..c184442ca 100644 --- a/.changeset/stash-supabase-contains-substrings.md +++ b/.changeset/stash-supabase-contains-substrings.md @@ -2,8 +2,8 @@ "stash": patch --- -Correct the bundled `stash-supabase` agent skill: EQL v3 `contains()` matches -substrings. The skill previously carried the reverse — that `contains()` matched +Correct the bundled `stash-supabase` agent skill: encrypted free-text search +matches substrings. The skill previously carried the reverse — that it matched only exact values because the query's bloom filter appended the whole search term as an extra token. That was never true: `include_original` is inert in protect-ffi (the match bloom is trigram-only either way), so any substring of at diff --git a/.changeset/supabase-in-list-operands.md b/.changeset/supabase-in-list-operands.md index 360e23370..f4b5fa1b0 100644 --- a/.changeset/supabase-in-list-operands.md +++ b/.changeset/supabase-in-list-operands.md @@ -1,5 +1,5 @@ --- -'@cipherstash/stack': minor +'@cipherstash/stack-supabase': minor --- Fix encrypted `in`-list operands in the Supabase adapter, and widen the `is` / @@ -16,9 +16,7 @@ in.("{"v":1,"c":"…"}",…) ``` Encrypted lists are now emitted through `filter(col, 'in', …)` with each element -quoted and escaped, matching what the `.or()` path already did. This affects -**v2 as well as v3** — v2's `("a@b.com")` composite literal is itself -quote-bearing and was equally broken. +quoted and escaped, matching what the `.or()` path already did. **`not(col, 'in', […])` encrypted the whole list as a single ciphertext**, so the filter silently matched nothing, and emitted an unparenthesized @@ -30,11 +28,8 @@ array. **`filter(col, 'in', […])` encrypted the whole list as a single ciphertext.** The raw `.filter()` path reached `in` with none of the element-splitting the `in()`, `not(…, 'in', …)` and `.or()` paths perform, so the entire list operand -was encrypted as one equality term. The two wire formats then failed -differently, which is why this went unnoticed: **v2**'s `("json")` composite -literal is already parenthesized, so PostgREST parsed it as a one-element list -and answered `200 []` — a filter that silently matched nothing. **v3**'s bare -`{…}` envelope is not, so PostgREST rejected the request outright with +was encrypted as one equality term. A bare `{…}` envelope is not parenthesized, +so PostgREST rejected the request outright with `PGRST100 (failed to parse filter)`. Each element is now encrypted separately and the operand rendered as a quoted @@ -56,7 +51,8 @@ plaintext jsonb/array column falls through to PostgREST's native containment, so `contains('tags', ['vip'])` and `contains('meta', { plan: 'pro' })` now typecheck. A plaintext SCALAR column does not: `@>` is undefined on `text`, so the operand type follows the column's own shape and a scalar rejects every -containment operand. Encrypted match columns still take a `string` token. +containment operand. Encrypted free-text search is `matches()`, which takes a +`string` token; `contains()` on an encrypted non-JSON column throws and names it. Relatedly, `.or([{ op: 'contains' }])` now emits PostgREST's `cs` operator for plaintext columns too — previously only encrypted conditions were translated, so a plaintext containment reached the wire as `.contains.` and failed to parse. @@ -87,6 +83,6 @@ ciphertext. **In-list operands encrypt in one crossing per column.** The element-wise `in` / `not.in` encoding above spent one ZeroKMS round-trip per element; terms are now grouped by column and each group takes a single `bulkEncrypt` call, matching the -Drizzle v3 path. Falls back to per-term encryption for clients without +Drizzle path. Falls back to per-term encryption for clients without `bulkEncrypt`, and rejects a bulk response whose length does not match the list rather than silently truncating the predicate. diff --git a/.changeset/supabase-is-null-operands.md b/.changeset/supabase-is-null-operands.md index 46478aa24..c4a2e19b8 100644 --- a/.changeset/supabase-is-null-operands.md +++ b/.changeset/supabase-is-null-operands.md @@ -1,5 +1,5 @@ --- -'@cipherstash/stack': patch +'@cipherstash/stack-supabase': patch --- Fix the Supabase adapter encrypting `is` and `null` filter operands. @@ -14,10 +14,9 @@ NULL column rather than ciphertext, so it is found with an unencrypted `IS NULL`; encrypting the operand could never match. A single `isEncryptableTerm(operator, value)` predicate now guards every term -collector. Affects both `encryptedSupabase` (v2) and `encryptedSupabaseV3`. On -v3 this additionally removes a spurious `does not support equality queries` -error, which `is` raised because it maps to the `equality` query type and so hit -the column-capability guard — `or('active.is.null')` on a storage-only column +collector. This additionally removes a spurious `does not support equality +queries` error, which `is` raised because it maps to the `equality` query type +and so hit the column-capability guard — `or('active.is.null')` on a storage-only column threw rather than querying. Relatedly, an `or()` string is now rebuilt whenever a condition *references* an diff --git a/.changeset/supabase-or-string-parser.md b/.changeset/supabase-or-string-parser.md index 25db66e67..84fd89975 100644 --- a/.changeset/supabase-or-string-parser.md +++ b/.changeset/supabase-or-string-parser.md @@ -1,8 +1,8 @@ --- -'@cipherstash/stack': patch +'@cipherstash/stack-supabase': patch --- -Fix the Supabase adapter's `.or()` string parser mis-splitting conditions, and pin `contains()` on a mixed union column key to the encrypted operand. +Fix the Supabase adapter's `.or()` string parser mis-splitting conditions. An `.or()` string is only rebuilt from its parse when it references an encrypted column — otherwise the caller's string is forwarded verbatim — so each of these corrupts precisely the mixed encrypted/plaintext case. @@ -15,5 +15,3 @@ An `.or()` string is only rebuilt from its parse when it references an encrypted **A parenthesized operand was read as a list for every operator.** Only `in` and the range operators (`ov`, `sl`, `sr`, `nxr`, `nxl`, `adj`) take a paren-delimited operand; elsewhere `(` is an ordinary character. `email.eq.(foo)` parsed as `['foo']` and encrypted a JS array rather than the string, matching nothing. **A string operand spelling `null`, `true` or `false` is now quoted.** PostgREST reads a bare `null` as SQL NULL, so `.or([{ column: 'name', op: 'eq', value: 'null' }])` emitted `name.eq.null` and compared against NULL instead of the three-character string. - -**`contains(col, …)` where `col` is a union spanning an encrypted and a plaintext column** accepted an array or object operand. The union is now only as permissive as its strictest member: any declared encrypted column in the union pins the operand to `string`. A literal column argument was never affected. diff --git a/.changeset/supabase-v3-order-by-ope-term.md b/.changeset/supabase-v3-order-by-ope-term.md index 33d450239..ad7d612db 100644 --- a/.changeset/supabase-v3-order-by-ope-term.md +++ b/.changeset/supabase-v3-order-by-ope-term.md @@ -1,34 +1,33 @@ --- -'@cipherstash/stack': minor +'@cipherstash/stack-supabase': minor --- -**`order()` now works on EQL v3 encrypted ordering columns in the Supabase -adapter.** It was rejected outright on every encrypted column. +**`order()` works on EQL v3 encrypted ordering columns.** -A bare `ORDER BY col` on an EQL v3 domain really is wrong — the bundle declares -no btree operator class on any domain, so the sort falls through to jsonb's -default `jsonb_cmp` and compares the envelope's keys in storage order, starting -at the random ciphertext `c`. Measured over ten rows it returns -`r00,r04,r08,r01,…` where the plaintext order is `r00..r09`. No error, a stable -and plausible-looking meaningless order. +A bare `ORDER BY col` on an EQL v3 domain is wrong — the bundle declares no btree +operator class on any domain, so the sort falls through to jsonb's default +`jsonb_cmp` and compares the envelope's keys in storage order, starting at the +random ciphertext `c`. Measured over ten rows it returns `r00,r04,r08,r01,…` +where the plaintext order is `r00..r09`. No error, a stable and +plausible-looking meaningless order. But the correct sort key is reachable without a function call. `eql_v3.ord_term` returns the domain's `op` term, and OPE is order-preserving, so ordering by the term reproduces the plaintext order. PostgREST cannot emit -`ORDER BY eql_v3.ord_term(col)`, but it can emit a jsonb path. The builder now -emits `order=col->op` for an encrypted ordering column, verified against a live -PostgREST for `integer_ord` and `text_search` in both directions. +`ORDER BY eql_v3.ord_term(col)`, but it can emit a jsonb path. The builder emits +`order=col->op` for an encrypted ordering column, verified against a live +PostgREST for `eql_v3_integer_ord` and `eql_v3_text_search` in both directions. -The guard is now on the ordering FLAVOUR, not on encryption: +The guard is on the ordering FLAVOUR, not on encryption: -- **`ope` present → supported.** Every plain `*_ord` domain, plus `text_ord` and - `text_search`. +- **`ope` present → supported.** Every plain `eql_v3_*_ord` domain, plus + `eql_v3_text_ord` and `eql_v3_text_search`. - **`ore` present → rejected.** The `ob` term is an array of ORE blocks whose comparison needs the superuser-only operator class, which no jsonb path can reach. (Such a column cannot hold data on managed Postgres anyway: its domain - CHECK raises `ore_domain_unavailable`.) ORE columns are now excluded from - `order()` at COMPILE time too, not only at runtime — `.order(oreColumn)` is a - type error, matching the rejection. + CHECK raises `ore_domain_unavailable`.) ORE columns are excluded from `order()` + at COMPILE time as well as at runtime — `.order(oreColumn)` is a type error, + matching the rejection. - **neither → rejected.** Storage-only, equality-only and match-only columns carry no ordering term. @@ -40,8 +39,8 @@ numeric and date domains, and per-character (16 hex chars each) for text, so lexicographic order reproduces plaintext order including the prefix case (`ada` < `adam`). `ope-term.integration.test.ts` pins that shape. -`V3OrderableKeys` widens to admit OPE-backed ordering columns (`*_ord`, -`text_ord`, `text_search`) while still excluding ORE (`*_ord_ore`) columns, so -`order()` typechecks exactly where it works. `is(col, true)` is unaffected — it -stays plaintext-only, and now has its own `V3PlaintextKeys` rather than -borrowing the orderable set. +`OrderableKeys` admits OPE-backed ordering columns (`eql_v3_*_ord`, +`eql_v3_text_ord`, `eql_v3_text_search`) while excluding ORE +(`eql_v3_*_ord_ore`) columns, so `order()` typechecks exactly where it works. +`is(col, true)` is unaffected — it stays plaintext-only, with its own +`PlaintextKeys` rather than borrowing the orderable set. diff --git a/DIFFERENTIAL_REVIEW_REPORT.md b/DIFFERENTIAL_REVIEW_REPORT.md new file mode 100644 index 000000000..40509631b --- /dev/null +++ b/DIFFERENTIAL_REVIEW_REPORT.md @@ -0,0 +1,161 @@ +# Differential Review Report — PR #772 + +## Executive Summary + +| Severity | Count | +|---|---:| +| Critical | 0 | +| High | 3 | +| Medium | 3 | +| Low | 0 | + +**Overall risk:** High +**Recommendation:** Conditional — reconcile the release contract and changesets before merge/release. + +**Key metrics:** + +- Range: `origin/main...origin/remove-v2` at `3a6395c2` +- PR size: 397 files, +20,083 / -30,091 +- Pending changesets inspected: 124; changed changeset markdown files: 42 +- Current GitHub checks: all reported checks passing +- Security regressions found: none in the focused scope + +## What Changed + +PR #772 removes EQL v2 authoring surfaces across core packages and adapters while retaining selected legacy read/migration paths. The review concentrated on public API consistency, the CLI handoff prompt, and the pending changesets that will be consolidated for the 1.0.0 release. + +## Findings + +### HIGH — Supabase handoff names a nonexistent EQL domain + +**Files:** + +- `packages/cli/src/commands/init/lib/setup-prompt.ts:103` +- `packages/cli/src/commands/init/lib/__tests__/setup-prompt.test.ts:190-192` +- `.changeset/decrypt-chaining-docs.md:34-36` + +The generated `stash init` agent prompt tells Supabase users to declare `eql_v3_encrypted`. EQL v3 has no catch-all domain; columns must use a concrete `public.eql_v3_*` domain such as `public.eql_v3_text_search`. The test and changeset repeat the invalid name, so CI currently preserves the defect. + +**Recommendation:** Name the appropriate concrete-domain family (with an example), and update the test and changeset together. + +### HIGH — The consolidated changelog advertises APIs removed by the same release + +**Primary files:** + +- `.changeset/adapter-package-split.md:12-24` +- `.changeset/adapter-split-skills.md:7-9` +- `.changeset/eql-v3-drizzle.md:5-13` +- `.changeset/eql-v3-adapter-type-robustness.md:26-28` +- `.changeset/eql-v3-drizzle-fail-open-guards.md:7-37` +- `.changeset/eql-v3-rename-contains-to-matches.md:14` +- `.changeset/init-drizzle-eql-v3.md:11-14` +- `.changeset/init-placeholder-eql-v3.md:15-23` +- `.changeset/eql-v3-supabase-adapter.md:25-66` + +A simulated `changeset pre exit` followed by `changeset version` generated 1.0.0 notes that direct users to `@cipherstash/stack-drizzle/v3`, `createEncryptionOperatorsV3`, and `extractEncryptionSchemaV3`, while the same section later says those have no aliases and are removed. The Supabase entry also says encrypted ordering is always rejected, free-text uses `contains`, and the v2 wrapper is unchanged; later entries respectively add OPE ordering, rename the operator to `matches`, and remove the v2 wrapper. + +**Recommendation:** Rewrite the consumed changesets to describe the final 1.0 surface, rather than retaining intermediate RC states or a “superseded later” paragraph. + +### HIGH — The release notes promise v3-only authoring while the exported client code on `remove-v2` still emits v2 + +**Files:** + +- `.changeset/stack-audit-on-decrypt.md:51-54` +- `.changeset/reject-v2-wire-over-v3-schemas.md:22-30` +- `packages/stack/src/encryption/index.ts:85-95,140-154` + +Here, “exported client” means the consumer-reachable `Encryption()` API in the +code on this branch, not the version currently published to npm. One changeset +states that the client authors EQL v3 only. Another says an EQL v2 schema plus +`eqlVersion: 2` still emits v2 and recommends building that client; the branch +implementation also defaults an all-v2 schema set to the FFI's v2 wire format. +The consolidated changelog therefore gives incompatible guarantees, and the +implementation follows the latter. + +**Recommendation:** Decide the final supported contract. If v2 emission remains a migration escape hatch, document it consistently; if authoring is v3-only, reject the public v2 write path and mint compatibility fixtures through an internal test mechanism. + +### MEDIUM — Adapter fixes are assigned to the core package changelog + +**Files/frontmatter:** + +- `.changeset/eql-v3-adapter-type-robustness.md:2` +- `.changeset/eql-v3-drizzle-fail-open-guards.md:2` +- `.changeset/eql-v3-drizzle.md:2` +- `.changeset/eql-v3-supabase-adapter.md:2` +- `.changeset/supabase-in-list-operands.md:2` +- `.changeset/supabase-is-null-operands.md:2` +- `.changeset/supabase-or-string-parser.md:2` +- `.changeset/supabase-v3-order-by-ope-term.md:2` + +These entries describe code that ends the release in `@cipherstash/stack-drizzle` or `@cipherstash/stack-supabase`, but their frontmatter targets only `@cipherstash/stack`. The simulated GA changelogs put the details in core and omit them from the adapter package that actually exposes the behavior. + +**Recommendation:** Re-home each changeset to the final owning adapter package; retain a core bump only where the entry also describes a real core API change. + +### MEDIUM — DynamoDB changeset contradicts the typed decrypt audit surface + +**Files:** + +- `.changeset/dynamodb-eql-v3.md:10-12,39-40` +- `.changeset/stack-audit-on-decrypt.md:6-18` +- `.changeset/stack-skills-eql-v3-audit.md:6-12` + +`dynamodb-eql-v3.md` says the typed `EncryptionV3` client has no decrypt audit surface and that audit requires the nominal client. The same release adds audit chaining to the typed client and explicitly removes that caveat. + +**Recommendation:** Update the original DynamoDB entry to the final `Encryption` typed-client behavior and remove the nominal-client-only warning. + +### MEDIUM — `@cipherstash/nextjs` receives an unrelated deletion changelog entry + +**Files:** + +- `.changeset/remove-eql-v2-packages.md:2-4` +- `packages/nextjs/package.json:4,33` + +The changeset bumps `@cipherstash/nextjs`, but its body only discusses deleting `protect`, `schema`, and `protect-dynamodb`. The actual Next.js changes are a package-description correction and a typecheck script, so the generated Next.js changelog claims work that package did not perform. + +**Recommendation:** Split the Next.js metadata change into its own changeset or add a package-specific paragraph that accurately explains its patch. + +## Test Coverage Analysis + +- `git diff --check origin/main...origin/remove-v2`: passed. +- GitHub's current lint, unit, E2E, integration, CodeQL, OSV, and complexity checks: passed. +- Changesets validation: ran `changeset status`, then simulated prerelease exit and `changeset version` in an isolated clone; generated versions were 1.0.0 and reproduced the contradictions above. +- No live ZeroKMS tests were run locally. + +The invalid Supabase-domain prompt has a unit assertion, but the assertion checks the wrong literal rather than validating it against the EQL domain catalog. + +## Blast Radius Analysis + +The code defect affects every Supabase `stash init` handoff that follows the generated schema-authoring step. The changeset issues affect the first stable 1.0 changelogs for the fixed release train and can direct all Drizzle/Supabase adopters to removed APIs. + +## Historical Context + +The contradictory entries were introduced across prerelease work and remain editable because Changesets retains consumed markdown during prerelease mode for the final stable aggregation. Several branch changes already corrected individual entries, but the final release simulation shows the remaining set still needs reconciliation. + +## Recommendations + +### Immediate + +- Correct `eql_v3_encrypted` in the CLI prompt, test, and changeset. +- Normalize pending changesets to the final API surface before exiting prerelease mode. +- Resolve and document the v2-emission contract. + +### Before release + +- Generate the 1.0 changelogs in a disposable worktree and lint them for removed specifiers/symbols. +- Add a test that validates domain names used in generated prompts against the concrete EQL domain family. + +## Analysis Methodology + +**Strategy:** Surgical/focused because the PR spans 397 files. + +Techniques used: + +- Established the live PR base/head from GitHub and refreshed refs. +- Reviewed the full changeset set, not only changed changesets. +- Compared claims against final exports, implementation, tests, and repository guidance. +- Simulated the final Changesets prerelease-exit/version workflow. +- Checked existing PR reviews to avoid treating already-resolved comments as new findings. + +**Limitations:** This was not a line-by-line audit of all 397 files. Product-code review concentrated on public API boundaries implicated by the changesets and the newly generated CLI guidance. No credentialed live encryption tests were run locally. + +**Confidence:** High for the listed findings; medium for the untouched portions of the overall PR. diff --git a/examples/supabase-worker/supabase/functions/cipherstash-roundtrip/index.ts b/examples/supabase-worker/supabase/functions/cipherstash-roundtrip/index.ts index ada5f2d07..db3a49f4d 100644 --- a/examples/supabase-worker/supabase/functions/cipherstash-roundtrip/index.ts +++ b/examples/supabase-worker/supabase/functions/cipherstash-roundtrip/index.ts @@ -18,7 +18,7 @@ import { encryptedTable, isEncrypted, types, -} from 'npm:@cipherstash/stack@^1.0.0-rc.3/wasm-inline' +} from 'npm:@cipherstash/stack@1.0.0/wasm-inline' // EQL v3: the WASM entry exports the v3 authoring surface only (`types.*`), // not the v2 chainable builders — `encryptedColumn('email').equality()` is diff --git a/packages/cli/src/__tests__/release-train.test.ts b/packages/cli/src/__tests__/release-train.test.ts index 64dc1da48..3c8d5afee 100644 --- a/packages/cli/src/__tests__/release-train.test.ts +++ b/packages/cli/src/__tests__/release-train.test.ts @@ -1,4 +1,4 @@ -import { readFileSync } from 'node:fs' +import { readdirSync, readFileSync } from 'node:fs' import { dirname, resolve } from 'node:path' import { fileURLToPath } from 'node:url' import { describe, expect, it } from 'vitest' @@ -7,6 +7,21 @@ import { RELEASE_TRAIN_MANIFESTS } from '../release-train.js' const CLI_ROOT = resolve(dirname(fileURLToPath(import.meta.url)), '../..') const REPO_ROOT = resolve(CLI_ROOT, '../..') +const SKILLS_ROOT = resolve(REPO_ROOT, 'skills') + +/** The stable version a workspace manifest belongs to: `1.0.0-rc.4` → `1.0.0`. */ +function stableVersion(version: string): string { + return version.split('-')[0] as string +} + +function manifestVersion(pkg: string): string { + const rel = RELEASE_TRAIN_MANIFESTS[pkg] + if (!rel) throw new Error(`${pkg} is not on the release train`) + const manifest = JSON.parse(readFileSync(resolve(CLI_ROOT, rel), 'utf8')) as { + version: string + } + return manifest.version +} // The growth guard for #661: `RELEASE_TRAIN_MANIFESTS` is the single source // the build embeds versions from, and `INTEGRATION_ADAPTER_PACKAGES` is what @@ -34,19 +49,71 @@ describe('release train coverage', () => { }) it('pins the bare-project stash invocation in the published CLI skill', () => { - const cliManifest = JSON.parse( - readFileSync(resolve(CLI_ROOT, 'package.json'), 'utf8'), - ) as { version: string } const skill = readFileSync( - resolve(REPO_ROOT, 'skills/stash-cli/SKILL.md'), + resolve(SKILLS_ROOT, 'stash-cli/SKILL.md'), 'utf8', ) + // The pin names the STABLE version of this release line, not the raw + // manifest version: the skill is read in a customer's repo against what is + // published, and a prerelease build's own `1.0.0-rc.4` would tell them to + // run a release candidate in production (#791). expect(skill).toContain( - `npx --package=stash@${cliManifest.version} stash eql install --database-url 'postgres://...'`, + `npx --package=stash@${stableVersion(manifestVersion('stash'))} stash eql install --database-url 'postgres://...'`, ) }) + // #791: `skills/` ships inside the `stash` tarball and is copied into + // customer repos by `stash init`, and NOTHING in the build rewrites the + // version literals inside it — `tsup.config.ts` copies the directory + // verbatim, and the `__STASH_RUNTIME_VERSIONS__` embed only reaches compiled + // CLI code. So a hardcoded `@cipherstash/stack@1.0.0-rc.4` would keep telling + // Deno and Supabase Edge users to pin a release candidate long after the + // stable release. This is the guard: it fires on the version-bump PR, when + // someone is in a position to update the surrounding prose too. + describe('skill version pins', () => { + const skillFiles = readdirSync(SKILLS_ROOT, { withFileTypes: true }) + .filter((entry) => entry.isDirectory()) + .map((entry) => ({ + skill: entry.name, + body: readFileSync( + resolve(SKILLS_ROOT, entry.name, 'SKILL.md'), + 'utf8', + ), + })) + + it('finds skills to check (a moved directory must not silently pass)', () => { + expect(skillFiles.length).toBeGreaterThan(0) + }) + + it.each( + skillFiles, + )('$skill pins release-train packages at a stable version on the current major', ({ + body, + }) => { + // Exact pins only (`pkg@1.2.3`, optionally `npm:`-prefixed and with a + // trailing subpath). A range spec (`^1.0.0`) carries its own semantics + // and is not a pin to check. + const PIN = + /(?:npm:)?(stash|@cipherstash\/[a-z0-9-]+)@(\d+\.\d+\.\d+(?:-[0-9A-Za-z.-]+)?)/g + + for (const [, pkg, pinned] of body.matchAll(PIN)) { + if (!((pkg as string) in RELEASE_TRAIN_MANIFESTS)) continue + const current = manifestVersion(pkg as string) + + expect( + pinned, + `${pkg}@${pinned} pins a prerelease — skills ship to customers, so pin the stable release (${stableVersion(current)})`, + ).not.toContain('-') + + expect( + (pinned as string).split('.')[0], + `${pkg}@${pinned} is off this release line (${current}) — update the pin and the prose around it`, + ).toBe(stableVersion(current).split('.')[0]) + } + }) + }) + it('every train manifest exists and carries a version (what tsup will embed)', () => { // Exercises the exact inputs tsup.config.ts reads at build time, so a // renamed/moved workspace package fails HERE in source-mode tests, not diff --git a/skills/stash-cli/SKILL.md b/skills/stash-cli/SKILL.md index 6dbb9a987..52644619a 100644 --- a/skills/stash-cli/SKILL.md +++ b/skills/stash-cli/SKILL.md @@ -354,7 +354,7 @@ Gets a project from zero to a direct EQL v3 install. It loads an existing `stash The removed `--eql-version`, `--latest`, `--drizzle`, `--migration`, `--direct`, `--migrations-dir`, and `--exclude-operator-family` options fail clearly instead of being ignored. A request for EQL v2 points dump-recovery users to the upstream EQL 2.3.1 SQL release. New installs are EQL v3 only; its pinned bundle self-adapts when a database role cannot create the optional operator family. -**`--database-url` is a one-shot.** It installs against that database and leaves the project untouched — no config is loaded, and none is scaffolded, nor is an encryption client. This lets `npx --package=stash@1.0.0-rc.4 stash eql install --database-url 'postgres://...'` run in a bare project with no CipherStash dependencies while pinning the CLI to this skill's release. It also means the flag always wins: loading a config could pick up a parent-directory `databaseUrl` literal and install against the wrong database. +**`--database-url` is a one-shot.** It installs against that database and leaves the project untouched — no config is loaded, and none is scaffolded, nor is an encryption client. This lets `npx --package=stash@1.0.0 stash eql install --database-url 'postgres://...'` run in a bare project with no CipherStash dependencies while pinning the CLI to this skill's release. It also means the flag always wins: loading a config could pick up a parent-directory `databaseUrl` literal and install against the wrong database. #### `eql migration` diff --git a/skills/stash-edge/SKILL.md b/skills/stash-edge/SKILL.md index ae4a11efb..ca68d3c7c 100644 --- a/skills/stash-edge/SKILL.md +++ b/skills/stash-edge/SKILL.md @@ -56,15 +56,12 @@ build step. ```ts import { Encryption, encryptedTable, types, isEncrypted, -} from 'npm:@cipherstash/stack@1.0.0-rc.4/wasm-inline' +} from 'npm:@cipherstash/stack@1.0.0/wasm-inline' ``` **Pin an exact version.** Deno caches by specifier, so an unpinned import -drifts between deploys. And while the package is on a prerelease line, a -caret range does not do what it looks like: `@^1.0.0` will **not** match -`1.0.0-rc.4`, because semver ranges exclude prereleases unless the range -itself names one. Use the exact version, or a prerelease-bearing range -(`@^1.0.0-rc.4`). Check what is current with `npm view @cipherstash/stack dist-tags`. +drifts between deploys — pin, and bump the pin deliberately. Check what is +current with `npm view @cipherstash/stack dist-tags`. ### Deno with an import map @@ -74,7 +71,7 @@ name everywhere: ```jsonc { "imports": { - "@cipherstash/stack/wasm-inline": "npm:@cipherstash/stack@1.0.0-rc.4/wasm-inline" + "@cipherstash/stack/wasm-inline": "npm:@cipherstash/stack@1.0.0/wasm-inline" } } ``` From eca17583ed40118423e2bc463700c92e518802d8 Mon Sep 17 00:00:00 2001 From: Dan Draper Date: Thu, 30 Jul 2026 12:37:40 +1000 Subject: [PATCH 3/6] =?UTF-8?q?chore:=20drop=20DIFFERENTIAL=5FREVIEW=5FREP?= =?UTF-8?q?ORT.md=20=E2=80=94=20local=20review=20notes,=20committed=20by?= =?UTF-8?q?=20accident?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- DIFFERENTIAL_REVIEW_REPORT.md | 161 ---------------------------------- 1 file changed, 161 deletions(-) delete mode 100644 DIFFERENTIAL_REVIEW_REPORT.md diff --git a/DIFFERENTIAL_REVIEW_REPORT.md b/DIFFERENTIAL_REVIEW_REPORT.md deleted file mode 100644 index 40509631b..000000000 --- a/DIFFERENTIAL_REVIEW_REPORT.md +++ /dev/null @@ -1,161 +0,0 @@ -# Differential Review Report — PR #772 - -## Executive Summary - -| Severity | Count | -|---|---:| -| Critical | 0 | -| High | 3 | -| Medium | 3 | -| Low | 0 | - -**Overall risk:** High -**Recommendation:** Conditional — reconcile the release contract and changesets before merge/release. - -**Key metrics:** - -- Range: `origin/main...origin/remove-v2` at `3a6395c2` -- PR size: 397 files, +20,083 / -30,091 -- Pending changesets inspected: 124; changed changeset markdown files: 42 -- Current GitHub checks: all reported checks passing -- Security regressions found: none in the focused scope - -## What Changed - -PR #772 removes EQL v2 authoring surfaces across core packages and adapters while retaining selected legacy read/migration paths. The review concentrated on public API consistency, the CLI handoff prompt, and the pending changesets that will be consolidated for the 1.0.0 release. - -## Findings - -### HIGH — Supabase handoff names a nonexistent EQL domain - -**Files:** - -- `packages/cli/src/commands/init/lib/setup-prompt.ts:103` -- `packages/cli/src/commands/init/lib/__tests__/setup-prompt.test.ts:190-192` -- `.changeset/decrypt-chaining-docs.md:34-36` - -The generated `stash init` agent prompt tells Supabase users to declare `eql_v3_encrypted`. EQL v3 has no catch-all domain; columns must use a concrete `public.eql_v3_*` domain such as `public.eql_v3_text_search`. The test and changeset repeat the invalid name, so CI currently preserves the defect. - -**Recommendation:** Name the appropriate concrete-domain family (with an example), and update the test and changeset together. - -### HIGH — The consolidated changelog advertises APIs removed by the same release - -**Primary files:** - -- `.changeset/adapter-package-split.md:12-24` -- `.changeset/adapter-split-skills.md:7-9` -- `.changeset/eql-v3-drizzle.md:5-13` -- `.changeset/eql-v3-adapter-type-robustness.md:26-28` -- `.changeset/eql-v3-drizzle-fail-open-guards.md:7-37` -- `.changeset/eql-v3-rename-contains-to-matches.md:14` -- `.changeset/init-drizzle-eql-v3.md:11-14` -- `.changeset/init-placeholder-eql-v3.md:15-23` -- `.changeset/eql-v3-supabase-adapter.md:25-66` - -A simulated `changeset pre exit` followed by `changeset version` generated 1.0.0 notes that direct users to `@cipherstash/stack-drizzle/v3`, `createEncryptionOperatorsV3`, and `extractEncryptionSchemaV3`, while the same section later says those have no aliases and are removed. The Supabase entry also says encrypted ordering is always rejected, free-text uses `contains`, and the v2 wrapper is unchanged; later entries respectively add OPE ordering, rename the operator to `matches`, and remove the v2 wrapper. - -**Recommendation:** Rewrite the consumed changesets to describe the final 1.0 surface, rather than retaining intermediate RC states or a “superseded later” paragraph. - -### HIGH — The release notes promise v3-only authoring while the exported client code on `remove-v2` still emits v2 - -**Files:** - -- `.changeset/stack-audit-on-decrypt.md:51-54` -- `.changeset/reject-v2-wire-over-v3-schemas.md:22-30` -- `packages/stack/src/encryption/index.ts:85-95,140-154` - -Here, “exported client” means the consumer-reachable `Encryption()` API in the -code on this branch, not the version currently published to npm. One changeset -states that the client authors EQL v3 only. Another says an EQL v2 schema plus -`eqlVersion: 2` still emits v2 and recommends building that client; the branch -implementation also defaults an all-v2 schema set to the FFI's v2 wire format. -The consolidated changelog therefore gives incompatible guarantees, and the -implementation follows the latter. - -**Recommendation:** Decide the final supported contract. If v2 emission remains a migration escape hatch, document it consistently; if authoring is v3-only, reject the public v2 write path and mint compatibility fixtures through an internal test mechanism. - -### MEDIUM — Adapter fixes are assigned to the core package changelog - -**Files/frontmatter:** - -- `.changeset/eql-v3-adapter-type-robustness.md:2` -- `.changeset/eql-v3-drizzle-fail-open-guards.md:2` -- `.changeset/eql-v3-drizzle.md:2` -- `.changeset/eql-v3-supabase-adapter.md:2` -- `.changeset/supabase-in-list-operands.md:2` -- `.changeset/supabase-is-null-operands.md:2` -- `.changeset/supabase-or-string-parser.md:2` -- `.changeset/supabase-v3-order-by-ope-term.md:2` - -These entries describe code that ends the release in `@cipherstash/stack-drizzle` or `@cipherstash/stack-supabase`, but their frontmatter targets only `@cipherstash/stack`. The simulated GA changelogs put the details in core and omit them from the adapter package that actually exposes the behavior. - -**Recommendation:** Re-home each changeset to the final owning adapter package; retain a core bump only where the entry also describes a real core API change. - -### MEDIUM — DynamoDB changeset contradicts the typed decrypt audit surface - -**Files:** - -- `.changeset/dynamodb-eql-v3.md:10-12,39-40` -- `.changeset/stack-audit-on-decrypt.md:6-18` -- `.changeset/stack-skills-eql-v3-audit.md:6-12` - -`dynamodb-eql-v3.md` says the typed `EncryptionV3` client has no decrypt audit surface and that audit requires the nominal client. The same release adds audit chaining to the typed client and explicitly removes that caveat. - -**Recommendation:** Update the original DynamoDB entry to the final `Encryption` typed-client behavior and remove the nominal-client-only warning. - -### MEDIUM — `@cipherstash/nextjs` receives an unrelated deletion changelog entry - -**Files:** - -- `.changeset/remove-eql-v2-packages.md:2-4` -- `packages/nextjs/package.json:4,33` - -The changeset bumps `@cipherstash/nextjs`, but its body only discusses deleting `protect`, `schema`, and `protect-dynamodb`. The actual Next.js changes are a package-description correction and a typecheck script, so the generated Next.js changelog claims work that package did not perform. - -**Recommendation:** Split the Next.js metadata change into its own changeset or add a package-specific paragraph that accurately explains its patch. - -## Test Coverage Analysis - -- `git diff --check origin/main...origin/remove-v2`: passed. -- GitHub's current lint, unit, E2E, integration, CodeQL, OSV, and complexity checks: passed. -- Changesets validation: ran `changeset status`, then simulated prerelease exit and `changeset version` in an isolated clone; generated versions were 1.0.0 and reproduced the contradictions above. -- No live ZeroKMS tests were run locally. - -The invalid Supabase-domain prompt has a unit assertion, but the assertion checks the wrong literal rather than validating it against the EQL domain catalog. - -## Blast Radius Analysis - -The code defect affects every Supabase `stash init` handoff that follows the generated schema-authoring step. The changeset issues affect the first stable 1.0 changelogs for the fixed release train and can direct all Drizzle/Supabase adopters to removed APIs. - -## Historical Context - -The contradictory entries were introduced across prerelease work and remain editable because Changesets retains consumed markdown during prerelease mode for the final stable aggregation. Several branch changes already corrected individual entries, but the final release simulation shows the remaining set still needs reconciliation. - -## Recommendations - -### Immediate - -- Correct `eql_v3_encrypted` in the CLI prompt, test, and changeset. -- Normalize pending changesets to the final API surface before exiting prerelease mode. -- Resolve and document the v2-emission contract. - -### Before release - -- Generate the 1.0 changelogs in a disposable worktree and lint them for removed specifiers/symbols. -- Add a test that validates domain names used in generated prompts against the concrete EQL domain family. - -## Analysis Methodology - -**Strategy:** Surgical/focused because the PR spans 397 files. - -Techniques used: - -- Established the live PR base/head from GitHub and refreshed refs. -- Reviewed the full changeset set, not only changed changesets. -- Compared claims against final exports, implementation, tests, and repository guidance. -- Simulated the final Changesets prerelease-exit/version workflow. -- Checked existing PR reviews to avoid treating already-resolved comments as new findings. - -**Limitations:** This was not a line-by-line audit of all 397 files. Product-code review concentrated on public API boundaries implicated by the changesets and the newly generated CLI guidance. No credentialed live encryption tests were run locally. - -**Confidence:** High for the listed findings; medium for the untouched portions of the overall PR. From 9effcf10a9af09322188f68164ff3f3d9d084e3b Mon Sep 17 00:00:00 2001 From: Dan Draper Date: Thu, 30 Jul 2026 13:39:59 +1000 Subject: [PATCH 4/6] feat(stack-prisma,cli,wizard,skills): rename @cipherstash/prisma-next to @cipherstash/stack-prisma Closes #842 (revised plan: all adapters use the stack- prefix). - @cipherstash/prisma-next -> @cipherstash/stack-prisma (dir packages/stack-prisma), matching @cipherstash/stack-drizzle and @cipherstash/stack-supabase, which keep their names. - skills/stash-prisma-next -> skills/stash-prisma; CLI/wizard skill maps, install-deps, release-train manifests, workflows, docs, and SECURITY.md updated to match. - examples/prisma package renamed @cipherstash/prisma-next-example -> @cipherstash/prisma-example. The prisma-next provider id, --prisma-next init flag, and prisma-next.config.ts detection are unchanged - they name the external Prisma Next framework (@prisma-next/*), not our package. Retained changesets and .changeset/{config,pre}.json are rewritten to the new name so the pre-mode exit in #843 versions and publishes @cipherstash/stack-prisma as 1.0.0 (the name is unclaimed on npm). --- .changeset/adapter-package-split.md | 2 +- .changeset/config.json | 2 +- .changeset/encryption-schema-arrays.md | 2 +- .changeset/eql-baked-digest-verified.md | 2 +- .changeset/eql-v3-prisma-next.md | 4 +- .changeset/pre.json | 8 +- .changeset/prisma-example-eql-v3.md | 2 +- .changeset/prisma-next-0-14.md | 2 +- .changeset/prisma-next-0-16.md | 4 +- .../prisma-next-drop-encrypted-prefix.md | 4 +- .changeset/prisma-next-eql-runtime-source.md | 2 +- .changeset/prisma-next-joins-release-train.md | 4 +- .changeset/prisma-next-migrate-command.md | 4 +- .changeset/prisma-next-skill-accuracy.md | 4 +- .changeset/prisma-next-v3-client-config.md | 2 +- .changeset/prisma-next-v3-only-install.md | 4 +- .changeset/protect-ffi-030-json-selectors.md | 2 +- .changeset/release-train-coupling.md | 2 +- .changeset/rename-packages-1-0.md | 17 ++ .changeset/stack-logger-edge-safe.md | 2 +- .changeset/stash-indexing-skill.md | 2 +- .changeset/stash-prisma-next-skill-v3-only.md | 4 +- .changeset/stash-prisma-next-skill.md | 2 +- .../v3-only-config-typing-and-entry-parity.md | 2 +- .changeset/v3-only-encryption-client.md | 2 +- .changeset/v3-payload-routing.md | 2 +- .github/workflows/integration-prisma-next.yml | 6 +- .../workflows/prisma-example-readme-e2e.yml | 6 +- .github/workflows/prisma-next-e2e.yml | 18 +- .github/workflows/tests.yml | 4 +- AGENTS.md | 6 +- SECURITY.md | 2 +- examples/prisma/README.md | 6 +- examples/prisma/docker-compose.yml | 2 +- examples/prisma/package.json | 6 +- examples/prisma/prisma-next.config.ts | 2 +- examples/prisma/prisma/schema.prisma | 2 +- examples/prisma/src/db.ts | 2 +- examples/prisma/src/index.ts | 4 +- examples/prisma/test/e2e/README.md | 4 +- examples/prisma/test/e2e/bigint.e2e.test.ts | 2 +- examples/prisma/test/e2e/bool.e2e.test.ts | 2 +- examples/prisma/test/e2e/date.e2e.test.ts | 2 +- examples/prisma/test/e2e/json.e2e.test.ts | 2 +- examples/prisma/test/e2e/mixed.e2e.test.ts | 4 +- examples/prisma/test/e2e/num.e2e.test.ts | 2 +- .../prisma/test/e2e/str-range.e2e.test.ts | 2 +- .../src/__tests__/runtime-versions.test.ts | 6 +- .../prisma-next-install-guard.test.ts | 6 +- packages/cli/src/commands/db/detect.ts | 4 +- packages/cli/src/commands/db/install.ts | 2 +- .../commands/init/doctrine/AGENTS-doctrine.md | 2 +- .../lib/__tests__/build-agents-md.test.ts | 4 +- .../init/lib/__tests__/install-skills.test.ts | 8 +- .../init/lib/__tests__/setup-prompt.test.ts | 2 +- .../src/commands/init/lib/install-skills.ts | 2 +- .../cli/src/commands/init/lib/setup-prompt.ts | 4 +- .../commands/init/providers/prisma-next.ts | 2 +- .../src/commands/init/steps/install-deps.ts | 2 +- .../src/commands/init/steps/install-eql.ts | 2 +- packages/cli/src/release-train.ts | 2 +- .../CHANGELOG.md | 0 .../DEVELOPING.md | 4 +- .../{prisma-next => stack-prisma}/README.md | 10 +- .../integration/adapter.ts | 0 .../integration/families.integration.test.ts | 0 .../integration/json-adapter.ts | 0 .../integration/json.integration.test.ts | 0 .../integration/vitest.config.ts | 0 .../end-contract.d.ts | 0 .../end-contract.json | 0 .../migration.json | 0 .../migration.ts | 0 .../ops.json | 0 .../migration.json | 0 .../migration.ts | 0 .../ops.json | 0 .../migrations/refs/head.json | 0 .../package.json | 4 +- .../prisma-next.config.ts | 2 +- .../src/contract-authoring.ts | 0 .../src/contract.d.ts | 0 .../src/contract.json | 0 .../src/contract.prisma | 0 .../src/execution/abort.ts | 0 .../src/execution/decrypt-all.ts | 0 .../src/execution/envelope-base.ts | 0 .../src/execution/envelope-bigint.ts | 0 .../src/execution/envelope-boolean.ts | 0 .../src/execution/envelope-date.ts | 0 .../src/execution/envelope-json.ts | 0 .../src/execution/envelope-string.ts | 0 .../src/execution/middleware-registry.ts | 0 .../src/execution/routing.ts | 0 .../src/execution/sdk.ts | 0 .../src/exports/codec-types.ts | 0 .../src/exports/column-types.ts | 0 .../src/exports/contract-space-typing.ts | 0 .../src/exports/control.ts | 0 .../src/exports/operation-types.ts | 0 .../src/exports/pack.ts | 0 .../src/exports/runtime.ts | 0 .../src/exports/stack.ts | 2 +- .../src/exports/v3.ts | 2 +- .../src/extension-metadata/codec-metadata.ts | 0 .../src/extension-metadata/constants-v3.ts | 0 .../src/extension-metadata/constants.ts | 0 .../src/extension-metadata/descriptor-meta.ts | 0 .../src/migration/cipherstash-codec-v3.ts | 0 .../src/migration/eql-bundle-v3.ts | 0 .../src/stack/from-stack-v3.ts | 6 +- .../src/types/codec-types.ts | 0 .../src/types/operation-types.ts | 0 .../src/v3/barrel.ts | 0 .../src/v3/bulk-encrypt-v3.ts | 0 .../src/v3/catalog.ts | 0 .../src/v3/codec-runtime-v3.ts | 2 +- .../src/v3/derive-schemas-v3.ts | 2 +- .../src/v3/envelope-number.ts | 0 .../src/v3/from-stack-v3-validate.ts | 0 .../src/v3/operators-v3.ts | 2 +- .../src/v3/query-term.ts | 0 .../src/v3/runtime-v3.ts | 0 .../src/v3/sdk-adapter-v3.ts | 0 .../src/v3/wire-v3.ts | 0 .../test/abort.test.ts | 0 .../test/authoring.test.ts | 0 .../test/bulk-encrypt-middleware.helpers.ts | 0 .../test/bundling-isolation.test.ts | 2 +- .../test/column-types.test.ts | 0 .../test/decrypt-all.test.ts | 0 .../test/descriptor.test.ts | 0 .../test/envelope-bigint.test.ts | 0 .../test/envelope-boolean.test.ts | 0 .../test/envelope-date.test.ts | 0 .../test/envelope-json.test.ts | 0 .../test/envelope-string.test.ts | 0 .../test/envelope.types.test-d.ts | 0 .../test/equality-trait-removal.test.ts | 0 .../test/live/bigint-live-pg.test.ts | 0 .../test/live/boolean-storage-live-pg.test.ts | 0 .../test/live/bulk-encrypt-live-pg.test.ts | 0 .../test/live/helpers/eql-v3.ts | 0 .../test/live/helpers/harness.ts | 0 .../test/live/helpers/live-gate.ts | 0 .../test/live/migration-apply-live-pg.test.ts | 0 .../test/live/operators-live-pg.test.ts | 0 .../test/live/operators-null-live-pg.test.ts | 0 .../test/operation-types.types.test-d.ts | 0 .../test/psl-interpretation.test.ts | 0 .../test/routing.test.ts | 0 .../test/sdk.types.test-d.ts | 0 .../test/v3/bulk-encrypt-v3.test.ts | 0 .../test/v3/catalog-invariants.test.ts | 0 .../test/v3/catalog.test.ts | 0 .../test/v3/codec-runtime-v3.test.ts | 0 .../test/v3/codec-types-v3.test-d.ts | 0 .../test/v3/column-types.test-d.ts | 0 .../test/v3/constants-v3.test.ts | 0 .../test/v3/derive-schemas-v3.test.ts | 0 .../test/v3/envelope-number.test.ts | 0 .../test/v3/from-stack-divergence-v3.test.ts | 0 .../test/v3/from-stack-v3.test.ts | 0 .../test/v3/migration-v3.test.ts | 0 .../test/v3/operator-gating-v3.test.ts | 0 .../v3/operator-lowering-v3-equality.test.ts | 0 .../test/v3/operator-lowering-v3-json.test.ts | 0 .../operator-lowering-v3-order-range.test.ts | 0 .../operator-lowering-v3-text-search.test.ts | 0 .../test/v3/operator-lowering-v3.helpers.ts | 0 .../test/v3/properties.test.ts | 0 .../test/v3/runtime-v3.test.ts | 0 .../test/v3/sdk-adapter-v3.test.ts | 0 .../test/v3/vendored-space-parity.test.ts | 0 .../test/v3/wire-v3.test.ts | 0 .../tsconfig.json | 0 .../tsup.config.ts | 0 .../{prisma-next => stack-prisma}/turbo.json | 0 .../vitest.config.ts | 0 .../__tests__/logger-edge-safety.test.ts | 2 +- .../__tests__/types-public-surface.test-d.ts | 2 +- .../wasm-inline-bundle-isolation.test.ts | 2 +- packages/wizard/src/lib/install-skills.ts | 2 +- packages/wizard/tsconfig.json | 2 +- pnpm-lock.yaml | 194 +++++++++--------- .../workflow-turbo-build-deps.test.mjs | 4 +- skills/stash-deployment/SKILL.md | 8 +- skills/stash-encryption/SKILL.md | 2 +- skills/stash-indexing/SKILL.md | 4 +- skills/stash-postgres/SKILL.md | 2 +- .../SKILL.md | 30 +-- 191 files changed, 267 insertions(+), 248 deletions(-) create mode 100644 .changeset/rename-packages-1-0.md rename packages/{prisma-next => stack-prisma}/CHANGELOG.md (100%) rename packages/{prisma-next => stack-prisma}/DEVELOPING.md (99%) rename packages/{prisma-next => stack-prisma}/README.md (95%) rename packages/{prisma-next => stack-prisma}/integration/adapter.ts (100%) rename packages/{prisma-next => stack-prisma}/integration/families.integration.test.ts (100%) rename packages/{prisma-next => stack-prisma}/integration/json-adapter.ts (100%) rename packages/{prisma-next => stack-prisma}/integration/json.integration.test.ts (100%) rename packages/{prisma-next => stack-prisma}/integration/vitest.config.ts (100%) rename packages/{prisma-next => stack-prisma}/migrations/20260601T0100_install_eql_v3_bundle/end-contract.d.ts (100%) rename packages/{prisma-next => stack-prisma}/migrations/20260601T0100_install_eql_v3_bundle/end-contract.json (100%) rename packages/{prisma-next => stack-prisma}/migrations/20260601T0100_install_eql_v3_bundle/migration.json (100%) rename packages/{prisma-next => stack-prisma}/migrations/20260601T0100_install_eql_v3_bundle/migration.ts (100%) rename packages/{prisma-next => stack-prisma}/migrations/20260601T0100_install_eql_v3_bundle/ops.json (100%) rename packages/{prisma-next => stack-prisma}/migrations/20260720T0000_upgrade_eql_v3_3_0_2/migration.json (100%) rename packages/{prisma-next => stack-prisma}/migrations/20260720T0000_upgrade_eql_v3_3_0_2/migration.ts (100%) rename packages/{prisma-next => stack-prisma}/migrations/20260720T0000_upgrade_eql_v3_3_0_2/ops.json (100%) rename packages/{prisma-next => stack-prisma}/migrations/refs/head.json (100%) rename packages/{prisma-next => stack-prisma}/package.json (97%) rename packages/{prisma-next => stack-prisma}/prisma-next.config.ts (95%) rename packages/{prisma-next => stack-prisma}/src/contract-authoring.ts (100%) rename packages/{prisma-next => stack-prisma}/src/contract.d.ts (100%) rename packages/{prisma-next => stack-prisma}/src/contract.json (100%) rename packages/{prisma-next => stack-prisma}/src/contract.prisma (100%) rename packages/{prisma-next => stack-prisma}/src/execution/abort.ts (100%) rename packages/{prisma-next => stack-prisma}/src/execution/decrypt-all.ts (100%) rename packages/{prisma-next => stack-prisma}/src/execution/envelope-base.ts (100%) rename packages/{prisma-next => stack-prisma}/src/execution/envelope-bigint.ts (100%) rename packages/{prisma-next => stack-prisma}/src/execution/envelope-boolean.ts (100%) rename packages/{prisma-next => stack-prisma}/src/execution/envelope-date.ts (100%) rename packages/{prisma-next => stack-prisma}/src/execution/envelope-json.ts (100%) rename packages/{prisma-next => stack-prisma}/src/execution/envelope-string.ts (100%) rename packages/{prisma-next => stack-prisma}/src/execution/middleware-registry.ts (100%) rename packages/{prisma-next => stack-prisma}/src/execution/routing.ts (100%) rename packages/{prisma-next => stack-prisma}/src/execution/sdk.ts (100%) rename packages/{prisma-next => stack-prisma}/src/exports/codec-types.ts (100%) rename packages/{prisma-next => stack-prisma}/src/exports/column-types.ts (100%) rename packages/{prisma-next => stack-prisma}/src/exports/contract-space-typing.ts (100%) rename packages/{prisma-next => stack-prisma}/src/exports/control.ts (100%) rename packages/{prisma-next => stack-prisma}/src/exports/operation-types.ts (100%) rename packages/{prisma-next => stack-prisma}/src/exports/pack.ts (100%) rename packages/{prisma-next => stack-prisma}/src/exports/runtime.ts (100%) rename packages/{prisma-next => stack-prisma}/src/exports/stack.ts (95%) rename packages/{prisma-next => stack-prisma}/src/exports/v3.ts (97%) rename packages/{prisma-next => stack-prisma}/src/extension-metadata/codec-metadata.ts (100%) rename packages/{prisma-next => stack-prisma}/src/extension-metadata/constants-v3.ts (100%) rename packages/{prisma-next => stack-prisma}/src/extension-metadata/constants.ts (100%) rename packages/{prisma-next => stack-prisma}/src/extension-metadata/descriptor-meta.ts (100%) rename packages/{prisma-next => stack-prisma}/src/migration/cipherstash-codec-v3.ts (100%) rename packages/{prisma-next => stack-prisma}/src/migration/eql-bundle-v3.ts (100%) rename packages/{prisma-next => stack-prisma}/src/stack/from-stack-v3.ts (96%) rename packages/{prisma-next => stack-prisma}/src/types/codec-types.ts (100%) rename packages/{prisma-next => stack-prisma}/src/types/operation-types.ts (100%) rename packages/{prisma-next => stack-prisma}/src/v3/barrel.ts (100%) rename packages/{prisma-next => stack-prisma}/src/v3/bulk-encrypt-v3.ts (100%) rename packages/{prisma-next => stack-prisma}/src/v3/catalog.ts (100%) rename packages/{prisma-next => stack-prisma}/src/v3/codec-runtime-v3.ts (99%) rename packages/{prisma-next => stack-prisma}/src/v3/derive-schemas-v3.ts (98%) rename packages/{prisma-next => stack-prisma}/src/v3/envelope-number.ts (100%) rename packages/{prisma-next => stack-prisma}/src/v3/from-stack-v3-validate.ts (100%) rename packages/{prisma-next => stack-prisma}/src/v3/operators-v3.ts (99%) rename packages/{prisma-next => stack-prisma}/src/v3/query-term.ts (100%) rename packages/{prisma-next => stack-prisma}/src/v3/runtime-v3.ts (100%) rename packages/{prisma-next => stack-prisma}/src/v3/sdk-adapter-v3.ts (100%) rename packages/{prisma-next => stack-prisma}/src/v3/wire-v3.ts (100%) rename packages/{prisma-next => stack-prisma}/test/abort.test.ts (100%) rename packages/{prisma-next => stack-prisma}/test/authoring.test.ts (100%) rename packages/{prisma-next => stack-prisma}/test/bulk-encrypt-middleware.helpers.ts (100%) rename packages/{prisma-next => stack-prisma}/test/bundling-isolation.test.ts (98%) rename packages/{prisma-next => stack-prisma}/test/column-types.test.ts (100%) rename packages/{prisma-next => stack-prisma}/test/decrypt-all.test.ts (100%) rename packages/{prisma-next => stack-prisma}/test/descriptor.test.ts (100%) rename packages/{prisma-next => stack-prisma}/test/envelope-bigint.test.ts (100%) rename packages/{prisma-next => stack-prisma}/test/envelope-boolean.test.ts (100%) rename packages/{prisma-next => stack-prisma}/test/envelope-date.test.ts (100%) rename packages/{prisma-next => stack-prisma}/test/envelope-json.test.ts (100%) rename packages/{prisma-next => stack-prisma}/test/envelope-string.test.ts (100%) rename packages/{prisma-next => stack-prisma}/test/envelope.types.test-d.ts (100%) rename packages/{prisma-next => stack-prisma}/test/equality-trait-removal.test.ts (100%) rename packages/{prisma-next => stack-prisma}/test/live/bigint-live-pg.test.ts (100%) rename packages/{prisma-next => stack-prisma}/test/live/boolean-storage-live-pg.test.ts (100%) rename packages/{prisma-next => stack-prisma}/test/live/bulk-encrypt-live-pg.test.ts (100%) rename packages/{prisma-next => stack-prisma}/test/live/helpers/eql-v3.ts (100%) rename packages/{prisma-next => stack-prisma}/test/live/helpers/harness.ts (100%) rename packages/{prisma-next => stack-prisma}/test/live/helpers/live-gate.ts (100%) rename packages/{prisma-next => stack-prisma}/test/live/migration-apply-live-pg.test.ts (100%) rename packages/{prisma-next => stack-prisma}/test/live/operators-live-pg.test.ts (100%) rename packages/{prisma-next => stack-prisma}/test/live/operators-null-live-pg.test.ts (100%) rename packages/{prisma-next => stack-prisma}/test/operation-types.types.test-d.ts (100%) rename packages/{prisma-next => stack-prisma}/test/psl-interpretation.test.ts (100%) rename packages/{prisma-next => stack-prisma}/test/routing.test.ts (100%) rename packages/{prisma-next => stack-prisma}/test/sdk.types.test-d.ts (100%) rename packages/{prisma-next => stack-prisma}/test/v3/bulk-encrypt-v3.test.ts (100%) rename packages/{prisma-next => stack-prisma}/test/v3/catalog-invariants.test.ts (100%) rename packages/{prisma-next => stack-prisma}/test/v3/catalog.test.ts (100%) rename packages/{prisma-next => stack-prisma}/test/v3/codec-runtime-v3.test.ts (100%) rename packages/{prisma-next => stack-prisma}/test/v3/codec-types-v3.test-d.ts (100%) rename packages/{prisma-next => stack-prisma}/test/v3/column-types.test-d.ts (100%) rename packages/{prisma-next => stack-prisma}/test/v3/constants-v3.test.ts (100%) rename packages/{prisma-next => stack-prisma}/test/v3/derive-schemas-v3.test.ts (100%) rename packages/{prisma-next => stack-prisma}/test/v3/envelope-number.test.ts (100%) rename packages/{prisma-next => stack-prisma}/test/v3/from-stack-divergence-v3.test.ts (100%) rename packages/{prisma-next => stack-prisma}/test/v3/from-stack-v3.test.ts (100%) rename packages/{prisma-next => stack-prisma}/test/v3/migration-v3.test.ts (100%) rename packages/{prisma-next => stack-prisma}/test/v3/operator-gating-v3.test.ts (100%) rename packages/{prisma-next => stack-prisma}/test/v3/operator-lowering-v3-equality.test.ts (100%) rename packages/{prisma-next => stack-prisma}/test/v3/operator-lowering-v3-json.test.ts (100%) rename packages/{prisma-next => stack-prisma}/test/v3/operator-lowering-v3-order-range.test.ts (100%) rename packages/{prisma-next => stack-prisma}/test/v3/operator-lowering-v3-text-search.test.ts (100%) rename packages/{prisma-next => stack-prisma}/test/v3/operator-lowering-v3.helpers.ts (100%) rename packages/{prisma-next => stack-prisma}/test/v3/properties.test.ts (100%) rename packages/{prisma-next => stack-prisma}/test/v3/runtime-v3.test.ts (100%) rename packages/{prisma-next => stack-prisma}/test/v3/sdk-adapter-v3.test.ts (100%) rename packages/{prisma-next => stack-prisma}/test/v3/vendored-space-parity.test.ts (100%) rename packages/{prisma-next => stack-prisma}/test/v3/wire-v3.test.ts (100%) rename packages/{prisma-next => stack-prisma}/tsconfig.json (100%) rename packages/{prisma-next => stack-prisma}/tsup.config.ts (100%) rename packages/{prisma-next => stack-prisma}/turbo.json (100%) rename packages/{prisma-next => stack-prisma}/vitest.config.ts (100%) rename skills/{stash-prisma-next => stash-prisma}/SKILL.md (88%) diff --git a/.changeset/adapter-package-split.md b/.changeset/adapter-package-split.md index e5cb460f7..4117728bc 100644 --- a/.changeset/adapter-package-split.md +++ b/.changeset/adapter-package-split.md @@ -7,7 +7,7 @@ Split the Drizzle and Supabase integrations into their own packages. The adapters now ship as first-party packages that depend on `@cipherstash/stack`, -following the `@cipherstash/prisma-next` precedent: +following the `@cipherstash/stack-prisma` precedent: - **`@cipherstash/stack-drizzle`** — EQL v3 Drizzle integration on the package root (`types` factories, `createEncryptionOperators`, diff --git a/.changeset/config.json b/.changeset/config.json index 2bacd138c..fb05a4c16 100644 --- a/.changeset/config.json +++ b/.changeset/config.json @@ -8,7 +8,7 @@ "@cipherstash/stack", "@cipherstash/stack-drizzle", "@cipherstash/stack-supabase", - "@cipherstash/prisma-next", + "@cipherstash/stack-prisma", "@cipherstash/wizard" ] ], diff --git a/.changeset/encryption-schema-arrays.md b/.changeset/encryption-schema-arrays.md index c3cbb5f39..d2b1e829d 100644 --- a/.changeset/encryption-schema-arrays.md +++ b/.changeset/encryption-schema-arrays.md @@ -1,6 +1,6 @@ --- '@cipherstash/stack': minor -'@cipherstash/prisma-next': patch +'@cipherstash/stack-prisma': patch --- `Encryption({ schemas })` now accepts any non-empty array of EQL v3 tables, not diff --git a/.changeset/eql-baked-digest-verified.md b/.changeset/eql-baked-digest-verified.md index 1e7b239d5..b370a17bf 100644 --- a/.changeset/eql-baked-digest-verified.md +++ b/.changeset/eql-baked-digest-verified.md @@ -1,5 +1,5 @@ --- -'@cipherstash/prisma-next': minor +'@cipherstash/stack-prisma': minor --- Bake the EQL v3 install SQL into the migration artefacts at emit time, diff --git a/.changeset/eql-v3-prisma-next.md b/.changeset/eql-v3-prisma-next.md index 40d4564c0..93f3f2c82 100644 --- a/.changeset/eql-v3-prisma-next.md +++ b/.changeset/eql-v3-prisma-next.md @@ -1,5 +1,5 @@ --- -'@cipherstash/prisma-next': minor +'@cipherstash/stack-prisma': minor --- **Breaking:** EQL v3 columns are now authored through **concrete per-domain constructors** — the constructor you choose *is* the capability set. The legacy boolean-option surface (`EncryptedString({ equality, freeTextSearch, orderAndRange })`) is not carried into v3. @@ -11,7 +11,7 @@ - `EncryptedJson` — searchable encrypted JSONB (`public.eql_v3_json`, `ste_vec`), queried with `eqlJsonContains` (`@>` containment). Selector querying (comparing the value at a JSONPath) is tracked in #677. - **Impossible capability combinations have no constructor** (e.g. text equality + free-text without order/range) — they are unrepresentable, not runtime errors. - **BigInt is a first-class v3 family** (`EncryptedBigInt` / `EncryptedBigIntEq` / `EncryptedBigIntOrd`, JS `bigint` plaintext, backed by `public.eql_v3_bigint*`). -- New `@cipherstash/prisma-next/v3` entry point: `cipherstashFromStackV3({ contractJson })` builds the v3 runtime descriptor, bulk-encrypt middleware, and a stack `Encryption` client from the emitted contract. +- New `@cipherstash/stack-prisma/v3` entry point: `cipherstashFromStackV3({ contractJson })` builds the v3 runtime descriptor, bulk-encrypt middleware, and a stack `Encryption` client from the emitted contract. - Query operators use an **EQL-derived vocabulary** (`eqlEq`, `eqlNeq`, `eqlIn`, `eqlNotIn`, `eqlGt`, `eqlGte`, `eqlLt`, `eqlLte`, `eqlBetween`, `eqlNotBetween`, `eqlJsonContains`; ordering via `eqlAsc` / `eqlDesc`), lowering to the same-named `eql_v3.*` functions with operands cast to the domain's query type (`$n::eql_v3.query_`); ordering uses `eql_v3.ord_term` / `eql_v3.ord_term_ore` by the column's ordering flavour. The domains are `public.eql_v3_*`; the operator functions live in the `eql_v3` schema. - Free-text search is **`eqlMatch`** — fuzzy bloom token matching (`eql_v3.contains`), deliberately NOT named after SQL `ILIKE`: matching is case-insensitive, order/multiplicity-insensitive, and one-sided (may false-positive). Two guards run before encryption: SQL wildcards are normalised (leading/trailing `%` stripped; interior `%` or any `_` rejected), and needles the column's match index cannot answer (empty / below the tokenizer length) are rejected via the shared `matchNeedleError` guard. There is **no negated match operator** — negating a may-false-positive bloom test would silently drop matching rows. - A new baseline migration `20260601T0100_install_eql_v3_bundle` (invariant `cipherstash:install-eql-v3-bundle-v1`) installs the `public.eql_v3_*` domains and `eql_v3.*` functions from the pinned `@cipherstash/eql` release. Regenerate contracts and run migrations after changing constructors. diff --git a/.changeset/pre.json b/.changeset/pre.json index b874a8b82..89dab5375 100644 --- a/.changeset/pre.json +++ b/.changeset/pre.json @@ -4,13 +4,13 @@ "initialVersions": { "@cipherstash/e2e": "0.0.2", "@cipherstash/basic-example": "1.2.13", - "@cipherstash/prisma-next-example": "0.0.5", + "@cipherstash/prisma-example": "0.0.5", "@cipherstash/supabase-worker-example": "0.0.0", "@cipherstash/bench": "0.0.4", "stash": "0.17.1", "@cipherstash/migrate": "0.2.0", "@cipherstash/nextjs": "4.1.1", - "@cipherstash/prisma-next": "0.3.2", + "@cipherstash/stack-prisma": "0.3.2", "@cipherstash/stack": "0.19.0", "@cipherstash/stack-drizzle": "0.0.0", "@cipherstash/stack-supabase": "0.0.0", @@ -75,8 +75,8 @@ "stash-cli-skill-refresh", "stash-drizzle-skill-encrypt-query", "stash-env-mint-credentials", - "stash-prisma-next-skill-v3-only", - "stash-prisma-next-skill", + "stash-prisma-skill-v3-only", + "stash-prisma-skill", "stash-skills-contains-to-matches", "stash-supabase-contains-substrings", "supabase-encryption-error", diff --git a/.changeset/prisma-example-eql-v3.md b/.changeset/prisma-example-eql-v3.md index c5b55055d..3268a0955 100644 --- a/.changeset/prisma-example-eql-v3.md +++ b/.changeset/prisma-example-eql-v3.md @@ -1,5 +1,5 @@ --- -'@cipherstash/prisma-next-example': minor +'@cipherstash/prisma-example': minor --- Convert the example app to EQL v3. Every column is now a concrete `public.eql_v3_*` domain authored with the per-domain constructors (`EncryptedTextSearch`, `EncryptedDoubleOrd`, `EncryptedBigIntOrd`, `EncryptedDateOrd`, `EncryptedBoolean`, `EncryptedJson`), wired through `cipherstashFromStackV3({ contractJson })`. The e2e harness runs the full v3 surface against live Postgres + ZeroKMS with no skips: the `eql*` operator vocabulary (equality/range plus `eqlMatch` free-text token search), `eqlAsc`/`eqlDesc` order-term sorting, encrypted JSON containment (`eqlJsonContains` — the v2 `cipherstashJsonb*` helpers do not exist in v3), lossless `bigint` beyond `Number.MAX_SAFE_INTEGER`, and the storage-only `eql_v3_boolean` refusal (`EncryptionOperatorError`) pinned as a feature. Migrations regenerate from the v3 contract: the initial app migration creates the `users` table against the v3 domains with zero `add_search_config` ops, and the cipherstash space carries both bundle baselines (v2 + v3). diff --git a/.changeset/prisma-next-0-14.md b/.changeset/prisma-next-0-14.md index f1ad6d5a5..e3eb71a8a 100644 --- a/.changeset/prisma-next-0-14.md +++ b/.changeset/prisma-next-0-14.md @@ -1,5 +1,5 @@ --- -'@cipherstash/prisma-next': minor +'@cipherstash/stack-prisma': minor --- Upgrade to Prisma Next 0.14.0 (from 0.8.0). Every `@prisma-next/*` dependency is now pinned at 0.14.0; consuming apps must run Prisma Next 0.14 to use this release. diff --git a/.changeset/prisma-next-0-16.md b/.changeset/prisma-next-0-16.md index b025f3aed..7ddbff997 100644 --- a/.changeset/prisma-next-0-16.md +++ b/.changeset/prisma-next-0-16.md @@ -1,5 +1,5 @@ --- -'@cipherstash/prisma-next': minor +'@cipherstash/stack-prisma': minor 'stash': patch --- @@ -24,7 +24,7 @@ contract: prismaContract('./prisma/schema.prisma', { ``` Without it, `prisma-next contract emit` fails at runtime with `createNamespace is -not a function`. The bundled `stash-prisma-next` skill documents this too. +not a function`. The bundled `stash-prisma` skill documents this too. The bundled EQL v3 baseline migration is re-emitted so its label and hash reflect the pinned `@cipherstash/eql` 3.0.2 (the committed artifact still said 3.0.0). diff --git a/.changeset/prisma-next-drop-encrypted-prefix.md b/.changeset/prisma-next-drop-encrypted-prefix.md index 50624bcac..ff211ec37 100644 --- a/.changeset/prisma-next-drop-encrypted-prefix.md +++ b/.changeset/prisma-next-drop-encrypted-prefix.md @@ -1,5 +1,5 @@ --- -'@cipherstash/prisma-next': minor +'@cipherstash/stack-prisma': minor 'stash': patch --- @@ -22,5 +22,5 @@ Unchanged: the runtime value envelopes (`EncryptedString`, `EncryptedNumber`, `eql*` query operators. The legacy v2 constructors are removed elsewhere in this release. -The `stash-prisma-next` skill is updated to the new names (skills ship in the +The `stash-prisma` skill is updated to the new names (skills ship in the `stash` tarball). diff --git a/.changeset/prisma-next-eql-runtime-source.md b/.changeset/prisma-next-eql-runtime-source.md index bf61040f0..05f5e8f69 100644 --- a/.changeset/prisma-next-eql-runtime-source.md +++ b/.changeset/prisma-next-eql-runtime-source.md @@ -1,5 +1,5 @@ --- -'@cipherstash/prisma-next': minor +'@cipherstash/stack-prisma': minor --- Source the EQL v3 install SQL from `@cipherstash/eql` at runtime instead of diff --git a/.changeset/prisma-next-joins-release-train.md b/.changeset/prisma-next-joins-release-train.md index fe9c35e4b..fa2998807 100644 --- a/.changeset/prisma-next-joins-release-train.md +++ b/.changeset/prisma-next-joins-release-train.md @@ -1,8 +1,8 @@ --- -'@cipherstash/prisma-next': patch +'@cipherstash/stack-prisma': patch --- -`@cipherstash/prisma-next` now versions in lockstep with the Stack release +`@cipherstash/stack-prisma` now versions in lockstep with the Stack release train (`stash`, `@cipherstash/stack`, and the other adapters) via a Changesets `fixed` group — `stash init` installs it pinned by exact version, so the two must always release together. This moves the package from its previous `0.4.x` diff --git a/.changeset/prisma-next-migrate-command.md b/.changeset/prisma-next-migrate-command.md index 72f2fd098..a8e583c76 100644 --- a/.changeset/prisma-next-migrate-command.md +++ b/.changeset/prisma-next-migrate-command.md @@ -1,13 +1,13 @@ --- 'stash': patch -'@cipherstash/prisma-next': patch +'@cipherstash/stack-prisma': patch --- Fix the wrong `prisma-next migration apply` command name in the Prisma Next guidance. Prisma Next has no `migration apply` subcommand — the apply verb is the top-level `prisma-next migrate` (`migration` only has `plan`/`new`/`show`/ `status`/`log`/`list`/`graph`/`check`). The stale name appeared in the -`stash-prisma-next` and `stash-cli` skills, the `@cipherstash/prisma-next` +`stash-prisma` and `stash-cli` skills, the `@cipherstash/stack-prisma` README, and — user-visibly — in `stash init --prisma-next`'s printed next-steps, the `stash init` flag help, and the `stash eql install` Prisma-Next refusal message, all of which now say `prisma-next migrate`. Surfaced by the rc.4 diff --git a/.changeset/prisma-next-skill-accuracy.md b/.changeset/prisma-next-skill-accuracy.md index e7930e811..b72d319c5 100644 --- a/.changeset/prisma-next-skill-accuracy.md +++ b/.changeset/prisma-next-skill-accuracy.md @@ -2,10 +2,10 @@ 'stash': patch --- -Correct the `stash-prisma-next` skill against the current adapter, and fix a +Correct the `stash-prisma` skill against the current adapter, and fix a stale constructor name in `stash init --prisma-next`'s next steps. -The skill was verified line-by-line against `@cipherstash/prisma-next` on +The skill was verified line-by-line against `@cipherstash/stack-prisma` on main (constructors, domains, operators, `rawSql` shape, EQL function names, CLI commands — all confirmed current). Two real errors fixed: diff --git a/.changeset/prisma-next-v3-client-config.md b/.changeset/prisma-next-v3-client-config.md index 4a6aa723e..3d206f992 100644 --- a/.changeset/prisma-next-v3-client-config.md +++ b/.changeset/prisma-next-v3-client-config.md @@ -1,5 +1,5 @@ --- -'@cipherstash/prisma-next': major +'@cipherstash/stack-prisma': major --- **Breaking:** `CipherstashFromStackV3Options.encryptionConfig` — the config diff --git a/.changeset/prisma-next-v3-only-install.md b/.changeset/prisma-next-v3-only-install.md index 9c9eb7c8e..4625f1222 100644 --- a/.changeset/prisma-next-v3-only-install.md +++ b/.changeset/prisma-next-v3-only-install.md @@ -1,8 +1,8 @@ --- -'@cipherstash/prisma-next': minor +'@cipherstash/stack-prisma': minor --- -Make `@cipherstash/prisma-next` **EQL v3 only**. The EQL v2 surface is removed +Make `@cipherstash/stack-prisma` **EQL v3 only**. The EQL v2 surface is removed entirely — install path, authoring constructors, runtime codecs, and the v2 subpath exports. diff --git a/.changeset/protect-ffi-030-json-selectors.md b/.changeset/protect-ffi-030-json-selectors.md index abc38f637..8019db961 100644 --- a/.changeset/protect-ffi-030-json-selectors.md +++ b/.changeset/protect-ffi-030-json-selectors.md @@ -2,7 +2,7 @@ '@cipherstash/stack': minor '@cipherstash/stack-drizzle': minor '@cipherstash/stack-supabase': patch -'@cipherstash/prisma-next': minor +'@cipherstash/stack-prisma': minor 'stash': patch --- diff --git a/.changeset/release-train-coupling.md b/.changeset/release-train-coupling.md index dffd05790..a47c4ae21 100644 --- a/.changeset/release-train-coupling.md +++ b/.changeset/release-train-coupling.md @@ -16,7 +16,7 @@ be offered the reinstall fix, never "looks newer, leave it"). **Version lockstep.** The release-train packages (`stash`, `@cipherstash/stack`, `@cipherstash/stack-drizzle`, -`@cipherstash/stack-supabase`, `@cipherstash/prisma-next`, +`@cipherstash/stack-supabase`, `@cipherstash/stack-prisma`, `@cipherstash/wizard`) are now a Changesets `fixed` group: a release of any of them republishes all of them at the same version, so the CLI's embedded version map can never go stale against the packages it pins (previously a diff --git a/.changeset/rename-packages-1-0.md b/.changeset/rename-packages-1-0.md new file mode 100644 index 000000000..9cf9e12b2 --- /dev/null +++ b/.changeset/rename-packages-1-0.md @@ -0,0 +1,17 @@ +--- +'@cipherstash/stack-prisma': minor +'@cipherstash/wizard': patch +'stash': minor +--- + +Renamed `@cipherstash/prisma-next` to **`@cipherstash/stack-prisma`** (#842), +matching the `@cipherstash/stack-drizzle` / `@cipherstash/stack-supabase` +adapter naming. Only the npm name changes: the `prisma-next` CLI, +`prisma-next.config.ts`, and the `@prisma-next/*` framework packages are the +Prisma Next framework's own surface and keep their names. Update imports +(`@cipherstash/prisma-next/stack` → `@cipherstash/stack-prisma/stack`, and the +other subpaths likewise) and the `extensionPacks` import in +`prisma-next.config.ts`. + +`stash init` and the bundled skills now install and document the new name; the +`stash-prisma-next` skill is now `stash-prisma`. diff --git a/.changeset/stack-logger-edge-safe.md b/.changeset/stack-logger-edge-safe.md index c84c0d97e..0d1435bde 100644 --- a/.changeset/stack-logger-edge-safe.md +++ b/.changeset/stack-logger-edge-safe.md @@ -6,6 +6,6 @@ The shared logger read `process.env.STASH_STACK_LOG` unguarded while initialising at module scope, so importing adapter-kit — which re-exports that logger — threw `ReferenceError: process is not defined` before any user code ran. The environment read is now guarded. -This is not a single-adapter fix. `@cipherstash/stack-supabase`, `@cipherstash/stack-drizzle` and `@cipherstash/prisma-next` all value-import `@cipherstash/stack/adapter-kit`, so edge users of all three hit the same import-time throw, and all three are fixed by this release. +This is not a single-adapter fix. `@cipherstash/stack-supabase`, `@cipherstash/stack-drizzle` and `@cipherstash/stack-prisma` all value-import `@cipherstash/stack/adapter-kit`, so edge users of all three hit the same import-time throw, and all three are fixed by this release. **No behaviour change on Node.** `STASH_STACK_LOG`, its accepted values (`debug` / `info` / `error`), its `error` default, and the point at which the logger is configured are all unchanged. diff --git a/.changeset/stash-indexing-skill.md b/.changeset/stash-indexing-skill.md index 6303d9d64..a64ff23fa 100644 --- a/.changeset/stash-indexing-skill.md +++ b/.changeset/stash-indexing-skill.md @@ -19,5 +19,5 @@ during an encryption rollout (after backfill, before switching reads). prompt — now install it for **every** integration (Drizzle, Supabase, Prisma Next, plain PostgreSQL) — the gap is cross-cutting. The existing per-integration skills gained pointers to it (including the -missing `stash-prisma-next` one-line purpose in the setup prompt, which +missing `stash-prisma` one-line purpose in the setup prompt, which previously rendered "(no description)"). diff --git a/.changeset/stash-prisma-next-skill-v3-only.md b/.changeset/stash-prisma-next-skill-v3-only.md index 4e2bd8f71..56c5ae66c 100644 --- a/.changeset/stash-prisma-next-skill-v3-only.md +++ b/.changeset/stash-prisma-next-skill-v3-only.md @@ -2,7 +2,7 @@ 'stash': patch --- -Update the bundled `stash-prisma-next` skill for the EQL v3-only -`@cipherstash/prisma-next`: drop the stale references to the removed EQL v2 +Update the bundled `stash-prisma` skill for the EQL v3-only +`@cipherstash/stack-prisma`: drop the stale references to the removed EQL v2 surface (`cipherstashFromStackV2`, the `cipherstash*` operators, the "legacy v2" subpath note) so the guidance copied into customer repos matches the package. diff --git a/.changeset/stash-prisma-next-skill.md b/.changeset/stash-prisma-next-skill.md index a1617d521..6c5060efa 100644 --- a/.changeset/stash-prisma-next-skill.md +++ b/.changeset/stash-prisma-next-skill.md @@ -11,7 +11,7 @@ degrades an unmapped integration to the base skill set instead of crashing (`tsup` ships without type-checking, so the `Record` type alone didn't protect the build). -Ships a new **`stash-prisma-next`** agent skill documenting the EQL v3 Prisma +Ships a new **`stash-prisma`** agent skill documenting the EQL v3 Prisma Next surface — the domain-named encrypted column types (`EncryptedTextSearch`, `EncryptedDoubleOrd`, …), `cipherstashFromStackV3` wiring, the runtime value envelopes, the `eql*` query operators, and EQL installation via diff --git a/.changeset/v3-only-config-typing-and-entry-parity.md b/.changeset/v3-only-config-typing-and-entry-parity.md index 6f5822aa6..2a4faf31f 100644 --- a/.changeset/v3-only-config-typing-and-entry-parity.md +++ b/.changeset/v3-only-config-typing-and-entry-parity.md @@ -1,6 +1,6 @@ --- '@cipherstash/stack': major -'@cipherstash/prisma-next': patch +'@cipherstash/stack-prisma': patch 'stash': patch --- diff --git a/.changeset/v3-only-encryption-client.md b/.changeset/v3-only-encryption-client.md index f6ab4e055..3b3a60472 100644 --- a/.changeset/v3-only-encryption-client.md +++ b/.changeset/v3-only-encryption-client.md @@ -1,7 +1,7 @@ --- '@cipherstash/stack': major '@cipherstash/stack-supabase': major -'@cipherstash/prisma-next': major +'@cipherstash/stack-prisma': major 'stash': patch --- diff --git a/.changeset/v3-payload-routing.md b/.changeset/v3-payload-routing.md index 22ee70a44..c3056d99f 100644 --- a/.changeset/v3-payload-routing.md +++ b/.changeset/v3-payload-routing.md @@ -1,5 +1,5 @@ --- -'@cipherstash/prisma-next': minor +'@cipherstash/stack-prisma': minor --- Route v3 decoding from the EQL payload's own identifier, so encrypted columns diff --git a/.github/workflows/integration-prisma-next.yml b/.github/workflows/integration-prisma-next.yml index 6b7e19134..35544513c 100644 --- a/.github/workflows/integration-prisma-next.yml +++ b/.github/workflows/integration-prisma-next.yml @@ -19,7 +19,7 @@ on: branches: [main] paths: - 'packages/stack/src/eql/v3/**' - - 'packages/prisma-next/**' + - 'packages/stack-prisma/**' # Source layers the adapter's encoding/round-trip rests on: a break here # (not just under src/eql/v3) can produce wrong rows, so trigger the live # suite that would catch it. @@ -38,7 +38,7 @@ on: # Repeated verbatim: GitHub Actions does not support YAML anchors/aliases. paths: - 'packages/stack/src/eql/v3/**' - - 'packages/prisma-next/**' + - 'packages/stack-prisma/**' # Source layers the adapter's encoding/round-trip rests on: a break here # (not just under src/eql/v3) can produce wrong rows, so trigger the live # suite that would catch it. @@ -114,7 +114,7 @@ jobs: # `stash eql install --eql-version 3`, so an installer regression fails # here rather than hiding behind a test-only SQL apply. - name: prisma-next v3 family suites - run: pnpm exec turbo run test:integration --filter @cipherstash/prisma-next --env-mode=loose + run: pnpm exec turbo run test:integration --filter @cipherstash/stack-prisma --env-mode=loose env: # Step env, not a `.env` file: `dotenv/config` does not override an # already-set `process.env`, so these win and no secret hits disk. diff --git a/.github/workflows/prisma-example-readme-e2e.yml b/.github/workflows/prisma-example-readme-e2e.yml index 0a5a0c2d0..5df2dc58f 100644 --- a/.github/workflows/prisma-example-readme-e2e.yml +++ b/.github/workflows/prisma-example-readme-e2e.yml @@ -75,12 +75,12 @@ jobs: client-key: ${{ secrets.CS_CLIENT_KEY }} client-access-key: ${{ secrets.CS_CLIENT_ACCESS_KEY }} - # Build via turbo so `^build` on `@cipherstash/prisma-next` and + # Build via turbo so `^build` on `@cipherstash/stack-prisma` and # its `@cipherstash/stack` peer is honoured. The test's # `pnpm install` subprocess inside `examples/prisma/` is a no-op # given the lockfile is already in steady state from this step. - - name: Build @cipherstash/prisma-next - run: pnpm exec turbo run build --filter @cipherstash/prisma-next + - name: Build @cipherstash/stack-prisma + run: pnpm exec turbo run build --filter @cipherstash/stack-prisma - name: Run README walkthrough e2e run: pnpm exec turbo run test:e2e --filter @cipherstash/e2e -- --run tests/prisma-example-readme.e2e.test.ts diff --git a/.github/workflows/prisma-next-e2e.yml b/.github/workflows/prisma-next-e2e.yml index 4bccc8dd4..74f4c9552 100644 --- a/.github/workflows/prisma-next-e2e.yml +++ b/.github/workflows/prisma-next-e2e.yml @@ -1,6 +1,6 @@ name: Prisma Next E2E -# End-to-end tests for `@cipherstash/prisma-next`: spins up a real +# End-to-end tests for `@cipherstash/stack-prisma`: spins up a real # Postgres container, applies the cipherstash baseline migration # (EQL bundle install) + the example app's schema, then runs the # suite at `examples/prisma/test/e2e/` against a live ZeroKMS @@ -15,14 +15,14 @@ on: branches: - main paths: - - 'packages/prisma-next/**' + - 'packages/stack-prisma/**' - 'examples/prisma/**' - '.github/workflows/prisma-next-e2e.yml' pull_request: branches: - '**' paths: - - 'packages/prisma-next/**' + - 'packages/stack-prisma/**' - 'examples/prisma/**' - '.github/workflows/prisma-next-e2e.yml' @@ -95,16 +95,16 @@ jobs: echo "CS_CLIENT_ACCESS_KEY=${{ secrets.CS_CLIENT_ACCESS_KEY }}" >> ./examples/prisma/.env # Build via turbo so the `^build` dependency on - # `@cipherstash/stack` (which `@cipherstash/prisma-next` imports + # `@cipherstash/stack` (which `@cipherstash/stack-prisma` imports # `/schema` from) is honoured. A bare - # `pnpm --filter @cipherstash/prisma-next build` bypasses the + # `pnpm --filter @cipherstash/stack-prisma build` bypasses the # task graph and leaves the upstream dist/ empty, surfacing as # `Cannot find module '@cipherstash/stack/schema'` from tsc. - - name: Build @cipherstash/prisma-next - run: pnpm exec turbo run build --filter @cipherstash/prisma-next + - name: Build @cipherstash/stack-prisma + run: pnpm exec turbo run build --filter @cipherstash/stack-prisma - name: Emit example contract - run: pnpm --filter @cipherstash/prisma-next-example emit + run: pnpm --filter @cipherstash/prisma-example emit - name: Start E2E Postgres container working-directory: examples/prisma @@ -121,7 +121,7 @@ jobs: done - name: Run E2E suite - run: pnpm exec turbo run test:e2e --filter @cipherstash/prisma-next-example --env-mode=loose + run: pnpm exec turbo run test:e2e --filter @cipherstash/prisma-example --env-mode=loose - name: Stop E2E Postgres container if: always() diff --git a/.github/workflows/tests.yml b/.github/workflows/tests.yml index 4a656554d..59a1fa64c 100644 --- a/.github/workflows/tests.yml +++ b/.github/workflows/tests.yml @@ -134,7 +134,7 @@ jobs: # Its tsconfig resolves stack subpaths to SOURCE, so no build step is # needed first. - name: Typecheck (prisma-next — enforces v3 operator-capability gating) - run: pnpm --filter @cipherstash/prisma-next run typecheck + run: pnpm --filter @cipherstash/stack-prisma run typecheck # `packages/bench` is a live importer of `@cipherstash/stack` and # `@cipherstash/stack-drizzle`, but it has no `test` script (its suites @@ -181,7 +181,7 @@ jobs: run: pnpm exec turbo run typecheck --filter @cipherstash/nextjs - name: Typecheck (examples/prisma — guards the prisma-next importers) - run: pnpm exec turbo run typecheck --filter @cipherstash/prisma-next-example + run: pnpm exec turbo run typecheck --filter @cipherstash/prisma-example - name: Typecheck (e2e) run: pnpm exec turbo run typecheck --filter @cipherstash/e2e diff --git a/AGENTS.md b/AGENTS.md index 27c1f749b..3c64c93a7 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -76,7 +76,7 @@ If these variables are missing, tests that require live encryption will fail or - `packages/cli`: The `stash` CLI — auth, init, encryption schema, and database setup (`stash eql install`). Has its own `AGENTS.md`. - `packages/wizard`: AI-powered encryption setup (`@cipherstash/wizard`) - `packages/migrate`: Plaintext-to-encrypted column migration (`@cipherstash/migrate`) — resumable backfill, per-column state -- `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) +- `packages/stack-prisma`: Prisma Next integration (`@cipherstash/stack-prisma`) — 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) - `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`. - `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`. - `packages/nextjs`: Next.js helpers and Clerk integration (`./clerk` export) @@ -85,7 +85,7 @@ If these variables are missing, tests that require live encryption will fail or - `e2e/*`: Cross-package end-to-end tests (package managers, supply chain, Prisma example README) - `examples/*`: Working apps (basic, prisma, supabase-worker) - `docs/plans/*`: Internal design plans. User-facing documentation lives at https://cipherstash.com/docs (not in this repo). -- `skills/*`: Agent skills (`stash-cli`, `stash-encryption`, `stash-indexing`, `stash-deployment`, `stash-zerokms`, `stash-auth`, `stash-postgres`, `stash-edge`, `stash-drizzle`, `stash-dynamodb`, `stash-supabase`, `stash-prisma-next`, `stash-supply-chain-security`) +- `skills/*`: Agent skills (`stash-cli`, `stash-encryption`, `stash-indexing`, `stash-deployment`, `stash-zerokms`, `stash-auth`, `stash-postgres`, `stash-edge`, `stash-drizzle`, `stash-dynamodb`, `stash-supabase`, `stash-prisma`, `stash-supply-chain-security`) ## Agent Skills — these ship to customers @@ -110,7 +110,7 @@ nothing type-checks them, and the damage lands in a customer's repo, not ours. |---|---| | `packages/cli` commands, flags, or prompts | `skills/stash-cli` | | `packages/stack` encryption API, schema builders, subpath exports | `skills/stash-encryption` | -| Drizzle / Supabase / Prisma Next / DynamoDB integrations | `skills/stash-drizzle`, `skills/stash-supabase`, `skills/stash-prisma-next`, `skills/stash-dynamodb` | +| Drizzle / Supabase / Prisma Next / DynamoDB integrations | `skills/stash-drizzle`, `skills/stash-supabase`, `skills/stash-prisma`, `skills/stash-dynamodb` | | The rollout/cutover lifecycle (`packages/migrate`, `stash encrypt *`) | `skills/stash-encryption` and `skills/stash-cli` | | The deploy sequencing / deploy-gate story, `stash env`, or platform-specific deployment guidance | `skills/stash-deployment` | | The `@cipherstash/eql` pin, `eql install`/`eql migration` behaviour, or index-related SQL guidance | `skills/stash-indexing` | diff --git a/SECURITY.md b/SECURITY.md index ba3996d97..d1ff6fc03 100644 --- a/SECURITY.md +++ b/SECURITY.md @@ -13,7 +13,7 @@ This repository is the CipherStash Stack monorepo for JavaScript/TypeScript. It | `stash` | CipherStash CLI | | `@cipherstash/nextjs` | Next.js helpers | | `@cipherstash/migrate` | Plaintext-to-encrypted column migration tooling | -| `@cipherstash/prisma-next` | Prisma Next integration (searchable field-level encryption for Postgres) | +| `@cipherstash/stack-prisma` | Prisma Next integration (searchable field-level encryption for Postgres) | | `@cipherstash/stack-drizzle` | Drizzle ORM integration for `@cipherstash/stack` (EQL v3) | | `@cipherstash/stack-supabase` | Supabase integration for `@cipherstash/stack` (EQL v3) | | `@cipherstash/wizard` | AI-powered encryption setup | diff --git a/examples/prisma/README.md b/examples/prisma/README.md index afd336cf2..15fdad0e9 100644 --- a/examples/prisma/README.md +++ b/examples/prisma/README.md @@ -1,6 +1,6 @@ -# @cipherstash/prisma-next example +# @cipherstash/stack-prisma example -End-to-end demo of [`@cipherstash/prisma-next`](../../packages/prisma-next/README.md): searchable application-layer encryption for Postgres with [Prisma Next](https://www.npmjs.com/package/@prisma-next/cli), using [`@cipherstash/stack`](../../packages/stack/README.md) as the encryption SDK — on **EQL v3**, where every encrypted column is a concrete `public.eql_v3_*` Postgres domain and the constructor you pick *is* the capability set. +End-to-end demo of [`@cipherstash/stack-prisma`](../../packages/stack-prisma/README.md): searchable application-layer encryption for Postgres with [Prisma Next](https://www.npmjs.com/package/@prisma-next/cli), using [`@cipherstash/stack`](../../packages/stack/README.md) as the encryption SDK — on **EQL v3**, where every encrypted column is a concrete `public.eql_v3_*` Postgres domain and the constructor you pick *is* the capability set. A single `User` model with one column per plaintext family, exercised end-to-end: insert, equality, free-text token search, range, between, in-array, encrypted-order-term sort, JSON containment, and `decryptAll`-amortised read. @@ -108,4 +108,4 @@ Two v3 behaviours worth noticing in that output: ## References - 📖 [Prisma Next encryption docs](https://cipherstash.com/docs/stack/cipherstash/encryption/prisma-next) — the canonical reference. -- [`@cipherstash/prisma-next` package README](../../packages/prisma-next/README.md) — install, subpath exports, quick start. +- [`@cipherstash/stack-prisma` package README](../../packages/stack-prisma/README.md) — install, subpath exports, quick start. diff --git a/examples/prisma/docker-compose.yml b/examples/prisma/docker-compose.yml index 491c246b3..0ec2f00de 100644 --- a/examples/prisma/docker-compose.yml +++ b/examples/prisma/docker-compose.yml @@ -1,4 +1,4 @@ -# Local Postgres for the @cipherstash/prisma-next example. +# Local Postgres for the @cipherstash/stack-prisma example. # # Usage: # docker compose up -d # start diff --git a/examples/prisma/package.json b/examples/prisma/package.json index cab49036f..10304d38c 100644 --- a/examples/prisma/package.json +++ b/examples/prisma/package.json @@ -1,8 +1,8 @@ { - "name": "@cipherstash/prisma-next-example", + "name": "@cipherstash/prisma-example", "private": true, "version": "0.1.0-rc.4", - "description": "End-to-end example of @cipherstash/prisma-next: searchable application-layer encryption for Postgres with Prisma Next, using @cipherstash/stack as the SDK.", + "description": "End-to-end example of @cipherstash/stack-prisma: searchable application-layer encryption for Postgres with Prisma Next, using @cipherstash/stack as the SDK.", "type": "module", "scripts": { "emit": "prisma-next contract emit", @@ -13,7 +13,7 @@ "typecheck": "tsc --project tsconfig.json --noEmit" }, "dependencies": { - "@cipherstash/prisma-next": "workspace:*", + "@cipherstash/stack-prisma": "workspace:*", "@cipherstash/stack": "workspace:*", "@prisma-next/adapter-postgres": "0.16.0", "@prisma-next/contract": "0.16.0", diff --git a/examples/prisma/prisma-next.config.ts b/examples/prisma/prisma-next.config.ts index 94f4458c2..1cb5a2bdb 100644 --- a/examples/prisma/prisma-next.config.ts +++ b/examples/prisma/prisma-next.config.ts @@ -1,5 +1,5 @@ import 'dotenv/config' -import cipherstash from '@cipherstash/prisma-next/control' +import cipherstash from '@cipherstash/stack-prisma/control' import postgresAdapter from '@prisma-next/adapter-postgres/control' import { defineConfig } from '@prisma-next/cli/config-types' import postgresDriver from '@prisma-next/driver-postgres/control' diff --git a/examples/prisma/prisma/schema.prisma b/examples/prisma/prisma/schema.prisma index 5be400e4e..1f57f9bf3 100644 --- a/examples/prisma/prisma/schema.prisma +++ b/examples/prisma/prisma/schema.prisma @@ -1,4 +1,4 @@ -// @cipherstash/prisma-next example schema — EQL v3. +// @cipherstash/stack-prisma example schema — EQL v3. // // One User model exercising one v3 domain per plaintext family. Each // v3 constructor is argument-less and maps 1:1 to a concrete diff --git a/examples/prisma/src/db.ts b/examples/prisma/src/db.ts index df793398f..511680c52 100644 --- a/examples/prisma/src/db.ts +++ b/examples/prisma/src/db.ts @@ -13,7 +13,7 @@ import 'dotenv/config' -import { cipherstashFromStack } from '@cipherstash/prisma-next/v3' +import { cipherstashFromStack } from '@cipherstash/stack-prisma/v3' import postgres from '@prisma-next/postgres/runtime' import type { Contract } from './prisma/contract.d' diff --git a/examples/prisma/src/index.ts b/examples/prisma/src/index.ts index 5725236b3..f0aeeb183 100644 --- a/examples/prisma/src/index.ts +++ b/examples/prisma/src/index.ts @@ -1,5 +1,5 @@ /** - * @cipherstash/prisma-next example — end-to-end demo (EQL v3). + * @cipherstash/stack-prisma example — end-to-end demo (EQL v3). * * Exercises one v3 domain per plaintext family, plus the * trait-dispatched predicate operators and the encrypted ORDER BY @@ -47,7 +47,7 @@ import { EncryptedNumber, EncryptedString, eqlAsc, -} from '@cipherstash/prisma-next/runtime' +} from '@cipherstash/stack-prisma/runtime' import { db } from './db' diff --git a/examples/prisma/test/e2e/README.md b/examples/prisma/test/e2e/README.md index ebb051cf4..2e129ff7d 100644 --- a/examples/prisma/test/e2e/README.md +++ b/examples/prisma/test/e2e/README.md @@ -1,6 +1,6 @@ # Live PG + EQL v3 + ZeroKMS e2e harness -This directory hosts the live-Postgres + EQL v3 bundle + ZeroKMS end-to-end harness for the @cipherstash/prisma-next example app. Seven `*.e2e.test.ts` files cover one domain or scenario each: +This directory hosts the live-Postgres + EQL v3 bundle + ZeroKMS end-to-end harness for the @cipherstash/stack-prisma example app. Seven `*.e2e.test.ts` files cover one domain or scenario each: - `num.e2e.test.ts` — `eql_v3_double_ord` round-trip (decrypts to `EncryptedNumber`); `eqlGt`/`eqlGte`/`eqlLt`/`eqlLte`/`eqlBetween`; `eqlAsc`/`eqlDesc` order-term sort. - `bigint.e2e.test.ts` — `eql_v3_bigint_ord` round-trip **lossless beyond `Number.MAX_SAFE_INTEGER`** (native `bigint` pipeline); equality + range + in-array + sort. @@ -14,7 +14,7 @@ This directory hosts the live-Postgres + EQL v3 bundle + ZeroKMS end-to-end harn ```bash docker compose -f test/e2e/docker-compose.yml up -d # from examples/prisma -pnpm --filter @cipherstash/prisma-next-example test:e2e +pnpm --filter @cipherstash/prisma-example test:e2e ``` The harness's Vitest global setup (`global-setup.ts`): diff --git a/examples/prisma/test/e2e/bigint.e2e.test.ts b/examples/prisma/test/e2e/bigint.e2e.test.ts index 602b974d9..f1e742114 100644 --- a/examples/prisma/test/e2e/bigint.e2e.test.ts +++ b/examples/prisma/test/e2e/bigint.e2e.test.ts @@ -20,7 +20,7 @@ import { EncryptedNumber, EncryptedString, eqlAsc, -} from '@cipherstash/prisma-next/runtime' +} from '@cipherstash/stack-prisma/runtime' import { beforeAll, describe, expect, it } from 'vitest' import { db, ensureConnected, truncateUsers } from './harness' diff --git a/examples/prisma/test/e2e/bool.e2e.test.ts b/examples/prisma/test/e2e/bool.e2e.test.ts index f565458c5..f9ae12678 100644 --- a/examples/prisma/test/e2e/bool.e2e.test.ts +++ b/examples/prisma/test/e2e/bool.e2e.test.ts @@ -28,7 +28,7 @@ import { EncryptedNumber, EncryptedString, EncryptionOperatorError, -} from '@cipherstash/prisma-next/runtime' +} from '@cipherstash/stack-prisma/runtime' import { beforeAll, describe, expect, it } from 'vitest' import { db, ensureConnected, truncateUsers } from './harness' diff --git a/examples/prisma/test/e2e/date.e2e.test.ts b/examples/prisma/test/e2e/date.e2e.test.ts index c1146cd03..2608610e0 100644 --- a/examples/prisma/test/e2e/date.e2e.test.ts +++ b/examples/prisma/test/e2e/date.e2e.test.ts @@ -23,7 +23,7 @@ import { EncryptedString, eqlAsc, eqlDesc, -} from '@cipherstash/prisma-next/runtime' +} from '@cipherstash/stack-prisma/runtime' import { beforeAll, describe, expect, it } from 'vitest' import { db, ensureConnected, truncateUsers } from './harness' diff --git a/examples/prisma/test/e2e/json.e2e.test.ts b/examples/prisma/test/e2e/json.e2e.test.ts index 22a530422..b86a2058d 100644 --- a/examples/prisma/test/e2e/json.e2e.test.ts +++ b/examples/prisma/test/e2e/json.e2e.test.ts @@ -29,7 +29,7 @@ import { EncryptedNumber, EncryptedString, EncryptionOperatorError, -} from '@cipherstash/prisma-next/runtime' +} from '@cipherstash/stack-prisma/runtime' import { beforeAll, describe, expect, it } from 'vitest' import { db, ensureConnected, truncateUsers } from './harness' diff --git a/examples/prisma/test/e2e/mixed.e2e.test.ts b/examples/prisma/test/e2e/mixed.e2e.test.ts index 4f361c2db..da8c6b7d9 100644 --- a/examples/prisma/test/e2e/mixed.e2e.test.ts +++ b/examples/prisma/test/e2e/mixed.e2e.test.ts @@ -38,12 +38,12 @@ import { EncryptedNumber, EncryptedString, eqlAsc, -} from '@cipherstash/prisma-next/runtime' +} from '@cipherstash/stack-prisma/runtime' import { cipherstashFromStack, createCipherstashV3Sdk, deriveStackSchemasV3, -} from '@cipherstash/prisma-next/v3' +} from '@cipherstash/stack-prisma/v3' import postgres from '@prisma-next/postgres/runtime' import { and } from '@prisma-next/sql-orm-client' import { afterAll, beforeAll, describe, expect, it } from 'vitest' diff --git a/examples/prisma/test/e2e/num.e2e.test.ts b/examples/prisma/test/e2e/num.e2e.test.ts index 8bb41bc45..5b474735c 100644 --- a/examples/prisma/test/e2e/num.e2e.test.ts +++ b/examples/prisma/test/e2e/num.e2e.test.ts @@ -30,7 +30,7 @@ import { EncryptedString, eqlAsc, eqlDesc, -} from '@cipherstash/prisma-next/runtime' +} from '@cipherstash/stack-prisma/runtime' import { beforeAll, describe, expect, it } from 'vitest' import { db, ensureConnected, truncateUsers } from './harness' diff --git a/examples/prisma/test/e2e/str-range.e2e.test.ts b/examples/prisma/test/e2e/str-range.e2e.test.ts index 2c7f77dd8..62e118aef 100644 --- a/examples/prisma/test/e2e/str-range.e2e.test.ts +++ b/examples/prisma/test/e2e/str-range.e2e.test.ts @@ -27,7 +27,7 @@ import { EncryptedString, eqlAsc, eqlDesc, -} from '@cipherstash/prisma-next/runtime' +} from '@cipherstash/stack-prisma/runtime' import { beforeAll, describe, expect, it } from 'vitest' import { db, ensureConnected, truncateUsers } from './harness' diff --git a/packages/cli/src/__tests__/runtime-versions.test.ts b/packages/cli/src/__tests__/runtime-versions.test.ts index 20f35dea6..b10a8b5e5 100644 --- a/packages/cli/src/__tests__/runtime-versions.test.ts +++ b/packages/cli/src/__tests__/runtime-versions.test.ts @@ -70,7 +70,7 @@ describe('runtime-versions (explicit version map)', () => { const versions = { stash: '9.9.9-test.1', '@cipherstash/stack': '9.9.9-test.1', - '@cipherstash/prisma-next': '8.8.8-test.2', + '@cipherstash/stack-prisma': '8.8.8-test.2', } it('pins known packages to the release version', () => { @@ -79,8 +79,8 @@ describe('runtime-versions (explicit version map)', () => { ) // prisma-next versions on its own line — the map, not a shared constant, // is the source of truth. - expect(pinnedSpec('@cipherstash/prisma-next', versions)).toBe( - '@cipherstash/prisma-next@8.8.8-test.2', + expect(pinnedSpec('@cipherstash/stack-prisma', versions)).toBe( + '@cipherstash/stack-prisma@8.8.8-test.2', ) }) diff --git a/packages/cli/src/commands/db/__tests__/prisma-next-install-guard.test.ts b/packages/cli/src/commands/db/__tests__/prisma-next-install-guard.test.ts index 469a8fcee..1dbd81acf 100644 --- a/packages/cli/src/commands/db/__tests__/prisma-next-install-guard.test.ts +++ b/packages/cli/src/commands/db/__tests__/prisma-next-install-guard.test.ts @@ -24,10 +24,12 @@ describe('prismaNextInstallGuard', () => { expect(msg).toContain('--force') }) - it('blocks when @cipherstash/prisma-next is a dependency', () => { + it('blocks when @cipherstash/stack-prisma is a dependency', () => { writeFileSync( join(dir, 'package.json'), - JSON.stringify({ dependencies: { '@cipherstash/prisma-next': '1.0.0' } }), + JSON.stringify({ + dependencies: { '@cipherstash/stack-prisma': '1.0.0' }, + }), ) expect(prismaNextInstallGuard(dir, {})).toContain( diff --git a/packages/cli/src/commands/db/detect.ts b/packages/cli/src/commands/db/detect.ts index 93b681ee6..3684c5ca5 100644 --- a/packages/cli/src/commands/db/detect.ts +++ b/packages/cli/src/commands/db/detect.ts @@ -130,7 +130,7 @@ export function detectDrizzle(cwd: string): boolean { * Return true when the project uses Prisma Next. * * Detected via a `prisma-next.config.*` at the cwd (fast path) or - * a `@prisma-next/cli` / `@cipherstash/prisma-next` entry in + * a `@prisma-next/cli` / `@cipherstash/stack-prisma` entry in * package.json. Either signal alone is enough. */ export function detectPrismaNext(cwd: string): boolean { @@ -160,7 +160,7 @@ export function detectPrismaNext(cwd: string): boolean { ...pkg.peerDependencies, ...pkg.optionalDependencies, } - return '@prisma-next/cli' in deps || '@cipherstash/prisma-next' in deps + return '@prisma-next/cli' in deps || '@cipherstash/stack-prisma' in deps } catch { return false } diff --git a/packages/cli/src/commands/db/install.ts b/packages/cli/src/commands/db/install.ts index b17c9061a..edfd1f196 100644 --- a/packages/cli/src/commands/db/install.ts +++ b/packages/cli/src/commands/db/install.ts @@ -197,7 +197,7 @@ export function prismaNextInstallGuard( ): string | null { if (options.force || !detectPrismaNext(cwd)) return null return ( - `${messages.eql.prismaNextDetected} (found prisma-next.config.* or @cipherstash/prisma-next). ` + + `${messages.eql.prismaNextDetected} (found prisma-next.config.* or @cipherstash/stack-prisma). ` + 'Prisma Next installs the EQL bundle through its own migration system — run ' + '`prisma-next migrate` instead of `stash eql install`. ' + 'Pass --force to run the standalone installer against this database anyway.' diff --git a/packages/cli/src/commands/init/doctrine/AGENTS-doctrine.md b/packages/cli/src/commands/init/doctrine/AGENTS-doctrine.md index ec56cf110..a95bac92b 100644 --- a/packages/cli/src/commands/init/doctrine/AGENTS-doctrine.md +++ b/packages/cli/src/commands/init/doctrine/AGENTS-doctrine.md @@ -47,4 +47,4 @@ The CipherStash setup skills carry the API details. Use them when you need speci - `.codex/skills//SKILL.md` (Codex) - Under `## Skill references` at the bottom of this file (editor agents, or when a skills directory could not be written — if the section exists, it is the current copy) -Skills relevant to this project depend on the integration. Common ones: `stash-encryption` (encryption API), `stash-indexing` (indexes on encrypted columns), `stash-deployment` (taking a rollout to production), `stash-zerokms` (keysets, clients, and key management), `stash-auth` (credentials, auth strategies, lock context), `stash-cli` (`stash` commands), and one of `stash-drizzle` / `stash-supabase` / `stash-prisma-next` / `stash-dynamodb` for the chosen ORM. +Skills relevant to this project depend on the integration. Common ones: `stash-encryption` (encryption API), `stash-indexing` (indexes on encrypted columns), `stash-deployment` (taking a rollout to production), `stash-zerokms` (keysets, clients, and key management), `stash-auth` (credentials, auth strategies, lock context), `stash-cli` (`stash` commands), and one of `stash-drizzle` / `stash-supabase` / `stash-prisma` / `stash-dynamodb` for the chosen ORM. diff --git a/packages/cli/src/commands/init/lib/__tests__/build-agents-md.test.ts b/packages/cli/src/commands/init/lib/__tests__/build-agents-md.test.ts index 6599656b2..69015d000 100644 --- a/packages/cli/src/commands/init/lib/__tests__/build-agents-md.test.ts +++ b/packages/cli/src/commands/init/lib/__tests__/build-agents-md.test.ts @@ -53,11 +53,11 @@ describe('buildAgentsMdBody', () => { expect(out).not.toContain('# Skill: stash-supabase') }) - it('prisma-next inlines the stash-prisma-next skill (no crash on undefined map)', () => { + it('prisma-next inlines the stash-prisma skill (no crash on undefined map)', () => { // Regression: SKILL_MAP once lacked a prisma-next key, so this call // threw "SKILL_MAP[integration] is not iterable" for any Prisma repo. const out = buildAgentsMdBody('prisma-next', 'doctrine-plus-skills') - expect(out).toContain('# Skill: stash-prisma-next') + expect(out).toContain('# Skill: stash-prisma') expect(out).toContain('# Skill: stash-encryption') expect(out).not.toContain('# Skill: stash-drizzle') }) diff --git a/packages/cli/src/commands/init/lib/__tests__/install-skills.test.ts b/packages/cli/src/commands/init/lib/__tests__/install-skills.test.ts index 5f9f93e11..46940b53e 100644 --- a/packages/cli/src/commands/init/lib/__tests__/install-skills.test.ts +++ b/packages/cli/src/commands/init/lib/__tests__/install-skills.test.ts @@ -89,14 +89,14 @@ describe('SKILL_MAP', () => { expect(SKILL_MAP.supabase).toContain('stash-supabase') }) - it('prisma-next includes stash-prisma-next', () => { - expect(SKILL_MAP['prisma-next']).toContain('stash-prisma-next') + it('prisma-next includes stash-prisma', () => { + expect(SKILL_MAP['prisma-next']).toContain('stash-prisma') }) it('postgresql skips ORM-specific skills', () => { expect(SKILL_MAP.postgresql).not.toContain('stash-drizzle') expect(SKILL_MAP.postgresql).not.toContain('stash-supabase') - expect(SKILL_MAP.postgresql).not.toContain('stash-prisma-next') + expect(SKILL_MAP.postgresql).not.toContain('stash-prisma') }) // #754: the no-ORM path had no source for the raw-SQL binding surface or @@ -126,7 +126,7 @@ describe('skillsFor', () => { it('returns the mapped skills for a known integration', () => { expect(skillsFor('prisma-next')).toEqual([ 'stash-encryption', - 'stash-prisma-next', + 'stash-prisma', 'stash-indexing', 'stash-deployment', 'stash-zerokms', diff --git a/packages/cli/src/commands/init/lib/__tests__/setup-prompt.test.ts b/packages/cli/src/commands/init/lib/__tests__/setup-prompt.test.ts index bd9dbff9f..4003a3edf 100644 --- a/packages/cli/src/commands/init/lib/__tests__/setup-prompt.test.ts +++ b/packages/cli/src/commands/init/lib/__tests__/setup-prompt.test.ts @@ -271,7 +271,7 @@ describe('renderSetupPrompt — orient + route (implement mode)', () => { it('has a purpose line for every skill SKILL_MAP can install', () => { // renderSkillIndex falls back to "(no description)" for a skill missing // from SKILL_PURPOSES — a silent gap no per-skill assertion catches when - // a new skill lands (stash-prisma-next shipped that way). Render the + // a new skill lands (stash-prisma shipped that way). Render the // union of every installable skill and require zero fallbacks. const everyInstallable = [...new Set(Object.values(SKILL_MAP).flat())] const out = renderSetupPrompt({ diff --git a/packages/cli/src/commands/init/lib/install-skills.ts b/packages/cli/src/commands/init/lib/install-skills.ts index 989db8a17..8f798bed5 100644 --- a/packages/cli/src/commands/init/lib/install-skills.ts +++ b/packages/cli/src/commands/init/lib/install-skills.ts @@ -37,7 +37,7 @@ export const SKILL_MAP: Record = { ], 'prisma-next': [ 'stash-encryption', - 'stash-prisma-next', + 'stash-prisma', 'stash-indexing', 'stash-deployment', 'stash-zerokms', diff --git a/packages/cli/src/commands/init/lib/setup-prompt.ts b/packages/cli/src/commands/init/lib/setup-prompt.ts index fc18a3f12..a74cac5a0 100644 --- a/packages/cli/src/commands/init/lib/setup-prompt.ts +++ b/packages/cli/src/commands/init/lib/setup-prompt.ts @@ -102,7 +102,7 @@ function schemaAuthoringGuidance(integration: Integration): string { case 'supabase': return 'Declare the column with a concrete `public.eql_v3_*` domain in the migration SQL — for example, `email public.eql_v3_text_search` (`encryptedSupabase` derives its encryption config by introspecting those domains)' case 'prisma-next': - return 'Declare the field with the `cipherstash.*` constructors in `prisma/schema.prisma` (`cipherstash.TextSearch()`, `cipherstash.DoubleOrd()`, …), with the `cipherstash` extension pack wired up per `@cipherstash/prisma-next/control`' + return 'Declare the field with the `cipherstash.*` constructors in `prisma/schema.prisma` (`cipherstash.TextSearch()`, `cipherstash.DoubleOrd()`, …), with the `cipherstash` extension pack wired up per `@cipherstash/stack-prisma/control`' default: return 'Declare the table with `encryptedTable` and the `types.*` domain factories from `@cipherstash/stack/v3`, then pass it to `Encryption({ schemas })`' } @@ -194,7 +194,7 @@ const SKILL_PURPOSES: Record = { 'Drizzle-specific patterns: declaring encrypted columns, query operators, the rollout/cutover walkthrough for an existing column', 'stash-supabase': 'Supabase-specific patterns: `encryptedSupabase` wrapper, encrypted query filters, transparent decryption, the rollout/cutover walkthrough', - 'stash-prisma-next': + 'stash-prisma': 'Prisma Next-specific patterns: `cipherstash.*` field constructors, migration flow, encrypted query operators', 'stash-indexing': 'index recipes for encrypted columns — the `eql_v3` extractor functional indexes, Supabase/managed-Postgres constraints, EXPLAIN verification', diff --git a/packages/cli/src/commands/init/providers/prisma-next.ts b/packages/cli/src/commands/init/providers/prisma-next.ts index be1e5a698..523c5e543 100644 --- a/packages/cli/src/commands/init/providers/prisma-next.ts +++ b/packages/cli/src/commands/init/providers/prisma-next.ts @@ -18,7 +18,7 @@ export function createPrismaNextProvider(): InitProvider { 'Register the extension: add `cipherstash` to `extensionPacks` in prisma-next.config.ts', `Generate the contract: ${prismaNext} contract emit`, `Plan + apply (installs the EQL bundle alongside your app schema): ${prismaNext} migration plan && ${prismaNext} migrate`, - 'Wire the runtime: cipherstashFromStack({ contractJson }) — see @cipherstash/prisma-next/stack', + 'Wire the runtime: cipherstashFromStack({ contractJson }) — see @cipherstash/stack-prisma/stack', `Customize your schema: ${stash} wizard (AI-guided, automated)`, 'Prisma Next guide: https://cipherstash.com/docs/stack/cipherstash/encryption/prisma-next', 'Dashboard: https://dashboard.cipherstash.com/workspaces', diff --git a/packages/cli/src/commands/init/steps/install-deps.ts b/packages/cli/src/commands/init/steps/install-deps.ts index 8357f11ca..70e382d0a 100644 --- a/packages/cli/src/commands/init/steps/install-deps.ts +++ b/packages/cli/src/commands/init/steps/install-deps.ts @@ -34,7 +34,7 @@ const CLI_PACKAGE = 'stash' * skew warning, silently reintroducing #661 for exactly the newest package. */ export const INTEGRATION_ADAPTER_PACKAGES: Readonly> = { - 'prisma-next': '@cipherstash/prisma-next', + 'prisma-next': '@cipherstash/stack-prisma', drizzle: '@cipherstash/stack-drizzle', supabase: '@cipherstash/stack-supabase', } diff --git a/packages/cli/src/commands/init/steps/install-eql.ts b/packages/cli/src/commands/init/steps/install-eql.ts index e8e5003a8..704c5a3f8 100644 --- a/packages/cli/src/commands/init/steps/install-eql.ts +++ b/packages/cli/src/commands/init/steps/install-eql.ts @@ -41,7 +41,7 @@ export const installEqlStep: InitStep = { const integration = state.integration ?? 'postgresql' // Prisma Next ships the EQL bundle as a baseline migration inside - // `@cipherstash/prisma-next`. `prisma-next migrate` runs + // `@cipherstash/stack-prisma`. `prisma-next migrate` runs // it in the same control-plane sweep as the user's application // migrations — running `stash eql install` here would be a // duplicate install and would race with the framework's diff --git a/packages/cli/src/release-train.ts b/packages/cli/src/release-train.ts index 3ad6ffd60..eb80083e1 100644 --- a/packages/cli/src/release-train.ts +++ b/packages/cli/src/release-train.ts @@ -20,7 +20,7 @@ export const RELEASE_TRAIN_MANIFESTS = { '@cipherstash/stack': '../stack/package.json', '@cipherstash/stack-drizzle': '../stack-drizzle/package.json', '@cipherstash/stack-supabase': '../stack-supabase/package.json', - '@cipherstash/prisma-next': '../prisma-next/package.json', + '@cipherstash/stack-prisma': '../stack-prisma/package.json', '@cipherstash/wizard': '../wizard/package.json', } as const diff --git a/packages/prisma-next/CHANGELOG.md b/packages/stack-prisma/CHANGELOG.md similarity index 100% rename from packages/prisma-next/CHANGELOG.md rename to packages/stack-prisma/CHANGELOG.md diff --git a/packages/prisma-next/DEVELOPING.md b/packages/stack-prisma/DEVELOPING.md similarity index 99% rename from packages/prisma-next/DEVELOPING.md rename to packages/stack-prisma/DEVELOPING.md index 78aa21937..273fbb42d 100644 --- a/packages/prisma-next/DEVELOPING.md +++ b/packages/stack-prisma/DEVELOPING.md @@ -1,4 +1,4 @@ -# Developing `@cipherstash/prisma-next` +# Developing `@cipherstash/stack-prisma` Contributor-facing notes for the cipherstash extension. The user-facing surface lives in [`README.md`](./README.md); this file collects the @@ -15,7 +15,7 @@ per-column search-mode flags. ## Source layout ```text -packages/prisma-next/ +packages/stack-prisma/ ├── src/ │ ├── contract.prisma PSL contract source (models NO storage — v3 │ │ declares none; the bundle creates the domains) diff --git a/packages/prisma-next/README.md b/packages/stack-prisma/README.md similarity index 95% rename from packages/prisma-next/README.md rename to packages/stack-prisma/README.md index acc29ce63..050361dbb 100644 --- a/packages/prisma-next/README.md +++ b/packages/stack-prisma/README.md @@ -1,4 +1,4 @@ -# @cipherstash/prisma-next +# @cipherstash/stack-prisma **Searchable field-level encryption for Postgres with [Prisma Next](https://www.npmjs.com/package/prisma-next)** — powered by [`@cipherstash/stack`](../stack/README.md) and the [EQL bundle](https://cipherstash.com/docs/stack/platform/eql). @@ -18,7 +18,7 @@ Declare encrypted columns directly in `schema.prisma`, and the framework's migra ## Installation ```bash -npm install @cipherstash/stack @cipherstash/prisma-next +npm install @cipherstash/stack @cipherstash/stack-prisma ``` ## Quick start @@ -36,7 +36,7 @@ model User { ```typescript // prisma-next.config.ts -import cipherstash from "@cipherstash/prisma-next/control" +import cipherstash from "@cipherstash/stack-prisma/control" // ... other imports export default defineConfig({ // ... family, target, adapter, contract @@ -47,7 +47,7 @@ export default defineConfig({ ```typescript // src/db.ts import "dotenv/config" -import { cipherstashFromStack } from "@cipherstash/prisma-next/v3" +import { cipherstashFromStack } from "@cipherstash/stack-prisma/v3" import postgres from "@prisma-next/postgres/runtime" import type { Contract } from "./prisma/contract.d" import contractJson from "./prisma/contract.json" with { type: "json" } @@ -69,7 +69,7 @@ npx prisma-next migrate # installs EQL bundle + your schema (t ``` ```typescript -import { EncryptedString, decryptAll } from "@cipherstash/prisma-next/runtime" +import { EncryptedString, decryptAll } from "@cipherstash/stack-prisma/runtime" await db.orm.public.User.create({ id: "user-0", diff --git a/packages/prisma-next/integration/adapter.ts b/packages/stack-prisma/integration/adapter.ts similarity index 100% rename from packages/prisma-next/integration/adapter.ts rename to packages/stack-prisma/integration/adapter.ts diff --git a/packages/prisma-next/integration/families.integration.test.ts b/packages/stack-prisma/integration/families.integration.test.ts similarity index 100% rename from packages/prisma-next/integration/families.integration.test.ts rename to packages/stack-prisma/integration/families.integration.test.ts diff --git a/packages/prisma-next/integration/json-adapter.ts b/packages/stack-prisma/integration/json-adapter.ts similarity index 100% rename from packages/prisma-next/integration/json-adapter.ts rename to packages/stack-prisma/integration/json-adapter.ts diff --git a/packages/prisma-next/integration/json.integration.test.ts b/packages/stack-prisma/integration/json.integration.test.ts similarity index 100% rename from packages/prisma-next/integration/json.integration.test.ts rename to packages/stack-prisma/integration/json.integration.test.ts diff --git a/packages/prisma-next/integration/vitest.config.ts b/packages/stack-prisma/integration/vitest.config.ts similarity index 100% rename from packages/prisma-next/integration/vitest.config.ts rename to packages/stack-prisma/integration/vitest.config.ts diff --git a/packages/prisma-next/migrations/20260601T0100_install_eql_v3_bundle/end-contract.d.ts b/packages/stack-prisma/migrations/20260601T0100_install_eql_v3_bundle/end-contract.d.ts similarity index 100% rename from packages/prisma-next/migrations/20260601T0100_install_eql_v3_bundle/end-contract.d.ts rename to packages/stack-prisma/migrations/20260601T0100_install_eql_v3_bundle/end-contract.d.ts diff --git a/packages/prisma-next/migrations/20260601T0100_install_eql_v3_bundle/end-contract.json b/packages/stack-prisma/migrations/20260601T0100_install_eql_v3_bundle/end-contract.json similarity index 100% rename from packages/prisma-next/migrations/20260601T0100_install_eql_v3_bundle/end-contract.json rename to packages/stack-prisma/migrations/20260601T0100_install_eql_v3_bundle/end-contract.json diff --git a/packages/prisma-next/migrations/20260601T0100_install_eql_v3_bundle/migration.json b/packages/stack-prisma/migrations/20260601T0100_install_eql_v3_bundle/migration.json similarity index 100% rename from packages/prisma-next/migrations/20260601T0100_install_eql_v3_bundle/migration.json rename to packages/stack-prisma/migrations/20260601T0100_install_eql_v3_bundle/migration.json diff --git a/packages/prisma-next/migrations/20260601T0100_install_eql_v3_bundle/migration.ts b/packages/stack-prisma/migrations/20260601T0100_install_eql_v3_bundle/migration.ts similarity index 100% rename from packages/prisma-next/migrations/20260601T0100_install_eql_v3_bundle/migration.ts rename to packages/stack-prisma/migrations/20260601T0100_install_eql_v3_bundle/migration.ts diff --git a/packages/prisma-next/migrations/20260601T0100_install_eql_v3_bundle/ops.json b/packages/stack-prisma/migrations/20260601T0100_install_eql_v3_bundle/ops.json similarity index 100% rename from packages/prisma-next/migrations/20260601T0100_install_eql_v3_bundle/ops.json rename to packages/stack-prisma/migrations/20260601T0100_install_eql_v3_bundle/ops.json diff --git a/packages/prisma-next/migrations/20260720T0000_upgrade_eql_v3_3_0_2/migration.json b/packages/stack-prisma/migrations/20260720T0000_upgrade_eql_v3_3_0_2/migration.json similarity index 100% rename from packages/prisma-next/migrations/20260720T0000_upgrade_eql_v3_3_0_2/migration.json rename to packages/stack-prisma/migrations/20260720T0000_upgrade_eql_v3_3_0_2/migration.json diff --git a/packages/prisma-next/migrations/20260720T0000_upgrade_eql_v3_3_0_2/migration.ts b/packages/stack-prisma/migrations/20260720T0000_upgrade_eql_v3_3_0_2/migration.ts similarity index 100% rename from packages/prisma-next/migrations/20260720T0000_upgrade_eql_v3_3_0_2/migration.ts rename to packages/stack-prisma/migrations/20260720T0000_upgrade_eql_v3_3_0_2/migration.ts diff --git a/packages/prisma-next/migrations/20260720T0000_upgrade_eql_v3_3_0_2/ops.json b/packages/stack-prisma/migrations/20260720T0000_upgrade_eql_v3_3_0_2/ops.json similarity index 100% rename from packages/prisma-next/migrations/20260720T0000_upgrade_eql_v3_3_0_2/ops.json rename to packages/stack-prisma/migrations/20260720T0000_upgrade_eql_v3_3_0_2/ops.json diff --git a/packages/prisma-next/migrations/refs/head.json b/packages/stack-prisma/migrations/refs/head.json similarity index 100% rename from packages/prisma-next/migrations/refs/head.json rename to packages/stack-prisma/migrations/refs/head.json diff --git a/packages/prisma-next/package.json b/packages/stack-prisma/package.json similarity index 97% rename from packages/prisma-next/package.json rename to packages/stack-prisma/package.json index 9c335aa2b..41669e002 100644 --- a/packages/prisma-next/package.json +++ b/packages/stack-prisma/package.json @@ -1,5 +1,5 @@ { - "name": "@cipherstash/prisma-next", + "name": "@cipherstash/stack-prisma", "version": "1.0.0-rc.4", "license": "MIT", "author": "CipherStash ", @@ -19,7 +19,7 @@ "repository": { "type": "git", "url": "git+https://github.com/cipherstash/stack.git", - "directory": "packages/prisma-next" + "directory": "packages/stack-prisma" }, "type": "module", "sideEffects": false, diff --git a/packages/prisma-next/prisma-next.config.ts b/packages/stack-prisma/prisma-next.config.ts similarity index 95% rename from packages/prisma-next/prisma-next.config.ts rename to packages/stack-prisma/prisma-next.config.ts index 2c7434dfe..5a9aac56d 100644 --- a/packages/prisma-next/prisma-next.config.ts +++ b/packages/stack-prisma/prisma-next.config.ts @@ -1,5 +1,5 @@ /** - * Prisma Next config for the `@cipherstash/prisma-next` package itself. + * Prisma Next config for the `@cipherstash/stack-prisma` package itself. * * The extension package is treated as a self-contained "project" for * the CLI: `prisma-next contract emit` writes diff --git a/packages/prisma-next/src/contract-authoring.ts b/packages/stack-prisma/src/contract-authoring.ts similarity index 100% rename from packages/prisma-next/src/contract-authoring.ts rename to packages/stack-prisma/src/contract-authoring.ts diff --git a/packages/prisma-next/src/contract.d.ts b/packages/stack-prisma/src/contract.d.ts similarity index 100% rename from packages/prisma-next/src/contract.d.ts rename to packages/stack-prisma/src/contract.d.ts diff --git a/packages/prisma-next/src/contract.json b/packages/stack-prisma/src/contract.json similarity index 100% rename from packages/prisma-next/src/contract.json rename to packages/stack-prisma/src/contract.json diff --git a/packages/prisma-next/src/contract.prisma b/packages/stack-prisma/src/contract.prisma similarity index 100% rename from packages/prisma-next/src/contract.prisma rename to packages/stack-prisma/src/contract.prisma diff --git a/packages/prisma-next/src/execution/abort.ts b/packages/stack-prisma/src/execution/abort.ts similarity index 100% rename from packages/prisma-next/src/execution/abort.ts rename to packages/stack-prisma/src/execution/abort.ts diff --git a/packages/prisma-next/src/execution/decrypt-all.ts b/packages/stack-prisma/src/execution/decrypt-all.ts similarity index 100% rename from packages/prisma-next/src/execution/decrypt-all.ts rename to packages/stack-prisma/src/execution/decrypt-all.ts diff --git a/packages/prisma-next/src/execution/envelope-base.ts b/packages/stack-prisma/src/execution/envelope-base.ts similarity index 100% rename from packages/prisma-next/src/execution/envelope-base.ts rename to packages/stack-prisma/src/execution/envelope-base.ts diff --git a/packages/prisma-next/src/execution/envelope-bigint.ts b/packages/stack-prisma/src/execution/envelope-bigint.ts similarity index 100% rename from packages/prisma-next/src/execution/envelope-bigint.ts rename to packages/stack-prisma/src/execution/envelope-bigint.ts diff --git a/packages/prisma-next/src/execution/envelope-boolean.ts b/packages/stack-prisma/src/execution/envelope-boolean.ts similarity index 100% rename from packages/prisma-next/src/execution/envelope-boolean.ts rename to packages/stack-prisma/src/execution/envelope-boolean.ts diff --git a/packages/prisma-next/src/execution/envelope-date.ts b/packages/stack-prisma/src/execution/envelope-date.ts similarity index 100% rename from packages/prisma-next/src/execution/envelope-date.ts rename to packages/stack-prisma/src/execution/envelope-date.ts diff --git a/packages/prisma-next/src/execution/envelope-json.ts b/packages/stack-prisma/src/execution/envelope-json.ts similarity index 100% rename from packages/prisma-next/src/execution/envelope-json.ts rename to packages/stack-prisma/src/execution/envelope-json.ts diff --git a/packages/prisma-next/src/execution/envelope-string.ts b/packages/stack-prisma/src/execution/envelope-string.ts similarity index 100% rename from packages/prisma-next/src/execution/envelope-string.ts rename to packages/stack-prisma/src/execution/envelope-string.ts diff --git a/packages/prisma-next/src/execution/middleware-registry.ts b/packages/stack-prisma/src/execution/middleware-registry.ts similarity index 100% rename from packages/prisma-next/src/execution/middleware-registry.ts rename to packages/stack-prisma/src/execution/middleware-registry.ts diff --git a/packages/prisma-next/src/execution/routing.ts b/packages/stack-prisma/src/execution/routing.ts similarity index 100% rename from packages/prisma-next/src/execution/routing.ts rename to packages/stack-prisma/src/execution/routing.ts diff --git a/packages/prisma-next/src/execution/sdk.ts b/packages/stack-prisma/src/execution/sdk.ts similarity index 100% rename from packages/prisma-next/src/execution/sdk.ts rename to packages/stack-prisma/src/execution/sdk.ts diff --git a/packages/prisma-next/src/exports/codec-types.ts b/packages/stack-prisma/src/exports/codec-types.ts similarity index 100% rename from packages/prisma-next/src/exports/codec-types.ts rename to packages/stack-prisma/src/exports/codec-types.ts diff --git a/packages/prisma-next/src/exports/column-types.ts b/packages/stack-prisma/src/exports/column-types.ts similarity index 100% rename from packages/prisma-next/src/exports/column-types.ts rename to packages/stack-prisma/src/exports/column-types.ts diff --git a/packages/prisma-next/src/exports/contract-space-typing.ts b/packages/stack-prisma/src/exports/contract-space-typing.ts similarity index 100% rename from packages/prisma-next/src/exports/contract-space-typing.ts rename to packages/stack-prisma/src/exports/contract-space-typing.ts diff --git a/packages/prisma-next/src/exports/control.ts b/packages/stack-prisma/src/exports/control.ts similarity index 100% rename from packages/prisma-next/src/exports/control.ts rename to packages/stack-prisma/src/exports/control.ts diff --git a/packages/prisma-next/src/exports/operation-types.ts b/packages/stack-prisma/src/exports/operation-types.ts similarity index 100% rename from packages/prisma-next/src/exports/operation-types.ts rename to packages/stack-prisma/src/exports/operation-types.ts diff --git a/packages/prisma-next/src/exports/pack.ts b/packages/stack-prisma/src/exports/pack.ts similarity index 100% rename from packages/prisma-next/src/exports/pack.ts rename to packages/stack-prisma/src/exports/pack.ts diff --git a/packages/prisma-next/src/exports/runtime.ts b/packages/stack-prisma/src/exports/runtime.ts similarity index 100% rename from packages/prisma-next/src/exports/runtime.ts rename to packages/stack-prisma/src/exports/runtime.ts diff --git a/packages/prisma-next/src/exports/stack.ts b/packages/stack-prisma/src/exports/stack.ts similarity index 95% rename from packages/prisma-next/src/exports/stack.ts rename to packages/stack-prisma/src/exports/stack.ts index 59276f1dc..b2d57ea9c 100644 --- a/packages/prisma-next/src/exports/stack.ts +++ b/packages/stack-prisma/src/exports/stack.ts @@ -1,5 +1,5 @@ /** - * `@cipherstash/prisma-next/stack` — one-call setup for the + * `@cipherstash/stack-prisma/stack` — one-call setup for the * `@cipherstash/stack` SDK against a Prisma Next contract (EQL v3). * * Most consumers want {@link cipherstashFromStack}: it derives the v3 diff --git a/packages/prisma-next/src/exports/v3.ts b/packages/stack-prisma/src/exports/v3.ts similarity index 97% rename from packages/prisma-next/src/exports/v3.ts rename to packages/stack-prisma/src/exports/v3.ts index 48dceaee9..21734b85a 100644 --- a/packages/prisma-next/src/exports/v3.ts +++ b/packages/stack-prisma/src/exports/v3.ts @@ -1,5 +1,5 @@ /** - * `@cipherstash/prisma-next/v3` — the complete EQL v3 surface in one + * `@cipherstash/stack-prisma/v3` — the complete EQL v3 surface in one * import (decision 1b: v3 is a SEPARATE entry point from the v2 * `./runtime` / `./stack` composition — a client is v2 or v3, never * both; the two runtime descriptors collide if co-registered). diff --git a/packages/prisma-next/src/extension-metadata/codec-metadata.ts b/packages/stack-prisma/src/extension-metadata/codec-metadata.ts similarity index 100% rename from packages/prisma-next/src/extension-metadata/codec-metadata.ts rename to packages/stack-prisma/src/extension-metadata/codec-metadata.ts diff --git a/packages/prisma-next/src/extension-metadata/constants-v3.ts b/packages/stack-prisma/src/extension-metadata/constants-v3.ts similarity index 100% rename from packages/prisma-next/src/extension-metadata/constants-v3.ts rename to packages/stack-prisma/src/extension-metadata/constants-v3.ts diff --git a/packages/prisma-next/src/extension-metadata/constants.ts b/packages/stack-prisma/src/extension-metadata/constants.ts similarity index 100% rename from packages/prisma-next/src/extension-metadata/constants.ts rename to packages/stack-prisma/src/extension-metadata/constants.ts diff --git a/packages/prisma-next/src/extension-metadata/descriptor-meta.ts b/packages/stack-prisma/src/extension-metadata/descriptor-meta.ts similarity index 100% rename from packages/prisma-next/src/extension-metadata/descriptor-meta.ts rename to packages/stack-prisma/src/extension-metadata/descriptor-meta.ts diff --git a/packages/prisma-next/src/migration/cipherstash-codec-v3.ts b/packages/stack-prisma/src/migration/cipherstash-codec-v3.ts similarity index 100% rename from packages/prisma-next/src/migration/cipherstash-codec-v3.ts rename to packages/stack-prisma/src/migration/cipherstash-codec-v3.ts diff --git a/packages/prisma-next/src/migration/eql-bundle-v3.ts b/packages/stack-prisma/src/migration/eql-bundle-v3.ts similarity index 100% rename from packages/prisma-next/src/migration/eql-bundle-v3.ts rename to packages/stack-prisma/src/migration/eql-bundle-v3.ts diff --git a/packages/prisma-next/src/stack/from-stack-v3.ts b/packages/stack-prisma/src/stack/from-stack-v3.ts similarity index 96% rename from packages/prisma-next/src/stack/from-stack-v3.ts rename to packages/stack-prisma/src/stack/from-stack-v3.ts index c144d5c22..b17104c8c 100644 --- a/packages/prisma-next/src/stack/from-stack-v3.ts +++ b/packages/stack-prisma/src/stack/from-stack-v3.ts @@ -1,6 +1,6 @@ /** - * One-call setup for `@cipherstash/prisma-next` against the - * `@cipherstash/stack` EQL v3 client. `@cipherstash/prisma-next` is EQL + * One-call setup for `@cipherstash/stack-prisma` against the + * `@cipherstash/stack` EQL v3 client. `@cipherstash/stack-prisma` is EQL * v3 only; this is the sole `cipherstashFromStack` entry point. * * const cipherstash = await cipherstashFromStack({ contractJson }) @@ -89,7 +89,7 @@ export async function cipherstashFromStack( if (foreignIds.length > 0) { throw new Error( `cipherstashFromStack: contract.json contains non-v3 cipherstash codec ids [${foreignIds.join(', ')}]. ` + - '`@cipherstash/prisma-next` is EQL v3 only — author columns with the v3 ' + + '`@cipherstash/stack-prisma` is EQL v3 only — author columns with the v3 ' + '`cipherstash.*()` constructors and re-emit the contract (`prisma-next contract emit`).', ) } diff --git a/packages/prisma-next/src/types/codec-types.ts b/packages/stack-prisma/src/types/codec-types.ts similarity index 100% rename from packages/prisma-next/src/types/codec-types.ts rename to packages/stack-prisma/src/types/codec-types.ts diff --git a/packages/prisma-next/src/types/operation-types.ts b/packages/stack-prisma/src/types/operation-types.ts similarity index 100% rename from packages/prisma-next/src/types/operation-types.ts rename to packages/stack-prisma/src/types/operation-types.ts diff --git a/packages/prisma-next/src/v3/barrel.ts b/packages/stack-prisma/src/v3/barrel.ts similarity index 100% rename from packages/prisma-next/src/v3/barrel.ts rename to packages/stack-prisma/src/v3/barrel.ts diff --git a/packages/prisma-next/src/v3/bulk-encrypt-v3.ts b/packages/stack-prisma/src/v3/bulk-encrypt-v3.ts similarity index 100% rename from packages/prisma-next/src/v3/bulk-encrypt-v3.ts rename to packages/stack-prisma/src/v3/bulk-encrypt-v3.ts diff --git a/packages/prisma-next/src/v3/catalog.ts b/packages/stack-prisma/src/v3/catalog.ts similarity index 100% rename from packages/prisma-next/src/v3/catalog.ts rename to packages/stack-prisma/src/v3/catalog.ts diff --git a/packages/prisma-next/src/v3/codec-runtime-v3.ts b/packages/stack-prisma/src/v3/codec-runtime-v3.ts similarity index 99% rename from packages/prisma-next/src/v3/codec-runtime-v3.ts rename to packages/stack-prisma/src/v3/codec-runtime-v3.ts index 32e2965fa..ec5a5fe0f 100644 --- a/packages/prisma-next/src/v3/codec-runtime-v3.ts +++ b/packages/stack-prisma/src/v3/codec-runtime-v3.ts @@ -216,7 +216,7 @@ export class CipherstashV3CellCodec< ' extensions: [createCipherstashV3RuntimeDescriptor({ sdk })],\n' + ' middleware: [bulkEncryptMiddlewareV3(sdk)],\n' + ' });\n\n' + - 'Both must close over the SAME `sdk` reference. See the @cipherstash/prisma-next README for the full wiring example.', + 'Both must close over the SAME `sdk` reference. See the @cipherstash/stack-prisma README for the full wiring example.', { codecId: this.descriptor.codecId, reason: 'cipherstash-bulk-encrypt-middleware-not-registered', diff --git a/packages/prisma-next/src/v3/derive-schemas-v3.ts b/packages/stack-prisma/src/v3/derive-schemas-v3.ts similarity index 98% rename from packages/prisma-next/src/v3/derive-schemas-v3.ts rename to packages/stack-prisma/src/v3/derive-schemas-v3.ts index 5bc82a75c..c52d9e356 100644 --- a/packages/prisma-next/src/v3/derive-schemas-v3.ts +++ b/packages/stack-prisma/src/v3/derive-schemas-v3.ts @@ -136,7 +136,7 @@ export function deriveStackSchemasV3( throw new Error( `deriveStackSchemasV3: column "${tableName}"."${columnName}" has v3 codec id "${codecId}" ` + `but nativeType "${nativeType}" maps to no eql/v3 factory. ` + - 'Re-emit the contract with a current @cipherstash/prisma-next.', + 'Re-emit the contract with a current @cipherstash/stack-prisma.', ) } columns[columnName] = factory(columnName) diff --git a/packages/prisma-next/src/v3/envelope-number.ts b/packages/stack-prisma/src/v3/envelope-number.ts similarity index 100% rename from packages/prisma-next/src/v3/envelope-number.ts rename to packages/stack-prisma/src/v3/envelope-number.ts diff --git a/packages/prisma-next/src/v3/from-stack-v3-validate.ts b/packages/stack-prisma/src/v3/from-stack-v3-validate.ts similarity index 100% rename from packages/prisma-next/src/v3/from-stack-v3-validate.ts rename to packages/stack-prisma/src/v3/from-stack-v3-validate.ts diff --git a/packages/prisma-next/src/v3/operators-v3.ts b/packages/stack-prisma/src/v3/operators-v3.ts similarity index 99% rename from packages/prisma-next/src/v3/operators-v3.ts rename to packages/stack-prisma/src/v3/operators-v3.ts index 723204b7a..02957d278 100644 --- a/packages/prisma-next/src/v3/operators-v3.ts +++ b/packages/stack-prisma/src/v3/operators-v3.ts @@ -372,7 +372,7 @@ function requireQueryCast(ctx: ColumnContext, method: string): string { throw operatorError( ctx, method, - `cipherstash ${method}: domain ${ctx.meta.nativeType} passed its capability gate but has no eql_v3.query_* operand type. This is a bug in @cipherstash/prisma-next — please report it.`, + `cipherstash ${method}: domain ${ctx.meta.nativeType} passed its capability gate but has no eql_v3.query_* operand type. This is a bug in @cipherstash/stack-prisma — please report it.`, ) } return cast diff --git a/packages/prisma-next/src/v3/query-term.ts b/packages/stack-prisma/src/v3/query-term.ts similarity index 100% rename from packages/prisma-next/src/v3/query-term.ts rename to packages/stack-prisma/src/v3/query-term.ts diff --git a/packages/prisma-next/src/v3/runtime-v3.ts b/packages/stack-prisma/src/v3/runtime-v3.ts similarity index 100% rename from packages/prisma-next/src/v3/runtime-v3.ts rename to packages/stack-prisma/src/v3/runtime-v3.ts diff --git a/packages/prisma-next/src/v3/sdk-adapter-v3.ts b/packages/stack-prisma/src/v3/sdk-adapter-v3.ts similarity index 100% rename from packages/prisma-next/src/v3/sdk-adapter-v3.ts rename to packages/stack-prisma/src/v3/sdk-adapter-v3.ts diff --git a/packages/prisma-next/src/v3/wire-v3.ts b/packages/stack-prisma/src/v3/wire-v3.ts similarity index 100% rename from packages/prisma-next/src/v3/wire-v3.ts rename to packages/stack-prisma/src/v3/wire-v3.ts diff --git a/packages/prisma-next/test/abort.test.ts b/packages/stack-prisma/test/abort.test.ts similarity index 100% rename from packages/prisma-next/test/abort.test.ts rename to packages/stack-prisma/test/abort.test.ts diff --git a/packages/prisma-next/test/authoring.test.ts b/packages/stack-prisma/test/authoring.test.ts similarity index 100% rename from packages/prisma-next/test/authoring.test.ts rename to packages/stack-prisma/test/authoring.test.ts diff --git a/packages/prisma-next/test/bulk-encrypt-middleware.helpers.ts b/packages/stack-prisma/test/bulk-encrypt-middleware.helpers.ts similarity index 100% rename from packages/prisma-next/test/bulk-encrypt-middleware.helpers.ts rename to packages/stack-prisma/test/bulk-encrypt-middleware.helpers.ts diff --git a/packages/prisma-next/test/bundling-isolation.test.ts b/packages/stack-prisma/test/bundling-isolation.test.ts similarity index 98% rename from packages/prisma-next/test/bundling-isolation.test.ts rename to packages/stack-prisma/test/bundling-isolation.test.ts index a6d2ebdc2..fa7793799 100644 --- a/packages/prisma-next/test/bundling-isolation.test.ts +++ b/packages/stack-prisma/test/bundling-isolation.test.ts @@ -195,7 +195,7 @@ function isAllowedSharedChunk(chunk: string): boolean { } describe('bundling isolation', () => { - it('dist entry files exist (run `pnpm --filter @cipherstash/prisma-next build` first)', () => { + it('dist entry files exist (run `pnpm --filter @cipherstash/stack-prisma build` first)', () => { for (const entry of ENTRY_FILES) { expect(existsSync(join(DIST, entry)), `dist/${entry} is missing`).toBe( true, diff --git a/packages/prisma-next/test/column-types.test.ts b/packages/stack-prisma/test/column-types.test.ts similarity index 100% rename from packages/prisma-next/test/column-types.test.ts rename to packages/stack-prisma/test/column-types.test.ts diff --git a/packages/prisma-next/test/decrypt-all.test.ts b/packages/stack-prisma/test/decrypt-all.test.ts similarity index 100% rename from packages/prisma-next/test/decrypt-all.test.ts rename to packages/stack-prisma/test/decrypt-all.test.ts diff --git a/packages/prisma-next/test/descriptor.test.ts b/packages/stack-prisma/test/descriptor.test.ts similarity index 100% rename from packages/prisma-next/test/descriptor.test.ts rename to packages/stack-prisma/test/descriptor.test.ts diff --git a/packages/prisma-next/test/envelope-bigint.test.ts b/packages/stack-prisma/test/envelope-bigint.test.ts similarity index 100% rename from packages/prisma-next/test/envelope-bigint.test.ts rename to packages/stack-prisma/test/envelope-bigint.test.ts diff --git a/packages/prisma-next/test/envelope-boolean.test.ts b/packages/stack-prisma/test/envelope-boolean.test.ts similarity index 100% rename from packages/prisma-next/test/envelope-boolean.test.ts rename to packages/stack-prisma/test/envelope-boolean.test.ts diff --git a/packages/prisma-next/test/envelope-date.test.ts b/packages/stack-prisma/test/envelope-date.test.ts similarity index 100% rename from packages/prisma-next/test/envelope-date.test.ts rename to packages/stack-prisma/test/envelope-date.test.ts diff --git a/packages/prisma-next/test/envelope-json.test.ts b/packages/stack-prisma/test/envelope-json.test.ts similarity index 100% rename from packages/prisma-next/test/envelope-json.test.ts rename to packages/stack-prisma/test/envelope-json.test.ts diff --git a/packages/prisma-next/test/envelope-string.test.ts b/packages/stack-prisma/test/envelope-string.test.ts similarity index 100% rename from packages/prisma-next/test/envelope-string.test.ts rename to packages/stack-prisma/test/envelope-string.test.ts diff --git a/packages/prisma-next/test/envelope.types.test-d.ts b/packages/stack-prisma/test/envelope.types.test-d.ts similarity index 100% rename from packages/prisma-next/test/envelope.types.test-d.ts rename to packages/stack-prisma/test/envelope.types.test-d.ts diff --git a/packages/prisma-next/test/equality-trait-removal.test.ts b/packages/stack-prisma/test/equality-trait-removal.test.ts similarity index 100% rename from packages/prisma-next/test/equality-trait-removal.test.ts rename to packages/stack-prisma/test/equality-trait-removal.test.ts diff --git a/packages/prisma-next/test/live/bigint-live-pg.test.ts b/packages/stack-prisma/test/live/bigint-live-pg.test.ts similarity index 100% rename from packages/prisma-next/test/live/bigint-live-pg.test.ts rename to packages/stack-prisma/test/live/bigint-live-pg.test.ts diff --git a/packages/prisma-next/test/live/boolean-storage-live-pg.test.ts b/packages/stack-prisma/test/live/boolean-storage-live-pg.test.ts similarity index 100% rename from packages/prisma-next/test/live/boolean-storage-live-pg.test.ts rename to packages/stack-prisma/test/live/boolean-storage-live-pg.test.ts diff --git a/packages/prisma-next/test/live/bulk-encrypt-live-pg.test.ts b/packages/stack-prisma/test/live/bulk-encrypt-live-pg.test.ts similarity index 100% rename from packages/prisma-next/test/live/bulk-encrypt-live-pg.test.ts rename to packages/stack-prisma/test/live/bulk-encrypt-live-pg.test.ts diff --git a/packages/prisma-next/test/live/helpers/eql-v3.ts b/packages/stack-prisma/test/live/helpers/eql-v3.ts similarity index 100% rename from packages/prisma-next/test/live/helpers/eql-v3.ts rename to packages/stack-prisma/test/live/helpers/eql-v3.ts diff --git a/packages/prisma-next/test/live/helpers/harness.ts b/packages/stack-prisma/test/live/helpers/harness.ts similarity index 100% rename from packages/prisma-next/test/live/helpers/harness.ts rename to packages/stack-prisma/test/live/helpers/harness.ts diff --git a/packages/prisma-next/test/live/helpers/live-gate.ts b/packages/stack-prisma/test/live/helpers/live-gate.ts similarity index 100% rename from packages/prisma-next/test/live/helpers/live-gate.ts rename to packages/stack-prisma/test/live/helpers/live-gate.ts diff --git a/packages/prisma-next/test/live/migration-apply-live-pg.test.ts b/packages/stack-prisma/test/live/migration-apply-live-pg.test.ts similarity index 100% rename from packages/prisma-next/test/live/migration-apply-live-pg.test.ts rename to packages/stack-prisma/test/live/migration-apply-live-pg.test.ts diff --git a/packages/prisma-next/test/live/operators-live-pg.test.ts b/packages/stack-prisma/test/live/operators-live-pg.test.ts similarity index 100% rename from packages/prisma-next/test/live/operators-live-pg.test.ts rename to packages/stack-prisma/test/live/operators-live-pg.test.ts diff --git a/packages/prisma-next/test/live/operators-null-live-pg.test.ts b/packages/stack-prisma/test/live/operators-null-live-pg.test.ts similarity index 100% rename from packages/prisma-next/test/live/operators-null-live-pg.test.ts rename to packages/stack-prisma/test/live/operators-null-live-pg.test.ts diff --git a/packages/prisma-next/test/operation-types.types.test-d.ts b/packages/stack-prisma/test/operation-types.types.test-d.ts similarity index 100% rename from packages/prisma-next/test/operation-types.types.test-d.ts rename to packages/stack-prisma/test/operation-types.types.test-d.ts diff --git a/packages/prisma-next/test/psl-interpretation.test.ts b/packages/stack-prisma/test/psl-interpretation.test.ts similarity index 100% rename from packages/prisma-next/test/psl-interpretation.test.ts rename to packages/stack-prisma/test/psl-interpretation.test.ts diff --git a/packages/prisma-next/test/routing.test.ts b/packages/stack-prisma/test/routing.test.ts similarity index 100% rename from packages/prisma-next/test/routing.test.ts rename to packages/stack-prisma/test/routing.test.ts diff --git a/packages/prisma-next/test/sdk.types.test-d.ts b/packages/stack-prisma/test/sdk.types.test-d.ts similarity index 100% rename from packages/prisma-next/test/sdk.types.test-d.ts rename to packages/stack-prisma/test/sdk.types.test-d.ts diff --git a/packages/prisma-next/test/v3/bulk-encrypt-v3.test.ts b/packages/stack-prisma/test/v3/bulk-encrypt-v3.test.ts similarity index 100% rename from packages/prisma-next/test/v3/bulk-encrypt-v3.test.ts rename to packages/stack-prisma/test/v3/bulk-encrypt-v3.test.ts diff --git a/packages/prisma-next/test/v3/catalog-invariants.test.ts b/packages/stack-prisma/test/v3/catalog-invariants.test.ts similarity index 100% rename from packages/prisma-next/test/v3/catalog-invariants.test.ts rename to packages/stack-prisma/test/v3/catalog-invariants.test.ts diff --git a/packages/prisma-next/test/v3/catalog.test.ts b/packages/stack-prisma/test/v3/catalog.test.ts similarity index 100% rename from packages/prisma-next/test/v3/catalog.test.ts rename to packages/stack-prisma/test/v3/catalog.test.ts diff --git a/packages/prisma-next/test/v3/codec-runtime-v3.test.ts b/packages/stack-prisma/test/v3/codec-runtime-v3.test.ts similarity index 100% rename from packages/prisma-next/test/v3/codec-runtime-v3.test.ts rename to packages/stack-prisma/test/v3/codec-runtime-v3.test.ts diff --git a/packages/prisma-next/test/v3/codec-types-v3.test-d.ts b/packages/stack-prisma/test/v3/codec-types-v3.test-d.ts similarity index 100% rename from packages/prisma-next/test/v3/codec-types-v3.test-d.ts rename to packages/stack-prisma/test/v3/codec-types-v3.test-d.ts diff --git a/packages/prisma-next/test/v3/column-types.test-d.ts b/packages/stack-prisma/test/v3/column-types.test-d.ts similarity index 100% rename from packages/prisma-next/test/v3/column-types.test-d.ts rename to packages/stack-prisma/test/v3/column-types.test-d.ts diff --git a/packages/prisma-next/test/v3/constants-v3.test.ts b/packages/stack-prisma/test/v3/constants-v3.test.ts similarity index 100% rename from packages/prisma-next/test/v3/constants-v3.test.ts rename to packages/stack-prisma/test/v3/constants-v3.test.ts diff --git a/packages/prisma-next/test/v3/derive-schemas-v3.test.ts b/packages/stack-prisma/test/v3/derive-schemas-v3.test.ts similarity index 100% rename from packages/prisma-next/test/v3/derive-schemas-v3.test.ts rename to packages/stack-prisma/test/v3/derive-schemas-v3.test.ts diff --git a/packages/prisma-next/test/v3/envelope-number.test.ts b/packages/stack-prisma/test/v3/envelope-number.test.ts similarity index 100% rename from packages/prisma-next/test/v3/envelope-number.test.ts rename to packages/stack-prisma/test/v3/envelope-number.test.ts diff --git a/packages/prisma-next/test/v3/from-stack-divergence-v3.test.ts b/packages/stack-prisma/test/v3/from-stack-divergence-v3.test.ts similarity index 100% rename from packages/prisma-next/test/v3/from-stack-divergence-v3.test.ts rename to packages/stack-prisma/test/v3/from-stack-divergence-v3.test.ts diff --git a/packages/prisma-next/test/v3/from-stack-v3.test.ts b/packages/stack-prisma/test/v3/from-stack-v3.test.ts similarity index 100% rename from packages/prisma-next/test/v3/from-stack-v3.test.ts rename to packages/stack-prisma/test/v3/from-stack-v3.test.ts diff --git a/packages/prisma-next/test/v3/migration-v3.test.ts b/packages/stack-prisma/test/v3/migration-v3.test.ts similarity index 100% rename from packages/prisma-next/test/v3/migration-v3.test.ts rename to packages/stack-prisma/test/v3/migration-v3.test.ts diff --git a/packages/prisma-next/test/v3/operator-gating-v3.test.ts b/packages/stack-prisma/test/v3/operator-gating-v3.test.ts similarity index 100% rename from packages/prisma-next/test/v3/operator-gating-v3.test.ts rename to packages/stack-prisma/test/v3/operator-gating-v3.test.ts diff --git a/packages/prisma-next/test/v3/operator-lowering-v3-equality.test.ts b/packages/stack-prisma/test/v3/operator-lowering-v3-equality.test.ts similarity index 100% rename from packages/prisma-next/test/v3/operator-lowering-v3-equality.test.ts rename to packages/stack-prisma/test/v3/operator-lowering-v3-equality.test.ts diff --git a/packages/prisma-next/test/v3/operator-lowering-v3-json.test.ts b/packages/stack-prisma/test/v3/operator-lowering-v3-json.test.ts similarity index 100% rename from packages/prisma-next/test/v3/operator-lowering-v3-json.test.ts rename to packages/stack-prisma/test/v3/operator-lowering-v3-json.test.ts diff --git a/packages/prisma-next/test/v3/operator-lowering-v3-order-range.test.ts b/packages/stack-prisma/test/v3/operator-lowering-v3-order-range.test.ts similarity index 100% rename from packages/prisma-next/test/v3/operator-lowering-v3-order-range.test.ts rename to packages/stack-prisma/test/v3/operator-lowering-v3-order-range.test.ts diff --git a/packages/prisma-next/test/v3/operator-lowering-v3-text-search.test.ts b/packages/stack-prisma/test/v3/operator-lowering-v3-text-search.test.ts similarity index 100% rename from packages/prisma-next/test/v3/operator-lowering-v3-text-search.test.ts rename to packages/stack-prisma/test/v3/operator-lowering-v3-text-search.test.ts diff --git a/packages/prisma-next/test/v3/operator-lowering-v3.helpers.ts b/packages/stack-prisma/test/v3/operator-lowering-v3.helpers.ts similarity index 100% rename from packages/prisma-next/test/v3/operator-lowering-v3.helpers.ts rename to packages/stack-prisma/test/v3/operator-lowering-v3.helpers.ts diff --git a/packages/prisma-next/test/v3/properties.test.ts b/packages/stack-prisma/test/v3/properties.test.ts similarity index 100% rename from packages/prisma-next/test/v3/properties.test.ts rename to packages/stack-prisma/test/v3/properties.test.ts diff --git a/packages/prisma-next/test/v3/runtime-v3.test.ts b/packages/stack-prisma/test/v3/runtime-v3.test.ts similarity index 100% rename from packages/prisma-next/test/v3/runtime-v3.test.ts rename to packages/stack-prisma/test/v3/runtime-v3.test.ts diff --git a/packages/prisma-next/test/v3/sdk-adapter-v3.test.ts b/packages/stack-prisma/test/v3/sdk-adapter-v3.test.ts similarity index 100% rename from packages/prisma-next/test/v3/sdk-adapter-v3.test.ts rename to packages/stack-prisma/test/v3/sdk-adapter-v3.test.ts diff --git a/packages/prisma-next/test/v3/vendored-space-parity.test.ts b/packages/stack-prisma/test/v3/vendored-space-parity.test.ts similarity index 100% rename from packages/prisma-next/test/v3/vendored-space-parity.test.ts rename to packages/stack-prisma/test/v3/vendored-space-parity.test.ts diff --git a/packages/prisma-next/test/v3/wire-v3.test.ts b/packages/stack-prisma/test/v3/wire-v3.test.ts similarity index 100% rename from packages/prisma-next/test/v3/wire-v3.test.ts rename to packages/stack-prisma/test/v3/wire-v3.test.ts diff --git a/packages/prisma-next/tsconfig.json b/packages/stack-prisma/tsconfig.json similarity index 100% rename from packages/prisma-next/tsconfig.json rename to packages/stack-prisma/tsconfig.json diff --git a/packages/prisma-next/tsup.config.ts b/packages/stack-prisma/tsup.config.ts similarity index 100% rename from packages/prisma-next/tsup.config.ts rename to packages/stack-prisma/tsup.config.ts diff --git a/packages/prisma-next/turbo.json b/packages/stack-prisma/turbo.json similarity index 100% rename from packages/prisma-next/turbo.json rename to packages/stack-prisma/turbo.json diff --git a/packages/prisma-next/vitest.config.ts b/packages/stack-prisma/vitest.config.ts similarity index 100% rename from packages/prisma-next/vitest.config.ts rename to packages/stack-prisma/vitest.config.ts diff --git a/packages/stack/__tests__/logger-edge-safety.test.ts b/packages/stack/__tests__/logger-edge-safety.test.ts index 87e607f40..f6f441c67 100644 --- a/packages/stack/__tests__/logger-edge-safety.test.ts +++ b/packages/stack/__tests__/logger-edge-safety.test.ts @@ -3,7 +3,7 @@ * (`src/adapter-kit.ts:60`), and three first-party adapters value-import * adapter-kit: `packages/stack-supabase/src/column-map.ts:1`, * `packages/stack-drizzle/src/column.ts:1`, - * `packages/prisma-next/src/exports/column-types.ts:19`. A realm with no + * `packages/stack-prisma/src/exports/column-types.ts:19`. A realm with no * `process` binding turns an unguarded module-scope `process.env` read in the * logger into a `ReferenceError` at import time on exactly the runtimes those * builds exist to serve. diff --git a/packages/stack/__tests__/types-public-surface.test-d.ts b/packages/stack/__tests__/types-public-surface.test-d.ts index 68d3ac5c6..70886ae1f 100644 --- a/packages/stack/__tests__/types-public-surface.test-d.ts +++ b/packages/stack/__tests__/types-public-surface.test-d.ts @@ -9,7 +9,7 @@ * - REMOVING a name breaks consumers who legitimately need to NAME a type that * appears in a public signature (declaring a variable before the `await`, * typing an adapter's parameter). `@cipherstash/stack-drizzle`, - * `@cipherstash/stack-supabase` and `@cipherstash/prisma-next` all import from + * `@cipherstash/stack-supabase` and `@cipherstash/stack-prisma` all import from * this subpath. * - ADDING a name is how the EQL v2 authoring surface comes back. `src/types.ts` * still declares v2-shaped types — the client must keep DECRYPTING v2 payloads, diff --git a/packages/stack/__tests__/wasm-inline-bundle-isolation.test.ts b/packages/stack/__tests__/wasm-inline-bundle-isolation.test.ts index 2e8a65e27..38f6c5e64 100644 --- a/packages/stack/__tests__/wasm-inline-bundle-isolation.test.ts +++ b/packages/stack/__tests__/wasm-inline-bundle-isolation.test.ts @@ -23,7 +23,7 @@ import { describe, expect, it } from 'vitest' // see it — they mock the `/wasm-inline` subpath and run under Node, where the // native root resolves fine — so the assertion has to be on the built artifact. // -// Mirrors `packages/prisma-next/test/bundling-isolation.test.ts`. +// Mirrors `packages/stack-prisma/test/bundling-isolation.test.ts`. const packageRoot = path.resolve(fileURLToPath(import.meta.url), '../..') const distDir = path.join(packageRoot, 'dist') diff --git a/packages/wizard/src/lib/install-skills.ts b/packages/wizard/src/lib/install-skills.ts index 68c6831cf..a870652f2 100644 --- a/packages/wizard/src/lib/install-skills.ts +++ b/packages/wizard/src/lib/install-skills.ts @@ -36,7 +36,7 @@ export const SKILL_MAP: Record = { ], prisma: [ 'stash-encryption', - 'stash-prisma-next', + 'stash-prisma', 'stash-indexing', 'stash-deployment', 'stash-zerokms', diff --git a/packages/wizard/tsconfig.json b/packages/wizard/tsconfig.json index 7cc1059cb..d85358a58 100644 --- a/packages/wizard/tsconfig.json +++ b/packages/wizard/tsconfig.json @@ -14,7 +14,7 @@ // not include `node` by default, so without this the wizard's three // `auth.AutoStrategy` call sites fail to typecheck even though they run // fine — the wizard is a Node CLI and always loads the `node` branch. - // Matches `packages/stack`, `packages/prisma-next`, `packages/test-kit`, + // Matches `packages/stack`, `packages/stack-prisma`, `packages/test-kit`, // `packages/stack-drizzle` and `packages/stack-supabase`. "customConditions": ["node"], diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index cb4888fe8..8af502263 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -142,12 +142,12 @@ importers: examples/prisma: dependencies: - '@cipherstash/prisma-next': - specifier: workspace:* - version: link:../../packages/prisma-next '@cipherstash/stack': specifier: workspace:* version: link:../../packages/stack + '@cipherstash/stack-prisma': + specifier: workspace:* + version: link:../../packages/stack-prisma '@prisma-next/adapter-postgres': specifier: 0.16.0 version: 0.16.0(typanion@3.14.0)(typescript@5.9.3) @@ -374,100 +374,6 @@ importers: specifier: 4.62.2 version: 4.62.2 - packages/prisma-next: - dependencies: - '@cipherstash/eql': - specifier: 3.0.2 - version: 3.0.2 - '@cipherstash/stack': - specifier: workspace:* - version: link:../stack - '@prisma-next/contract': - specifier: 0.16.0 - version: 0.16.0(typescript@5.9.3) - '@prisma-next/family-sql': - specifier: 0.16.0 - version: 0.16.0(typescript@5.9.3) - '@prisma-next/framework-components': - specifier: 0.16.0 - version: 0.16.0(typescript@5.9.3) - '@prisma-next/migration-tools': - specifier: 0.16.0 - version: 0.16.0(typescript@5.9.3) - '@prisma-next/sql-contract': - specifier: 0.16.0 - version: 0.16.0(typescript@5.9.3) - '@prisma-next/sql-operations': - specifier: 0.16.0 - version: 0.16.0(typescript@5.9.3) - '@prisma-next/sql-relational-core': - specifier: 0.16.0 - version: 0.16.0(typescript@5.9.3) - '@prisma-next/sql-runtime': - specifier: 0.16.0 - version: 0.16.0(typescript@5.9.3) - '@prisma-next/ts-render': - specifier: 0.16.0 - version: 0.16.0(typescript@5.9.3) - '@prisma-next/utils': - specifier: 0.16.0 - version: 0.16.0(typescript@5.9.3) - arktype: - specifier: ^2.2.3 - version: 2.2.3 - devDependencies: - '@cipherstash/test-kit': - specifier: workspace:* - version: link:../test-kit - '@prisma-next/adapter-postgres': - specifier: 0.16.0 - version: 0.16.0(typanion@3.14.0)(typescript@5.9.3) - '@prisma-next/cli': - specifier: 0.16.0 - version: 0.16.0(typanion@3.14.0)(typescript@5.9.3) - '@prisma-next/driver-postgres': - specifier: 0.16.0 - version: 0.16.0(typescript@5.9.3) - '@prisma-next/extension-author-tools': - specifier: 0.16.0 - version: 0.16.0(typescript@5.9.3) - '@prisma-next/psl-parser': - specifier: 0.16.0 - version: 0.16.0(typescript@5.9.3) - '@prisma-next/sql-contract-psl': - specifier: 0.16.0 - version: 0.16.0(typescript@5.9.3) - '@prisma-next/sql-contract-ts': - specifier: 0.16.0 - version: 0.16.0(typescript@5.9.3) - '@prisma-next/sql-schema-ir': - specifier: 0.16.0 - version: 0.16.0(typescript@5.9.3) - '@prisma-next/target-postgres': - specifier: 0.16.0 - version: 0.16.0(typanion@3.14.0)(typescript@5.9.3) - dotenv: - specifier: 17.4.2 - version: 17.4.2 - fast-check: - specifier: ^4.8.0 - version: 4.9.0 - pathe: - specifier: ^2.0.3 - version: 2.0.3 - postgres: - specifier: ^3.4.8 - version: 3.4.9 - tsup: - specifier: catalog:repo - version: 8.5.1(jiti@2.7.0)(postcss@8.5.14)(tsx@4.23.0)(typescript@5.9.3)(yaml@2.9.0) - typescript: - specifier: catalog:repo - version: 5.9.3 - vitest: - specifier: catalog:repo - version: 3.2.7(@types/node@26.1.1)(jiti@2.7.0)(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.23.0)(yaml@2.9.0) - packages/stack: dependencies: '@byteslice/result': @@ -603,6 +509,100 @@ importers: specifier: catalog:repo version: 3.2.7(@types/node@26.1.1)(jiti@2.7.0)(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.23.0)(yaml@2.9.0) + packages/stack-prisma: + dependencies: + '@cipherstash/eql': + specifier: 3.0.2 + version: 3.0.2 + '@cipherstash/stack': + specifier: workspace:* + version: link:../stack + '@prisma-next/contract': + specifier: 0.16.0 + version: 0.16.0(typescript@5.9.3) + '@prisma-next/family-sql': + specifier: 0.16.0 + version: 0.16.0(typescript@5.9.3) + '@prisma-next/framework-components': + specifier: 0.16.0 + version: 0.16.0(typescript@5.9.3) + '@prisma-next/migration-tools': + specifier: 0.16.0 + version: 0.16.0(typescript@5.9.3) + '@prisma-next/sql-contract': + specifier: 0.16.0 + version: 0.16.0(typescript@5.9.3) + '@prisma-next/sql-operations': + specifier: 0.16.0 + version: 0.16.0(typescript@5.9.3) + '@prisma-next/sql-relational-core': + specifier: 0.16.0 + version: 0.16.0(typescript@5.9.3) + '@prisma-next/sql-runtime': + specifier: 0.16.0 + version: 0.16.0(typescript@5.9.3) + '@prisma-next/ts-render': + specifier: 0.16.0 + version: 0.16.0(typescript@5.9.3) + '@prisma-next/utils': + specifier: 0.16.0 + version: 0.16.0(typescript@5.9.3) + arktype: + specifier: ^2.2.3 + version: 2.2.3 + devDependencies: + '@cipherstash/test-kit': + specifier: workspace:* + version: link:../test-kit + '@prisma-next/adapter-postgres': + specifier: 0.16.0 + version: 0.16.0(typanion@3.14.0)(typescript@5.9.3) + '@prisma-next/cli': + specifier: 0.16.0 + version: 0.16.0(typanion@3.14.0)(typescript@5.9.3) + '@prisma-next/driver-postgres': + specifier: 0.16.0 + version: 0.16.0(typescript@5.9.3) + '@prisma-next/extension-author-tools': + specifier: 0.16.0 + version: 0.16.0(typescript@5.9.3) + '@prisma-next/psl-parser': + specifier: 0.16.0 + version: 0.16.0(typescript@5.9.3) + '@prisma-next/sql-contract-psl': + specifier: 0.16.0 + version: 0.16.0(typescript@5.9.3) + '@prisma-next/sql-contract-ts': + specifier: 0.16.0 + version: 0.16.0(typescript@5.9.3) + '@prisma-next/sql-schema-ir': + specifier: 0.16.0 + version: 0.16.0(typescript@5.9.3) + '@prisma-next/target-postgres': + specifier: 0.16.0 + version: 0.16.0(typanion@3.14.0)(typescript@5.9.3) + dotenv: + specifier: 17.4.2 + version: 17.4.2 + fast-check: + specifier: ^4.8.0 + version: 4.9.0 + pathe: + specifier: ^2.0.3 + version: 2.0.3 + postgres: + specifier: ^3.4.8 + version: 3.4.9 + tsup: + specifier: catalog:repo + version: 8.5.1(jiti@2.7.0)(postcss@8.5.14)(tsx@4.23.0)(typescript@5.9.3)(yaml@2.9.0) + typescript: + specifier: catalog:repo + version: 5.9.3 + vitest: + specifier: catalog:repo + version: 3.2.7(@types/node@26.1.1)(jiti@2.7.0)(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.23.0)(yaml@2.9.0) + packages/stack-supabase: dependencies: '@cipherstash/stack': diff --git a/scripts/__tests__/workflow-turbo-build-deps.test.mjs b/scripts/__tests__/workflow-turbo-build-deps.test.mjs index 82386574d..50261d4be 100644 --- a/scripts/__tests__/workflow-turbo-build-deps.test.mjs +++ b/scripts/__tests__/workflow-turbo-build-deps.test.mjs @@ -56,7 +56,7 @@ const WORKFLOWS = readdirSync(resolve(REPO_ROOT, '.github/workflows')) * not add to it. Route new steps through `turbo run` instead. */ const KNOWN_BARE = new Set([ - 'pnpm --filter @cipherstash/prisma-next run typecheck', + 'pnpm --filter @cipherstash/stack-prisma run typecheck', 'pnpm --filter @cipherstash/wizard run typecheck', ]) @@ -110,7 +110,7 @@ function invokedTask(line) { * Only ever consult this for an UNFILTERED invocation. `pnpm --filter * ` runs that package's script, so the root script's delegation says * nothing about it — reading it either way exempted a genuinely bare - * `pnpm --filter @cipherstash/prisma-next-example test:e2e` purely because the + * `pnpm --filter @cipherstash/prisma-example test:e2e` purely because the * root happens to define `"test:e2e": "turbo run test:e2e"` (#787 review * follow-up). */ diff --git a/skills/stash-deployment/SKILL.md b/skills/stash-deployment/SKILL.md index 1d32ba023..88285d4d0 100644 --- a/skills/stash-deployment/SKILL.md +++ b/skills/stash-deployment/SKILL.md @@ -14,7 +14,7 @@ user reads the row. This skill covers how to sequence that across deploys. For the API and the lifecycle model see `stash-encryption`; for the commands see `stash-cli`; for -framework specifics see `stash-drizzle` / `stash-supabase` / `stash-prisma-next`. +framework specifics see `stash-drizzle` / `stash-supabase` / `stash-prisma`. Everything here describes **EQL v3**, the only authoring generation. The EQL v2 rollout commands were removed — `stash encrypt cutover` (the old v2 rename swap) @@ -170,7 +170,7 @@ Then **build the `eql_v3.*` extractor indexes** for every capability you query a index maintenance during the backfill, and the switched reads engage an index from the first query. Ship the DDL through whatever migration flow owns the schema — a Drizzle or Supabase migration, an index migration in the Prisma Next graph -(never out-of-band there — see `stash-prisma-next`), or your SQL migration tool. +(never out-of-band there — see `stash-prisma`), or your SQL migration tool. Never ad-hoc against production. Recipes in `stash-indexing`. ### Deploy 2 — read cutover @@ -322,7 +322,7 @@ every deploy. Prisma Next is **contract-first**: `contract.prisma` is emitted to `contract.json` / `contract.d.ts`, and the database is advanced along a migration graph. CipherStash -integrates through `@cipherstash/prisma-next`, which contributes its own contract +integrates through `@cipherstash/stack-prisma`, which contributes its own contract space, so **EQL installs as part of your migration graph** — `prisma-next migrate` (the top-level apply verb) installs the bundle alongside your schema. Never `stash eql install`, which refuses on a Prisma Next project. @@ -468,4 +468,4 @@ id is printed in the check output itself. - **`stash-zerokms`** — the keyset/grant model that governs who can decrypt what - **`stash-auth`** — auth strategies, the `CS_*` variables, and credential resolution order - **`stash-edge`** — edge/serverless runtimes and the `@cipherstash/stack/wasm-inline` entry -- **`stash-prisma-next`** / **`stash-drizzle`** / **`stash-supabase`** — integration specifics +- **`stash-prisma`** / **`stash-drizzle`** / **`stash-supabase`** — integration specifics diff --git a/skills/stash-encryption/SKILL.md b/skills/stash-encryption/SKILL.md index b2b776c61..2999f217e 100644 --- a/skills/stash-encryption/SKILL.md +++ b/skills/stash-encryption/SKILL.md @@ -981,7 +981,7 @@ Useful when the backfill needs to run in a worker, on a schedule, or alongside a |---|---|---| | Drizzle ORM | `@cipherstash/stack-drizzle` — v3 column factories (each `types.*` factory emits its domain as the column's SQL type for `drizzle-kit generate`), schema extraction, auto-encrypting operators (`ops.eq`, `ops.matches`, `ops.contains`, `ops.selector`, `ops.asc`, ...) | `stash-drizzle` | | Supabase | `encryptedSupabase` from `@cipherstash/stack-supabase` — schema-aware query builder (`eq`, `matches`, `contains`, `selectorEq`/`selectorNe`, ...) that works through PostgREST, including as `anon` | `stash-supabase` | -| Prisma | `@cipherstash/prisma-next` — searchable field-level encryption for Postgres | — | +| Prisma | `@cipherstash/stack-prisma` — searchable field-level encryption for Postgres | — | | DynamoDB | `encryptedDynamoDB` from `@cipherstash/stack/dynamodb` — encrypt is **EQL v3 only**; decrypt still reads existing v2 items | `stash-dynamodb` | ## Complete API Reference diff --git a/skills/stash-indexing/SKILL.md b/skills/stash-indexing/SKILL.md index 08b803648..4dc3de8cd 100644 --- a/skills/stash-indexing/SKILL.md +++ b/skills/stash-indexing/SKILL.md @@ -255,7 +255,7 @@ Index not being used: **The integrations emit the query operators for you — none applies index DDL on its own. Making sure these indexes exist is always your job.** This skill is the general model — recipes, engagement rules, verification. How to apply it in a specific integration lives in that integration's skill: - **Drizzle** — `encryptedIndexes(t)` from `@cipherstash/stack-drizzle` derives the recommended indexes for every encrypted column in the table, or declare individual expression indexes in the schema DSL. See `stash-drizzle` § Indexing Encrypted Columns. -- **Prisma Next** — Prisma's schema language cannot express functional indexes; the DDL goes in a migration in the adapter's flow. See `stash-prisma-next`. +- **Prisma Next** — Prisma's schema language cannot express functional indexes; the DDL goes in a migration in the adapter's flow. See `stash-prisma`. - **Supabase** — a `supabase/migrations/` file; no superuser needed (see above). See `stash-supabase`. - **Raw SQL / plain PostgreSQL** — the recipes in this skill, in whatever migration tool owns the schema. Never ad-hoc in production. The predicates those indexes serve are in `stash-postgres`. @@ -270,6 +270,6 @@ Index not being used: - `stash-encryption` — the `types.*` domain catalog, wire-format operators and ordering, and the staged rollout lifecycle. - `stash-cli` — `stash eql install`, `stash db validate` (its "No indexes on an encrypted column" Info finding is resolved by this skill), and `stash encrypt backfill` / `drop`. -- `stash-drizzle`, `stash-supabase`, `stash-prisma-next` — per-integration query patterns; index DDL placement per the section above. +- `stash-drizzle`, `stash-supabase`, `stash-prisma` — per-integration query patterns; index DDL placement per the section above. - `stash-postgres` — the hand-written predicate forms these indexes serve (`pg` / `postgres-js`, no ORM). - `stash-edge` — the WASM entry, for apps whose queries run on Deno / Workers / Supabase Edge Functions. diff --git a/skills/stash-postgres/SKILL.md b/skills/stash-postgres/SKILL.md index 35f422d5c..4f01be7b7 100644 --- a/skills/stash-postgres/SKILL.md +++ b/skills/stash-postgres/SKILL.md @@ -20,7 +20,7 @@ An EQL v3 encrypted column is a **Postgres domain over `jsonb`** (`public.eql_v3 This covers the `pg` and `postgres-js` drivers with no ORM — plain Node services, Hono, edge functions. If you use Drizzle, Prisma Next, or the Supabase client, those integrations emit correct operands for you: see -`stash-drizzle`, `stash-prisma-next`, `stash-supabase` instead. +`stash-drizzle`, `stash-prisma`, `stash-supabase` instead. > **Using CipherStash Proxy? None of this applies.** This skill assumes the > app connects to Postgres **directly** and encrypts **client-side**: Stack diff --git a/skills/stash-prisma-next/SKILL.md b/skills/stash-prisma/SKILL.md similarity index 88% rename from skills/stash-prisma-next/SKILL.md rename to skills/stash-prisma/SKILL.md index 35f02688d..f91af86d1 100644 --- a/skills/stash-prisma-next/SKILL.md +++ b/skills/stash-prisma/SKILL.md @@ -1,17 +1,17 @@ --- -name: stash-prisma-next -description: Integrate CipherStash searchable field-level encryption with Prisma Next using @cipherstash/prisma-next (EQL v3). Covers the full 31-constructor catalog of domain-named encrypted column types in schema.prisma (per plaintext type × capability tier — Text/TextEq/TextOrd/TextMatch/TextSearch, Integer/Smallint/BigInt/Numeric/Real/Double × Eq/Ord, Date/Timestamp × Eq/Ord, Boolean, Json), the one-call cipherstashFromStack wiring, the runtime value envelopes (EncryptedString/Number/BigInt/Date/Boolean/Json) and decryptAll, the eql* query operators (eqlEq, eqlMatch, eqlGt, eqlBetween, eqlIn, eqlJsonContains, eqlAsc/eqlDesc, eqlJsonPathAsc/eqlJsonPathDesc), EQL bundle installation via prisma-next migrate, and authentication. Use when adding encryption to a Prisma Next project, choosing a column type, or querying encrypted columns. +name: stash-prisma +description: Integrate CipherStash searchable field-level encryption with Prisma Next using @cipherstash/stack-prisma (EQL v3). Covers the full 31-constructor catalog of domain-named encrypted column types in schema.prisma (per plaintext type × capability tier — Text/TextEq/TextOrd/TextMatch/TextSearch, Integer/Smallint/BigInt/Numeric/Real/Double × Eq/Ord, Date/Timestamp × Eq/Ord, Boolean, Json), the one-call cipherstashFromStack wiring, the runtime value envelopes (EncryptedString/Number/BigInt/Date/Boolean/Json) and decryptAll, the eql* query operators (eqlEq, eqlMatch, eqlGt, eqlBetween, eqlIn, eqlJsonContains, eqlAsc/eqlDesc, eqlJsonPathAsc/eqlJsonPathDesc), EQL bundle installation via prisma-next migrate, and authentication. Use when adding encryption to a Prisma Next project, choosing a column type, or querying encrypted columns. --- # CipherStash Stack — Prisma Next Integration Guide for searchable field-level encryption in a **Prisma Next** app with -`@cipherstash/prisma-next` (EQL v3), powered by `@cipherstash/stack`. You declare +`@cipherstash/stack-prisma` (EQL v3), powered by `@cipherstash/stack`. You declare encrypted columns directly in `schema.prisma`; Prisma Next's migration system installs the EQL bundle in the same sweep that creates your tables — there is no separate `stash eql install` step. -> `@cipherstash/prisma-next` is **EQL v3 only** — there is no EQL v2 surface. +> `@cipherstash/stack-prisma` is **EQL v3 only** — there is no EQL v2 surface. > Everything below is v3. In EQL v3 every encrypted column is a **concrete Postgres domain** @@ -30,7 +30,7 @@ capability semantics; this skill covers the Prisma-Next-specific surface. ## Installation ```bash -npm install @cipherstash/stack @cipherstash/prisma-next +npm install @cipherstash/stack @cipherstash/stack-prisma ``` Or run `npx stash init --prisma-next`, which detects Prisma Next, installs both @@ -101,7 +101,7 @@ sort needs the matching `*Eq` / `*Ord` / text-search domain. ### 2. Register the extension pack in `prisma-next.config.ts` ```typescript -import cipherstash from '@cipherstash/prisma-next/control' +import cipherstash from '@cipherstash/stack-prisma/control' import { defineConfig } from '@prisma-next/cli/config-types' import { prismaContract } from '@prisma-next/sql-contract-psl/provider' import postgresPack from '@prisma-next/target-postgres/pack' @@ -127,7 +127,7 @@ longer materialises a placeholder namespace. Omitting it fails at runtime with ```typescript import 'dotenv/config' -import { cipherstashFromStack } from '@cipherstash/prisma-next/v3' +import { cipherstashFromStack } from '@cipherstash/stack-prisma/v3' import postgres from '@prisma-next/postgres/runtime' import type { Contract } from './prisma/contract.d' import contractJson from './prisma/contract.json' with { type: 'json' } @@ -242,7 +242,7 @@ import { decryptAll, EncryptedString, EncryptedNumber, EncryptedBigInt, EncryptedDate, EncryptedBoolean, EncryptedJson, -} from '@cipherstash/prisma-next/runtime' +} from '@cipherstash/stack-prisma/runtime' await db.orm.public.User.create({ id: 'user-0', @@ -301,11 +301,11 @@ await db.orm.public.User.where((u) => u.preferences.eqlJsonPathEq('$.theme', 'da // JSONPath ordering (ciphertext-free selector + scalar term) await db.orm.public.User.where((u) => u.preferences.eqlJsonPathGte('$.score', 80)).all() // ordering -import { eqlAsc } from '@cipherstash/prisma-next/runtime' +import { eqlAsc } from '@cipherstash/stack-prisma/runtime' await db.orm.public.User.orderBy((u) => eqlAsc(u.salary)).all() // ordering by a JSONPath leaf; missing paths follow PostgreSQL NULL ordering -import { eqlJsonPathAsc } from '@cipherstash/prisma-next/runtime' +import { eqlJsonPathAsc } from '@cipherstash/stack-prisma/runtime' await db.orm.public.User.orderBy((u) => eqlJsonPathAsc(u.preferences, '$.score')).all() ``` @@ -339,11 +339,11 @@ Run Prisma Next apps on a Node runtime where the native module loads. | Subpath | Purpose | |---|---| -| `@cipherstash/prisma-next/v3` | The v3 surface: `cipherstashFromStack`, the SDK adapter, envelopes/middleware | -| `@cipherstash/prisma-next/control` | The extension pack for `extensionPacks: [...]` | -| `@cipherstash/prisma-next/runtime` | Envelope classes, `decryptAll`, `eql*` operators, `EncryptedString.from()`… | -| `@cipherstash/prisma-next/stack` | One-call setup against `@cipherstash/stack`: `cipherstashFromStack` | -| `@cipherstash/prisma-next/column-types` | camelCase factories (`textSearch`, `bigIntOrd`, …) for **TS-authored** contracts — emits byte-identical `contract.json` to the PSL constructors | +| `@cipherstash/stack-prisma/v3` | The v3 surface: `cipherstashFromStack`, the SDK adapter, envelopes/middleware | +| `@cipherstash/stack-prisma/control` | The extension pack for `extensionPacks: [...]` | +| `@cipherstash/stack-prisma/runtime` | Envelope classes, `decryptAll`, `eql*` operators, `EncryptedString.from()`… | +| `@cipherstash/stack-prisma/stack` | One-call setup against `@cipherstash/stack`: `cipherstashFromStack` | +| `@cipherstash/stack-prisma/column-types` | camelCase factories (`textSearch`, `bigIntOrd`, …) for **TS-authored** contracts — emits byte-identical `contract.json` to the PSL constructors | ## Gotchas From 43dc9063b278586edf7231d0da5ad2046f57b399 Mon Sep 17 00:00:00 2001 From: Dan Draper Date: Thu, 30 Jul 2026 13:41:27 +1000 Subject: [PATCH 5/6] Merge feat/842-rename-packages-1-0: reconcile retained changesets with the @cipherstash/stack-prisma rename --- CONTRIBUTE.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CONTRIBUTE.md b/CONTRIBUTE.md index 456ab9883..e38dd9bc0 100644 --- a/CONTRIBUTE.md +++ b/CONTRIBUTE.md @@ -109,7 +109,7 @@ Releases are **stable** — Changesets is not in pre mode. Merging a changeset t merging that PR publishes to npm under the `latest` dist-tag. The `stash` / `@cipherstash/stack` / `@cipherstash/stack-drizzle` / -`@cipherstash/stack-supabase` / `@cipherstash/prisma-next` / `@cipherstash/wizard` +`@cipherstash/stack-supabase` / `@cipherstash/stack-prisma` / `@cipherstash/wizard` packages are a `fixed` group in [`.changeset/config.json`](./.changeset/config.json): they always version together, so a bump to any one of them bumps all six. From 29ee37a288b9cd380b0a1015bbb96059b6d75195 Mon Sep 17 00:00:00 2001 From: Dan Draper Date: Thu, 30 Jul 2026 14:14:14 +1000 Subject: [PATCH 6/6] fix(changesets,cli): address CodeRabbit review on the pre-exit PR - CONTRIBUTE.md: hyphenate the "Pre-release process" heading. - eql-v3-drizzle-fail-open-guards: tie the unaffected-terms claim to the configured token_length instead of hardcoding 3. - eql-v3-supabase-adapter: unmodelled-column errors fire when the table is named via from(); construction-time verification covers declared schemas (matches the "NOT a construction-time veto" contract in packages/stack-supabase/src/index.ts). - release-train.test.ts: type the manifest key - isReleaseTrainPackage() guard narrows the regex capture, manifestVersion() takes ReleaseTrainPackage, and the type-erasing `as string` casts are gone. --- .changeset/eql-v3-drizzle-fail-open-guards.md | 3 ++- .changeset/eql-v3-supabase-adapter.md | 7 ++++--- CONTRIBUTE.md | 2 +- .../cli/src/__tests__/release-train.test.ts | 17 ++++++++++++----- 4 files changed, 19 insertions(+), 10 deletions(-) diff --git a/.changeset/eql-v3-drizzle-fail-open-guards.md b/.changeset/eql-v3-drizzle-fail-open-guards.md index d40c95869..ee7fb142e 100644 --- a/.changeset/eql-v3-drizzle-fail-open-guards.md +++ b/.changeset/eql-v3-drizzle-fail-open-guards.md @@ -17,7 +17,8 @@ check would wave through an astral-plane term — `"👍👍"` is 4 code units b only 2 codepoints, yields no trigram, and matched every row. **Breaking for callers passing short terms:** free-text calls that previously -returned every row now throw. Terms of 3+ codepoints are unaffected. +returned every row now throw. Terms at or above the configured `token_length` +are unaffected. `v3FromDriver()` now throws the new `EqlV3CodecError` on a payload that is not an EQL envelope, instead of surfacing a raw `SyntaxError` for malformed JSON and diff --git a/.changeset/eql-v3-supabase-adapter.md b/.changeset/eql-v3-supabase-adapter.md index a4ac8bbf7..f8d6a61fe 100644 --- a/.changeset/eql-v3-supabase-adapter.md +++ b/.changeset/eql-v3-supabase-adapter.md @@ -10,9 +10,10 @@ config from its domain — callers no longer pass a schema to `from()`. `select('*')` is supported (expanded from the introspected column list, and aliased back to each declared column's JS property name so a property→DB rename round-trips). A column using a `public.eql_v3_*` domain this SDK version does not -model throws at construction rather than silently passing through. Supplying -`schemas` remains optional and adds compile-time types plus startup verification -of the declared tables against the database. Requires a Postgres connection for +model throws when its table is named via `from()` rather than silently passing +through. Supplying `schemas` remains optional and adds compile-time types plus +eager construction-time verification of the declared tables against the +database — including that same unmodelled-column check. Requires a Postgres connection for introspection (`pg` is an optional peer), so it cannot run in a Worker or the browser. diff --git a/CONTRIBUTE.md b/CONTRIBUTE.md index e38dd9bc0..f3f433eb8 100644 --- a/CONTRIBUTE.md +++ b/CONTRIBUTE.md @@ -113,7 +113,7 @@ The `stash` / `@cipherstash/stack` / `@cipherstash/stack-drizzle` / packages are a `fixed` group in [`.changeset/config.json`](./.changeset/config.json): they always version together, so a bump to any one of them bumps all six. -## Pre release process +## Pre-release process The 1.0 line published its `1.0.0-rc.*` series through [changesets pre mode](https://github.com/changesets/changesets/blob/main/docs/prereleases.md). diff --git a/packages/cli/src/__tests__/release-train.test.ts b/packages/cli/src/__tests__/release-train.test.ts index 3c8d5afee..4a322eac1 100644 --- a/packages/cli/src/__tests__/release-train.test.ts +++ b/packages/cli/src/__tests__/release-train.test.ts @@ -3,7 +3,10 @@ import { dirname, resolve } from 'node:path' import { fileURLToPath } from 'node:url' import { describe, expect, it } from 'vitest' import { INTEGRATION_ADAPTER_PACKAGES } from '../commands/init/steps/install-deps.js' -import { RELEASE_TRAIN_MANIFESTS } from '../release-train.js' +import { + RELEASE_TRAIN_MANIFESTS, + type ReleaseTrainPackage, +} from '../release-train.js' const CLI_ROOT = resolve(dirname(fileURLToPath(import.meta.url)), '../..') const REPO_ROOT = resolve(CLI_ROOT, '../..') @@ -14,7 +17,11 @@ function stableVersion(version: string): string { return version.split('-')[0] as string } -function manifestVersion(pkg: string): string { +function isReleaseTrainPackage(pkg: string): pkg is ReleaseTrainPackage { + return Object.hasOwn(RELEASE_TRAIN_MANIFESTS, pkg) +} + +function manifestVersion(pkg: ReleaseTrainPackage): string { const rel = RELEASE_TRAIN_MANIFESTS[pkg] if (!rel) throw new Error(`${pkg} is not on the release train`) const manifest = JSON.parse(readFileSync(resolve(CLI_ROOT, rel), 'utf8')) as { @@ -98,8 +105,8 @@ describe('release train coverage', () => { /(?:npm:)?(stash|@cipherstash\/[a-z0-9-]+)@(\d+\.\d+\.\d+(?:-[0-9A-Za-z.-]+)?)/g for (const [, pkg, pinned] of body.matchAll(PIN)) { - if (!((pkg as string) in RELEASE_TRAIN_MANIFESTS)) continue - const current = manifestVersion(pkg as string) + if (!isReleaseTrainPackage(pkg)) continue + const current = manifestVersion(pkg) expect( pinned, @@ -107,7 +114,7 @@ describe('release train coverage', () => { ).not.toContain('-') expect( - (pinned as string).split('.')[0], + pinned.split('.')[0], `${pkg}@${pinned} is off this release line (${current}) — update the pin and the prose around it`, ).toBe(stableVersion(current).split('.')[0]) }