Skip to content

chore: maintenance update for Node.js 24 and current Ubuntu LTS releases - #4875

Merged
sebastijankuzner merged 22 commits into
developfrom
chore/node-24-maintenance
Oct 29, 2026
Merged

sebastijankuzner merged 22 commits into
developfrom
chore/node-24-maintenance

Conversation

@oXtxNt9U

@oXtxNt9U oXtxNt9U commented Oct 28, 2026 •

Copy link
Copy Markdown
Collaborator

Summary

Core 3.13 can't be installed on a supported operating system. This PR makes Core run on Node.js ≥ 24.22.1 and updates its dependencies, Docker and CI. The installer changes for Ubuntu 22.04–26.04 are in #, stacked on this one.

Scope: only changes that reach a running or installing node, plus the build and CI changes needed to ship them.

Note

This is not a hard fork. It changes no consensus rules, milestones or network configuration, and P2P messages are byte-identical to 3.13.0. Nodes on 3.13.0 and nodes on this release run side by side on the same network, so operators can upgrade at their own pace.

This release will be published under a new npm dist-tag, not latest. The publishing change comes in a follow-up PR, which lands before the release. Existing nodes are not affected: ark update on a 3.13.0 node only checks latest, so a node that runs it by accident stays on 3.13.0 and isn't offered this release. Upgrading is a deliberate, manual step, described in the upgrade guide.

Changes

Runs on Node 24

Change Why
better-sqlite3 → 12.11.1 9.x doesn't compile against Node 24
Keep-alive disabled on the global HTTP agents Node ≥ 19 reuses sockets that Core's API closes, which caused ECONNRESET
engines → ^24.22.1 Rejects older Node.js versions at install time instead of failing mid-compile
node-gyp 11, nan 2.30.0 (build only) node-gyp 9 breaks on Python ≥ 3.12. With nan 2.18, CI ran tiny-secp256k1 and bstring on their JavaScript fallbacks instead of the native code production uses

Dependency updates

No code changes; behaviour verified identical.

  • ws 7.5.13, protobufjs 7.6.6
  • joi 17.13.8, qs 6.16.1, node-forge 1.4.2, tar 6.2.1
  • reflect-metadata 0.2.2, @hapi/boom 9.1.4, @pm2/io 6.1.0, uuid 11.1.1
  • pg declared in core-snapshots; pm2 peer dependency ^7.0.0, marked optional

Removed: ark relay:share and ngrok

  • Already broken for most operators: it bundles ngrok agent v2.3.41, which ngrok rejects for free accounts since 15 January 2024.
  • Single point of failure: every install downloads that end-of-life binary from ngrok's CDN, and a failed download aborts the whole Core install.

Operators who need a tunnel can run a current agent, e.g. ngrok http 4003.

Docker and CI

  • Docker: node:24-alpine and postgres:18-alpine pinned
  • CI: latest Node 24 in every job including CodeQL; database tests on PostgreSQL 18
  • Publishing: removed the publish step for the deleted core-manager package

Testing

On Node 24.22.1, Ubuntu 26.04 and PostgreSQL 18:

  • ✅ Clean install builds all native modules; the lockfile is consistent at every commit
  • ✅ All unit tests (546 suites, 5,404 tests)
  • ✅ All 21 forging functional suites and the database suite, the same set CI runs
  • ✅ A fresh install from a local registry synced the live devnet without errors
  • ✅ P2P messages are byte-identical in both directions with 3.13.0 nodes on Node 16

Release notes

To be added before the release.


Operator notice

Important

Core <version> requires Node.js 24.22.1 or newer. Not every server can run it. Check the table below before upgrading.

Can my server upgrade?

Server Upgrade path
Ubuntu 22.04, 24.04, 26.04 ✅ Upgrade in place with the upgrade guide
Ubuntu 20.04 or older · CentOS 7 · 32-bit ❌ Cannot upgrade. Stay on 3.13 or move to a new server

Upgrading in place

To be added before the release.

Moving to a new server

To be added before the release.

Other changes

  • ark relay:share has been removed. To expose a relay, run a current ngrok agent yourself (e.g. ngrok http 4003).
  • Docker: to be added before the release.

Checklist

  • Documentation (if necessary)
  • Tests (if necessary)
  • Ready to be merged

oXtxNt9U and others added 22 commits October 28, 2026 03:33
lerna 7 hoists node-gyp 9.4.1, whose bundled gyp still imports
`distutils`. Python 3.12 removed `distutils`, so `yarn setup` fails while
compiling bcrypto on Ubuntu 24.04 (Python 3.12) and 26.04 (Python 3.14).

Adding node-gyp 11 as a root devDependency hoists a modern node-gyp to
`node_modules/.bin`, which yarn uses for native install scripts.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
With nan 2.18.0 from the lockfile, tiny-secp256k1 and bstring fail to
compile against the Node.js 24 headers and silently fall back to their
JavaScript implementations. Production installs resolve the newest nan
and build them natively, so CI tested different code than nodes run.

Only the lockfile changes, the version ranges stay the same.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
better-sqlite3 9.x compiles as C++17, but the V8 headers shipped with
Node 24 require C++20, so the transaction pool's storage cannot be built.

Majors 10, 11 and 12 only dropped support for EOL Node.js and Electron
versions; the JavaScript API used in `storage.ts` is unchanged. 12.x ships
prebuilt binaries for Node 24 (glibc and musl). Pool database files are
compatible in both directions between 9.3.0 and 12.11.1.

@types/better-sqlite3 is updated to 7.6.13 alongside.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Node.js >= 19 enables keep-alive on `http.globalAgent` and
`https.globalAgent`. Core's API server destroys the socket once a response
has finished (core-api `server.ts`) while still advertising keep-alive,
so a client that reuses the pooled socket fails with
`ECONNRESET: socket hang up`.

Core's own outbound requests hit this when they talk to other Core nodes
(peer API port checks) and in webhooks; on Node 24 it also broke 14 of 18
transaction-forging functional tests. Turn keep-alive off on the existing
global agents during application bootstrap so every request opens a new
connection, as before Node 19. Changing the agents instead of replacing
them keeps their other defaults, such as the proxy configuration used with
`NODE_USE_ENV_PROXY` and the request timeout.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Updates ws to the latest 7.x release. The changes since 7.5.10 do not
affect the API Core uses, and P2P messages are unchanged.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Updates protobufjs to the latest 7.x release. The committed static code
only requires `protobufjs/minimal` and keeps working unchanged.
protobufjs-cli is updated to 1.3.3 so that future `yarn build:proto` runs
match the runtime.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Updates joi to the latest 17.x release. Same major; schema behaviour is
unchanged for the features Core uses.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Core only uses `qs.stringify` with `encode: false` to build pagination
links; the generated links are unchanged.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Core only uses random bytes, AES-CBC, PBKDF2 and base64 for BIP38. Of
these, only AES-CBC decryption changed: it now rejects invalid padding,
which Core's own encrypt and decrypt round trip never produces.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
npm marks reflect-metadata 0.2.1 as deprecated ("This version has a
critical bug in fallback handling. Please upgrade to reflect-metadata@0.2.2
or newer."), so yarn prints that warning for core-cli, core-database and
core-kernel on every install, including `yarn global add @ArkEcosystem/core`.

The fallback is used when an older reflect-metadata without a metadata
registry was loaded first. typeorm still depends on reflect-metadata 0.1.x
(0.1.14 is installed nested under it), so that combination can occur in
Core. In 0.2.1 the fallback reports no metadata for a property once it has
recorded metadata for another property of the same object; 0.2.2 fixes
that, and its only other code change is in the random bytes helper.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
npm marks @hapi/boom 9.0.0 as deprecated ("no longer supported or
maintained"), so every install prints that warning twice. core-api and
core-magistrate-api already use 9.1.4 and hapi 20 itself depends on
^9.1.0; the changes since 9.0.0 do not affect how Core creates or checks
Boom errors.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@pm2/io 6 drops the tracing support built on @opencensus, which pulled in
uuid@3, and npm reports that as deprecated three times during every
install. Core only registers process actions through `pmx.action()`, which
is unchanged in 6.x; process error handling, exit codes and IPC messages
behave as in 5.0.2.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
npm marks uuid 10 and below as unsupported, so every install prints a
deprecation warning for core-webhooks' uuid 9.0.1. uuid 11 still ships a
CommonJS build, and `v4()`, the only function Core uses to create webhook
ids, is unchanged.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Updates tar to the latest 6.x release. tar only extracts plugin archives
the operator installs with `ark plugin:install`; the `extract()` call used
there is unchanged.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
pg-query-stream depends on pg-cursor, which lists `pg` as a peer
dependency and requires `pg/lib/*` at runtime. core-snapshots never
declared `pg`, so every install printed an "unmet peer dependency" warning
and the module was only found because core-database's copy is hoisted.
Declare the same pg version core-database uses.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
`ark reinstall` installs the newest pm2 that satisfies this range
globally (Installer.installPeerDependencies -> installRangeLatest). With
`^4.5.0` that is pm2 4.5.6, which is no longer maintained and prints a
`util._extend` deprecation warning on every command under Node 24.
install.sh already installs the latest pm2, so fresh installations run
pm2 7 and this aligns `ark reinstall` with them.

Mark the peer dependency as optional: install.sh installs pm2 for root,
outside the global folder `yarn global add @ArkEcosystem/core` sees, so
every install printed an "unmet peer dependency" warning. The CLI still
reads the range to install pm2 on `ark reinstall`.

`ark update` is not affected: it passes the channel dist-tag to
`yarn info <pkg>@<tag> peerDependencies`, which returns no data for a
dist-tag in yarn 1, so it never installs peer dependencies.

The pm2 commands used by the process manager (start, jlist, id, trigger,
reload, restart, reset, stop, delete, flush, reloadLogs, ping, update)
work unchanged with pm2 7.1.0.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
`relay:share` only exposed a local relay through an ngrok tunnel, but the
ngrok package it needs is a liability for every installation:

- ngrok 4.3.3 has a postinstall script that downloads the deprecated
  ngrok v2 agent (a 14 MB archive from bin.equinox.io) on every Core
  install and exits with code 1 if that download fails, which aborts the
  whole `yarn global add`.
- Commands are discovered eagerly, so the module was loaded on every
  `ark` invocation, not only for `relay:share`.

Operators who want to share a relay can run the ngrok agent themselves.

BREAKING CHANGE: the `ark relay:share` command has been removed.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Node.js 16 and 18 are end-of-life and this release is built and tested on
Node.js 24. Declare `^24.22.1` in `engines`: Node.js 24 only, at least
24.22.1, the latest release at the time (2026-10-20). `yarn global add`
then refuses to install Core on an older runtime instead of failing while
compiling native modules, and `.nvmrc` is pinned to the same version.

yarn also enforces `engines` when running package scripts, so building
the monorepo (`yarn setup`, `yarn build`) requires Node.js >= 24.22.1.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
- Build the image on node:24-alpine.
- Pin postgres:18-alpine instead of the floating postgres:alpine tag, and
  mount the volume at /var/lib/postgresql as PostgreSQL 18 images require.
  The floating tag already resolves to 18, and those images refuse to
  start with a volume mounted at /var/lib/postgresql/data, so pulling a
  fresh image broke existing compose setups without any change on our side.
- Document how to keep or upgrade an existing volume, and warn against
  migrating with pg_dump/pg_restore, which silently skips the blocks and
  transactions tables (the integrity check functions reference tables
  without a schema while pg_restore runs with an empty search_path).

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The packages now require Node.js ^24.22.1 and yarn enforces `engines` when
running package scripts. Run every job that installs or builds Core on the
latest Node.js 24 release, the same version operators get from NodeSource
`node_24.x` and the `node:24` Docker images. actions/setup-node@v4 with
`check-latest` is needed for that: setup-node otherwise uses the 24.x
cached on the runner image, which can be older than the required 24.22.1,
and v1 has no way to skip the cache. The CodeQL job gains the same setup
step and moves from the retired github/codeql-action v1 to v4.

Include the Node.js major in the node_modules cache key so a cache built
on Node.js 16 (native modules for ABI 93) is not restored. The e2e node
image runs the repository built on the runner and moves to node:24.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
PostgreSQL 12 is end-of-life and outside the supported 16 and 18. Run
the functional and integration jobs against PostgreSQL 18, and pin the
e2e network to 18 instead of the floating alpine tag.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
packages/core-manager no longer exists, so its publish line failed on
every release.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@sebastijankuzner
sebastijankuzner merged commit 38a7d9b into develop Oct 29, 2026
47 checks passed
@sebastijankuzner
sebastijankuzner deleted the chore/node-24-maintenance branch October 29, 2026 09:54
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants