You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
@cipherstash/stack/wasm-inline exposes no model operations at all. The native entry offers encryptModel / decryptModel / bulkEncryptModels / bulkDecryptModels; the WASM entry offers none of them, so edge code has to map every encrypted field by hand.
Verified in tree
$ grep -n "encryptModel\|decryptModel\|bulkEncryptModels\|bulkDecryptModels" packages/stack/src/wasm-inline.ts
(no matches)
The full WASM client surface today is encrypt, decrypt, isEncrypted, encryptQuery, encryptQueryBulk, and — as of #741 — bulkEncrypt / bulkDecrypt.
#737 asked for bulk values "and the*Modelsvariants, for parity with the native entry". #741 implemented the value-level halves only, deliberately: there is no single-model operation on this entry to build a bulk one on top of. Adding bulkEncryptModels while encryptModel doesn't exist would be an incoherent surface, and the round-trip cost #737 was actually about is fully addressed by the value-level primitives.
So this is the remaining, and larger, half: port the model layer itself.
Impact
Model helpers are the ergonomic surface — they walk a model against its table schema, encrypt every declared column, and leave everything else alone. Without them, edge code does that traversal by hand for every read and write:
// Today, on the edge — manual, and easy to get wrong as the schema growsconst[email,bio]=awaitclient.bulkEncrypt([{plaintext: user.email,table: users,column: users.email},{plaintext: user.bio,table: users,column: users.bio},])constrow={ ...user, email, bio }// What the native entry gives youconstrow=awaitclient.encryptModel(user,users)
The failure mode is a quiet one: add a column to the schema and forget to add it to the hand-written mapping, and it silently persists in plaintext. The model helpers close that gap by construction, which is exactly why they matter more on a surface where people are hand-rolling the traversal.
Scope
encryptModel / decryptModel — the single-model traversal, ported to this entry.
Worth deciding up front which conventions to follow, since the WASM entry has deliberately diverged from the native one before (see #741): this surface throws rather than returning { data } | { failure }, and its bulk methods take plain index-aligned arrays rather than { id, … } envelopes. The model helpers should match the local surface for the same reason the bulk ones did — a WASM caller is reading this module's API, not the Node one.
Summary
@cipherstash/stack/wasm-inlineexposes no model operations at all. The native entry offersencryptModel/decryptModel/bulkEncryptModels/bulkDecryptModels; the WASM entry offers none of them, so edge code has to map every encrypted field by hand.Verified in tree
The full WASM client surface today is
encrypt,decrypt,isEncrypted,encryptQuery,encryptQueryBulk, and — as of #741 —bulkEncrypt/bulkDecrypt.Why this is separate from #737
#737 asked for bulk values "and the
*Modelsvariants, for parity with the native entry". #741 implemented the value-level halves only, deliberately: there is no single-model operation on this entry to build a bulk one on top of. AddingbulkEncryptModelswhileencryptModeldoesn't exist would be an incoherent surface, and the round-trip cost #737 was actually about is fully addressed by the value-level primitives.So this is the remaining, and larger, half: port the model layer itself.
Impact
Model helpers are the ergonomic surface — they walk a model against its table schema, encrypt every declared column, and leave everything else alone. Without them, edge code does that traversal by hand for every read and write:
The failure mode is a quiet one: add a column to the schema and forget to add it to the hand-written mapping, and it silently persists in plaintext. The model helpers close that gap by construction, which is exactly why they matter more on a surface where people are hand-rolling the traversal.
Scope
encryptModel/decryptModel— the single-model traversal, ported to this entry.bulkEncryptModels/bulkDecryptModels— layered on those plus thebulkEncrypt/bulkDecryptprimitives added in feat(stack)!: align wasm-inline to the Result contract, and add bulkEncrypt/bulkDecrypt #741, so a list of models stays one ZeroKMS round trip.Worth deciding up front which conventions to follow, since the WASM entry has deliberately diverged from the native one before (see #741): this surface throws rather than returning
{ data } | { failure }, and its bulk methods take plain index-aligned arrays rather than{ id, … }envelopes. The model helpers should match the local surface for the same reason the bulk ones did — a WASM caller is reading this module's API, not the Node one.Related
bulkEncrypt/bulkDecrypthere; its class docblock records the model gap as a separate port.