Repository navigation
Description
Summary
Introduce runtime-neutral BinaryLike and KeyLike types in src/types.ts, and use them across the public API in place of crypto.BinaryLike / crypto.KeyLike.
export type BinaryLike = crypto.BinaryLike | ArrayBuffer;
export type KeyLike = crypto.KeyLike | CryptoKey | Uint8Array;Why
Today every public signature that touches key material or data to be signed is typed against node:crypto directly — SignedXmlOptions.privateKey, SignedXmlOptions.publicCert, GetKeyInfoContentArgs.publicCert, and both methods on the SignatureAlgorithm interface.
That hard-codes Node into the type surface. A caller cannot pass a CryptoKey, which is the only key representation the Web Crypto API produces, so the public types themselves block any Web Crypto backend before a line of implementation is written. This abstraction is a prerequisite for #477, and it is the piece of #513 that stands on its own regardless of what shape the rest of that work eventually takes.
Why 7.0
Altering types exported from src/types.ts is breaking for consumers, so this belongs in a major even though it is additive in practice. Widening a parameter type is source-compatible for callers, but it is not compatible for anyone who implements SignatureAlgorithm — third-party HSM- and KMS-backed implementations exist, and their method signatures have to widen to match.
Design note
In #513 these were introduced as blanket unions, which forced casts back out at every use site:
signer.update(signedInfo as crypto.BinaryLike);
const res = signer.sign(privateKey as crypto.KeyLike, "base64");The cast is load-bearing: without it TypeScript correctly rejects the call (TS2345: Type 'CryptoKey' is not assignable to parameter of type 'KeyLike | SignKeyObjectInput | SignPrivateKeyInput'). So the widened type promises support that RsaSha1/RsaSha256/RsaSha512/HmacSha1 do not have, and the cast deletes the diagnostic that would have said so.
What happens at runtime differs by arm, and the CryptoKey case is the concerning one:
Uint8Arrayfails withERR_OSSL_UNSUPPORTED: error:1E08010C:DECODER routines::unsupported— an opaque OpenSSL error a long way from the cause.CryptoKeydoes not fail at all. Node accepts it and emitsDEP0203 DeprecationWarning: Passing a CryptoKey to node:crypto functions is deprecated. It appears to work, tests pass, and it breaks whenever Node removes the shim — and it can never work off-Node, wherenode:cryptodoes not exist. A Node-backed algorithm would look like it supports Web Crypto keys while doing nothing of the kind.
Options that avoid the cast rather than suppressing it:
- Make the interface generic in its key type, so each implementation declares what it accepts.
- Keep the union, but narrow through a helper that validates and throws a clear error instead of an
as. - Separate interfaces per backend, so a Node algorithm never claims to take a
CryptoKeyat all.
Whichever way it goes, the goal is that each algorithm states what it actually accepts, rather than casting out of a union that promises more than it can take.
Scope
In scope:
- Define
BinaryLike/KeyLikeinsrc/types.ts - Apply them to
SignedXmlOptions,GetKeyInfoContentArgs, and theSignatureAlgorithminterface - Decide how the bundled Node-backed algorithms narrow to concrete types without blanket casts
- Document the change for implementers of
SignatureAlgorithm
Out of scope — these get their own issues:
- Any Web Crypto algorithm implementation
- Async / callback API changes
HashAlgorithmchanges
References
- [ENHANCEMENT]: web-crypto support #477 — Web Crypto support request
- Added web-crypto support (#1) #513 — draft Web Crypto PR these types were taken from
Activity
cjbarth commentedon Sep 8, 2026
The control-flow half of this work is now tracked in #546 — sync/async model, Web Crypto entry points, and retiring the callback overloads. The two are independent to implement but should be designed together.