From f1733e58374b4e4a4821c2144d79792357cdfc1c Mon Sep 17 00:00:00 2001 From: ItsRauf <31735267+ItsRauf@users.noreply.github.com> Date: Sat, 11 Apr 2026 12:57:52 +0000 Subject: [PATCH 1/4] =?UTF-8?q?=E2=99=BB=EF=B8=8F=20revert(platforms):=20s?= =?UTF-8?q?witch=20URL=20matching=20back=20to=20regex?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- packages/platforms/src/CBC.test.ts | 4 +- packages/platforms/src/CBC.ts | 16 +++----- packages/platforms/src/Instagram.test.ts | 12 +----- packages/platforms/src/Instagram.ts | 15 +++----- packages/platforms/src/Mastodon.ts | 20 +++++----- packages/platforms/src/Platform.ts | 8 +--- packages/platforms/src/Reddit.ts | 47 +++++------------------- packages/platforms/src/Threads.test.ts | 5 +-- packages/platforms/src/Threads.ts | 14 +++---- packages/platforms/src/TikTok.test.ts | 14 +++---- packages/platforms/src/TikTok.ts | 20 ++++------ packages/platforms/src/Twitter.test.ts | 4 +- packages/platforms/src/Twitter.ts | 14 +++---- packages/platforms/src/utils.ts | 15 ++++---- 14 files changed, 71 insertions(+), 137 deletions(-) diff --git a/packages/platforms/src/CBC.test.ts b/packages/platforms/src/CBC.test.ts index 9638d5d..6ebaa19 100644 --- a/packages/platforms/src/CBC.test.ts +++ b/packages/platforms/src/CBC.test.ts @@ -24,9 +24,9 @@ describe("CBC", () => { }); it("extracts cbc id", () => { - const match = cbc.pattern.exec( + const match = cbc.regex.exec( "https://www.cbc.ca/news/canada/1.7654321" ); - expect(match?.pathname.groups.cbc_id).toBe("1.7654321"); + expect(match?.groups?.cbc_id).toBe("1.7654321"); }); }); diff --git a/packages/platforms/src/CBC.ts b/packages/platforms/src/CBC.ts index 1a3749c..ce6f7c0 100644 --- a/packages/platforms/src/CBC.ts +++ b/packages/platforms/src/CBC.ts @@ -4,27 +4,21 @@ import he from "he"; import { CF_CACHE_OPTIONS } from "./constants.ts"; import { type BaseEmbedData, EmbedlyPlatform } from "./Platform.ts"; import { EmbedlyPlatformType } from "./types.ts"; -import { signProxyUrl, validatePatternMatch } from "./utils.ts"; +import { signProxyUrl, validateRegexMatch } from "./utils.ts"; export class CBC extends EmbedlyPlatform { readonly color = [215, 36, 42] as const; readonly emoji = "<:cbc:1409997044495683674>"; - readonly pattern = new URLPattern({ - hostname: "{*.}?cbc.ca", - pathname: "*/:cbc_id{/}?" - }); + readonly regex = /cbc.ca\/.*(?\d\.\d+)/; constructor() { super(EmbedlyPlatformType.CBC, "cbc.ca"); } async parsePostId(url: string): Promise { - const match = this.pattern.exec(url); - validatePatternMatch( - match, - "Invalid CBC URL: could not extract ID" - ); - const { cbc_id } = match.pathname.groups; + const match = this.regex.exec(url); + validateRegexMatch(match, "Invalid CBC URL: could not extract ID"); + const { cbc_id } = match.groups; return cbc_id; } diff --git a/packages/platforms/src/Instagram.test.ts b/packages/platforms/src/Instagram.test.ts index 220ff54..8bb4116 100644 --- a/packages/platforms/src/Instagram.test.ts +++ b/packages/platforms/src/Instagram.test.ts @@ -32,17 +32,9 @@ describe("Instagram", () => { }); it("extracts shortcode", () => { - const match = instagram.pattern.exec( + const match = instagram.regex.exec( "https://www.instagram.com/p/CxYz123_Ab/" ); - expect(match?.pathname.groups.ig_shortcode).toBe("CxYz123_Ab"); - }); - - it("extracts shortcode with user prefix", () => { - const match = instagram.pattern.exec( - "https://www.instagram.com/natgeo/reel/CxYz123/" - ); - expect(match?.pathname.groups.ig_shortcode).toBe("CxYz123"); - expect(match?.pathname.groups.user).toBe("natgeo"); + expect(match?.groups?.ig_shortcode).toBe("CxYz123_Ab"); }); }); diff --git a/packages/platforms/src/Instagram.ts b/packages/platforms/src/Instagram.ts index e066acd..63ce935 100644 --- a/packages/platforms/src/Instagram.ts +++ b/packages/platforms/src/Instagram.ts @@ -6,16 +6,13 @@ import { EmbedlyPlatform } from "./Platform.ts"; import { EmbedlyPlatformType } from "./types.ts"; -import { validatePatternMatch } from "./utils.ts"; +import { validateRegexMatch } from "./utils.ts"; export class Instagram extends EmbedlyPlatform { readonly color = [225, 48, 108] as const; readonly emoji = "<:instagram:1386639712013254748>"; - readonly pattern = new URLPattern({ - hostname: "{*.}?instagram.com", - pathname: - "/{:user/}?(p|share|reels|reel|stories)/:ig_shortcode{/*}?" - }); + readonly regex = + /instagram.com\/(?:[A-Za-z0-9_.]+\/)?(p|share|reels|reel|stories)\/(?[A-Za-z0-9-_]+)/; constructor() { super(EmbedlyPlatformType.Instagram, "insta"); @@ -31,12 +28,12 @@ export class Instagram extends EmbedlyPlatform { }); url = req.url; } - const match = this.pattern.exec(url); - validatePatternMatch( + const match = this.regex.exec(url); + validateRegexMatch( match, "Invalid Instagram URL: could not extract shortcode" ); - const { ig_shortcode } = match.pathname.groups; + const { ig_shortcode } = match.groups; return ig_shortcode; } diff --git a/packages/platforms/src/Mastodon.ts b/packages/platforms/src/Mastodon.ts index 2fbf0ba..210f9d8 100644 --- a/packages/platforms/src/Mastodon.ts +++ b/packages/platforms/src/Mastodon.ts @@ -7,14 +7,12 @@ import { EmbedlyPlatform } from "./Platform.ts"; import type { EmbedlyPlatformType } from "./types.ts"; -import { signProxyUrl, validatePatternMatch } from "./utils.ts"; +import { signProxyUrl, validateRegexMatch } from "./utils.ts"; export abstract class EmbedlyMastodon extends EmbedlyPlatform { abstract readonly base_url: string; - readonly pattern = new URLPattern({ - hostname: "{*.}?__PLACEHOLDER__" - }); + readonly regex: RegExp; constructor( name: EmbedlyPlatformType, @@ -22,19 +20,19 @@ export abstract class EmbedlyMastodon extends EmbedlyPlatform { hostname: string ) { super(name, cache_prefix); - this.pattern = new URLPattern({ - hostname: `{*.}?${hostname}`, - pathname: "/@:username/posts/:status_id{/}?" - }); + const escapedHostname = hostname.replaceAll(".", "\\."); + this.regex = new RegExp( + `(?:https?:\\/\\/)?(?:[\\w-]+\\.)*${escapedHostname}\\/@[^/]+\\/posts\\/(?[^/?#]+)` + ); } async parsePostId(url: string): Promise { - const match = this.pattern.exec(url); - validatePatternMatch( + const match = this.regex.exec(url); + validateRegexMatch( match, `Invalid ${this.name} URL: could not extract status ID` ); - return match.pathname.groups.status_id; + return match.groups.status_id; } async fetchPost( diff --git a/packages/platforms/src/Platform.ts b/packages/platforms/src/Platform.ts index 28d2473..a03488a 100644 --- a/packages/platforms/src/Platform.ts +++ b/packages/platforms/src/Platform.ts @@ -27,7 +27,7 @@ export interface CloudflareEnv { export abstract class EmbedlyPlatform { abstract readonly color: readonly [number, number, number]; abstract readonly emoji: string; - abstract readonly pattern: URLPattern; + abstract readonly regex: RegExp; public log_messages: EmbedlyPlatformLogMessages; @@ -42,11 +42,7 @@ export abstract class EmbedlyPlatform { } public matchesUrl(url: string): boolean { - try { - return this.pattern.test(url); - } catch { - return false; - } + return this.regex.test(url); } abstract parsePostId( diff --git a/packages/platforms/src/Reddit.ts b/packages/platforms/src/Reddit.ts index c10a815..aba5770 100644 --- a/packages/platforms/src/Reddit.ts +++ b/packages/platforms/src/Reddit.ts @@ -6,46 +6,17 @@ import { EmbedlyPlatform } from "./Platform.ts"; import { EmbedlyPlatformType } from "./types.ts"; -import { validatePatternMatch } from "./utils.ts"; +import { validateRegexMatch } from "./utils.ts"; -const REDDIT_PATTERN_COMMENTS = new URLPattern({ - hostname: "{(www|old).}?reddit.com", - pathname: "/r/:subreddit/comments/:post_id{/*}?" -}); - -const REDDIT_PATTERN_SHARE = new URLPattern({ - hostname: "{(www|old).}?reddit.com", - pathname: "/r/:subreddit/s/:share_id{/}?" -}); - -const REDDIT_PATTERN_SHORTLINK = new URLPattern({ - hostname: "redd.it", - pathname: "/:short_id{/}?" -}); - -const REDDIT_PATTERN_FOLLOWUP = new URLPattern({ - hostname: "{(www|old|m).}?reddit.com", - pathname: "/r/:subreddit/comments/:post_id{/*}?" -}); +const REDDIT_REGEX_MAIN = + /https?:\/\/(?:www\.|old\.)?(?:reddit\.com\/r\/[A-Za-z0-9_]+\/(?:comments\/[A-Za-z0-9]+(?:\/[^/\s]+)?|s\/[A-Za-z0-9]+)|redd\.it\/[A-Za-z0-9]+)\/?/; +const REDDIT_REGEX_FOLLOWUP = + /https?:\/\/(?:www\.|old\.|m\.)?reddit\.com\/r\/(?\w+)\/comments\/(?[a-z0-9]+)/; export class Reddit extends EmbedlyPlatform { readonly color = [255, 86, 0] as const; readonly emoji = "<:reddit:1461320093240655922>"; - readonly pattern = REDDIT_PATTERN_COMMENTS; - - public matchesUrl(url: string): boolean { - return [ - REDDIT_PATTERN_COMMENTS, - REDDIT_PATTERN_SHARE, - REDDIT_PATTERN_SHORTLINK - ].some((p) => { - try { - return p.test(url); - } catch { - return false; - } - }); - } + readonly regex = REDDIT_REGEX_MAIN; constructor() { super(EmbedlyPlatformType.Reddit, "reddit"); @@ -65,12 +36,12 @@ export class Reddit extends EmbedlyPlatform { ...CF_CACHE_OPTIONS }); console.log(req); - const match = REDDIT_PATTERN_FOLLOWUP.exec(req.url); - validatePatternMatch( + const match = REDDIT_REGEX_FOLLOWUP.exec(req.url); + validateRegexMatch( match, "Invalid Reddit URL: could not extract post ID or subreddit" ); - const { post_id, subreddit } = match.pathname.groups; + const { post_id, subreddit } = match.groups; return `${subreddit}/${post_id}`; } diff --git a/packages/platforms/src/Threads.test.ts b/packages/platforms/src/Threads.test.ts index 20b5f26..74ab2e5 100644 --- a/packages/platforms/src/Threads.test.ts +++ b/packages/platforms/src/Threads.test.ts @@ -26,10 +26,9 @@ describe("Threads", () => { }); it("extracts shortcode and username", () => { - const match = threads.pattern.exec( + const match = threads.regex.exec( "https://www.threads.net/@zuck/post/CxYz123_Ab" ); - expect(match?.pathname.groups.thread_shortcode).toBe("CxYz123_Ab"); - expect(match?.pathname.groups.username).toBe("zuck"); + expect(match?.groups?.thread_shortcode).toBe("CxYz123_Ab"); }); }); diff --git a/packages/platforms/src/Threads.ts b/packages/platforms/src/Threads.ts index 8b1341f..c2f7d8e 100644 --- a/packages/platforms/src/Threads.ts +++ b/packages/platforms/src/Threads.ts @@ -5,7 +5,7 @@ import { EmbedlyPlatform } from "./Platform.ts"; import { EmbedlyPlatformType } from "./types.ts"; -import { validatePatternMatch } from "./utils.ts"; +import { validateRegexMatch } from "./utils.ts"; const alphabet = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-_"; @@ -13,22 +13,20 @@ const alphabet = export class Threads extends EmbedlyPlatform { readonly color = [0, 0, 0] as const; readonly emoji = "<:threads:1413343483929956446>"; - readonly pattern = new URLPattern({ - hostname: "{*.}?threads.net", - pathname: "/@:username/post/:thread_shortcode{/}?" - }); + readonly regex = + /threads\.net\/@.*\/post\/(?[A-Za-z0-9-_]+)/; constructor() { super(EmbedlyPlatformType.Threads, "threads"); } async parsePostId(url: string): Promise { - const match = this.pattern.exec(url); - validatePatternMatch( + const match = this.regex.exec(url); + validateRegexMatch( match, "Invalid Threads URL: could not extract shortcode" ); - const { thread_shortcode } = match.pathname.groups; + const { thread_shortcode } = match.groups; const thread_id = thread_shortcode .split("") .reduce( diff --git a/packages/platforms/src/TikTok.test.ts b/packages/platforms/src/TikTok.test.ts index 7423533..0b050f1 100644 --- a/packages/platforms/src/TikTok.test.ts +++ b/packages/platforms/src/TikTok.test.ts @@ -26,16 +26,12 @@ describe("TikTok", () => { }); it("extracts user and video id from detail pattern", () => { - const detail_pattern = new URLPattern({ - hostname: "{(m|www|vm).}?tiktok.com", - pathname: "/:tiktok_user/video/:tiktok_id{/}?" - }); - const match = detail_pattern.exec( + const detail_regex = + /https:\/\/(?:m|www|vm)?\.?tiktok\.com\/(?@[\w.-]+)\/video\/(?\d+)/; + const match = detail_regex.exec( "https://www.tiktok.com/@cooluser/video/7234567890123456789" ); - expect(match?.pathname.groups.tiktok_user).toBe("@cooluser"); - expect(match?.pathname.groups.tiktok_id).toBe( - "7234567890123456789" - ); + expect(match?.groups?.tiktok_user).toBe("@cooluser"); + expect(match?.groups?.tiktok_id).toBe("7234567890123456789"); }); }); diff --git a/packages/platforms/src/TikTok.ts b/packages/platforms/src/TikTok.ts index 77b5489..855e6e4 100644 --- a/packages/platforms/src/TikTok.ts +++ b/packages/platforms/src/TikTok.ts @@ -7,21 +7,17 @@ import { EmbedlyPlatform } from "./Platform.ts"; import { EmbedlyPlatformType } from "./types.ts"; -import { validatePatternMatch } from "./utils.ts"; +import { validateRegexMatch } from "./utils.ts"; -const TIKTOK_PATTERN_MAIN = new URLPattern({ - hostname: "{*.}?tiktok.com" -}); +const TIKTOK_REGEX_MAIN = /(https?:\/\/)?(?:[\w-]+\.)*tiktok\.com/; -const TIKTOK_PATTERN_DETAIL = new URLPattern({ - hostname: "{(m|www|vm).}?tiktok.com", - pathname: "/:tiktok_user/video/:tiktok_id{/}?" -}); +const TIKTOK_REGEX_DETAIL = + /https:\/\/(?:m|www|vm)?\.?tiktok\.com\/(?@[\w.-]+)\/video\/(?\d+)/; export class TikTok extends EmbedlyPlatform { readonly color = [57, 118, 132] as const; readonly emoji = "<:tiktok:1386641825963708446>"; - readonly pattern = TIKTOK_PATTERN_MAIN; + readonly regex = TIKTOK_REGEX_MAIN; constructor() { super(EmbedlyPlatformType.TikTok, "tiktok"); @@ -29,12 +25,12 @@ export class TikTok extends EmbedlyPlatform { async parsePostId(url: string): Promise { const req = await fetch(url, { redirect: "follow" }); - const match = TIKTOK_PATTERN_DETAIL.exec(req.url); - validatePatternMatch( + const match = TIKTOK_REGEX_DETAIL.exec(req.url); + validateRegexMatch( match, "Invalid TikTok URL: could not extract user/id" ); - const { tiktok_user, tiktok_id } = match.pathname.groups; + const { tiktok_user, tiktok_id } = match.groups; return `${tiktok_user}/${tiktok_id}`; } diff --git a/packages/platforms/src/Twitter.test.ts b/packages/platforms/src/Twitter.test.ts index ac62c6c..0784688 100644 --- a/packages/platforms/src/Twitter.test.ts +++ b/packages/platforms/src/Twitter.test.ts @@ -31,9 +31,9 @@ describe("Twitter", () => { }); it("extracts tweet id", () => { - const match = twitter.pattern.exec( + const match = twitter.regex.exec( "https://x.com/elonmusk/status/1234567890" ); - expect(match?.pathname.groups.tweet_id).toBe("1234567890"); + expect(match?.groups?.tweet_id).toBe("1234567890"); }); }); diff --git a/packages/platforms/src/Twitter.ts b/packages/platforms/src/Twitter.ts index 63e9f1f..f039085 100644 --- a/packages/platforms/src/Twitter.ts +++ b/packages/platforms/src/Twitter.ts @@ -4,27 +4,25 @@ import packageJSON from "../package.json" with { type: "json" }; import { CF_CACHE_OPTIONS } from "./constants.ts"; import { type BaseEmbedData, EmbedlyPlatform } from "./Platform.ts"; import { EmbedlyPlatformType } from "./types.ts"; -import { validatePatternMatch } from "./utils.ts"; +import { validateRegexMatch } from "./utils.ts"; export class Twitter extends EmbedlyPlatform { readonly color = [29, 161, 242] as const; readonly emoji = "<:twitter:1386639732179599481>"; - readonly pattern = new URLPattern({ - hostname: "{*.}?(twitter|x).com", - pathname: "/*/status{es}?/:tweet_id{/}?" - }); + readonly regex = + /(?:twitter|x).com\/.*\/status(?:es)?\/(?[^/?]+)/; constructor() { super(EmbedlyPlatformType.Twitter, "tweet"); } async parsePostId(url: string): Promise { - const match = this.pattern.exec(url); - validatePatternMatch( + const match = this.regex.exec(url); + validateRegexMatch( match, "Invalid Twitter URL: could not extract tweet ID" ); - const { tweet_id } = match.pathname.groups; + const { tweet_id } = match.groups; return tweet_id; } diff --git a/packages/platforms/src/utils.ts b/packages/platforms/src/utils.ts index b41144c..776f9cb 100644 --- a/packages/platforms/src/utils.ts +++ b/packages/platforms/src/utils.ts @@ -1,5 +1,4 @@ import { createHmac } from "node:crypto"; -import type { URLPatternResult } from "node:url"; import { GENERIC_LINK_REGEX } from "./constants.ts"; export function hasLink(content: string): boolean { @@ -23,13 +22,13 @@ export function signProxyUrl(url: string): string { return `https://${process.env.EMBEDLY_API_DOMAIN!}/api/_image?url=${url}&sig=${signature}`; } -export function validatePatternMatch( - match: URLPatternResult | null, +export function validateRegexMatch( + match: RegExpExecArray | null, errorMessage?: string -): asserts match is URLPatternResult { - if (match === null) { - throw new Error( - errorMessage ?? "Invalid URL: pattern match failed" - ); +): asserts match is RegExpExecArray & { + groups: Record; +} { + if (match === null || match.groups === undefined) { + throw new Error(errorMessage ?? "Invalid URL: regex match failed"); } } From 6801d9f4f82cb24333c582f1bc76d37dcda45902 Mon Sep 17 00:00:00 2001 From: ItsRauf <31735267+ItsRauf@users.noreply.github.com> Date: Sat, 11 Apr 2026 13:03:53 +0000 Subject: [PATCH 2/4] =?UTF-8?q?=F0=9F=90=9B=20fix(platforms):=20escape=20l?= =?UTF-8?q?iteral=20dots=20in=20domain=20regexes?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- packages/platforms/src/CBC.ts | 2 +- packages/platforms/src/Instagram.ts | 2 +- packages/platforms/src/Twitter.ts | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/packages/platforms/src/CBC.ts b/packages/platforms/src/CBC.ts index ce6f7c0..3733846 100644 --- a/packages/platforms/src/CBC.ts +++ b/packages/platforms/src/CBC.ts @@ -9,7 +9,7 @@ import { signProxyUrl, validateRegexMatch } from "./utils.ts"; export class CBC extends EmbedlyPlatform { readonly color = [215, 36, 42] as const; readonly emoji = "<:cbc:1409997044495683674>"; - readonly regex = /cbc.ca\/.*(?\d\.\d+)/; + readonly regex = /cbc\.ca\/.*(?\d\.\d+)/; constructor() { super(EmbedlyPlatformType.CBC, "cbc.ca"); diff --git a/packages/platforms/src/Instagram.ts b/packages/platforms/src/Instagram.ts index 63ce935..3029f58 100644 --- a/packages/platforms/src/Instagram.ts +++ b/packages/platforms/src/Instagram.ts @@ -12,7 +12,7 @@ export class Instagram extends EmbedlyPlatform { readonly color = [225, 48, 108] as const; readonly emoji = "<:instagram:1386639712013254748>"; readonly regex = - /instagram.com\/(?:[A-Za-z0-9_.]+\/)?(p|share|reels|reel|stories)\/(?[A-Za-z0-9-_]+)/; + /instagram\.com\/(?:[A-Za-z0-9_.]+\/)?(p|share|reels|reel|stories)\/(?[A-Za-z0-9-_]+)/; constructor() { super(EmbedlyPlatformType.Instagram, "insta"); diff --git a/packages/platforms/src/Twitter.ts b/packages/platforms/src/Twitter.ts index f039085..36b8253 100644 --- a/packages/platforms/src/Twitter.ts +++ b/packages/platforms/src/Twitter.ts @@ -10,7 +10,7 @@ export class Twitter extends EmbedlyPlatform { readonly color = [29, 161, 242] as const; readonly emoji = "<:twitter:1386639732179599481>"; readonly regex = - /(?:twitter|x).com\/.*\/status(?:es)?\/(?[^/?]+)/; + /(?:twitter|x)\.com\/.*\/status(?:es)?\/(?[^/?]+)/; constructor() { super(EmbedlyPlatformType.Twitter, "tweet"); From e208d037a46f70c2ac0cb56d10ba565517c3c93e Mon Sep 17 00:00:00 2001 From: ItsRauf <31735267+ItsRauf@users.noreply.github.com> Date: Sat, 11 Apr 2026 13:09:17 +0000 Subject: [PATCH 3/4] =?UTF-8?q?=F0=9F=90=9B=20fix(platforms):=20anchor=20p?= =?UTF-8?q?latform=20host=20regexes?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- packages/platforms/src/CBC.ts | 3 ++- packages/platforms/src/Instagram.ts | 2 +- packages/platforms/src/Mastodon.ts | 2 +- packages/platforms/src/Threads.ts | 2 +- packages/platforms/src/TikTok.ts | 5 +++-- packages/platforms/src/Twitter.ts | 2 +- 6 files changed, 9 insertions(+), 7 deletions(-) diff --git a/packages/platforms/src/CBC.ts b/packages/platforms/src/CBC.ts index 3733846..cf0dc01 100644 --- a/packages/platforms/src/CBC.ts +++ b/packages/platforms/src/CBC.ts @@ -9,7 +9,8 @@ import { signProxyUrl, validateRegexMatch } from "./utils.ts"; export class CBC extends EmbedlyPlatform { readonly color = [215, 36, 42] as const; readonly emoji = "<:cbc:1409997044495683674>"; - readonly regex = /cbc\.ca\/.*(?\d\.\d+)/; + readonly regex = + /^(?:https?:\/\/)?(?:[\w-]+\.)*cbc\.ca\/.*(?\d\.\d+)/; constructor() { super(EmbedlyPlatformType.CBC, "cbc.ca"); diff --git a/packages/platforms/src/Instagram.ts b/packages/platforms/src/Instagram.ts index 3029f58..fdb5cd6 100644 --- a/packages/platforms/src/Instagram.ts +++ b/packages/platforms/src/Instagram.ts @@ -12,7 +12,7 @@ export class Instagram extends EmbedlyPlatform { readonly color = [225, 48, 108] as const; readonly emoji = "<:instagram:1386639712013254748>"; readonly regex = - /instagram\.com\/(?:[A-Za-z0-9_.]+\/)?(p|share|reels|reel|stories)\/(?[A-Za-z0-9-_]+)/; + /^(?:https?:\/\/)?(?:[\w-]+\.)*instagram\.com\/(?:[A-Za-z0-9_.]+\/)?(p|share|reels|reel|stories)\/(?[A-Za-z0-9-_]+)/; constructor() { super(EmbedlyPlatformType.Instagram, "insta"); diff --git a/packages/platforms/src/Mastodon.ts b/packages/platforms/src/Mastodon.ts index 210f9d8..9fab37a 100644 --- a/packages/platforms/src/Mastodon.ts +++ b/packages/platforms/src/Mastodon.ts @@ -22,7 +22,7 @@ export abstract class EmbedlyMastodon extends EmbedlyPlatform { super(name, cache_prefix); const escapedHostname = hostname.replaceAll(".", "\\."); this.regex = new RegExp( - `(?:https?:\\/\\/)?(?:[\\w-]+\\.)*${escapedHostname}\\/@[^/]+\\/posts\\/(?[^/?#]+)` + `^(?:https?:\\/\\/)?(?:[\\w-]+\\.)*${escapedHostname}\\/@[^/]+\\/posts\\/(?[^/?#]+)` ); } diff --git a/packages/platforms/src/Threads.ts b/packages/platforms/src/Threads.ts index c2f7d8e..b448ef5 100644 --- a/packages/platforms/src/Threads.ts +++ b/packages/platforms/src/Threads.ts @@ -14,7 +14,7 @@ export class Threads extends EmbedlyPlatform { readonly color = [0, 0, 0] as const; readonly emoji = "<:threads:1413343483929956446>"; readonly regex = - /threads\.net\/@.*\/post\/(?[A-Za-z0-9-_]+)/; + /^(?:https?:\/\/)?(?:[\w-]+\.)*threads\.net\/@.*\/post\/(?[A-Za-z0-9-_]+)/; constructor() { super(EmbedlyPlatformType.Threads, "threads"); diff --git a/packages/platforms/src/TikTok.ts b/packages/platforms/src/TikTok.ts index 855e6e4..67f2007 100644 --- a/packages/platforms/src/TikTok.ts +++ b/packages/platforms/src/TikTok.ts @@ -9,10 +9,11 @@ import { import { EmbedlyPlatformType } from "./types.ts"; import { validateRegexMatch } from "./utils.ts"; -const TIKTOK_REGEX_MAIN = /(https?:\/\/)?(?:[\w-]+\.)*tiktok\.com/; +const TIKTOK_REGEX_MAIN = + /^(?:https?:\/\/)?(?:[\w-]+\.)*tiktok\.com(?:\/|$)/; const TIKTOK_REGEX_DETAIL = - /https:\/\/(?:m|www|vm)?\.?tiktok\.com\/(?@[\w.-]+)\/video\/(?\d+)/; + /^https:\/\/(?:m|www|vm)?\.?tiktok\.com\/(?@[\w.-]+)\/video\/(?\d+)/; export class TikTok extends EmbedlyPlatform { readonly color = [57, 118, 132] as const; diff --git a/packages/platforms/src/Twitter.ts b/packages/platforms/src/Twitter.ts index 36b8253..a03ef22 100644 --- a/packages/platforms/src/Twitter.ts +++ b/packages/platforms/src/Twitter.ts @@ -10,7 +10,7 @@ export class Twitter extends EmbedlyPlatform { readonly color = [29, 161, 242] as const; readonly emoji = "<:twitter:1386639732179599481>"; readonly regex = - /(?:twitter|x)\.com\/.*\/status(?:es)?\/(?[^/?]+)/; + /^(?:https?:\/\/)?(?:[\w-]+\.)*(?:twitter|x)\.com\/.*\/status(?:es)?\/(?[^/?]+)/; constructor() { super(EmbedlyPlatformType.Twitter, "tweet"); From 4cf8ab0c372b7140d8d66508099fff15cfcd9e65 Mon Sep 17 00:00:00 2001 From: ItsRauf <31735267+ItsRauf@users.noreply.github.com> Date: Sat, 11 Apr 2026 13:20:11 +0000 Subject: [PATCH 4/4] =?UTF-8?q?=F0=9F=90=9B=20fix(platforms):=20anchor=20R?= =?UTF-8?q?eddit=20regexes=20and=20add=20changeset?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .changeset/loose-pears-divide.md | 5 +++++ packages/platforms/src/Reddit.ts | 4 ++-- 2 files changed, 7 insertions(+), 2 deletions(-) create mode 100644 .changeset/loose-pears-divide.md diff --git a/.changeset/loose-pears-divide.md b/.changeset/loose-pears-divide.md new file mode 100644 index 0000000..44263fc --- /dev/null +++ b/.changeset/loose-pears-divide.md @@ -0,0 +1,5 @@ +--- +"@embedly/platforms": minor +--- + +Revert platform URL matching back to regex-based matchers. diff --git a/packages/platforms/src/Reddit.ts b/packages/platforms/src/Reddit.ts index aba5770..0b48fab 100644 --- a/packages/platforms/src/Reddit.ts +++ b/packages/platforms/src/Reddit.ts @@ -9,9 +9,9 @@ import { EmbedlyPlatformType } from "./types.ts"; import { validateRegexMatch } from "./utils.ts"; const REDDIT_REGEX_MAIN = - /https?:\/\/(?:www\.|old\.)?(?:reddit\.com\/r\/[A-Za-z0-9_]+\/(?:comments\/[A-Za-z0-9]+(?:\/[^/\s]+)?|s\/[A-Za-z0-9]+)|redd\.it\/[A-Za-z0-9]+)\/?/; + /^https?:\/\/(?:www\.|old\.)?(?:reddit\.com\/r\/[A-Za-z0-9_]+\/(?:comments\/[A-Za-z0-9]+(?:\/[^/\s]+)?|s\/[A-Za-z0-9]+)|redd\.it\/[A-Za-z0-9]+)\/?/; const REDDIT_REGEX_FOLLOWUP = - /https?:\/\/(?:www\.|old\.|m\.)?reddit\.com\/r\/(?\w+)\/comments\/(?[a-z0-9]+)/; + /^https?:\/\/(?:www\.|old\.|m\.)?reddit\.com\/r\/(?\w+)\/comments\/(?[a-z0-9]+)/; export class Reddit extends EmbedlyPlatform { readonly color = [255, 86, 0] as const;