fix(updater): only toast 'Up to Date' on manual user-initiated checks
This commit is contained in:
1 parent
bea8aa9542
commit
7f2d028080
3 files changed
+52
-8
No files matched your search
@@ -28,7 +28,7 @@ export interface RegisterCoreHandlersDependencies {
|
|||||||
checkConnector: (id: ConnectorId) => Promise<void>;
|
checkConnector: (id: ConnectorId) => Promise<void>;
|
||||||
openConnectorAuthTerminal: (id: ConnectorId) => Promise<boolean>;
|
openConnectorAuthTerminal: (id: ConnectorId) => Promise<boolean>;
|
||||||
openGenericTerminal: (input: { commandKey: string }) => Promise<boolean>;
|
openGenericTerminal: (input: { commandKey: string }) => Promise<boolean>;
|
||||||
checkForUpdates: () => Promise<boolean>;
|
checkForUpdates: (options?: { manual?: boolean }) => Promise<boolean>;
|
||||||
getWorkerProcess: () => { postMessage: (message: unknown) => void } | null;
|
getWorkerProcess: () => { postMessage: (message: unknown) => void } | null;
|
||||||
resetAfterRestore: () => void;
|
resetAfterRestore: () => void;
|
||||||
getApiPort: () => number;
|
getApiPort: () => number;
|
||||||
|
|||||||
@@ -91,7 +91,9 @@ export function registerCoreReadHandlers({
|
|||||||
});
|
});
|
||||||
|
|
||||||
registerHandle(IPC_CHANNELS.checkForUpdates, async () => {
|
registerHandle(IPC_CHANNELS.checkForUpdates, async () => {
|
||||||
return ok(await checkForUpdates());
|
// Invocation via IPC only happens when the user opens Settings and clicks
|
||||||
|
// "Check for updates". Pass manual:true so the Up-to-Date toast fires.
|
||||||
|
return ok(await checkForUpdates({ manual: true }));
|
||||||
});
|
});
|
||||||
|
|
||||||
registerHandle(IPC_CHANNELS.getSidebarBadges, async (_event, companyId) => {
|
registerHandle(IPC_CHANNELS.getSidebarBadges, async (_event, companyId) => {
|
||||||
|
|||||||
@@ -14,12 +14,38 @@ interface UpdaterServiceDependencies {
|
|||||||
notify: (options: NotificationOptions) => void;
|
notify: (options: NotificationOptions) => void;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type SkipUpdateReason = "updates_disabled" | "insecure_url" | "dev_without_real_url";
|
||||||
|
|
||||||
|
function shouldSkipUpdateCheck(input: {
|
||||||
|
isPackaged: boolean;
|
||||||
|
updatesEnabled: boolean;
|
||||||
|
updateUrl: string | undefined;
|
||||||
|
updatesDisabledEnv: boolean;
|
||||||
|
}): SkipUpdateReason | null {
|
||||||
|
if (!input.updatesEnabled || input.updatesDisabledEnv) {
|
||||||
|
return "updates_disabled";
|
||||||
|
}
|
||||||
|
if (input.updateUrl && !input.updateUrl.startsWith("https://")) {
|
||||||
|
return "insecure_url";
|
||||||
|
}
|
||||||
|
if (!input.isPackaged && (!input.updateUrl || input.updateUrl.includes("example.invalid"))) {
|
||||||
|
return "dev_without_real_url";
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
export function createUpdaterService({
|
export function createUpdaterService({
|
||||||
db,
|
db,
|
||||||
logger,
|
logger,
|
||||||
notify,
|
notify,
|
||||||
}: UpdaterServiceDependencies) {
|
}: UpdaterServiceDependencies) {
|
||||||
let listenersAttached = false;
|
let listenersAttached = false;
|
||||||
|
/**
|
||||||
|
* Set by checkForUpdates({ manual: true }) from the UI. Gates the
|
||||||
|
* "Up to Date" toast so the auto-every-24h check stays silent when
|
||||||
|
* nothing happened. Cleared inside the update-not-available handler.
|
||||||
|
*/
|
||||||
|
let manualCheckPending = false;
|
||||||
|
|
||||||
function attachListeners() {
|
function attachListeners() {
|
||||||
if (listenersAttached) {
|
if (listenersAttached) {
|
||||||
@@ -31,6 +57,7 @@ export function createUpdaterService({
|
|||||||
});
|
});
|
||||||
autoUpdater.on("update-available", (info) => {
|
autoUpdater.on("update-available", (info) => {
|
||||||
logger.info("[updater] update available", info.version);
|
logger.info("[updater] update available", info.version);
|
||||||
|
manualCheckPending = false;
|
||||||
notify({
|
notify({
|
||||||
title: "Update Available",
|
title: "Update Available",
|
||||||
body: `Version ${info.version} is downloading in the background`,
|
body: `Version ${info.version} is downloading in the background`,
|
||||||
@@ -55,6 +82,10 @@ export function createUpdaterService({
|
|||||||
});
|
});
|
||||||
});
|
});
|
||||||
autoUpdater.on("update-not-available", () => {
|
autoUpdater.on("update-not-available", () => {
|
||||||
|
if (!manualCheckPending) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
manualCheckPending = false;
|
||||||
notify({
|
notify({
|
||||||
title: "Up to Date",
|
title: "Up to Date",
|
||||||
body: "You are running the latest version",
|
body: "You are running the latest version",
|
||||||
@@ -64,6 +95,7 @@ export function createUpdaterService({
|
|||||||
});
|
});
|
||||||
autoUpdater.on("error", (error) => {
|
autoUpdater.on("error", (error) => {
|
||||||
logger.error("[updater] error", error);
|
logger.error("[updater] error", error);
|
||||||
|
manualCheckPending = false;
|
||||||
notify({
|
notify({
|
||||||
title: "Update Check Failed",
|
title: "Update Check Failed",
|
||||||
body: "Could not check for updates. Try again later.",
|
body: "Could not check for updates. Try again later.",
|
||||||
@@ -73,20 +105,29 @@ export function createUpdaterService({
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
async function checkForUpdates() {
|
async function checkForUpdates(options: { manual?: boolean } = {}) {
|
||||||
const snapshot = db.listSnapshot();
|
const snapshot = db.listSnapshot();
|
||||||
if (!snapshot.updatesEnabled || process.env.AGENTCOMPANY_DISABLE_UPDATES === "true") {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
const updateUrl = process.env.AGENTCOMPANY_UPDATE_URL?.trim();
|
const updateUrl = process.env.AGENTCOMPANY_UPDATE_URL?.trim();
|
||||||
if (updateUrl && !updateUrl.startsWith("https://")) {
|
const skipReason = shouldSkipUpdateCheck({
|
||||||
|
isPackaged: app.isPackaged,
|
||||||
|
updatesEnabled: snapshot.updatesEnabled,
|
||||||
|
updateUrl,
|
||||||
|
updatesDisabledEnv: process.env.AGENTCOMPANY_DISABLE_UPDATES === "true",
|
||||||
|
});
|
||||||
|
if (skipReason === "insecure_url") {
|
||||||
logger.error("[updater] AGENTCOMPANY_UPDATE_URL must use HTTPS — refusing insecure update source.");
|
logger.error("[updater] AGENTCOMPANY_UPDATE_URL must use HTTPS — refusing insecure update source.");
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
if (!app.isPackaged && (!updateUrl || updateUrl.includes("example.invalid"))) {
|
if (skipReason === "dev_without_real_url") {
|
||||||
logger.info("[updater] Skipping update check because no real update URL is configured.");
|
logger.info("[updater] Skipping update check because no real update URL is configured.");
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
if (skipReason) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
if (options.manual) {
|
||||||
|
manualCheckPending = true;
|
||||||
|
}
|
||||||
try {
|
try {
|
||||||
autoUpdater.logger = {
|
autoUpdater.logger = {
|
||||||
info: (...args: unknown[]) => logger.info(...args),
|
info: (...args: unknown[]) => logger.info(...args),
|
||||||
@@ -100,6 +141,7 @@ export function createUpdaterService({
|
|||||||
return Boolean(result?.updateInfo);
|
return Boolean(result?.updateInfo);
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
logger.error(error);
|
logger.error(error);
|
||||||
|
manualCheckPending = false;
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in new issue
Block a user