chore: cleanup images (#14380)

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

## Summary by CodeRabbit

* **New Features**
* Added canary build version support with automatic validation and
age-based restrictions for testing pre-release versions.

* **Chores**
* Enhanced Docker build process with multi-stage builds, image
optimization, and memory allocation improvements.
  * Reorganized dependencies to distinguish development-only packages.

<!-- end of auto-generated comment: release notes by coderabbit.ai -->
This commit is contained in:
DarkSky
2026-02-06 19:49:02 +08:00
committed by GitHub
parent 8c15df489b
commit a0cf5681c4
12 changed files with 793 additions and 8 deletions
@@ -14,6 +14,7 @@ import {
AccessDenied,
AuthenticationRequired,
Cache,
checkCanaryDateClientVersion,
Config,
CryptoHelper,
getClientVersionFromRequest,
@@ -35,6 +36,7 @@ export class AuthGuard implements CanActivate, OnModuleInit {
private auth!: AuthService;
private readonly cachedVersionRange = new Map<string, semver.Range | null>();
private static readonly HARD_REQUIRED_VERSION = '>=0.25.0';
private static readonly CANARY_REQUIRED_VERSION = 'canary (within 2 months)';
constructor(
private readonly crypto: CryptoHelper,
@@ -218,6 +220,15 @@ export class AuthGuard implements CanActivate, OnModuleInit {
): { ok: true } | { ok: false; requiredVersion: string } {
const requiredVersion = this.config.client.versionControl.requiredVersion;
if (clientVersion && env.namespaces.canary) {
const canaryCheck = checkCanaryDateClientVersion(clientVersion);
if (canaryCheck.matched) {
return canaryCheck.allowed
? { ok: true }
: { ok: false, requiredVersion: AuthGuard.CANARY_REQUIRED_VERSION };
}
}
const configRange = this.getVersionRange(requiredVersion);
if (
configRange &&
@@ -14,6 +14,7 @@ import { type Server, Socket } from 'socket.io';
import {
CallMetric,
checkCanaryDateClientVersion,
DocNotFound,
DocUpdateBlocked,
EventBus,
@@ -71,14 +72,33 @@ const DOC_UPDATES_PROTOCOL_026 = new semver.Range('>=0.26.0-0', {
type SyncProtocolRoomType = Extract<RoomType, 'sync-025' | 'sync-026'>;
function normalizeWsClientVersion(clientVersion: string): string | null {
if (env.namespaces.canary) {
const canaryCheck = checkCanaryDateClientVersion(clientVersion);
if (canaryCheck.matched) {
return canaryCheck.allowed ? canaryCheck.normalized : null;
}
}
return clientVersion;
}
function isSupportedWsClientVersion(clientVersion: string): boolean {
const normalized = normalizeWsClientVersion(clientVersion);
if (!normalized) {
return false;
}
return Boolean(
semver.valid(clientVersion) && MIN_WS_CLIENT_VERSION.test(clientVersion)
semver.valid(normalized) && MIN_WS_CLIENT_VERSION.test(normalized)
);
}
function getSyncProtocolRoomType(clientVersion: string): SyncProtocolRoomType {
return DOC_UPDATES_PROTOCOL_026.test(clientVersion) ? 'sync-026' : 'sync-025';
const normalized = normalizeWsClientVersion(clientVersion);
return DOC_UPDATES_PROTOCOL_026.test(normalized ?? clientVersion)
? 'sync-026'
: 'sync-025';
}
enum SpaceType {
@@ -1,18 +1,37 @@
import { Injectable, Logger } from '@nestjs/common';
import semver from 'semver';
import { Config, UnsupportedClientVersion } from '../../base';
import {
checkCanaryDateClientVersion,
Config,
UnsupportedClientVersion,
} from '../../base';
@Injectable()
export class VersionService {
private readonly logger = new Logger(VersionService.name);
private static readonly HARD_REQUIRED_VERSION = '>=0.25.0';
private static readonly CANARY_REQUIRED_VERSION = 'canary (within 2 months)';
constructor(private readonly config: Config) {}
async checkVersion(clientVersion?: string) {
const requiredVersion = this.config.client.versionControl.requiredVersion;
if (clientVersion && env.namespaces.canary) {
const canaryCheck = checkCanaryDateClientVersion(clientVersion);
if (canaryCheck.matched) {
if (canaryCheck.allowed) {
return true;
}
throw new UnsupportedClientVersion({
clientVersion,
requiredVersion: VersionService.CANARY_REQUIRED_VERSION,
});
}
}
const hardRange = await this.getVersionRange(
VersionService.HARD_REQUIRED_VERSION
);