Skip to content

Consolidate the three hand-rolled encryption-client views into @cipherstash/stack/adapter-kit #807

Description

@tobyhede

Follow-up from the portable-encryptedSupabase design (#708). Named as a deferred item by three of the four plans in that series.

What exists

After the portable-runtime series lands there will be three hand-rolled structural views of the encryption client, in three published packages:

Type Location Methods
OperandEncryptionClient packages/stack-drizzle/src/operators.ts:67-73 encryptQuery only
CipherstashV3Client packages/prisma-next/src/v3/sdk-adapter-v3.ts:74-90 bulkEncrypt, decrypt, bulkDecrypt, encryptQuery
AdapterEncryptionClient packages/stack-supabase (new) five model/bulk methods, no encryptQuery

Plus a fourth, smaller duplication: two structural v3-column predicates — hasBuildColumnKeyMap (packages/stack/src/types.ts:276) and the new isV3ColumnLike in stack-supabase.

The trap

The three method sets are disjoint. Drizzle's view is operand-shaped, Prisma Next's is model-shaped, the Supabase one is the five methods that pipeline actually calls — no two of them are a subset of a third. So consolidation is a union of three views, not a pick-the-biggest, and it is a design job (which methods are core, which stay per-adapter) rather than a copy-paste.

packages/stack/src/adapter-kit.ts is 60 lines today with no client interface at all, so there is nothing to reuse yet and nothing currently being duplicated in the strict sense — the three existing views solve a genuinely different problem (a structural view so a test double needs no cast) and none of them has a WASM adapter.

The shape

  • AdapterEncryptionClient + fromNativeEncryptionClientpackages/stack/src/adapter-kit.ts
  • fromWasmEncryptionClientpackages/stack/src/wasm-inline.ts

Split that way so neither entry drags the other's dependency. Only core knows both client shapes, which is the argument for the move. The Adapter… name was chosen up front specifically so this becomes a file move rather than a rename.

Why it was deferred

Additions to adapter-kit are audit decisions (packages/stack/src/adapter-kit.ts:1-19), the move touches three published packages, and the second consumer of the new port does not exist yet.

Two smaller items to fold in

  • An entry check on top of the name check for options.encryptionClient. assertClientShape validates method names, and both client shapes carry all five, so it cannot detect a native client passed through fromWasmEncryptionClient. bulkEncrypt.length discriminates reliably — 2 on nominal (encryption/index.ts:651), 2 on typed (v3.ts:367), 1 on WASM (wasm-inline.ts:944) — where decryptModel.length does not. That is validation of an already-bound choice, not runtime sniffing.
  • Verify supportsLockContext rather than hardcoding it. fromNativeEncryptionClient sets it true unconditionally. A client whose ops lack .withLockContext passes the builder guard and then dies at execute with a raw TypeError, which query-builder.ts:596-598 reports as encryptionError: undefined — the anonymous 500 that a lock-context failure is specifically supposed to never become.

Metadata

Metadata

Assignees

Labels

Type

No type

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions