Skip to content

stash init scaffolds the EQL v2 authoring surface into customer repos, against a v3 database #733

Description

@tobyhede

stash init installs an EQL v3 database (since #732 / PR #705) but the client-scaffold code it writes into the customer's repo still teaches v2. So init hands the customer's coding agent v2 authoring guidance — Encryption, encryptedColumn('x').equality().freeTextSearch(), encryptedType<T>('x', { equality: true }) — against a v3 database. The scaffold and the database disagree.

Split out from #732, which fixed the database side (routing) but explicitly left the code side (scaffold templates) as follow-up.

Where

packages/cli/src/commands/init/utils.ts. Two live surfaces emit v2:

  • generatePlaceholderClientDRIZZLE_PLACEHOLDER / GENERIC_PLACEHOLDER — what stash init writes, and the eql install safety net (db/client-scaffold.ts).
  • generateClientFromSchemas → the Drizzle/generic generators — reached via stash schema build introspection.

The core difficulty

v3 has no chainable capability tuners — capabilities are fixed by the concrete domain type. So { equality: true, freeTextSearch: true } does not map mechanically to v3; each SearchOp combination has to be resolved to the v3 domain whose fixed capability set matches (packages/stack/src/eql/v3/columns.ts).

Fix

PR #734. Ports both placeholders and both live plural generators to EncryptionV3 + types.* (@cipherstash/stack/v3, @cipherstash/stack-drizzle/v3), via a shared SearchOp-set → v3-domain mapping. Deletes the dead singular generators (generateClientFromSchema + helpers — zero callers) rather than porting v2 dead code.

Surfaced one real capability difference: v2 allowed equality on a boolean; v3 has no boolean eq/ord domain, so booleans map to storage-only.

Follow-up beyond this

Numeric collapses to the Integer* family — there is no width/float signal in the introspected SearchOp model, matching how v2 collapsed everything to dataType: 'number'. If v3 float/decimal domains should be scaffolded distinctly, that needs a richer introspection signal and is out of scope here.

Metadata

Metadata

Assignees

Labels

Type

No type

Fields

No fields configured for issues without a type.

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions