diff --git a/src/ipc/handlers/release_note_handlers.ts b/src/ipc/handlers/release_note_handlers.ts new file mode 100644 index 0000000..107f532 --- /dev/null +++ b/src/ipc/handlers/release_note_handlers.ts @@ -0,0 +1,59 @@ +import log from "electron-log"; +import fetch from "node-fetch"; +import { createLoggedHandler } from "./safe_handle"; +import { DoesReleaseNoteExistParams } from "../ipc_types"; + +const logger = log.scope("release_note_handlers"); + +const handle = createLoggedHandler(logger); + +export function registerReleaseNoteHandlers() { + handle( + "does-release-note-exist", + async (_, params: DoesReleaseNoteExistParams) => { + const { version } = params; + + if (!version || typeof version !== "string") { + throw new Error("Invalid version provided"); + } + + const releaseNoteUrl = `https://www.dyad.sh/docs/releases/${version}`; + + logger.debug(`Checking for release note at: ${releaseNoteUrl}`); + + try { + const response = await fetch(releaseNoteUrl, { method: "HEAD" }); // Use HEAD to check existence without downloading content + if (response.ok) { + logger.debug( + `Release note found for version ${version} at ${releaseNoteUrl}`, + ); + return { exists: true, url: releaseNoteUrl }; + } else if (response.status === 404) { + logger.debug( + `Release note not found for version ${version} at ${releaseNoteUrl}`, + ); + return { exists: false }; + } else { + // Log other non-404 errors but still treat as "not found" for the client, + // as the primary goal is to check existence. + logger.warn( + `Unexpected status code ${response.status} when checking for release note: ${releaseNoteUrl}`, + ); + return { exists: false }; + } + } catch (error) { + logger.error( + `Error fetching release note for version ${version} at ${releaseNoteUrl}:`, + error, + ); + // In case of network errors, etc., assume it doesn't exist or is inaccessible. + // Throwing an error here would propagate to the client and might be too disruptive + // if the check is just for UI purposes (e.g., showing a link). + // Consider if specific errors should be thrown based on requirements. + return { exists: false }; + } + }, + ); + + logger.debug("Registered release note IPC handlers"); +} diff --git a/src/ipc/ipc_client.ts b/src/ipc/ipc_client.ts index 542628d..46ee80b 100644 --- a/src/ipc/ipc_client.ts +++ b/src/ipc/ipc_client.ts @@ -25,6 +25,7 @@ import type { LanguageModel, CreateCustomLanguageModelProviderParams, CreateCustomLanguageModelParams, + DoesReleaseNoteExistParams, } from "./ipc_types"; import type { ProposalResult } from "@/lib/schemas"; import { showError } from "@/lib/toast"; @@ -736,6 +737,12 @@ export class IpcClient { return this.ipcRenderer.invoke("get-system-platform"); } + public async doesReleaseNoteExist( + params: DoesReleaseNoteExistParams, + ): Promise<{ exists: boolean; url?: string }> { + return this.ipcRenderer.invoke("does-release-note-exist", params); + } + public async getLanguageModelProviders(): Promise { return this.ipcRenderer.invoke("get-language-model-providers"); } diff --git a/src/ipc/ipc_host.ts b/src/ipc/ipc_host.ts index 03cf4a0..68c617e 100644 --- a/src/ipc/ipc_host.ts +++ b/src/ipc/ipc_host.ts @@ -15,6 +15,7 @@ import { registerWindowHandlers } from "./handlers/window_handlers"; import { registerUploadHandlers } from "./handlers/upload_handlers"; import { registerVersionHandlers } from "./handlers/version_handlers"; import { registerLanguageModelHandlers } from "./handlers/language_model_handlers"; +import { registerReleaseNoteHandlers } from "./handlers/release_note_handlers"; export function registerIpcHandlers() { // Register all IPC handlers by category @@ -35,4 +36,5 @@ export function registerIpcHandlers() { registerUploadHandlers(); registerVersionHandlers(); registerLanguageModelHandlers(); + registerReleaseNoteHandlers(); } diff --git a/src/ipc/ipc_types.ts b/src/ipc/ipc_types.ts index be33de1..74b50b0 100644 --- a/src/ipc/ipc_types.ts +++ b/src/ipc/ipc_types.ts @@ -181,3 +181,7 @@ export interface CreateCustomLanguageModelParams { maxOutputTokens?: number; contextWindow?: number; } + +export interface DoesReleaseNoteExistParams { + version: string; +} diff --git a/src/pages/home.tsx b/src/pages/home.tsx index 5127614..84318dd 100644 --- a/src/pages/home.tsx +++ b/src/pages/home.tsx @@ -58,17 +58,25 @@ export default function HomePage() { lastShownReleaseNotesVersion: appVersion, }); - // Check if release notes exist for this version - const url = `https://www.dyad.sh/docs/releases/${appVersion}`; - const exists = await checkPageExists(url); - if (exists) { - setReleaseUrl(url + "?hideHeader=true&theme=" + theme); - setReleaseNotesOpen(true); + try { + const result = await IpcClient.getInstance().doesReleaseNoteExist({ + version: appVersion, + }); + + if (result.exists && result.url) { + setReleaseUrl(result.url + "?hideHeader=true&theme=" + theme); + setReleaseNotesOpen(true); + } + } catch (err) { + console.warn( + "Unable to check if release note exists for: " + appVersion, + err, + ); } } }; updateLastVersionLaunched(); - }, [appVersion, settings, updateSettings]); + }, [appVersion, settings, updateSettings, theme]); // Get the appId from search params const appId = search.appId ? Number(search.appId) : null; @@ -251,15 +259,3 @@ export default function HomePage() { ); } - -function checkPageExists(url: string) { - return fetch(url, { mode: "no-cors" }) - .then(() => { - // Promise resolved - resource likely exists - return true; - }) - .catch(() => { - // Promise rejected - resource likely doesn't exist or network error - return false; - }); -} diff --git a/src/preload.ts b/src/preload.ts index 3e1d47a..ff7b2db 100644 --- a/src/preload.ts +++ b/src/preload.ts @@ -68,6 +68,7 @@ const validInvokeChannels = [ "delete-chat", "delete-messages", "start-chat-stream", + "does-release-note-exist", ] as const; // Add valid receive channels