From 420bd69aa7bc8c2f809b059f70e2a1823b4dd36e Mon Sep 17 00:00:00 2001 From: Douglas Lowder Date: Thu, 8 Oct 2026 15:31:35 -0700 Subject: [PATCH 1/2] [eas-cli][local-build-plugin] Deprecate Node 20, use Node 22 in CI Print a deprecation warning from the eas-cli and local-build-plugin bin scripts when running on Node.js < 22. Develop and test on Node.js 22: bump mise, drop 20.18.3 from the test matrix, and move to @tsconfig/node22 and @types/node 22. Published engines are unchanged. Co-Authored-By: Claude Opus 5.5 --- .github/workflows/test.yml | 4 +- CHANGELOG.md | 1 + mise.toml | 2 +- package.json | 2 +- packages/build-tools/package.json | 2 +- .../create-eas-build-function/package.json | 2 +- .../templates/typescript/package.json | 2 +- packages/downloader/package.json | 2 +- .../eas-build-cache-provider/package.json | 2 +- .../eas-build-cache-provider/tsconfig.json | 2 +- packages/eas-build-job/package.json | 2 +- packages/eas-cli/CLAUDE.md | 2 +- packages/eas-cli/bin/run | 8 ++++ packages/eas-cli/package.json | 6 +-- packages/eas-cli/tsconfig.json | 2 +- packages/eas-json/package.json | 2 +- packages/eas-json/tsconfig.json | 2 +- packages/local-build-plugin/bin/run | 12 +++++ packages/logger/package.json | 2 +- packages/steps/package.json | 2 +- packages/template-file/package.json | 2 +- packages/turtle-spawn/package.json | 2 +- packages/worker/package.json | 2 +- scripts/package.json | 2 +- scripts/yarn.lock | 10 ++--- yarn.lock | 44 +++++++++---------- 26 files changed, 72 insertions(+), 51 deletions(-) diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index 3905c25abe..9822f71d81 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -15,9 +15,9 @@ jobs: runs-on: ubuntu-latest strategy: matrix: - node: ['20.18.3', '22', '24'] + node: ['22', '24'] include: - - node: '20.18.3' + - node: '22' coverage: true name: Test with Node ${{ matrix.node }} steps: diff --git a/CHANGELOG.md b/CHANGELOG.md index f4da87dd02..fecafa2ff0 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -9,6 +9,7 @@ This is the log of notable changes to EAS CLI and related packages. ### 🎉 New features - [build-tools] Let the MCP server read text and image files from sandboxes. ([#4555](https://github.com/expo/eas-cli/pull/4555) by [@AHGIJMKLKKZNPJKQR](https://github.com/AHGIJMKLKKZNPJKQR)) +- [eas-cli][local-build-plugin] Deprecate Node.js 20, and print a warning when running on it. A future release will require Node.js 22 or newer. Development and CI now use Node.js 22. ([#4579](https://github.com/expo/eas-cli/pull/4579) by [@douglowder](https://github.com/douglowder)) ### 🐛 Bug fixes diff --git a/mise.toml b/mise.toml index 0cfa311f17..a2cccfdfd8 100644 --- a/mise.toml +++ b/mise.toml @@ -6,4 +6,4 @@ MISE_NODE_COREPACK = "true" actionlint = "1.7.12" gcloud = "570.0.0" jq = "1.8.1" -node = "20.19.4" +node = "22.23.3" diff --git a/package.json b/package.json index ac8bc49b44..ea4c9758a0 100644 --- a/package.json +++ b/package.json @@ -22,7 +22,7 @@ }, "devDependencies": { "@types/jest": "29.5.11", - "@types/node": "20.19.43", + "@types/node": "22.20.5", "eslint-plugin-async-protect": "3.1.0", "jest": "29.7.0", "jest-watch-typeahead": "2.2.2", diff --git a/packages/build-tools/package.json b/packages/build-tools/package.json index d60b26f949..caf4f0d982 100644 --- a/packages/build-tools/package.json +++ b/packages/build-tools/package.json @@ -88,7 +88,7 @@ "@types/fs-extra": "^11.0.4", "@types/jest": "^29.5.12", "@types/lodash": "^4.17.4", - "@types/node": "20.19.43", + "@types/node": "22.20.5", "@types/node-fetch": "^2.6.11", "@types/node-forge": "^1.3.11", "@types/plist": "^3.0.5", diff --git a/packages/create-eas-build-function/package.json b/packages/create-eas-build-function/package.json index dcb0d78758..1844224e19 100644 --- a/packages/create-eas-build-function/package.json +++ b/packages/create-eas-build-function/package.json @@ -41,7 +41,7 @@ "@expo/package-manager": "1.9.10", "@jest/globals": "^29.7.0", "@types/jest": "^29.5.12", - "@types/node": "20.19.43", + "@types/node": "22.20.5", "@types/prompts": "^2.4.9", "@vercel/ncc": "^0.38.1", "arg": "^5.0.2", diff --git a/packages/create-eas-build-function/templates/typescript/package.json b/packages/create-eas-build-function/templates/typescript/package.json index b14e7385aa..a4d0f88e10 100644 --- a/packages/create-eas-build-function/templates/typescript/package.json +++ b/packages/create-eas-build-function/templates/typescript/package.json @@ -11,7 +11,7 @@ }, "devDependencies": { "@expo/steps": "^1.0.119", - "@types/node": "20.19.43", + "@types/node": "22.20.5", "@vercel/ncc": "^0.38.1", "typescript": "^6.0.3" } diff --git a/packages/downloader/package.json b/packages/downloader/package.json index e200f2ff3f..2c14c9e3dd 100644 --- a/packages/downloader/package.json +++ b/packages/downloader/package.json @@ -31,7 +31,7 @@ "devDependencies": { "@types/fs-extra": "^11.0.4", "@types/jest": "^29.5.12", - "@types/node": "20.19.43", + "@types/node": "22.20.5", "jest": "^29.7.0", "rimraf": "3.0.2", "ts-jest": "^29.4.12", diff --git a/packages/eas-build-cache-provider/package.json b/packages/eas-build-cache-provider/package.json index d8b40df880..fa1dce2091 100644 --- a/packages/eas-build-cache-provider/package.json +++ b/packages/eas-build-cache-provider/package.json @@ -44,7 +44,7 @@ "tslib": "2.4.1" }, "devDependencies": { - "@tsconfig/node20": "20.1.8", + "@tsconfig/node22": "22.0.6", "@types/babel__code-frame": "7.0.3", "@types/fs-extra": "11.0.4", "@types/getenv": "^1.0.0", diff --git a/packages/eas-build-cache-provider/tsconfig.json b/packages/eas-build-cache-provider/tsconfig.json index 177de02595..ff6941f809 100644 --- a/packages/eas-build-cache-provider/tsconfig.json +++ b/packages/eas-build-cache-provider/tsconfig.json @@ -1,5 +1,5 @@ { - "extends": "@tsconfig/node20/tsconfig.json", + "extends": "@tsconfig/node22/tsconfig.json", "compilerOptions": { "declaration": true, "importHelpers": true, diff --git a/packages/eas-build-job/package.json b/packages/eas-build-job/package.json index b083000b7a..9d260e75ba 100644 --- a/packages/eas-build-job/package.json +++ b/packages/eas-build-job/package.json @@ -34,7 +34,7 @@ }, "devDependencies": { "@types/jest": "^29.5.12", - "@types/node": "20.19.43", + "@types/node": "22.20.5", "jest": "^29.7.0", "rimraf": "3.0.2", "ts-jest": "^29.4.12", diff --git a/packages/eas-cli/CLAUDE.md b/packages/eas-cli/CLAUDE.md index 33161c0a04..19e382f395 100644 --- a/packages/eas-cli/CLAUDE.md +++ b/packages/eas-cli/CLAUDE.md @@ -299,4 +299,4 @@ describe('MyCommand', () => { - **README**: Auto-generated from oclif - update via `yarn oclif readme` - **Manifest**: Generated during `prepack` step - **Templates**: `src/commandUtils/new/templates` are copied to `build/` during build -- **Node Version**: ^20.18.3 or >= 22.0.0 +- **Node Version**: Develop on Node 22. Users can run Node ^20.18.3 (deprecated, `bin/run` prints a warning) or >= 22.0.0 diff --git a/packages/eas-cli/bin/run b/packages/eas-cli/bin/run index 6c80a3c26c..c22f74ac77 100755 --- a/packages/eas-cli/bin/run +++ b/packages/eas-cli/bin/run @@ -1,5 +1,13 @@ #!/usr/bin/env node +if (require('semver').lt(process.version, '22.0.0')) { + console.warn( + require('chalk').yellow( + `Node.js ${process.version} is deprecated. A future release of EAS CLI will require Node.js 22 or newer.` + ) + ); +} + (async () => { const oclif = require('@oclif/core'); await oclif.execute({ dir: __dirname }); diff --git a/packages/eas-cli/package.json b/packages/eas-cli/package.json index da131c69b2..64aa349dd1 100644 --- a/packages/eas-cli/package.json +++ b/packages/eas-cli/package.json @@ -142,7 +142,7 @@ "@graphql-codegen/introspection": "5.0.2", "@graphql-codegen/typescript": "5.0.10", "@graphql-codegen/typescript-operations": "5.1.0", - "@tsconfig/node20": "20.1.8", + "@tsconfig/node22": "22.0.6", "@types/cli-progress": "3.11.5", "@types/dateformat": "3.0.1", "@types/debug": "4.1.13", @@ -152,7 +152,7 @@ "@types/getenv": "^1.0.0", "@types/invariant": "^2.2.37", "@types/mime": "3.0.1", - "@types/node": "20.19.43", + "@types/node": "22.20.5", "@types/node-fetch": "2.6.12", "@types/node-forge": "1.3.1", "@types/pngjs": "6.0.4", @@ -250,7 +250,7 @@ }, "update": { "node": { - "version": "20.19.4" + "version": "22.23.3" }, "s3": { "templates": { diff --git a/packages/eas-cli/tsconfig.json b/packages/eas-cli/tsconfig.json index 05cb91f92f..f8e30da444 100644 --- a/packages/eas-cli/tsconfig.json +++ b/packages/eas-cli/tsconfig.json @@ -1,5 +1,5 @@ { - "extends": "@tsconfig/node20/tsconfig.json", + "extends": "@tsconfig/node22/tsconfig.json", "compilerOptions": { "declaration": true, "importHelpers": true, diff --git a/packages/eas-json/package.json b/packages/eas-json/package.json index 87a9594231..6ecb59aa72 100644 --- a/packages/eas-json/package.json +++ b/packages/eas-json/package.json @@ -44,7 +44,7 @@ "tslib": "2.4.1" }, "devDependencies": { - "@tsconfig/node20": "20.1.8", + "@tsconfig/node22": "22.0.6", "@types/babel__code-frame": "7.0.3", "@types/fs-extra": "11.0.4", "jest": "29.7.0", diff --git a/packages/eas-json/tsconfig.json b/packages/eas-json/tsconfig.json index 434ce940f9..f7a0f266b9 100644 --- a/packages/eas-json/tsconfig.json +++ b/packages/eas-json/tsconfig.json @@ -1,5 +1,5 @@ { - "extends": "@tsconfig/node20/tsconfig.json", + "extends": "@tsconfig/node22/tsconfig.json", "compilerOptions": { "declaration": true, "importHelpers": true, diff --git a/packages/local-build-plugin/bin/run b/packages/local-build-plugin/bin/run index efb207c4af..4220c6ddee 100755 --- a/packages/local-build-plugin/bin/run +++ b/packages/local-build-plugin/bin/run @@ -4,9 +4,21 @@ function red(text) { return '\u001b[31m' + text + '\u001b[39m'; } +function yellow(text) { + return '\u001b[33m' + text + '\u001b[39m'; +} + if (!require('semver').gte(process.version, '12.9.0')) { console.error(red('Node.js version 12.9.0 or newer is required.')); process.exit(1); } +if (require('semver').lt(process.version, '22.0.0')) { + console.warn( + yellow( + `Node.js ${process.version} is deprecated. A future release of eas-cli-local-build-plugin will require Node.js 22 or newer.` + ) + ); +} + require('../dist/main.js'); diff --git a/packages/logger/package.json b/packages/logger/package.json index d001c2b9b8..3226fd2db2 100644 --- a/packages/logger/package.json +++ b/packages/logger/package.json @@ -30,7 +30,7 @@ }, "devDependencies": { "@types/jest": "^29.5.12", - "@types/node": "20.19.43", + "@types/node": "22.20.5", "jest": "^29.7.0", "rimraf": "3.0.2", "ts-jest": "^29.4.12", diff --git a/packages/steps/package.json b/packages/steps/package.json index 322c08c56a..e2d2f33767 100644 --- a/packages/steps/package.json +++ b/packages/steps/package.json @@ -44,7 +44,7 @@ "@jest/globals": "^29.7.0", "@types/jest": "^29.5.12", "@types/lodash.clonedeep": "^4.5.9", - "@types/node": "20.19.43", + "@types/node": "22.20.5", "bunyan": "^1.8.15", "eslint-plugin-async-protect": "^3.1.0", "jest": "^29.7.0", diff --git a/packages/template-file/package.json b/packages/template-file/package.json index b0abc3a143..f12f946b17 100644 --- a/packages/template-file/package.json +++ b/packages/template-file/package.json @@ -31,7 +31,7 @@ "@types/jest": "^29.5.12", "@types/lodash": "^4.17.4", "@types/lodash.template": "^4.5.3", - "@types/node": "20.19.43", + "@types/node": "22.20.5", "jest": "^29.7.0", "rimraf": "3.0.2", "ts-jest": "^29.4.12", diff --git a/packages/turtle-spawn/package.json b/packages/turtle-spawn/package.json index 65e9c5cd80..6c75a6e5b9 100644 --- a/packages/turtle-spawn/package.json +++ b/packages/turtle-spawn/package.json @@ -30,7 +30,7 @@ }, "devDependencies": { "@types/jest": "^29.5.12", - "@types/node": "20.19.43", + "@types/node": "22.20.5", "jest": "^29.7.0", "rimraf": "3.0.2", "ts-jest": "^29.4.12", diff --git a/packages/worker/package.json b/packages/worker/package.json index 42aa8cf62d..1f5b95e44e 100644 --- a/packages/worker/package.json +++ b/packages/worker/package.json @@ -59,7 +59,7 @@ "@types/koa-router": "7.4.9", "@types/lodash": "4.17.4", "@types/micromatch": "4.0.7", - "@types/node": "20.19.43", + "@types/node": "22.20.5", "@types/node-fetch": "2.6.7", "@types/node-os-utils": "1.3.0", "@types/semver": "7.5.8", diff --git a/scripts/package.json b/scripts/package.json index 4e7304af28..625f3027fb 100644 --- a/scripts/package.json +++ b/scripts/package.json @@ -27,7 +27,7 @@ "@types/dateformat": "3.0.1", "@types/fs-extra": "11.0.4", "@types/lodash-es": "4.17.12", - "@types/node": "20.19.43", + "@types/node": "22.20.5", "@types/semver": "7.5.6", "ts-node": "10.9.2", "typescript": "6.0.3" diff --git a/scripts/yarn.lock b/scripts/yarn.lock index 163e50ed51..86af818abe 100644 --- a/scripts/yarn.lock +++ b/scripts/yarn.lock @@ -115,12 +115,12 @@ __metadata: languageName: node linkType: hard -"@types/node@npm:20.19.43": - version: 20.19.43 - resolution: "@types/node@npm:20.19.43" +"@types/node@npm:22.20.5": + version: 22.20.5 + resolution: "@types/node@npm:22.20.5" dependencies: undici-types: "npm:~6.21.0" - checksum: 10c0/9bcec3b5295bdd77ff0b44a528a69f7e22028c347507ba2c69be47ec84e30299f45043b222e9c86c510e138c9c53b2419dd5cd34920602a4a5a381c288075318 + checksum: 10c0/0cf61a89c6a69917ab49f976a6bb11a29e3b348a6ae19f5827ceb91d3ade781faab58dcf3b8fa625f975f5d7536b9166ff94e8250c29272c667164f77c28fa88 languageName: node linkType: hard @@ -252,7 +252,7 @@ __metadata: "@types/dateformat": "npm:3.0.1" "@types/fs-extra": "npm:11.0.4" "@types/lodash-es": "npm:4.17.12" - "@types/node": "npm:20.19.43" + "@types/node": "npm:22.20.5" "@types/semver": "npm:7.5.6" chalk: "npm:5.2.0" dateformat: "npm:4.5.1" diff --git a/yarn.lock b/yarn.lock index d164ea2eef..1669a21434 100644 --- a/yarn.lock +++ b/yarn.lock @@ -2328,7 +2328,7 @@ __metadata: "@types/fs-extra": "npm:^11.0.4" "@types/jest": "npm:^29.5.12" "@types/lodash": "npm:^4.17.4" - "@types/node": "npm:20.19.43" + "@types/node": "npm:22.20.5" "@types/node-fetch": "npm:^2.6.11" "@types/node-forge": "npm:^1.3.11" "@types/plist": "npm:^3.0.5" @@ -2562,7 +2562,7 @@ __metadata: dependencies: "@types/fs-extra": "npm:^11.0.4" "@types/jest": "npm:^29.5.12" - "@types/node": "npm:20.19.43" + "@types/node": "npm:22.20.5" fs-extra: "npm:^11.2.0" got: "npm:11.8.5" jest: "npm:^29.7.0" @@ -2580,7 +2580,7 @@ __metadata: "@expo/results": "npm:1.0.0" "@expo/turtle-spawn": "npm:24.8.0" "@types/jest": "npm:^29.5.12" - "@types/node": "npm:20.19.43" + "@types/node": "npm:22.20.5" jest: "npm:^29.7.0" joi: "npm:^17.13.1" rimraf: "npm:3.0.2" @@ -2597,7 +2597,7 @@ __metadata: dependencies: "@babel/code-frame": "npm:7.23.5" "@expo/eas-build-job": "npm:24.9.0" - "@tsconfig/node20": "npm:20.1.8" + "@tsconfig/node22": "npm:22.0.6" "@types/babel__code-frame": "npm:7.0.3" "@types/fs-extra": "npm:11.0.4" chalk: "npm:4.1.2" @@ -2716,7 +2716,7 @@ __metadata: dependencies: "@types/bunyan": "npm:^1.8.11" "@types/jest": "npm:^29.5.12" - "@types/node": "npm:20.19.43" + "@types/node": "npm:22.20.5" bunyan: "npm:^1.8.15" jest: "npm:^29.7.0" rimraf: "npm:3.0.2" @@ -2920,7 +2920,7 @@ __metadata: "@jest/globals": "npm:^29.7.0" "@types/jest": "npm:^29.5.12" "@types/lodash.clonedeep": "npm:^4.5.9" - "@types/node": "npm:20.19.43" + "@types/node": "npm:22.20.5" arg: "npm:^5.0.2" bunyan: "npm:^1.8.15" eslint-plugin-async-protect: "npm:^3.1.0" @@ -2948,7 +2948,7 @@ __metadata: "@types/jest": "npm:^29.5.12" "@types/lodash": "npm:^4.17.4" "@types/lodash.template": "npm:^4.5.3" - "@types/node": "npm:20.19.43" + "@types/node": "npm:22.20.5" jest: "npm:^29.7.0" lodash: "npm:^4.18.1" rimraf: "npm:3.0.2" @@ -2971,7 +2971,7 @@ __metadata: "@expo/logger": "npm:24.8.0" "@expo/spawn-async": "npm:^1.7.2" "@types/jest": "npm:^29.5.12" - "@types/node": "npm:20.19.43" + "@types/node": "npm:22.20.5" jest: "npm:^29.7.0" rimraf: "npm:3.0.2" ts-jest: "npm:^29.4.12" @@ -3002,7 +3002,7 @@ __metadata: "@types/koa-router": "npm:7.4.9" "@types/lodash": "npm:4.17.4" "@types/micromatch": "npm:4.0.7" - "@types/node": "npm:20.19.43" + "@types/node": "npm:22.20.5" "@types/node-fetch": "npm:2.6.7" "@types/node-os-utils": "npm:1.3.0" "@types/semver": "npm:7.5.8" @@ -6998,10 +6998,10 @@ __metadata: languageName: node linkType: hard -"@tsconfig/node20@npm:20.1.8": - version: 20.1.8 - resolution: "@tsconfig/node20@npm:20.1.8" - checksum: 10c0/5a9fcc0234e639c26f36f01d5912a59c47964361e9b9a8981a10806553799441f929474aed71cdec0ce5464ad1d757698df1651ac94cd55bb6bc01601a6003ea +"@tsconfig/node22@npm:22.0.6": + version: 22.0.6 + resolution: "@tsconfig/node22@npm:22.0.6" + checksum: 10c0/595f70f90820a16b34db5e192ac47f66567b694c14a2249e24009df27214fab665f6634c6346ad1b6aa2d222aee7377edfeba7821f0076cba075bc79a0be728c languageName: node linkType: hard @@ -7592,12 +7592,12 @@ __metadata: languageName: node linkType: hard -"@types/node@npm:20.19.43": - version: 20.19.43 - resolution: "@types/node@npm:20.19.43" +"@types/node@npm:22.20.5": + version: 22.20.5 + resolution: "@types/node@npm:22.20.5" dependencies: undici-types: "npm:~6.21.0" - checksum: 10c0/9bcec3b5295bdd77ff0b44a528a69f7e22028c347507ba2c69be47ec84e30299f45043b222e9c86c510e138c9c53b2419dd5cd34920602a4a5a381c288075318 + checksum: 10c0/0cf61a89c6a69917ab49f976a6bb11a29e3b348a6ae19f5827ceb91d3ade781faab58dcf3b8fa625f975f5d7536b9166ff94e8250c29272c667164f77c28fa88 languageName: node linkType: hard @@ -9837,7 +9837,7 @@ __metadata: "@expo/steps": "npm:24.9.0" "@jest/globals": "npm:^29.7.0" "@types/jest": "npm:^29.5.12" - "@types/node": "npm:20.19.43" + "@types/node": "npm:22.20.5" "@types/prompts": "npm:^2.4.9" "@vercel/ncc": "npm:^0.38.1" arg: "npm:^5.0.2" @@ -10395,7 +10395,7 @@ __metadata: "@babel/code-frame": "npm:7.23.5" "@expo/config": "npm:11.0.10" "@expo/spawn-async": "npm:^1.7.2" - "@tsconfig/node20": "npm:20.1.8" + "@tsconfig/node22": "npm:22.0.6" "@types/babel__code-frame": "npm:7.0.3" "@types/fs-extra": "npm:11.0.4" "@types/getenv": "npm:^1.0.0" @@ -10452,7 +10452,7 @@ __metadata: resolution: "eas-cli-root@workspace:." dependencies: "@types/jest": "npm:29.5.11" - "@types/node": "npm:20.19.43" + "@types/node": "npm:22.20.5" eslint-plugin-async-protect: "npm:3.1.0" jest: "npm:29.7.0" jest-watch-typeahead: "npm:2.2.2" @@ -10501,7 +10501,7 @@ __metadata: "@oclif/plugin-autocomplete": "npm:^3.2.40" "@segment/ajv-human-errors": "npm:^2.1.2" "@sentry/node": "npm:7.77.0" - "@tsconfig/node20": "npm:20.1.8" + "@tsconfig/node22": "npm:22.0.6" "@types/cli-progress": "npm:3.11.5" "@types/dateformat": "npm:3.0.1" "@types/debug": "npm:4.1.13" @@ -10511,7 +10511,7 @@ __metadata: "@types/getenv": "npm:^1.0.0" "@types/invariant": "npm:^2.2.37" "@types/mime": "npm:3.0.1" - "@types/node": "npm:20.19.43" + "@types/node": "npm:22.20.5" "@types/node-fetch": "npm:2.6.12" "@types/node-forge": "npm:1.3.1" "@types/pngjs": "npm:6.0.4" From b8eaceb58fb5ca672b84eef6889b2b8243154fdf Mon Sep 17 00:00:00 2001 From: Douglas Lowder Date: Sun, 11 Oct 2026 14:48:29 -0700 Subject: [PATCH 2/2] [docs] Update tsconfig base in CLAUDE.md to @tsconfig/node22 Co-Authored-By: Claude Opus 5.5 --- CLAUDE.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CLAUDE.md b/CLAUDE.md index d542f46084..d38b6119a0 100644 --- a/CLAUDE.md +++ b/CLAUDE.md @@ -164,7 +164,7 @@ Each package has independent TypeScript compilation: TypeScript configs: -- `tsconfig.json` - Base configuration (extends @tsconfig/node20) +- `tsconfig.json` - Base configuration (extends @tsconfig/node22) - `tsconfig.build.json` - Production builds - `tsconfig.allowUnused.json` - Development with relaxed rules