From 7181682724d53af47e260e7b064c3aa4135e5c11 Mon Sep 17 00:00:00 2001 From: Alumos <1281610535@qq.com> Date: Wed, 11 Nov 2026 13:16:32 +0800 Subject: [PATCH] fix(updates): accept fork revision releases on the update page The update page validated release metadata against the upstream repository URL and plain X.Y.Z versions, so this fork's X.Y.Z-revised.N releases from Alumos/SubLane failed client validation and showed a request error. Accept the fork's stable version format and release URL, and treat revision builds as stable builds. Co-Authored-By: Claude Opus 5.5 --- web/src/lib/updates.ts | 9 +++++---- web/src/pages/Updates.test.tsx | 25 ++++++++++++++++++++++++- web/src/pages/Updates.tsx | 3 ++- 3 files changed, 31 insertions(+), 6 deletions(-) diff --git a/web/src/lib/updates.ts b/web/src/lib/updates.ts index 13fe41a7..9404e726 100644 --- a/web/src/lib/updates.ts +++ b/web/src/lib/updates.ts @@ -3,16 +3,17 @@ import { z } from 'zod' import { authKey, type AuthState } from './auth' import { ApiError, request } from './request' -const version = z - .string() - .regex(/^(0|[1-9][0-9]{0,5})\.(0|[1-9][0-9]{0,5})\.(0|[1-9][0-9]{0,5})$/) +// Stable fork releases are X.Y.Z or X.Y.Z-revised.N, matching the server's update channel. +export const stableVersion = + /^(0|[1-9][0-9]{0,5})\.(0|[1-9][0-9]{0,5})\.(0|[1-9][0-9]{0,5})(-revised\.[1-9][0-9]{0,5})?$/ +const version = z.string().regex(stableVersion) const schema = z.object({ current_version: z.string().max(64), latest_version: z.union([z.literal(''), version]), release_url: z .string() .regex( - /^(|https:\/\/github\.com\/murongg\/SubLane\/releases\/tag\/v[0-9.]+)$/, + /^(|https:\/\/github\.com\/Alumos\/SubLane\/releases\/tag\/v[0-9.]+(-revised\.[0-9]+)?)$/, ), checked_at: z.number().int().nonnegative(), check_failed: z.boolean(), diff --git a/web/src/pages/Updates.test.tsx b/web/src/pages/Updates.test.tsx index 5c402514..38b857fe 100644 --- a/web/src/pages/Updates.test.tsx +++ b/web/src/pages/Updates.test.tsx @@ -10,7 +10,7 @@ import { Updates } from './Updates' const state = { current_version: '1.2.0', latest_version: '1.3.0', - release_url: 'https://github.com/murongg/SubLane/releases/tag/v1.3.0', + release_url: 'https://github.com/Alumos/SubLane/releases/tag/v1.3.0', checked_at: 1900000000, check_failed: false, available: true, @@ -162,3 +162,26 @@ it.each([ ).toBeNull() }, ) + +it('accepts fork revision releases from this repository', async () => { + vi.stubGlobal( + 'fetch', + vi.fn(() => + Promise.resolve( + response({ + ...state, + current_version: '0.19.2-revised.8', + latest_version: '0.19.2-revised.9', + release_url: + 'https://github.com/Alumos/SubLane/releases/tag/v0.19.2-revised.9', + }), + ), + ), + ) + mount() + // A revision build is a stable build: the page offers the newer revision instead of failing. + expect( + await screen.findByRole('button', { name: /0\.19\.2-revised\.9/ }), + ).toBeTruthy() + expect(screen.queryByText(/could not confirm/i)).toBeNull() +}) diff --git a/web/src/pages/Updates.tsx b/web/src/pages/Updates.tsx index c959e7b0..86b814b5 100644 --- a/web/src/pages/Updates.tsx +++ b/web/src/pages/Updates.tsx @@ -6,6 +6,7 @@ import { authOptions } from '@/lib/auth' import { checkUpdate, installUpdate, + stableVersion, updateError, updatePending, updatesOptions, @@ -58,7 +59,7 @@ function UpdateSettings({ userID }: { userID: number }) { const value = query.data const busy = value ? updatePending(value) : false const error = check.error ?? install.error - const stableBuild = value && /^\d+\.\d+\.\d+$/.test(value.current_version) + const stableBuild = value && stableVersion.test(value.current_version) const result = value?.job const status = result?.status === 'succeeded' && result.version !== value?.current_version