feat: Migrate from Node.js 18 to Node.js 24 LTS#6
Conversation
…reaking changes
- Upgrade Node.js from 18.x to 24.x LTS (v24.15.0)
- Replace crypto.createCipher/createDecipher with createCipheriv/createDecipheriv
- Replace deprecated new Buffer() with Buffer.from() across all utils
- Replace deprecated require('punycode') with native String.normalize('NFKC')
- Replace deprecated url.parse() with WHATWG URL API (new URL())
- Replace deprecated querystring module with URLSearchParams/decodeURIComponent
- Replace deprecated util._extend() with Object.assign()
- Replace deprecated fs.R_OK/fs.W_OK with fs.constants.R_OK/fs.constants.W_OK
- Upgrade better-sqlite3 from 9.x to 12.x (required for Node 24 native addon support)
- Upgrade express from 4.18.x to 4.22.x
- Upgrade helmet from 7.x to 8.x
- Upgrade supertest from 6.x to 7.x
- Upgrade uuid from 9.x to 11.x
- Update all other dependencies to latest compatible versions
- Update .nvmrc, package.json engines, README.md, and .eslintrc.json
- All 53 existing tests continue to pass
Co-Authored-By: Chris Livingston <chris.livingston@cognition.ai>
🤖 Devin AI EngineerI'll be helping with this pull request! Here's what you should know: ✅ I will automatically:
Note: I can only respond to comments from users who have write access to this repository. ⚙️ Control Options:
|
There was a problem hiding this comment.
🟡 parserOptions.ecmaVersion not updated to match env: es2024
The ESLint env was updated from es2021 to es2024 (line 4), but parserOptions.ecmaVersion on line 9 was left at 2021. This means the ESLint parser will reject any syntax newer than ES2021 (e.g., using declarations, decorator syntax, etc.) even though ES2024 globals are made available by the env setting. Since parserOptions.ecmaVersion explicitly overrides the implicit ecmaVersion from env, the parser is more restrictive than intended for a Node.js 24 upgrade.
(Refers to line 9)
Was this helpful? React with 👍 or 👎 to provide feedback.
| // Decode any percent-encoded characters using querystring | ||
| cleaned = querystring.unescape(cleaned); | ||
| // Decode any percent-encoded characters | ||
| cleaned = decodeURIComponent(cleaned); |
There was a problem hiding this comment.
🔴 decodeURIComponent throws URIError on malformed percent-encoded input, unlike the replaced querystring.unescape
The migration from querystring.unescape(cleaned) to decodeURIComponent(cleaned) introduces an unhandled exception for malformed percent-encoded input (e.g., %ZZ, hello%world). The old querystring.unescape had a built-in fallback that returned the original string when decodeURIComponent threw, but the new code has no such protection. When called from src/routes/api.js:32, the thrown URIError is caught by the route handler's outer try/catch and results in a 500 Internal Server Error instead of the previous graceful handling that would have sanitized and returned results normally.
| cleaned = decodeURIComponent(cleaned); | |
| try { | |
| cleaned = decodeURIComponent(cleaned); | |
| } catch { | |
| // If decodeURIComponent fails on malformed input (e.g., '%ZZ'), keep the original string | |
| } |
Was this helpful? React with 👍 or 👎 to provide feedback.
Summary
Migrates the TODO List app from Node.js 18 to Node.js 24 LTS (v24.15.0 — codename Krypton), fixing all breaking changes from removed/deprecated Node APIs and upgrading dependencies to their latest compatible versions.
Breaking Changes Fixed
src/utils/crypto.jscrypto.createCipher/crypto.createDeciphercrypto.createCipheriv/crypto.createDecipherivwith random IVsrc/utils/crypto.jsnew Buffer()Buffer.from()src/utils/encoding.jsrequire('punycode')(removed built-in)String.normalize('NFKC')src/utils/encoding.jsnew Buffer()Buffer.from()src/utils/sanitizer.jsurl.parse()new URL()APIsrc/utils/sanitizer.jsquerystringmoduleURLSearchParams/decodeURIComponentsrc/middleware/validators.jsutil._extend()Object.assign()src/db/connection.jsfs.R_OK/fs.W_OKfs.constants.R_OK/fs.constants.W_OKDependency Upgrades
Config Updates
.nvmrc: 18 → 24package.jsonengines:>=18.0.0 <19.0.0→>=24.0.0.eslintrc.jsonenv:es2021→es2024README.md: Updated all Node 18 references to Node 24Review & Testing Checklist for Human
crypto.createCipheriv/crypto.createDecipherivtoken generation/validation works correctly — the token format changed (now includes IV prefix), so any existing tokens from the old format will not be decodablenvm use 24 && npm testlocally to confirm all 53 tests pass on Node 24sanitizeSearchQueryfunction with URL inputs to ensure thenew URL()migration preserves the same behavior as the oldurl.parse()npm startand verify the web UI loads and CRUD operations work end-to-endNotes
better-sqlite3upgrade from v9 to v12 was required because v9 cannot compile native addons against Node 24Link to Devin session: https://app.devin.ai/sessions/aa96c67a5d46414fa2d8f5b35704cfd8
Requested by: @clivingston-cognition