fix(core): version guard (#15226)

fix #15225



#### PR Dependency Tree


* **PR #15226** 👈

This tree was auto-generated by
[Charcoal](https://github.com/danerwilliams/charcoal)

<!-- This is an auto-generated comment: release notes by coderabbit.ai
-->

## Summary by CodeRabbit

* **Bug Fixes**
  * Improved self-hosted server version validation.
  * Correctly supports compatible beta and release-candidate versions.
  * Rejects outdated pre-release versions consistently.
* Provides the appropriate unsupported-version guidance when
compatibility requirements are not met.

<!-- end of auto-generated comment: release notes by coderabbit.ai -->
This commit is contained in:
DarkSky
2026-07-13 19:04:12 +08:00
committed by GitHub
parent 0c16d7110d
commit cfd1b67d8c
3 changed files with 23 additions and 15 deletions
@@ -1,9 +1,11 @@
import type { Server } from '@affine/core/modules/cloud';
import { MIN_SUPPORTED_SERVER_VERSION } from '@affine/core/modules/cloud/stores/server-config';
import {
isSupportedServerVersion,
MIN_SUPPORTED_SERVER_VERSION,
} from '@affine/core/modules/cloud/stores/server-config';
import { useI18n } from '@affine/i18n';
import { useLiveData } from '@toeverything/infra';
import { cssVarV2 } from '@toeverything/theme/v2';
import semver from 'semver';
const rules = [
{
@@ -46,7 +48,7 @@ export const useSelfhostLoginVersionGuard = (server: Server) => {
useLiveData(server.config$.selector(c => c.version)) ?? '0.0.0';
for (const rule of rules) {
if (semver.lt(serverVersion, rule.min)) {
if (!isSupportedServerVersion(serverVersion)) {
return rule.tip(
t['error.UNSUPPORTED_SERVER_VERSION']({
requiredVersion: `>=${rule.min}`,
@@ -9,13 +9,17 @@ import {
describe('server config version guard', () => {
test('accepts supported server versions', () => {
expect(() => assertSupportedServerVersion('0.27.0')).not.toThrow();
expect(() => assertSupportedServerVersion('0.27.0-beta.5')).not.toThrow();
expect(() => assertSupportedServerVersion('0.27.0-rc.1')).not.toThrow();
expect(() => assertSupportedServerVersion('0.28.0')).not.toThrow();
});
test('rejects old server versions', () => {
expect(() => assertSupportedServerVersion('0.26.9')).toThrow(
UserFriendlyError
);
for (const version of ['0.26.9', '0.26.9-beta.5']) {
expect(() => assertSupportedServerVersion(version)).toThrow(
UserFriendlyError
);
}
});
test('rejects missing or invalid server versions', () => {
@@ -47,16 +47,18 @@ export function createUnsupportedServerVersionError(version?: string | null) {
});
}
export function assertSupportedServerVersion(version?: string | null) {
if (!version) {
throw createUnsupportedServerVersionError(version);
}
export function isSupportedServerVersion(version?: string | null) {
const normalized = version && semver.valid(version, { loose: true });
return (
!!normalized &&
semver.gte(normalized, `${MIN_SUPPORTED_SERVER_VERSION}-0`, {
loose: true,
})
);
}
const normalized = semver.valid(version, { loose: true });
if (
!normalized ||
semver.lt(normalized, MIN_SUPPORTED_SERVER_VERSION, { loose: true })
) {
export function assertSupportedServerVersion(version?: string | null) {
if (!isSupportedServerVersion(version)) {
throw createUnsupportedServerVersionError(version);
}
}