feat: signal server tag
This commit is contained in:
@@ -0,0 +1,39 @@
|
||||
import { firstValueFrom, of } from 'rxjs';
|
||||
import {
|
||||
describe,
|
||||
expect,
|
||||
it
|
||||
} from 'vitest';
|
||||
|
||||
import { UsersActions } from '../../../../store/users/users.actions';
|
||||
import { waitForAuthenticationOutcome } from './auth-navigation.rules';
|
||||
|
||||
describe('waitForAuthenticationOutcome', () => {
|
||||
it('resolves when authentication storage preparation succeeds', async () => {
|
||||
const user = {
|
||||
id: 'user-1',
|
||||
oderId: 'user-1',
|
||||
username: 'alice',
|
||||
displayName: 'Alice',
|
||||
status: 'online' as const,
|
||||
role: 'member' as const,
|
||||
joinedAt: 1
|
||||
};
|
||||
const outcome = await firstValueFrom(waitForAuthenticationOutcome(of(
|
||||
UsersActions.setCurrentUser({ user })
|
||||
)));
|
||||
|
||||
expect(outcome).toEqual({ kind: 'success', user });
|
||||
});
|
||||
|
||||
it('resolves with a failure when authentication storage preparation fails', async () => {
|
||||
const outcome = await firstValueFrom(waitForAuthenticationOutcome(of(
|
||||
UsersActions.loadCurrentUserFailure({ error: 'Failed to prepare local user state.' })
|
||||
)));
|
||||
|
||||
expect(outcome).toEqual({
|
||||
kind: 'failure',
|
||||
error: 'Failed to prepare local user state.'
|
||||
});
|
||||
});
|
||||
});
|
||||
@@ -0,0 +1,45 @@
|
||||
import {
|
||||
filter,
|
||||
map,
|
||||
Observable,
|
||||
take
|
||||
} from 'rxjs';
|
||||
|
||||
import { UsersActions } from '../../../../store/users/users.actions';
|
||||
import type { User } from '../../../../shared-kernel';
|
||||
|
||||
export type AuthenticationOutcome =
|
||||
| { kind: 'success'; user: User }
|
||||
| { kind: 'failure'; error: string };
|
||||
|
||||
export function waitForAuthenticationOutcome(
|
||||
actions$: Observable<{ type: string; user?: User; error?: string }>
|
||||
): Observable<AuthenticationOutcome> {
|
||||
return actions$.pipe(
|
||||
filter((action) =>
|
||||
action.type === UsersActions.setCurrentUser.type
|
||||
|| action.type === UsersActions.loadCurrentUserFailure.type
|
||||
),
|
||||
take(1),
|
||||
map((action) => {
|
||||
if (action.type === UsersActions.loadCurrentUserFailure.type) {
|
||||
return {
|
||||
kind: 'failure' as const,
|
||||
error: action.error || 'Authentication failed'
|
||||
};
|
||||
}
|
||||
|
||||
if (!action.user) {
|
||||
return {
|
||||
kind: 'failure' as const,
|
||||
error: 'Authentication failed'
|
||||
};
|
||||
}
|
||||
|
||||
return {
|
||||
kind: 'success' as const,
|
||||
user: action.user
|
||||
};
|
||||
})
|
||||
);
|
||||
}
|
||||
@@ -7,12 +7,15 @@ import {
|
||||
import { CommonModule } from '@angular/common';
|
||||
import { FormsModule } from '@angular/forms';
|
||||
import { ActivatedRoute, Router } from '@angular/router';
|
||||
import { Actions } from '@ngrx/effects';
|
||||
import { Store } from '@ngrx/store';
|
||||
import { NgIcon, provideIcons } from '@ng-icons/core';
|
||||
import { lucideLogIn } from '@ng-icons/lucide';
|
||||
import { firstValueFrom } from 'rxjs';
|
||||
|
||||
import { AuthenticationService } from '../../application/services/authentication.service';
|
||||
import { ServerDirectoryFacade } from '../../../server-directory';
|
||||
import { waitForAuthenticationOutcome } from '../../domain/logic/auth-navigation.rules';
|
||||
import { UsersActions } from '../../../../store/users/users.actions';
|
||||
import { User } from '../../../../shared-kernel';
|
||||
|
||||
@@ -40,6 +43,7 @@ export class LoginComponent {
|
||||
error = signal<string | null>(null);
|
||||
|
||||
private auth = inject(AuthenticationService);
|
||||
private actions$ = inject(Actions);
|
||||
private store = inject(Store);
|
||||
private route = inject(ActivatedRoute);
|
||||
private router = inject(Router);
|
||||
@@ -55,10 +59,12 @@ export class LoginComponent {
|
||||
this.auth.login({ username: this.username.trim(),
|
||||
password: this.password,
|
||||
serverId: sid }).subscribe({
|
||||
next: (resp) => {
|
||||
next: async (resp) => {
|
||||
if (sid)
|
||||
this.serversSvc.setActiveServer(sid);
|
||||
|
||||
const homeSignalServerUrl = this.serversSvc.servers().find((server) => server.id === sid)?.url
|
||||
?? this.serversSvc.activeServer()?.url;
|
||||
const user: User = {
|
||||
id: resp.id,
|
||||
oderId: resp.id,
|
||||
@@ -66,19 +72,27 @@ export class LoginComponent {
|
||||
displayName: resp.displayName,
|
||||
status: 'online',
|
||||
role: 'member',
|
||||
joinedAt: Date.now()
|
||||
joinedAt: Date.now(),
|
||||
homeSignalServerUrl
|
||||
};
|
||||
|
||||
this.store.dispatch(UsersActions.authenticateUser({ user }));
|
||||
const returnUrl = this.route.snapshot.queryParamMap.get('returnUrl')?.trim();
|
||||
|
||||
if (returnUrl?.startsWith('/')) {
|
||||
this.router.navigateByUrl(returnUrl);
|
||||
const outcome = await firstValueFrom(waitForAuthenticationOutcome(this.actions$));
|
||||
|
||||
if (outcome.kind === 'failure') {
|
||||
this.error.set(outcome.error);
|
||||
return;
|
||||
}
|
||||
|
||||
this.router.navigate(['/dashboard']);
|
||||
const returnUrl = this.route.snapshot.queryParamMap.get('returnUrl')?.trim();
|
||||
|
||||
if (returnUrl?.startsWith('/')) {
|
||||
await this.router.navigateByUrl(returnUrl);
|
||||
return;
|
||||
}
|
||||
|
||||
await this.router.navigate(['/dashboard']);
|
||||
},
|
||||
error: (err) => {
|
||||
this.error.set(err?.error?.error || 'Login failed');
|
||||
|
||||
@@ -7,12 +7,15 @@ import {
|
||||
import { CommonModule } from '@angular/common';
|
||||
import { FormsModule } from '@angular/forms';
|
||||
import { ActivatedRoute, Router } from '@angular/router';
|
||||
import { Actions } from '@ngrx/effects';
|
||||
import { Store } from '@ngrx/store';
|
||||
import { NgIcon, provideIcons } from '@ng-icons/core';
|
||||
import { lucideUserPlus } from '@ng-icons/lucide';
|
||||
import { firstValueFrom } from 'rxjs';
|
||||
|
||||
import { AuthenticationService } from '../../application/services/authentication.service';
|
||||
import { ServerDirectoryFacade } from '../../../server-directory';
|
||||
import { waitForAuthenticationOutcome } from '../../domain/logic/auth-navigation.rules';
|
||||
import { UsersActions } from '../../../../store/users/users.actions';
|
||||
import { User } from '../../../../shared-kernel';
|
||||
|
||||
@@ -41,6 +44,7 @@ export class RegisterComponent {
|
||||
error = signal<string | null>(null);
|
||||
|
||||
private auth = inject(AuthenticationService);
|
||||
private actions$ = inject(Actions);
|
||||
private store = inject(Store);
|
||||
private route = inject(ActivatedRoute);
|
||||
private router = inject(Router);
|
||||
@@ -57,10 +61,12 @@ export class RegisterComponent {
|
||||
password: this.password,
|
||||
displayName: this.displayName.trim(),
|
||||
serverId: sid }).subscribe({
|
||||
next: (resp) => {
|
||||
next: async (resp) => {
|
||||
if (sid)
|
||||
this.serversSvc.setActiveServer(sid);
|
||||
|
||||
const homeSignalServerUrl = this.serversSvc.servers().find((server) => server.id === sid)?.url
|
||||
?? this.serversSvc.activeServer()?.url;
|
||||
const user: User = {
|
||||
id: resp.id,
|
||||
oderId: resp.id,
|
||||
@@ -68,19 +74,27 @@ export class RegisterComponent {
|
||||
displayName: resp.displayName,
|
||||
status: 'online',
|
||||
role: 'member',
|
||||
joinedAt: Date.now()
|
||||
joinedAt: Date.now(),
|
||||
homeSignalServerUrl
|
||||
};
|
||||
|
||||
this.store.dispatch(UsersActions.authenticateUser({ user }));
|
||||
const returnUrl = this.route.snapshot.queryParamMap.get('returnUrl')?.trim();
|
||||
|
||||
if (returnUrl?.startsWith('/')) {
|
||||
this.router.navigateByUrl(returnUrl);
|
||||
const outcome = await firstValueFrom(waitForAuthenticationOutcome(this.actions$));
|
||||
|
||||
if (outcome.kind === 'failure') {
|
||||
this.error.set(outcome.error);
|
||||
return;
|
||||
}
|
||||
|
||||
this.router.navigate(['/dashboard']);
|
||||
const returnUrl = this.route.snapshot.queryParamMap.get('returnUrl')?.trim();
|
||||
|
||||
if (returnUrl?.startsWith('/')) {
|
||||
await this.router.navigateByUrl(returnUrl);
|
||||
return;
|
||||
}
|
||||
|
||||
await this.router.navigate(['/dashboard']);
|
||||
},
|
||||
error: (err) => {
|
||||
this.error.set(err?.error?.error || 'Registration failed');
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -14,9 +14,7 @@
|
||||
|
||||
@if (refreshLoading()) {
|
||||
<div class="pointer-events-none sticky top-0 z-10 flex justify-center py-1">
|
||||
<div class="rounded-full border border-border bg-background/85 px-2.5 py-1 text-[11px] text-muted-foreground shadow-sm">
|
||||
Loading...
|
||||
</div>
|
||||
<div class="rounded-full border border-border bg-background/85 px-2.5 py-1 text-[11px] text-muted-foreground shadow-sm">Loading...</div>
|
||||
</div>
|
||||
}
|
||||
|
||||
|
||||
@@ -87,9 +87,12 @@
|
||||
<button
|
||||
type="button"
|
||||
(click)="selectGif(gif)"
|
||||
[class]="(isMobile()
|
||||
? 'group block w-full overflow-hidden rounded-xl border border-border/80 bg-secondary/10 text-left shadow-sm transition-transform duration-200 hover:-translate-y-0.5 hover:border-primary/50 hover:bg-secondary/30'
|
||||
: 'group mx-auto mb-4 inline-block w-full max-w-[15.5rem] break-inside-avoid align-top overflow-hidden rounded-2xl border border-border/80 bg-secondary/10 text-left shadow-sm transition-transform duration-200 hover:-translate-y-0.5 hover:border-primary/50 hover:bg-secondary/30') + ' [content-visibility:auto] [contain-intrinsic-size:auto_180px]'"
|
||||
[class]="
|
||||
(isMobile()
|
||||
? 'group block w-full overflow-hidden rounded-xl border border-border/80 bg-secondary/10 text-left shadow-sm transition-transform duration-200 hover:-translate-y-0.5 hover:border-primary/50 hover:bg-secondary/30'
|
||||
: 'group mx-auto mb-4 inline-block w-full max-w-[15.5rem] break-inside-avoid align-top overflow-hidden rounded-2xl border border-border/80 bg-secondary/10 text-left shadow-sm transition-transform duration-200 hover:-translate-y-0.5 hover:border-primary/50 hover:bg-secondary/30') +
|
||||
' [content-visibility:auto] [contain-intrinsic-size:auto_180px]'
|
||||
"
|
||||
>
|
||||
<div
|
||||
class="relative flex items-center justify-center overflow-hidden bg-secondary/30"
|
||||
|
||||
@@ -1,4 +1,3 @@
|
||||
|
||||
<div class="relative">
|
||||
@if (compact()) {
|
||||
<div class="flex gap-1 rounded-lg border border-border bg-card p-2 shadow-lg">
|
||||
@@ -70,7 +69,9 @@
|
||||
/>
|
||||
</label>
|
||||
|
||||
<label class="mb-3 flex cursor-pointer items-center justify-center gap-2 rounded-md border border-dashed border-border px-3 py-2 text-xs font-medium text-muted-foreground transition-colors hover:border-primary/50 hover:text-foreground">
|
||||
<label
|
||||
class="mb-3 flex cursor-pointer items-center justify-center gap-2 rounded-md border border-dashed border-border px-3 py-2 text-xs font-medium text-muted-foreground transition-colors hover:border-primary/50 hover:text-foreground"
|
||||
>
|
||||
<ng-icon
|
||||
name="lucideUpload"
|
||||
class="h-4 w-4"
|
||||
@@ -133,5 +134,4 @@
|
||||
}
|
||||
</div>
|
||||
}
|
||||
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -1,5 +1,8 @@
|
||||
@if (session()) {
|
||||
<app-modal-backdrop [zIndex]="120" [dismissable]="false" />
|
||||
<app-modal-backdrop
|
||||
[zIndex]="120"
|
||||
[dismissable]="false"
|
||||
/>
|
||||
|
||||
<div class="pointer-events-none fixed inset-0 z-[121] flex items-center justify-center p-4">
|
||||
<section
|
||||
|
||||
@@ -255,7 +255,9 @@
|
||||
@if (filteredPlugins().length > 0) {
|
||||
<div class="grid gap-3">
|
||||
@for (plugin of filteredPlugins(); track trackPlugin($index, plugin)) {
|
||||
<article class="grid min-w-0 overflow-hidden rounded-lg border border-border bg-background sm:grid-cols-[5.5rem_minmax(0,1fr)] [content-visibility:auto] [contain-intrinsic-size:auto_140px]">
|
||||
<article
|
||||
class="grid min-w-0 overflow-hidden rounded-lg border border-border bg-background sm:grid-cols-[5.5rem_minmax(0,1fr)] [content-visibility:auto] [contain-intrinsic-size:auto_140px]"
|
||||
>
|
||||
<div class="grid min-h-24 place-items-center bg-secondary text-muted-foreground sm:min-h-full">
|
||||
@if (plugin.imageUrl && !hasBrokenImage(plugin)) {
|
||||
<img
|
||||
|
||||
@@ -93,9 +93,10 @@ export class ServerDirectoryService {
|
||||
endpointId: string,
|
||||
status: ServerEndpoint['status'],
|
||||
latency?: number,
|
||||
versions?: ServerEndpointVersions
|
||||
versions?: ServerEndpointVersions,
|
||||
serverTag?: string
|
||||
): void {
|
||||
this.endpointState.updateServerStatus(endpointId, status, latency, versions);
|
||||
this.endpointState.updateServerStatus(endpointId, status, latency, versions, serverTag);
|
||||
}
|
||||
|
||||
async ensureEndpointVersionCompatibility(selector?: ServerSourceSelector): Promise<boolean> {
|
||||
@@ -212,7 +213,8 @@ export class ServerDirectoryService {
|
||||
endpointId,
|
||||
healthResult.status,
|
||||
healthResult.latency,
|
||||
healthResult.versions
|
||||
healthResult.versions,
|
||||
healthResult.serverTag
|
||||
);
|
||||
|
||||
return healthResult.status === 'online';
|
||||
|
||||
@@ -228,7 +228,8 @@ export class ServerEndpointStateService {
|
||||
endpointId: string,
|
||||
status: ServerEndpoint['status'],
|
||||
latency?: number,
|
||||
versions?: ServerEndpointVersions
|
||||
versions?: ServerEndpointVersions,
|
||||
serverTag?: string
|
||||
): void {
|
||||
this._servers.update((endpoints) => ensureCompatibleActiveEndpoint(endpoints.map((endpoint) => {
|
||||
if (endpoint.id !== endpointId) {
|
||||
@@ -240,6 +241,7 @@ export class ServerEndpointStateService {
|
||||
instanceId: versions?.serverInstanceId ?? endpoint.instanceId,
|
||||
status,
|
||||
latency,
|
||||
serverTag: serverTag ?? endpoint.serverTag,
|
||||
isActive: status === 'incompatible' && !endpoint.isDefault ? false : endpoint.isActive,
|
||||
serverVersion: versions?.serverVersion ?? endpoint.serverVersion,
|
||||
clientVersion: versions?.clientVersion ?? endpoint.clientVersion
|
||||
|
||||
@@ -0,0 +1,80 @@
|
||||
import { describe, expect, it } from 'vitest';
|
||||
import {
|
||||
isSignalServerTagUrl,
|
||||
presentSignalServerTag,
|
||||
resolveEndpointSignalServerTag,
|
||||
resolveUserHomeSignalServerTag
|
||||
} from './signal-server-tag.rules';
|
||||
import type { ServerEndpoint } from '../models/server-directory.model';
|
||||
|
||||
describe('signal-server-tag.rules', () => {
|
||||
const endpoints: ServerEndpoint[] = [
|
||||
{
|
||||
id: 'endpoint-1',
|
||||
name: 'Primary',
|
||||
url: 'http://signal.example.com:3001',
|
||||
isActive: true,
|
||||
isDefault: true,
|
||||
status: 'online',
|
||||
serverTag: 'EU'
|
||||
},
|
||||
{
|
||||
id: 'endpoint-2',
|
||||
name: 'Fallback',
|
||||
url: 'https://signal-backup.example.com',
|
||||
isActive: true,
|
||||
isDefault: false,
|
||||
status: 'online'
|
||||
}
|
||||
];
|
||||
|
||||
it('uses configured serverTag when present on an endpoint', () => {
|
||||
expect(resolveEndpointSignalServerTag(endpoints[0])).toBe('EU');
|
||||
});
|
||||
|
||||
it('falls back to endpoint url when serverTag is missing', () => {
|
||||
expect(resolveEndpointSignalServerTag(endpoints[1])).toBe('https://signal-backup.example.com');
|
||||
});
|
||||
|
||||
it('resolves a user home signal server tag from known endpoints', () => {
|
||||
expect(resolveUserHomeSignalServerTag('http://signal.example.com:3001/', endpoints)).toBe('EU');
|
||||
});
|
||||
|
||||
it('falls back to the home signal server url when the endpoint is unknown', () => {
|
||||
expect(resolveUserHomeSignalServerTag('http://unknown.example.com:3001', endpoints))
|
||||
.toBe('http://unknown.example.com:3001');
|
||||
});
|
||||
|
||||
it('returns undefined when the user has no home signal server url', () => {
|
||||
expect(resolveUserHomeSignalServerTag(undefined, endpoints)).toBeUndefined();
|
||||
});
|
||||
|
||||
it('detects http and https values as urls', () => {
|
||||
expect(isSignalServerTagUrl('http://signal.example.com:3001')).toBe(true);
|
||||
expect(isSignalServerTagUrl('https://signal.example.com')).toBe(true);
|
||||
expect(isSignalServerTagUrl('EU')).toBe(false);
|
||||
});
|
||||
|
||||
it('prefixes non-url tags with #', () => {
|
||||
expect(presentSignalServerTag('EU')).toEqual({
|
||||
kind: 'label',
|
||||
label: 'EU',
|
||||
display: '#EU'
|
||||
});
|
||||
});
|
||||
|
||||
it('strips an existing # before re-prefixing label tags', () => {
|
||||
expect(presentSignalServerTag('#sweden')).toEqual({
|
||||
kind: 'label',
|
||||
label: 'sweden',
|
||||
display: '#sweden'
|
||||
});
|
||||
});
|
||||
|
||||
it('presents url tags as globe tooltip targets', () => {
|
||||
expect(presentSignalServerTag('https://signal.example.com')).toEqual({
|
||||
kind: 'url',
|
||||
url: 'https://signal.example.com'
|
||||
});
|
||||
});
|
||||
});
|
||||
@@ -0,0 +1,52 @@
|
||||
import type { ServerEndpoint } from '../models/server-directory.model';
|
||||
import { sanitiseServerBaseUrl } from './server-endpoint-defaults.logic';
|
||||
|
||||
export type SignalServerTagPresentation =
|
||||
| { kind: 'url'; url: string }
|
||||
| { kind: 'label'; label: string; display: string };
|
||||
|
||||
export function isSignalServerTagUrl(value: string): boolean {
|
||||
return /^https?:\/\//i.test(value.trim());
|
||||
}
|
||||
|
||||
export function presentSignalServerTag(tag: string): SignalServerTagPresentation {
|
||||
const normalized = tag.trim();
|
||||
|
||||
if (isSignalServerTagUrl(normalized)) {
|
||||
return { kind: 'url', url: normalized };
|
||||
}
|
||||
|
||||
const label = normalized.replace(/^#+/, '');
|
||||
|
||||
return { kind: 'label', label, display: `#${label}` };
|
||||
}
|
||||
|
||||
export function resolveEndpointSignalServerTag(
|
||||
endpoint: Pick<ServerEndpoint, 'serverTag' | 'url'>
|
||||
): string {
|
||||
const configuredTag = endpoint.serverTag?.trim();
|
||||
|
||||
return configuredTag || endpoint.url;
|
||||
}
|
||||
|
||||
export function resolveUserHomeSignalServerTag(
|
||||
homeSignalServerUrl: string | undefined,
|
||||
endpoints: ServerEndpoint[]
|
||||
): string | undefined {
|
||||
const normalizedHomeUrl = homeSignalServerUrl?.trim();
|
||||
|
||||
if (!normalizedHomeUrl) {
|
||||
return undefined;
|
||||
}
|
||||
|
||||
const sanitizedHomeUrl = sanitiseServerBaseUrl(normalizedHomeUrl);
|
||||
const matchingEndpoint = endpoints.find(
|
||||
(endpoint) => sanitiseServerBaseUrl(endpoint.url) === sanitizedHomeUrl
|
||||
);
|
||||
|
||||
if (matchingEndpoint) {
|
||||
return resolveEndpointSignalServerTag(matchingEndpoint);
|
||||
}
|
||||
|
||||
return sanitizedHomeUrl;
|
||||
}
|
||||
@@ -57,6 +57,8 @@ export interface ServerEndpoint {
|
||||
instanceId?: string;
|
||||
name: string;
|
||||
url: string;
|
||||
/** Display tag advertised by the signal server health endpoint. */
|
||||
serverTag?: string;
|
||||
isActive: boolean;
|
||||
isDefault: boolean;
|
||||
defaultKey?: string;
|
||||
@@ -141,10 +143,12 @@ export interface ServerVersionCompatibilityResult {
|
||||
export interface ServerHealthCheckPayload {
|
||||
serverInstanceId?: unknown;
|
||||
serverVersion?: unknown;
|
||||
serverTag?: unknown;
|
||||
}
|
||||
|
||||
export interface ServerEndpointHealthResult {
|
||||
status: ServerEndpointStatus;
|
||||
latency?: number;
|
||||
serverTag?: string;
|
||||
versions?: ServerEndpointVersions;
|
||||
}
|
||||
|
||||
@@ -91,7 +91,9 @@
|
||||
|
||||
<div class="relative shrink-0">
|
||||
@if (isJoinedServer(server)) {
|
||||
<div class="flex items-center overflow-hidden rounded-md border border-emerald-500/30 bg-emerald-500/10 text-xs font-semibold text-emerald-500">
|
||||
<div
|
||||
class="flex items-center overflow-hidden rounded-md border border-emerald-500/30 bg-emerald-500/10 text-xs font-semibold text-emerald-500"
|
||||
>
|
||||
<span class="px-2.5 py-1.5">Joined</span>
|
||||
<button
|
||||
type="button"
|
||||
|
||||
@@ -585,7 +585,8 @@ export class ServerBrowserComponent implements OnInit {
|
||||
await firstValueFrom(this.webrtc.connectToSignalingServer(wsUrl));
|
||||
this.webrtc.identify(currentUser.oderId || currentUser.id, currentUser.displayName || 'User', wsUrl, {
|
||||
description: currentUser.description,
|
||||
profileUpdatedAt: currentUser.profileUpdatedAt
|
||||
profileUpdatedAt: currentUser.profileUpdatedAt,
|
||||
homeSignalServerUrl: currentUser.homeSignalServerUrl
|
||||
});
|
||||
|
||||
this.webrtc.sendRawMessageToSignalUrl(wsUrl, {
|
||||
|
||||
@@ -33,11 +33,15 @@ export class ServerEndpointHealthService {
|
||||
const serverInstanceId = typeof payload.serverInstanceId === 'string' && payload.serverInstanceId.trim().length > 0
|
||||
? payload.serverInstanceId.trim()
|
||||
: undefined;
|
||||
const serverTag = typeof payload.serverTag === 'string' && payload.serverTag.trim().length > 0
|
||||
? payload.serverTag.trim()
|
||||
: undefined;
|
||||
|
||||
if (!versionCompatibility.isCompatible) {
|
||||
return {
|
||||
status: 'incompatible',
|
||||
latency,
|
||||
serverTag,
|
||||
versions: {
|
||||
serverInstanceId,
|
||||
serverVersion: versionCompatibility.serverVersion,
|
||||
@@ -49,6 +53,7 @@ export class ServerEndpointHealthService {
|
||||
return {
|
||||
status: 'online',
|
||||
latency,
|
||||
serverTag,
|
||||
versions: {
|
||||
serverInstanceId,
|
||||
serverVersion: versionCompatibility.serverVersion,
|
||||
|
||||
Reference in New Issue
Block a user