From 849902278329065787c109f804d50ef645e1b241 Mon Sep 17 00:00:00 2001 From: sufiyan733 Date: Mon, 21 Sep 2026 00:05:01 +0530 Subject: [PATCH] fix(cli): handle catalog: protocol in dependency update check (#3905) --- .changeset/cli-catalog-protocol-crash.md | 5 + packages/cli-v3/src/commands/update.test.ts | 120 ++++++++++++++++++++ packages/cli-v3/src/commands/update.ts | 92 ++++++++------- 3 files changed, 175 insertions(+), 42 deletions(-) create mode 100644 .changeset/cli-catalog-protocol-crash.md create mode 100644 packages/cli-v3/src/commands/update.test.ts diff --git a/.changeset/cli-catalog-protocol-crash.md b/.changeset/cli-catalog-protocol-crash.md new file mode 100644 index 00000000000..2beba9ec767 --- /dev/null +++ b/.changeset/cli-catalog-protocol-crash.md @@ -0,0 +1,5 @@ +--- +"trigger.dev": patch +--- + +Prevent CLI crash when @trigger.dev dependencies use bun/pnpm catalog: protocol. diff --git a/packages/cli-v3/src/commands/update.test.ts b/packages/cli-v3/src/commands/update.test.ts new file mode 100644 index 00000000000..9ced97a5333 --- /dev/null +++ b/packages/cli-v3/src/commands/update.test.ts @@ -0,0 +1,120 @@ +import { describe, expect, it } from "vitest"; +import { getTriggerDependencies, getVersionMismatches, type Dependency } from "./update.js"; + +describe("getTriggerDependencies", () => { + it("skips dependencies using catalog: and workspace: protocols", async () => { + const packageJson = { + dependencies: { + "@trigger.dev/sdk": "catalog:", + "@trigger.dev/core": "catalog:default", + "@trigger.dev/react-hooks": "workspace:*", + lodash: "^4.17.21", + }, + devDependencies: { + "@trigger.dev/build": "catalog:tools", + "@trigger.dev/schema-to-json": "workspace:^3.0.0", + "@trigger.dev/companyicons": "^1.0.0", + }, + }; + + const deps = await getTriggerDependencies(packageJson, "/fake/project/package.json"); + + expect(deps).toEqual([]); + }); + + it("includes normal @trigger.dev dependencies", async () => { + const packageJson = { + dependencies: { + "@trigger.dev/sdk": "^3.0.0", + }, + devDependencies: { + "@trigger.dev/core": "~3.0.0", + }, + }; + + const deps = await getTriggerDependencies(packageJson, "/fake/project/package.json"); + + expect(deps).toHaveLength(2); + expect(deps).toContainEqual({ + type: "dependencies", + name: "@trigger.dev/sdk", + version: "^3.0.0", + }); + expect(deps).toContainEqual({ + type: "devDependencies", + name: "@trigger.dev/core", + version: "~3.0.0", + }); + }); +}); + +describe("getVersionMismatches", () => { + it("does not throw when encountering non-semver strings like catalog: or workspace:", () => { + const deps: Dependency[] = [ + { + type: "dependencies", + name: "@trigger.dev/sdk", + version: "catalog:", + }, + { + type: "dependencies", + name: "@trigger.dev/core", + version: "catalog:named", + }, + { + type: "devDependencies", + name: "@trigger.dev/build", + version: "workspace:*", + }, + { + type: "devDependencies", + name: "@trigger.dev/react-hooks", + version: "invalid-semver-string", + }, + ]; + + expect(() => getVersionMismatches(deps, "3.0.0")).not.toThrow(); + + const { mismatches, isDowngrade } = getVersionMismatches(deps, "3.0.0"); + expect(mismatches).toHaveLength(4); + expect(isDowngrade).toBe(false); + }); + + it("correctly identifies downgrades when valid semver is newer than target CLI version", () => { + const deps: Dependency[] = [ + { + type: "dependencies", + name: "@trigger.dev/sdk", + version: "^4.0.0", + }, + ]; + + const { mismatches, isDowngrade } = getVersionMismatches(deps, "3.0.0"); + expect(mismatches).toHaveLength(1); + expect(isDowngrade).toBe(true); + }); + + it("ignores packages matching targetVersion, 0.0.0, or pkg.pr.new", () => { + const deps: Dependency[] = [ + { + type: "dependencies", + name: "@trigger.dev/sdk", + version: "3.0.0", + }, + { + type: "dependencies", + name: "@trigger.dev/core", + version: "0.0.0-prerelease", + }, + { + type: "devDependencies", + name: "@trigger.dev/build", + version: "https://pkg.pr.new/@trigger.dev/build@123", + }, + ]; + + const { mismatches, isDowngrade } = getVersionMismatches(deps, "3.0.0"); + expect(mismatches).toHaveLength(0); + expect(isDowngrade).toBe(false); + }); +}); diff --git a/packages/cli-v3/src/commands/update.ts b/packages/cli-v3/src/commands/update.ts index 88a9c28aed3..4dc40140a50 100644 --- a/packages/cli-v3/src/commands/update.ts +++ b/packages/cli-v3/src/commands/update.ts @@ -116,45 +116,6 @@ export async function updateTriggerPackages( logger.debug("Resolved trigger deps", { triggerDependencies }); - function getVersionMismatches( - deps: Dependency[], - targetVersion: string - ): { - mismatches: Dependency[]; - isDowngrade: boolean; - } { - logger.debug("Checking for version mismatches", { deps, targetVersion }); - - const mismatches: Dependency[] = []; - - for (const dep of deps) { - if ( - dep.version === targetVersion || - dep.version.startsWith("https://pkg.pr.new") || - dep.version.startsWith("0.0.0") - ) { - continue; - } - - mismatches.push(dep); - } - - const isDowngrade = mismatches.some((dep) => { - const depMinVersion = semver.minVersion(dep.version); - - if (!depMinVersion) { - return false; - } - - return semver.gt(depMinVersion, targetVersion); - }); - - return { - mismatches, - isDowngrade, - }; - } - const { mismatches, isDowngrade } = getVersionMismatches(triggerDependencies, cliVersion); logger.debug("Version mismatches", { mismatches, isDowngrade }); @@ -314,13 +275,60 @@ export async function updateTriggerPackages( return hasOutput; } -type Dependency = { +export type Dependency = { type: "dependencies" | "devDependencies"; name: string; version: string; }; -async function getTriggerDependencies( +export function getVersionMismatches( + deps: Dependency[], + targetVersion: string +): { + mismatches: Dependency[]; + isDowngrade: boolean; +} { + logger.debug("Checking for version mismatches", { deps, targetVersion }); + + const mismatches: Dependency[] = []; + + for (const dep of deps) { + if ( + dep.version === targetVersion || + dep.version.startsWith("https://pkg.pr.new") || + dep.version.startsWith("0.0.0") + ) { + continue; + } + + mismatches.push(dep); + } + + const isDowngrade = mismatches.some((dep) => { + if (!semver.validRange(dep.version)) { + return false; + } + + try { + const depMinVersion = semver.minVersion(dep.version); + + if (!depMinVersion) { + return false; + } + + return semver.gt(depMinVersion, targetVersion); + } catch { + return false; + } + }); + + return { + mismatches, + isDowngrade, + }; +} + +export async function getTriggerDependencies( packageJson: PackageJson, packageJsonPath: string ): Promise { @@ -332,7 +340,7 @@ async function getTriggerDependencies( continue; } - if (version.startsWith("workspace")) { + if (version.startsWith("workspace") || version.startsWith("catalog:")) { continue; }