From f1c67dc03f13d0976d978631b56e1d32c2d18628 Mon Sep 17 00:00:00 2001 From: Alpha4615 Date: Thu, 13 Nov 2025 15:58:40 -0500 Subject: [PATCH 1/2] Refactors url parsing to use the WHATWG URL API References OP-Engineering/link-preview-js#172. --- index.ts | 27 +++++++++++++++++++-------- package.json | 3 +-- 2 files changed, 20 insertions(+), 10 deletions(-) diff --git a/index.ts b/index.ts index 1e044ae..1e98501 100644 --- a/index.ts +++ b/index.ts @@ -1,7 +1,18 @@ import cheerio from "cheerio"; -import urlObj from "url"; import { CONSTANTS } from "./constants"; +/** + * Resolves a relative URL against a base URL using WHATWG URL API + */ +function resolveUrl(base: string, relative: string): string { + try { + return new URL(relative, base).href; + } catch (e) { + // If URL construction fails, return the relative URL as-is + return relative; + } +} + interface ILinkPreviewResponse { url: string; title: string; @@ -114,7 +125,7 @@ function getImages( if (node.type === `tag`) { src = node.attribs.content; if (src) { - src = urlObj.resolve(rootUrl, src); + src = resolveUrl(rootUrl, src); images.push(src); } } @@ -124,7 +135,7 @@ function getImages( if (images.length <= 0 && !imagesPropertyType) { src = doc(`link[rel=image_src]`).attr(`href`); if (src) { - src = urlObj.resolve(rootUrl, src); + src = resolveUrl(rootUrl, src); images = [src]; } else { nodes = doc(`img`); @@ -138,7 +149,7 @@ function getImages( dic[src] = true; // width = node.attribs.width; // height = node.attribs.height; - images.push(urlObj.resolve(rootUrl, src)); + images.push(resolveUrl(rootUrl, src)); } }); } @@ -213,7 +224,7 @@ function getVideos(doc: cheerio.Root) { // returns default favicon (//hostname/favicon.ico) for a url function getDefaultFavicon(rootUrl: string) { - return urlObj.resolve(rootUrl, `/favicon.ico`); + return resolveUrl(rootUrl, `/favicon.ico`); } // returns an array of URLs to favicon images @@ -237,7 +248,7 @@ function getFavicons(doc: cheerio.Root, rootUrl: string) { nodes.each((_: number, node: cheerio.Element) => { if (node.type === `tag`) src = node.attribs.href; if (src) { - src = urlObj.resolve(rootUrl, src); + src = resolveUrl(rootUrl, src); images.push(src); } }); @@ -471,12 +482,12 @@ export async function getLinkPreview( options?.handleRedirects ) { const locationHeader = response.headers.get(`location`) || ``; - const isAbsoluteURI = locationHeader.startsWith('http://') || locationHeader.startsWith('https://'); + const isAbsoluteURI = locationHeader.startsWith('http://') || locationHeader.startsWith('https://'); // Resolve the URL, handling both absolute and relative URLs const forwardedUrl = isAbsoluteURI ? locationHeader - : urlObj.resolve(fetchUrl, locationHeader); + : resolveUrl(fetchUrl, locationHeader); if (!options.handleRedirects(fetchUrl, forwardedUrl)) { throw new Error(`link-preview-js could not handle redirect`); diff --git a/package.json b/package.json index 38a9636..ecec196 100644 --- a/package.json +++ b/package.json @@ -30,8 +30,7 @@ "license": "MIT", "repository": "https://github.com/ospfranco/link-preview-js", "dependencies": { - "cheerio": "1.0.0-rc.11", - "url": "0.11.0" + "cheerio": "1.0.0-rc.11" }, "files": [ "build" From 99188ed78dd57eb710f169a5c5a4954c507bd00c Mon Sep 17 00:00:00 2001 From: Alpha4615 Date: Fri, 14 Nov 2025 10:31:57 -0500 Subject: [PATCH 2/2] Only use the WHATWG URL API when it's available (fixes compat issues with react-native) --- index.ts | 19 ++++++++++++++++--- package.json | 3 ++- 2 files changed, 18 insertions(+), 4 deletions(-) diff --git a/index.ts b/index.ts index 1e98501..e44d6c9 100644 --- a/index.ts +++ b/index.ts @@ -2,13 +2,26 @@ import cheerio from "cheerio"; import { CONSTANTS } from "./constants"; /** - * Resolves a relative URL against a base URL using WHATWG URL API + * Resolves a relative URL against a base URL + * Uses WHATWG URL API when available + * Falls back to legacy url.resolve() for environments like React Native */ function resolveUrl(base: string, relative: string): string { + // Try WHATWG URL API first + if (typeof URL !== 'undefined') { + try { + return new URL(relative, base).href; + } catch (e) { + // If exception raised, fall through to legacy method + } + } + + // Fallback to legacy url.resolve() for React Native and older environments try { - return new URL(relative, base).href; + const url = require('url'); + return url.resolve(base, relative); } catch (e) { - // If URL construction fails, return the relative URL as-is + // If all else fails, return the relative URL as-is return relative; } } diff --git a/package.json b/package.json index ecec196..38a9636 100644 --- a/package.json +++ b/package.json @@ -30,7 +30,8 @@ "license": "MIT", "repository": "https://github.com/ospfranco/link-preview-js", "dependencies": { - "cheerio": "1.0.0-rc.11" + "cheerio": "1.0.0-rc.11", + "url": "0.11.0" }, "files": [ "build"