From 930dc5c018ec1ca364118b74c00510abbbe45f18 Mon Sep 17 00:00:00 2001 From: Anthony Stirling Date: Tue, 26 May 2026 19:44:10 +0100 Subject: [PATCH] Use universal Mac installer + centralized installer URLs --- .../editor/src/core/constants/downloads.ts | 22 ++++-- .../src/core/services/updateService.test.ts | 76 +++++++++++++++++++ .../editor/src/core/services/updateService.ts | 21 ++--- 3 files changed, 103 insertions(+), 16 deletions(-) create mode 100644 frontend/editor/src/core/services/updateService.test.ts diff --git a/frontend/editor/src/core/constants/downloads.ts b/frontend/editor/src/core/constants/downloads.ts index cb5d2f21ba..686997b82c 100644 --- a/frontend/editor/src/core/constants/downloads.ts +++ b/frontend/editor/src/core/constants/downloads.ts @@ -1,8 +1,18 @@ -// Centralized download URLs for Stirling PDF desktop installers -export const DOWNLOAD_URLS = { - WINDOWS: "https://files.stirlingpdf.com/win-installer.exe", - MAC: "https://files.stirlingpdf.com/mac-installer.dmg", - LINUX_DOCS: "https://docs.stirlingpdf.com/Installation/Unix%20Installation/", +// Centralized download URLs for Stirling PDF desktop installers. +// File names match the GitHub release artifacts so files.stirlingpdf.com can +// alias them 1:1. +export const DOWNLOAD_BASE_URL = "https://files.stirlingpdf.com/"; + +export const DESKTOP_INSTALLER_FILES = { + // Universal Mac binary - works on both Intel and Apple silicon, so no arch + // detection is needed on the client. + MAC: "Stirling-PDF-macos-universal.dmg", + WINDOWS: "Stirling-PDF-windows-x86_64.msi", + LINUX_DEB: "Stirling-PDF-linux-x86_64.deb", } as const; -export const DOWNLOAD_BASE_URL = "https://files.stirlingpdf.com/"; +export const DOWNLOAD_URLS = { + WINDOWS: DOWNLOAD_BASE_URL + DESKTOP_INSTALLER_FILES.WINDOWS, + MAC: DOWNLOAD_BASE_URL + DESKTOP_INSTALLER_FILES.MAC, + LINUX_DOCS: "https://docs.stirlingpdf.com/Installation/Unix%20Installation/", +} as const; diff --git a/frontend/editor/src/core/services/updateService.test.ts b/frontend/editor/src/core/services/updateService.test.ts new file mode 100644 index 0000000000..cccaea2d3c --- /dev/null +++ b/frontend/editor/src/core/services/updateService.test.ts @@ -0,0 +1,76 @@ +import { afterEach, beforeEach, describe, expect, it, vi } from "vitest"; +import { updateService } from "@app/services/updateService"; +import { DOWNLOAD_URLS } from "@app/constants/downloads"; + +type MachineInfo = Parameters[0]; + +const stubMachineInfo: MachineInfo = { + machineType: "Server-jar", + activeSecurity: false, + licenseType: "FREE", +}; + +const setUserAgent = (value: string) => { + Object.defineProperty(window.navigator, "userAgent", { + value, + configurable: true, + }); +}; + +describe("updateService.getDownloadUrl (desktop)", () => { + const original = window.navigator.userAgent; + + beforeEach(() => { + vi.restoreAllMocks(); + }); + + afterEach(() => { + setUserAgent(original); + }); + + it("returns the universal Mac installer for Apple-silicon Macs", () => { + setUserAgent( + "Mozilla/5.0 (Macintosh; ARM Mac OS X 14_0) AppleWebKit/605.1.15", + ); + expect(updateService.getDownloadUrl(stubMachineInfo, true)).toBe( + DOWNLOAD_URLS.MAC, + ); + }); + + it("returns the universal Mac installer for Intel Macs", () => { + setUserAgent( + "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/605.1.15", + ); + expect(updateService.getDownloadUrl(stubMachineInfo, true)).toBe( + DOWNLOAD_URLS.MAC, + ); + }); + + it("returns the universal Mac URL even when the UA misreports Apple-silicon as Intel", () => { + setUserAgent("Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7)"); + const url = updateService.getDownloadUrl(stubMachineInfo, true); + expect(url).toBe(DOWNLOAD_URLS.MAC); + expect(url).toContain("Stirling-PDF-macos-universal.dmg"); + }); + + it("returns the Windows installer for Windows UAs", () => { + setUserAgent("Mozilla/5.0 (Windows NT 10.0; Win64; x64)"); + expect(updateService.getDownloadUrl(stubMachineInfo, true)).toBe( + DOWNLOAD_URLS.WINDOWS, + ); + }); + + it("returns a .deb URL for Linux UAs", () => { + setUserAgent("Mozilla/5.0 (X11; Linux x86_64)"); + expect(updateService.getDownloadUrl(stubMachineInfo, true)).toContain( + "Stirling-PDF-linux-x86_64.deb", + ); + }); + + it("falls back to the GitHub releases page for unknown platforms", () => { + setUserAgent("Mozilla/5.0 (Unknown OS)"); + expect(updateService.getDownloadUrl(stubMachineInfo, true)).toBe( + "https://github.com/Stirling-Tools/Stirling-PDF/releases/latest", + ); + }); +}); diff --git a/frontend/editor/src/core/services/updateService.ts b/frontend/editor/src/core/services/updateService.ts index d2b199f9b7..2cc1992800 100644 --- a/frontend/editor/src/core/services/updateService.ts +++ b/frontend/editor/src/core/services/updateService.ts @@ -1,4 +1,8 @@ -import { DOWNLOAD_BASE_URL } from "@app/constants/downloads"; +import { + DESKTOP_INSTALLER_FILES, + DOWNLOAD_BASE_URL, + DOWNLOAD_URLS, +} from "@app/constants/downloads"; export interface UpdateSummary { latest_version: string | null; @@ -76,17 +80,14 @@ export class UpdateService { if (isDesktop) { const userAgent = navigator.userAgent.toLowerCase(); if (userAgent.includes("win")) { - return DOWNLOAD_BASE_URL + "win-installer.exe"; + return DOWNLOAD_URLS.WINDOWS; } else if (userAgent.includes("mac")) { - const isARM = - userAgent.includes("arm") || userAgent.includes("aarch64"); - if (isARM) { - return DOWNLOAD_BASE_URL + "mac-installer.dmg"; - } else { - return DOWNLOAD_BASE_URL + "mac-x86_64-installer.dmg"; - } + // Universal Mac binary covers both Intel and Apple silicon, so we + // don't need to detect arch (which is unreliable on the web anyway - + // Apple-silicon Macs often report Intel in the UA). + return DOWNLOAD_URLS.MAC; } else if (userAgent.includes("linux")) { - return DOWNLOAD_BASE_URL + "linux-x86_64.deb"; + return DOWNLOAD_BASE_URL + DESKTOP_INSTALLER_FILES.LINUX_DEB; } return "https://github.com/Stirling-Tools/Stirling-PDF/releases/latest"; }