fix(server): update version check (#14784)

fix #14780


#### PR Dependency Tree


* **PR #14784** 👈

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

## Release Notes

* **Bug Fixes**
* Improved upgrade availability detection to properly compare semantic
versions, including support for prerelease and canary versions. The
system now accurately identifies when new versions are available,
ensuring users receive timely update notifications.

* **Tests**
* Added comprehensive unit tests for version comparison and upgrade
detection functionality.

<!-- end of auto-generated comment: release notes by coderabbit.ai -->
This commit is contained in:
DarkSky
2026-04-05 10:56:05 +08:00
committed by GitHub
parent d975bf46fb
commit ffc27af3ba
5 changed files with 44 additions and 10 deletions
+2 -2
View File
@@ -101,7 +101,7 @@
"react-dom": "19.2.1",
"reflect-metadata": "^0.2.2",
"rxjs": "^7.8.2",
"semver": "^7.7.3",
"semver": "^7.7.4",
"socket.io": "^4.8.1",
"stripe": "^17.7.0",
"tldts": "^7.0.19",
@@ -128,7 +128,7 @@
"@types/nodemailer": "^7.0.0",
"@types/on-headers": "^1.0.3",
"@types/react": "^19.0.1",
"@types/semver": "^7.5.8",
"@types/semver": "^7.7.1",
"@types/sinon": "^21.0.0",
"@types/supertest": "^7.0.0",
"ava": "^7.0.0",
@@ -6,6 +6,7 @@ import { AppModule } from '../app.module';
import {
CANARY_CLIENT_VERSION_MAX_AGE_DAYS,
ConfigFactory,
hasNewerVersion,
UseNamedGuard,
} from '../base';
import { Public } from '../core/auth/guard';
@@ -249,3 +250,11 @@ test('should reject old canary date version in canary namespace', async t => {
env.NAMESPACE = prevNamespace;
}
});
test('should compare release versions for available upgrades', t => {
t.false(hasNewerVersion('0.26.5', '0.26.4'));
t.false(hasNewerVersion('0.26.5', '0.26.5'));
t.true(hasNewerVersion('0.26.5', '0.26.6'));
t.true(hasNewerVersion('0.26.5', '0.26.6-beta.1'));
t.false(hasNewerVersion('0.26.6-beta.2', '0.26.6-beta.1'));
});
@@ -1,3 +1,5 @@
import semver from 'semver';
const DAY_MS = 24 * 60 * 60 * 1000;
// Example: 2026.2.6-canary.015
@@ -89,3 +91,26 @@ export function checkCanaryDateClientVersion(
normalized: parsed.normalized,
};
}
function normalizeComparableVersion(version: string): string | null {
const canary = parseCanaryDateClientVersion(version);
return semver.valid(canary?.normalized ?? version.trim(), {
loose: true,
});
}
export function hasNewerVersion(
currentVersion: string,
nextVersion: string
): boolean {
const current = normalizeComparableVersion(currentVersion);
const next = normalizeComparableVersion(nextVersion);
if (!current || !next) {
return currentVersion.trim() !== nextVersion.trim();
}
return semver.gt(next, current, {
loose: true,
});
}
@@ -12,7 +12,7 @@ import {
} from '@nestjs/graphql';
import { GraphQLJSON, GraphQLJSONObject } from 'graphql-scalars';
import { Config, URLHelper } from '../../base';
import { Config, hasNewerVersion, URLHelper } from '../../base';
import { Namespace } from '../../env';
import { Feature, type WorkspaceFeatureName } from '../../models';
import { CurrentUser, Public } from '../auth';
@@ -143,7 +143,7 @@ export class ServerConfigResolver {
}>;
const latest = releases.at(0);
if (!latest || latest.name === env.version) {
if (!latest || !hasNewerVersion(env.version, latest.name)) {
return null;
}
+6 -6
View File
@@ -977,7 +977,7 @@ __metadata:
"@types/nodemailer": "npm:^7.0.0"
"@types/on-headers": "npm:^1.0.3"
"@types/react": "npm:^19.0.1"
"@types/semver": "npm:^7.5.8"
"@types/semver": "npm:^7.7.1"
"@types/sinon": "npm:^21.0.0"
"@types/supertest": "npm:^7.0.0"
ava: "npm:^7.0.0"
@@ -1019,7 +1019,7 @@ __metadata:
react-email: "npm:^4.3.2"
reflect-metadata: "npm:^0.2.2"
rxjs: "npm:^7.8.2"
semver: "npm:^7.7.3"
semver: "npm:^7.7.4"
sinon: "npm:^21.0.1"
socket.io: "npm:^4.8.1"
socket.io-client: "npm:^4.8.3"
@@ -16451,10 +16451,10 @@ __metadata:
languageName: node
linkType: hard
"@types/semver@npm:^7, @types/semver@npm:^7.5.8":
version: 7.7.0
resolution: "@types/semver@npm:7.7.0"
checksum: 10/ee4514c6c852b1c38f951239db02f9edeea39f5310fad9396a00b51efa2a2d96b3dfca1ae84c88181ea5b7157c57d32d7ef94edacee36fbf975546396b85ba5b
"@types/semver@npm:^7, @types/semver@npm:^7.7.1":
version: 7.7.1
resolution: "@types/semver@npm:7.7.1"
checksum: 10/8f09e7e6ca3ded67d78ba7a8f7535c8d9cf8ced83c52e7f3ac3c281fe8c689c3fe475d199d94390dc04fc681d51f2358b430bb7b2e21c62de24f2bee2c719068
languageName: node
linkType: hard