1import dns from 'dns'; 2import { URL } from 'url'; 3 4import { fetchAsync } from '../api/rest/client'; 5 6/** Check if a server is available based on the URL. */ 7export function isUrlAvailableAsync(url: string): Promise<boolean> { 8 return new Promise<boolean>((resolve) => { 9 dns.lookup(url, (err) => { 10 resolve(!err); 11 }); 12 }); 13} 14 15/** Check if a request to the given URL is `ok` (status 200). */ 16export async function isUrlOk(url: string): Promise<boolean> { 17 try { 18 const res = await fetchAsync(url); 19 return res.ok; 20 } catch { 21 return false; 22 } 23} 24 25/** Determine if a string is a valid URL, can optionally ensure certain protocols (like `https` or `exp`) are adhered to. */ 26export function validateUrl( 27 urlString: string, 28 { 29 protocols, 30 requireProtocol, 31 }: { 32 /** Set of allowed protocols for the string to adhere to. @example ['exp', 'https'] */ 33 protocols?: string[]; 34 /** Ensure the URL has a protocol component (prefix before `://`). */ 35 requireProtocol?: boolean; 36 } = {} 37) { 38 try { 39 const results = new URL(urlString); 40 if (!results.protocol && !requireProtocol) { 41 return true; 42 } 43 return protocols 44 ? results.protocol 45 ? protocols.map((x) => `${x.toLowerCase()}:`).includes(results.protocol) 46 : false 47 : true; 48 } catch { 49 return false; 50 } 51} 52 53/** Remove the port from a given `host` URL string. */ 54export function stripPort(host?: string): string | null { 55 return coerceUrl(host)?.hostname ?? null; 56} 57 58function coerceUrl(urlString?: string): URL | null { 59 if (!urlString) { 60 return null; 61 } 62 try { 63 return new URL('/', urlString); 64 } catch (error: any) { 65 if (error.code !== 'ERR_INVALID_URL') { 66 throw error; 67 } 68 return new URL('/', `http://${urlString}`); 69 } 70} 71 72/** Strip a given extension from a URL string. */ 73export function stripExtension(url: string, extension: string): string { 74 return url.replace(new RegExp(`.${extension}$`), ''); 75} 76