Repository navigation
Implement .withLockContext() on the wasm-inline entry #797
Description
Ship .withLockContext() on the wasm-inline entry so identity-bound encryption works from both entries with the same call shape.
This is the implementation half of #793, which covers the diagnosis and the incorrect explanations currently in the source comment and the shipped skill. Filed separately so the code change can be tracked on its own; close or fold whichever is more convenient.
Current state
- Native:
.withLockContext({ identityClaim })chainable on operations, composing with.audit()in either order. - WASM: absent.
lockContextappears inpackages/stack/src/wasm-inline.tsonce, in a comment saying it is not there (:665).
Why it should be reachable
protect-ffi 0.30 accepts a lock context on both the single and bulk paths:
export type EncryptOptions = { plaintext; column; table; lockContext?: Context; unverifiedContext? }
export type EncryptPayload = { plaintext; column; table; lockContext?: Context }
export type Context = { identityClaim: string[] }The WASM binding's opts are typed any (dist/wasm/protect_ffi.d.ts) because they cross serde into the same Rust core, so the shape is likely already accepted and simply not plumbed on the JS side. Confirm against the Rust first.
Note the stack's own EncryptOptions (types.ts:340) is { column, table } — no lockContext field — so nothing is being silently dropped today. The type just does not offer it.
Impact of leaving it
- Edge functions cannot write identity-bound data at all.
- Edge functions cannot read anything Node wrote under a lock context, since decrypt needs the same context. A silent split in what the two entries can read, on top of the schema nominal-typing incompatibility already documented in
skills/stash-edge. - Supabase Edge Functions are the flagship WASM use case and the most likely place to want per-user key binding, since the user's JWT is already in hand.
Shape question to settle
The native surface is a chainable on a thenable operation. The WASM client's methods are async and return WasmResult directly (async encrypt(plaintext, opts): Promise<WasmResult<Encrypted>>), so a chainable requires returning a builder rather than a promise — a real change to the entry's shape. The alternatives are a per-call option, or converging both entries on one form.
Worth settling alongside #792, which raises the same "should these two entries have the same call shape" question for bulkEncrypt. Deciding them together avoids fixing the split in one place and widening it in another.
Coverage
The failure is silent — a wrong or missing claim surfaces as a failed decrypt, not a key error — so this needs round-trip tests: encrypt on one entry with a claim, decrypt on the other with the same claim; and the negative case, decrypt without it.
Docs that must follow
wasm-inline.ts:665— currently says an auth strategy is identity-bound encryption. Wrong regardless of whether this lands.skills/stash-edge— already updated in feat(cli): add the stash-postgres and stash-edge skills — raw-SQL predicates and the WASM entry #777 in anticipation of this, including a code example that assumes the chainable form. If the API lands as a per-call option, that example needs correcting before feat(cli): add the stash-postgres and stash-edge skills — raw-SQL predicates and the WASM entry #777 merges.
Activity
docs(skills): correct the lock-context explanation in stash-edge
coderdan commentedon Jul 25, 2026
Parent design issue: #798 — this is one of three symptoms of a single missing seam (the FFI backend is imported by the operation classes rather than injected, so
wasm-inlinecould not reuse them and reimplemented the surface).Worth settling the surface question in #798 first: taken independently, each of these three hard-codes an answer the other two have to live with.
docs(skills): correct the lock-context explanation in stash-edge
docs(skills): reconcile the WASM entry surface after the rebase
docs(skills,stack): document the wasm entry as having no lock context
feat(cli): add the stash-postgres and stash-edge skills — raw-SQL pre…
feat(cli): add the stash-postgres and stash-edge skills — raw-SQL pre…
feat(cli): add the stash-postgres and stash-edge skills — raw-SQL pre…
docs(skills): correct keyset/credential wording across shipped skills…
docs(skills): correct keyset/credential wording across shipped skills…
feat(skills): stash-zerokms and stash-auth — canonical keyset and aut…
docs(supabase): document the wasm-inline entry in the two files that …