Feat/node 26 support - #2699
Open
alleria173 wants to merge 3 commits into
Open
Conversation
- Widen engines range to >=24 <27 - Test against Node 24 and 26 in CI (build/deploy artefacts remain on 24) - Replace unmaintained 'cbor' dependency with 'cbor2': the cbor package's synchronous encode relies on a single stream read() returning the whole encoding, which breaks on Node 26 where readable streams return one buffer at a time - Remove stale dependabot ignore for the removed cbor package - Update Node.js support notes in README and AGENTS
alleria173
marked this pull request as ready for review
July 28, 2026 14:00
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Add Node 26 support alongside Node 24
Closes #2397
Summary
Adds Node.js 26 compatibility ahead of it becoming the active LTS release in November 2026, per the phased approach suggested in #2397: Node 24 remains the officially supported version, with Node 26 added to the CI test matrix. A follow-up change can make Node 26 official once it reaches LTS.
Branch:
feat/node-26-support(commita182fe74, based on upstreammaster@c56dd233)Diagnostics performed
The full toolchain was run under Node 26.5.0 (and re-verified under 24.18.0 as a baseline):
npm ci(incl. postinstall grunt tasks)npm test(2280 operation + 272 Node API tests)npm run lintnpm run build(webpack prod)npm run node+grunt testnodeconsumer(CJS + ESM)npm run testuiStatic analysis of the dependency tree found:
binding.gyp), so no NODE_MODULE_VERSION/ABI concerns. Heavy dependencies are WASM-based (argon2-browser, libyara-wasm, libbzip2-wasm, jq-web, tesseract.js).enginesfield._stream_*core modules (only present inside self-contained bundled copies ofreadable-stream),http.Server.writeHeader(),module.register(). The Temporal global being enabled by default causes no conflicts.--openssl-legacy-providerflag used bynpm teststill works on Node 26 (OpenSSL 3.5.x retains the legacy provider). Note: this is a future risk when Node moves to OpenSSL 4.The one incompatibility found:
cborAll five test failures were in the CBOR Encode operation. Outputs were truncated to the first CBOR byte, e.g. encoding
"Text"produced64instead of64 54 65 78 74.Root cause: Node 26 includes the semver-major change "stream: readable read one buffer at a time" (nodejs/node#60441).
cbor@10's synchronous encoder (Encoder._encodeAll) pipes the encoder stream into aNoFilterand performs a singlebs.read(), assuming it returns the entire concatenated encoding. On Node 26 that read returns only the first buffered chunk.Alternatives evaluated:
Upgrade—nofilternofilter@6has an incompatible API (NoFilter is not a constructorfrom cbor's CJS require); cbor@10 pinsnofilter@^3.Switch to— works (collectsCbor.encodeAsync()'data'events instead of a sync read), but keeps an effectively unmaintained dependency with a latent stream bug.cborwithcbor2— same author's actively maintained successor (cbor2@2.3.0, engines>=20), pure data API with no Node stream dependency, works in browsers and Node identically.Output equivalence verified byte-for-byte against the old package, including RFC 8949 canonical form:
encode(input, {sortKeys: sortCoreDeterministic})reproducesencodeCanonical's length-first key ordering (bsorts beforeaa) — the defaultcbor2encode does not sort keys, so the explicit sort option is required.1.5→f9 3e 00), maps, lists, integers, booleans, and null all match.Changes
engines:">=24 <25"→">=24 <27"cbor@10.0.12→cbor2@2.3.0(pinned exact, matching the previous pin convention)cbor2'sencodewithsortCoreDeterministickey sortingcbor2'sdecodeon the rawUint8Array(drops the old hex-string round-trip)node-versionbecomes a matrix[24, 26]withfail-fast: false; artefact upload and GitHub Pages deploy are gated to the Node 24 leg so they run exactly once.releases.ymlintentionally unchanged (npm publish stays on the officially supported Node 24 until Phase B).cbor >=10ignore entryTesting
Follow-up (Phase B — when Node 26 reaches LTS, ~Nov 2026)
engines→">=26 <27"; CInode-version: 26everywhere includingreleases.ymlnode:26-alpine@sha256:...— note dependabot was told to ignore this major version for the Docker node image when PR Bump node from 24-alpine to 26-alpine #2381 was closed, so this must be done manually.devcontainer/devcontainer.json→javascript-node:26-*node >= 26, CHANGELOG entry, version bump vianpm run minorAI disclosure
Compatibility and testing done with Github Copilot with Claude Fable.