Repository navigation
Labels
breaking changeRequires backward-incompatible changeRequires backward-incompatible changecomponent/buildBuild system and packagingBuild system and packagingcomponent/federationFederation object relatedFederation object relatedcomponent/signaturesOIP or HTTP/LD Signatures relatedOIP or HTTP/LD Signatures relatedruntime/nodeNode.js runtime relatedNode.js runtime related
Description
Summary
I use some node:crypto methods (webcrypto) to handle some key-related logic alongside fedify.
When I upgrade @types/node to version >=24.7.0, I start seeing type errors.
This is likely an incompatibility between types used by Fedify (Deno or DOM), and Node.js, which introduces crypto.subtle.decapsulateBits in v24.7.0.
Workaround
- Don't upgrade @types/node beyond v24.6.2, or
- Assert results of methods from
node:cryptoe.g.(await crypto.subtle.importKey(/*....*/)) as CryptoKey.
This issue is not pressing.
Expected Behavior
I'd expect these type errors not to be present.
Actual Behavior
I use some node:crypto methods (webcrypto) to handle some key-related logic.
When I upgrade @types/node to version >=24.7.0, I start seeing type errors like:
error TS2345: Argument of type '(ctx: Context<ContextData>) => Promise<{ privateKey: CryptoKey; publicKey: CryptoKey; }[]>' is not assignable to parameter of type 'ActorKeyPairsDispatcher<ContextData>'.
Type 'Promise<{ privateKey: CryptoKey; publicKey: CryptoKey; }[]>' is not assignable to type 'CryptoKeyPair[] | Promise<CryptoKeyPair[]>'.
Type 'Promise<{ privateKey: CryptoKey; publicKey: CryptoKey; }[]>' is not assignable to type 'Promise<CryptoKeyPair[]>'.
Type '{ privateKey: CryptoKey; publicKey: CryptoKey; }[]' is not assignable to type 'CryptoKeyPair[]'.
Type '{ privateKey: webcrypto.CryptoKey; publicKey: CryptoKey; }' is not assignable to type 'CryptoKeyPair'.
The types of 'privateKey.usages' are incompatible between these types.
Type 'import("node:crypto").webcrypto.KeyUsage[]' is not assignable to type 'KeyUsage[]'.
Type 'import("node:crypto").webcrypto.KeyUsage' is not assignable to type 'KeyUsage'.
Type '"decapsulateBits"' is not assignable to type 'KeyUsage'.
61 .setKeyPairsDispatcher(async ctx => {
Environment
OS: Arch Linux
Runtime: Node.js v25
This is a type error, not a runtime error.
Logs / Screenshots
No response
Steps to Reproduce
tbd if needed
Metadata
Metadata
Assignees
Labels
breaking changeRequires backward-incompatible changeRequires backward-incompatible changecomponent/buildBuild system and packagingBuild system and packagingcomponent/federationFederation object relatedFederation object relatedcomponent/signaturesOIP or HTTP/LD Signatures relatedOIP or HTTP/LD Signatures relatedruntime/nodeNode.js runtime relatedNode.js runtime related
Type
Fields
Priority
None yet
Effort
None yet
Activity
mrkvon commentedon Feb 3, 2026
I start feeling like this might not be a Fedify's problem, unless Fedify claims compatibility with
node:cryptomethods (which it doesn't, does it?). Please feel free to close this issue if that's the case.notJoon commentedon Feb 3, 2026
I remember there were similar issues before (maybe #423 ?). The related code will need to be updated
2chanhaeng commentedon Feb 16, 2026
The extended methods standardized. So I think it seems best for us to just apply type assertions for now, sit back, and enjoy a cup of tea. 🍵
[-]Broken type compatibility with node v24.7.0 and higher[/-][+]Broken type compatibility with Node.js v24.7.0 and higher[/+]dahlia commentedon Nov 5, 2026
Thanks for the detailed report. I can confirm the problem is still there.
It reproduces on
2.0-maintenance(2.0.36), on2.4-maintenance(2.4.5), and onmain. With@types/node24.6.0 the same consumer code compiles; with 24.7.0 and later it fails with theencapsulateBits/decapsulateBitsmismatch, under both TypeScript 6.0 and 7.1.The cause is that our public declarations use the ambient
CryptoKeyandCryptoKeyPairtypes without importing them, so the consumer'slibsetting decides which declaration those names resolve to. Since Node.js 24.7,webcrypto.KeyUsagealso includes the ML-KEM usages, which makes the Node.js union a superset of the DOM and Web Worker unions.usagesis a mutable array, sowebcrypto.KeyUsage[]is not assignable toKeyUsage[]. The incompatibility only goes one way: keys returned by Fedify still fit intonode:cryptoslots, and nothing is wrong at run time.This also means casts inside Fedify would not fix it. The error appears where application code passes its own keys to one of our functions, so the declared parameter types have to change.
What I would like to do is give Fedify its own structural input types,
CryptoKeyLikeandCryptoKeyPairLike, in@fedify/vocab-runtime, and widen only the input positions:ActorKeyPairsDispatcher,SharedInboxKeyDispatcher,SenderKeyPair, the signing and proof helpers,exportJwk(), the key export helpers in@fedify/vocab-runtime, and thepublicKeyinputs ofCryptographicKeyandMultikey. Return types would stay as the ambientCryptoKeyandCryptoKeyPair, so keys that Fedify produces can still be passed tocrypto.subtle.*without a cast. Inside Fedify, we narrow once at thecrypto.subtleboundary.Something like this:
type: stringandusages: readonly string[]are deliberate. Cloudflare Workers declaresCryptoKey.typeasstring, so a literal union would break Workers users, while the readonly string array accepts both the Node.js and DOM usage unions. I checked both cases against the Workers type definitions.Waiting for
lib.dom.d.tsto catch up does not look like a good option either: the TypeScript DOM lib and@types/nodeare versioned separately, so the mismatch can come back whenever either side adds a usage.The change is source-compatible for callers, so I would land it on
2.0-maintenancefirst and forward-port it through the later maintenance branches, thenmainandnext.ActorKeyPairsDispatcherwould get a defaulted type parameter (TKeyPair extends CryptoKeyPairLike = CryptoKeyPair) so that code calling a dispatcher directly keeps its narrow return type.The existing
mise run check:typescannot catch this, because the repository's own projects type-check with thewebworkerlib and never passnode:cryptokeys into the API. I will add a consumer fixture that compiles withlib: ["esnext", "dom"],types: ["node"],skipLibCheck: false, and@types/nodepinned at 24.7 or later, exercising the callbacks, the signing helpers, and the vocabulary constructors without casts.I will open a pull request against
2.0-maintenancewith the fix and the regression fixture.