From d1ffddb626122d1701d528abcc7327b68b1221b3 Mon Sep 17 00:00:00 2001 From: Noah Gregory Date: Tue, 7 Apr 2026 03:31:32 -0400 Subject: [PATCH 1/4] fix: don't let un-updateable builds check for an update --- apps/desktop/src/main.ts | 24 ++++++++++++----------- apps/desktop/src/updateState.test.ts | 29 ++++++++++++++++++++++++++++ apps/desktop/src/updateState.ts | 4 ++++ 3 files changed, 46 insertions(+), 11 deletions(-) diff --git a/apps/desktop/src/main.ts b/apps/desktop/src/main.ts index 3d61571df9..ee96547801 100644 --- a/apps/desktop/src/main.ts +++ b/apps/desktop/src/main.ts @@ -563,6 +563,7 @@ function handleCheckForUpdatesMenuClick(): void { platform: process.platform, appImage: process.env.APPIMAGE, disabledByEnv: process.env.T3CODE_DISABLE_AUTO_UPDATE === "1", + hasFeedURL: typeof autoUpdater.getFeedURL() === "string", }); if (disabledReason) { console.info("[desktop-updater] Manual update check requested, but updates are disabled."); @@ -786,6 +787,7 @@ function shouldEnableAutoUpdates(): boolean { platform: process.platform, appImage: process.env.APPIMAGE, disabledByEnv: process.env.T3CODE_DISABLE_AUTO_UPDATE === "1", + hasFeedURL: typeof autoUpdater.getFeedURL() === "string", }) === null ); } @@ -869,17 +871,6 @@ async function installDownloadedUpdate(): Promise<{ accepted: boolean; completed } function configureAutoUpdater(): void { - const enabled = shouldEnableAutoUpdates(); - setUpdateState({ - ...createInitialDesktopUpdateState(app.getVersion(), desktopRuntimeInfo), - enabled, - status: enabled ? "idle" : "disabled", - }); - if (!enabled) { - return; - } - updaterConfigured = true; - const githubToken = process.env.T3CODE_DESKTOP_UPDATE_GITHUB_TOKEN?.trim() || process.env.GH_TOKEN?.trim() || ""; if (githubToken) { @@ -904,6 +895,17 @@ function configureAutoUpdater(): void { }); } + const enabled = shouldEnableAutoUpdates(); + setUpdateState({ + ...createInitialDesktopUpdateState(app.getVersion(), desktopRuntimeInfo), + enabled, + status: enabled ? "idle" : "disabled", + }); + if (!enabled) { + return; + } + updaterConfigured = true; + autoUpdater.autoDownload = false; autoUpdater.autoInstallOnAppQuit = false; // Keep alpha branding, but force all installs onto the stable update track. diff --git a/apps/desktop/src/updateState.test.ts b/apps/desktop/src/updateState.test.ts index 43b718bd00..f43efb175d 100644 --- a/apps/desktop/src/updateState.test.ts +++ b/apps/desktop/src/updateState.test.ts @@ -71,10 +71,37 @@ describe("getAutoUpdateDisabledReason", () => { platform: "darwin", appImage: undefined, disabledByEnv: false, + hasFeedURL: false, }), ).toContain("packaged production builds"); }); + it("reports packaged local builds without an update feed as disabled", () => { + expect( + getAutoUpdateDisabledReason({ + isDevelopment: false, + isPackaged: true, + platform: "darwin", + appImage: undefined, + disabledByEnv: false, + hasFeedURL: false, + }), + ).toContain("packaged production builds"); + }); + + it("allows packaged builds with an update feed", () => { + expect( + getAutoUpdateDisabledReason({ + isDevelopment: false, + isPackaged: true, + platform: "darwin", + appImage: undefined, + disabledByEnv: false, + hasFeedURL: true, + }), + ).toBeNull(); + }); + it("reports env-disabled auto updates", () => { expect( getAutoUpdateDisabledReason({ @@ -83,6 +110,7 @@ describe("getAutoUpdateDisabledReason", () => { platform: "darwin", appImage: undefined, disabledByEnv: true, + hasFeedURL: true, }), ).toContain("T3CODE_DISABLE_AUTO_UPDATE"); }); @@ -95,6 +123,7 @@ describe("getAutoUpdateDisabledReason", () => { platform: "linux", appImage: undefined, disabledByEnv: false, + hasFeedURL: true, }), ).toContain("AppImage"); }); diff --git a/apps/desktop/src/updateState.ts b/apps/desktop/src/updateState.ts index 8c8ef1ddc9..8d006a2c2a 100644 --- a/apps/desktop/src/updateState.ts +++ b/apps/desktop/src/updateState.ts @@ -34,7 +34,11 @@ export function getAutoUpdateDisabledReason(args: { platform: NodeJS.Platform; appImage?: string | undefined; disabledByEnv: boolean; + hasFeedURL: boolean; }): string | null { + if (!args.hasFeedURL) { + return "Automatic updates are not available because no update feed URL is configured."; + } if (args.isDevelopment || !args.isPackaged) { return "Automatic updates are only available in packaged production builds."; } From 6d616d4e5d4409d39699d034d6edad57f3c203e7 Mon Sep 17 00:00:00 2001 From: Noah Gregory Date: Tue, 7 Apr 2026 03:41:14 -0400 Subject: [PATCH 2/4] fix: fix incorrect test --- apps/desktop/src/updateState.test.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps/desktop/src/updateState.test.ts b/apps/desktop/src/updateState.test.ts index f43efb175d..9722877f59 100644 --- a/apps/desktop/src/updateState.test.ts +++ b/apps/desktop/src/updateState.test.ts @@ -86,7 +86,7 @@ describe("getAutoUpdateDisabledReason", () => { disabledByEnv: false, hasFeedURL: false, }), - ).toContain("packaged production builds"); + ).toContain("no update feed URL"); }); it("allows packaged builds with an update feed", () => { From 6763cb639b446348990a4876d1d733143f375dd3 Mon Sep 17 00:00:00 2001 From: Noah Gregory Date: Tue, 7 Apr 2026 03:42:32 -0400 Subject: [PATCH 3/4] fix: fix other broken test --- apps/desktop/src/updateState.test.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps/desktop/src/updateState.test.ts b/apps/desktop/src/updateState.test.ts index 9722877f59..94e8cfcf01 100644 --- a/apps/desktop/src/updateState.test.ts +++ b/apps/desktop/src/updateState.test.ts @@ -71,7 +71,7 @@ describe("getAutoUpdateDisabledReason", () => { platform: "darwin", appImage: undefined, disabledByEnv: false, - hasFeedURL: false, + hasFeedURL: true, }), ).toContain("packaged production builds"); }); From 802d85fd4744ba9bd190cadece53a0f74125a641 Mon Sep 17 00:00:00 2001 From: Noah Gregory Date: Tue, 7 Apr 2026 03:59:36 -0400 Subject: [PATCH 4/4] fix: define wether we have an update config based on something that actually works --- apps/desktop/src/main.ts | 8 ++++++-- apps/desktop/src/updateState.test.ts | 12 ++++++------ apps/desktop/src/updateState.ts | 6 +++--- 3 files changed, 15 insertions(+), 11 deletions(-) diff --git a/apps/desktop/src/main.ts b/apps/desktop/src/main.ts index ee96547801..3adf8a3ca6 100644 --- a/apps/desktop/src/main.ts +++ b/apps/desktop/src/main.ts @@ -557,13 +557,15 @@ function dispatchMenuAction(action: string): void { } function handleCheckForUpdatesMenuClick(): void { + const hasUpdateFeedConfig = + readAppUpdateYml() !== null || Boolean(process.env.T3CODE_DESKTOP_MOCK_UPDATES); const disabledReason = getAutoUpdateDisabledReason({ isDevelopment, isPackaged: app.isPackaged, platform: process.platform, appImage: process.env.APPIMAGE, disabledByEnv: process.env.T3CODE_DISABLE_AUTO_UPDATE === "1", - hasFeedURL: typeof autoUpdater.getFeedURL() === "string", + hasUpdateFeedConfig, }); if (disabledReason) { console.info("[desktop-updater] Manual update check requested, but updates are disabled."); @@ -780,6 +782,8 @@ function setUpdateState(patch: Partial): void { } function shouldEnableAutoUpdates(): boolean { + const hasUpdateFeedConfig = + readAppUpdateYml() !== null || Boolean(process.env.T3CODE_DESKTOP_MOCK_UPDATES); return ( getAutoUpdateDisabledReason({ isDevelopment, @@ -787,7 +791,7 @@ function shouldEnableAutoUpdates(): boolean { platform: process.platform, appImage: process.env.APPIMAGE, disabledByEnv: process.env.T3CODE_DISABLE_AUTO_UPDATE === "1", - hasFeedURL: typeof autoUpdater.getFeedURL() === "string", + hasUpdateFeedConfig, }) === null ); } diff --git a/apps/desktop/src/updateState.test.ts b/apps/desktop/src/updateState.test.ts index 94e8cfcf01..8db92e1915 100644 --- a/apps/desktop/src/updateState.test.ts +++ b/apps/desktop/src/updateState.test.ts @@ -71,7 +71,7 @@ describe("getAutoUpdateDisabledReason", () => { platform: "darwin", appImage: undefined, disabledByEnv: false, - hasFeedURL: true, + hasUpdateFeedConfig: true, }), ).toContain("packaged production builds"); }); @@ -84,9 +84,9 @@ describe("getAutoUpdateDisabledReason", () => { platform: "darwin", appImage: undefined, disabledByEnv: false, - hasFeedURL: false, + hasUpdateFeedConfig: false, }), - ).toContain("no update feed URL"); + ).toContain("no update feed"); }); it("allows packaged builds with an update feed", () => { @@ -97,7 +97,7 @@ describe("getAutoUpdateDisabledReason", () => { platform: "darwin", appImage: undefined, disabledByEnv: false, - hasFeedURL: true, + hasUpdateFeedConfig: true, }), ).toBeNull(); }); @@ -110,7 +110,7 @@ describe("getAutoUpdateDisabledReason", () => { platform: "darwin", appImage: undefined, disabledByEnv: true, - hasFeedURL: true, + hasUpdateFeedConfig: true, }), ).toContain("T3CODE_DISABLE_AUTO_UPDATE"); }); @@ -123,7 +123,7 @@ describe("getAutoUpdateDisabledReason", () => { platform: "linux", appImage: undefined, disabledByEnv: false, - hasFeedURL: true, + hasUpdateFeedConfig: true, }), ).toContain("AppImage"); }); diff --git a/apps/desktop/src/updateState.ts b/apps/desktop/src/updateState.ts index 8d006a2c2a..928bb40886 100644 --- a/apps/desktop/src/updateState.ts +++ b/apps/desktop/src/updateState.ts @@ -34,10 +34,10 @@ export function getAutoUpdateDisabledReason(args: { platform: NodeJS.Platform; appImage?: string | undefined; disabledByEnv: boolean; - hasFeedURL: boolean; + hasUpdateFeedConfig: boolean; }): string | null { - if (!args.hasFeedURL) { - return "Automatic updates are not available because no update feed URL is configured."; + if (!args.hasUpdateFeedConfig) { + return "Automatic updates are not available because no update feed is configured."; } if (args.isDevelopment || !args.isPackaged) { return "Automatic updates are only available in packaged production builds.";