120 lines
4.0 KiB
TypeScript
120 lines
4.0 KiB
TypeScript
export type DiagnosticSiteStatus = 'available' | 'responded' | 'unavailable';
|
|
|
|
export interface DiagnosticIpResult extends Record<string, unknown> {
|
|
source: string;
|
|
address: string | null;
|
|
}
|
|
|
|
export interface DiagnosticSiteResult extends Record<string, unknown> {
|
|
id: string;
|
|
status: DiagnosticSiteStatus;
|
|
httpStatus: number | null;
|
|
latencyMs: number | null;
|
|
}
|
|
|
|
export interface DiagnosticNetworkResult extends Record<string, unknown> {
|
|
address: string | null;
|
|
asn: string | null;
|
|
provider: string | null;
|
|
city: string | null;
|
|
country: string | null;
|
|
}
|
|
|
|
export interface DiagnosticServer extends Record<string, unknown> {
|
|
id: string;
|
|
label: string;
|
|
}
|
|
|
|
export interface DiagnosticPath extends Record<string, unknown> {
|
|
available: boolean;
|
|
internetAvailable: boolean;
|
|
ipv4: {
|
|
addresses: string[];
|
|
sources: DiagnosticIpResult[];
|
|
};
|
|
ipv6: string | null;
|
|
ipv6Source: DiagnosticIpResult | null;
|
|
network?: DiagnosticNetworkResult | null;
|
|
sites: DiagnosticSiteResult[];
|
|
server?: DiagnosticServer | null;
|
|
}
|
|
|
|
export interface ConnectivityResult extends Record<string, unknown> {
|
|
direct: DiagnosticPath;
|
|
vpn: DiagnosticPath & { server: DiagnosticServer | null };
|
|
}
|
|
|
|
function record(value: unknown): value is Record<string, unknown> {
|
|
return Boolean(value) && typeof value === 'object' && !Array.isArray(value);
|
|
}
|
|
|
|
function nullableNonnegativeNumber(value: unknown): value is number | null {
|
|
return value === null || (typeof value === 'number' && Number.isFinite(value) && value >= 0);
|
|
}
|
|
|
|
function validIpResult(value: unknown): value is DiagnosticIpResult {
|
|
return record(value)
|
|
&& typeof value.source === 'string'
|
|
&& value.source.length > 0
|
|
&& (value.address === null || (typeof value.address === 'string' && value.address.length > 0));
|
|
}
|
|
|
|
function validSiteResult(value: unknown): value is DiagnosticSiteResult {
|
|
return record(value)
|
|
&& typeof value.id === 'string'
|
|
&& value.id.length > 0
|
|
&& (value.status === 'available' || value.status === 'responded' || value.status === 'unavailable')
|
|
&& nullableNonnegativeNumber(value.httpStatus)
|
|
&& nullableNonnegativeNumber(value.latencyMs);
|
|
}
|
|
|
|
function nullableText(value: unknown): value is string | null {
|
|
return value === null || (typeof value === 'string' && value.length > 0);
|
|
}
|
|
|
|
function validNetworkResult(value: unknown): value is DiagnosticNetworkResult {
|
|
return record(value)
|
|
&& nullableText(value.address)
|
|
&& nullableText(value.asn)
|
|
&& nullableText(value.provider)
|
|
&& nullableText(value.city)
|
|
&& nullableText(value.country);
|
|
}
|
|
|
|
function validServer(value: unknown): value is DiagnosticServer | null {
|
|
return value === null || (record(value)
|
|
&& typeof value.id === 'string'
|
|
&& typeof value.label === 'string');
|
|
}
|
|
|
|
function validPath(value: unknown): value is DiagnosticPath {
|
|
return record(value)
|
|
&& typeof value.available === 'boolean'
|
|
&& typeof value.internetAvailable === 'boolean'
|
|
&& record(value.ipv4)
|
|
&& Array.isArray(value.ipv4.addresses)
|
|
&& value.ipv4.addresses.every((address) => typeof address === 'string' && address.length > 0)
|
|
&& Array.isArray(value.ipv4.sources)
|
|
&& value.ipv4.sources.every(validIpResult)
|
|
&& (value.ipv6 === null || (typeof value.ipv6 === 'string' && value.ipv6.length > 0))
|
|
&& (value.ipv6Source === null || validIpResult(value.ipv6Source))
|
|
&& (!Object.hasOwn(value, 'network') || value.network === null || validNetworkResult(value.network))
|
|
&& Array.isArray(value.sites)
|
|
&& value.sites.every(validSiteResult);
|
|
}
|
|
|
|
function assertConnectivityResult(value: unknown): asserts value is ConnectivityResult {
|
|
if (!record(value)
|
|
|| !validPath(value.direct)
|
|
|| !validPath(value.vpn)
|
|
|| !Object.hasOwn(value.vpn, 'server')
|
|
|| !validServer(value.vpn.server)) {
|
|
throw new TypeError('Harbor connectivity diagnostics returned an invalid result');
|
|
}
|
|
}
|
|
|
|
export function parseConnectivityResult(value: unknown): ConnectivityResult {
|
|
assertConnectivityResult(value);
|
|
return value;
|
|
}
|