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