Skip to content

CHANGE @W-22462048@ Update CLI dependencies to released core packages - #2070

Open
nikhil-mittal-165 wants to merge 2 commits into
devfrom
nikhil.mittal/cli-dependency-upgrade-20260728
Open

CHANGE @W-22462048@ Update CLI dependencies to released core packages#2070
nikhil-mittal-165 wants to merge 2 commits into
devfrom
nikhil.mittal/cli-dependency-upgrade-20260728

Conversation

@nikhil-mittal-165

@nikhil-mittal-165 nikhil-mittal-165 commented Jul 27, 2026

Copy link
Copy Markdown
Contributor

What

Updates the CLI to depend on the freshly released @salesforce/code-analyzer-* core packages (monthly release), refreshes eligible non-core minor/patch dependencies, and adds a scoped override to keep the CLI working on its supported Node 20 floor.

Core package bumps (exact-pinned)

Package Old New
code-analyzer-core 0.49.0 0.50.0
code-analyzer-engine-api 0.39.0 0.40.0
code-analyzer-pmd-engine 0.43.0 0.44.0
code-analyzer-eslint-engine 0.44.0 0.45.0
code-analyzer-flow-engine 0.38.0 0.39.0
code-analyzer-regex-engine 0.37.0 0.38.0
code-analyzer-retirejs-engine 0.36.0 0.37.0
code-analyzer-sfge-engine 0.22.0 0.23.0
code-analyzer-apexguru-engine 0.39.0 0.40.0

Non-core (minor/patch only)

@oclif/core ^4.11.6→^4.11.14 · @salesforce/sf-plugins-core ^12.2.24→^12.2.26 · @eslint/eslintrc ^3.3.5→^3.3.6 · @oclif/plugin-help ^6.2.50→^6.2.53 · @salesforce/cli-plugins-testkit ^5.3.61→^5.3.62 · @vitest/coverage-istanbul & vitest ^4.1.9→^4.1.10 · oclif ^4.23.16→^4.23.28 · typescript-eslint ^8.61.1→^8.65.0

Intentionally not changed (compatibility): @salesforce/core (8.23.4), @types/node (^20), eslint/@eslint/js (^9), vite (^7), typescript (^5.9.3).


Node 20 fix — scoped undici override

"overrides": { "@jsforce/jsforce-node": { "undici": "^7.29.0" } }

⚠️ overrides was chosen as a last resort. Every less-invasive alternative was tested and ruled out with evidence (see "Alternatives considered" below). This is a temporary, narrowly-scoped, reversible constraint — not a preferred pattern. It should be removed as soon as the CLI drops its Node 20 floor.

Root cause (transitive caret float, not a manifest change)

  • @jsforce/[email protected] (published Jun 25) is the first jsforce version to depend on undici (^8.5.0). Earlier versions (3.10.13/3.10.16) had no undici. undici 8.x requires Node ≥22.19.0 (webidl.util.markAsUncloneable from node:worker_threads) and hard-crashes on Node 20 — the CLI's supported floor (engines.node: ">=20.0.0") — with TypeError: webidl.util.markAsUncloneable is not a function on any command that loads jsforce.
  • @salesforce/core (pinned at 8.23.4) depends on jsforce ^3.10.8 — a caret — so npm resolves the newest published jsforce (3.10.19 today). The prior release's lockfile was frozen at jsforce 3.10.13 (locked before jsforce added undici), so it never pulled undici; regenerating the lockfile for this dependency update floats jsforce forward and pulls in undici 8.
  • Evidence — the float is intrinsic to the caret, not to any one package: re-resolving the prior release's exact deps today (@salesforce/[email protected] + @salesforce/sf-plugins-core@^12.2.24, no apexguru) yields jsforce-node 3.10.19 + undici 8.9.0. So the crash reproduces with the old dependency set alone — the newer engines did not introduce it.
  • Not caught by CI: the CLI test matrix runs only lts/* + 24.x (never Node 20). Verified locally on Node v20.20.2: without the override the built CLI crashes on code-analyzer run; with it, a real scan and the full suite pass.

Alternatives considered (all tested, all rejected)

# Alternative Keeps Node 20 floor? Result Evidence
1 Pin undici as a top-level dependency ("undici": "^7.29.0" in dependencies) ❌ Ineffective jsforce declares undici ^8.5.0; npm keeps a nested undici@8 under node_modules/@jsforce/jsforce-node/ that jsforce's own require('undici') resolves. Same crash. A top-level pin only dedupes a transitive dep when our version satisfies the transitive range, and 7.x can never satisfy ^8.5.0.
2 Pin @jsforce/jsforce-node as a top-level dependency to 3.10.16 (last version with no undici) ❌ Ineffective Tested resolution: our pin is honored at top level, but sf-plugins-core and apexguru-engine each declare jsforce ^3.10.17, so npm gives them nested [email protected][email protected] reappears. A direct dependency cannot constrain another package's subtree.
3 Downgrade apexguru-engine's @salesforce/core to 8.23.4 and republish ❌ Ineffective The float lives in core → jsforce (a caret), not in apexguru → core. Even [email protected] resolves jsforce ^3.10.13 → 3.10.19 → undici 8. And there are parallel paths ([email protected] → core ^8.31.4, plus the CLI's own [email protected] → jsforce ^3.10.8) that reach undici 8 independently. Pinning apexguru fixes none of them. (For the record, apexguru only uses Connection/Org/Org.create, which do exist in 8.23.4 — but the change still wouldn't fix the crash, and would push apexguru below its declared ^8.31.2 range.)
4 resolutions field ❌ Not applicable Yarn-only; npm ignores it. This repo uses npm.
5 patch-package on jsforce's manifest ⚠️ Rejected Works, but strictly more invasive than overrides — it adds a postinstall hook that rewrites a dependency's package.json.
6 Raise the CLI Node floor to >=22 (drop the override, accept undici 8) ⚠️ Out of scope This is the ecosystem's direction (undici 8, jsforce, @salesforce/[email protected], and even this repo's CI all effectively target Node ≥22). But dropping Node 20 is a product/policy decision — Node 20 is our stated customer minimum — so it is out of scope for this dependency PR and should be a separate, deliberate change.
7 Wait for undici/jsforce to restore Node 20 support ❌ Not actionable undici 8 deliberately requires Node ≥22.19.0; it is not reverting.

Conclusion: within npm and while keeping the Node 20 floor, a scoped overrides is the only mechanism that constrains the transitive undici across every subtree at once. It is scoped under @jsforce/jsforce-node so the intent is explicit and narrow, and it is removable the moment the CLI drops its Node 20 floor (alternative #6).


Testing (Node v20.20.2)

  • npm run build
  • npm run lint
  • npm run test ✅ — 22/22 files, 393/393 tests (before the fix: 18/22 files failed at import time)
  • Smoke: code-analyzer run --rule-selector regex ✅ exit 0
  • CI (this PR): unit-tests + smoke-tests + tarball build all green on macOS/Ubuntu/Windows (lts/*)

Note: CLI version intentionally left at 5.14.0 — the release Action bumps it.

- Bump 9 @salesforce/code-analyzer-* deps to the newly released versions
  (core 0.50.0, engine-api 0.40.0, pmd 0.44.0, eslint 0.45.0, flow 0.39.0,
  regex 0.38.0, retirejs 0.37.0, sfge 0.23.0, apexguru 0.40.0)
- Bump eligible non-core minor/patch deps (oclif, sf-plugins-core,
  cli-plugins-testkit, vitest, typescript-eslint, etc.)
- Add scoped override pinning @jsforce/jsforce-node's undici to ^7.29.0.
  jsforce-node 3.10.17+ requires undici ^8.5.0, which needs Node >=22.19.0
  (webidl markAsUncloneable) and hard-crashes on the supported Node 20 floor.
  This restores Node 20 compatibility; removable once the Node 20 floor is dropped.

@aruntyagiTutu aruntyagiTutu left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Excellent, evidence-driven PR:

  • Core package bumps are exact-pinned to the just-released versions (0.50.0, 0.40.0, etc.) — correct for a CLI that depends on released (non-SNAPSHOT) core packages.
  • Non-core bumps are minor/patch only, and the compatibility holds (@salesforce/core, @types/node at ^20, eslint, vite, typescript) are explicit and justified — matches the Compatibility & Versioning guidance on not bumping without understanding downstream impact.
  • The Node 20 undici override is the standout part of this PR: the root-cause analysis (caret float in jsforce → undici 8 → Node 22+ API) is precise, and all 7 alternatives were actually tested rather than asserted, with the two npm-viable options (top-level pins) shown to be ineffective due to nested resolution. Landing on a scoped overrides under @jsforce/jsforce-node is the right minimal-blast-radius fix, and it's explicitly flagged as removable once Node 20 support is dropped — good forward-looking hygiene per the versioning guidelines.
  • Testing is thorough and reproducible: before/after behavior on Node 20.20.2, full test suite (393/393), and a real smoke run.

One minor nit (non-blocking): the second commit message "update critical dependency" doesn't follow the `NEW/FIX/CHANGE @W-XXXXX@" convention and doesn't say what was bumped (websocket-driver, per the diff) — worth a more descriptive message next time, but doesn't affect this PR's mergeability.

Approving.

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.

2 participants