From d58c0e27132f5e79cab3ccc8fd2aa3f9142a5c28 Mon Sep 17 00:00:00 2001 From: Thomas Kaul <4159106+dtslvr@users.noreply.github.com> Date: Sun, 28 Jun 2026 17:13:36 +0200 Subject: [PATCH] Refactoring --- apps/api/src/services/fetch/fetch.service.ts | 47 +++++++++++-------- .../fetch/interfaces/proxy-route.interface.ts | 5 +- 2 files changed, 29 insertions(+), 23 deletions(-) diff --git a/apps/api/src/services/fetch/fetch.service.ts b/apps/api/src/services/fetch/fetch.service.ts index 6006db04a..73eafbd6d 100644 --- a/apps/api/src/services/fetch/fetch.service.ts +++ b/apps/api/src/services/fetch/fetch.service.ts @@ -41,10 +41,6 @@ export class FetchService implements OnModuleInit { } public async fetch(input: RequestInfo | URL, init?: RequestInit) { - // Apply a generic per-domain origin override (e.g. route a provider through - // a local proxy) before doing anything else with the request - input = this.applyProxyRoute(input); - const method = ( init?.method ?? (input instanceof Request ? input.method : undefined) ?? @@ -71,8 +67,10 @@ export class FetchService implements OnModuleInit { } } + const proxiedInput = this.applyProxyRoute(input); + try { - return await globalThis.fetch(input, init); + return await globalThis.fetch(proxiedInput, init); } catch (error) { if (error instanceof Error) { this.logger.error( @@ -189,33 +187,44 @@ export class FetchService implements OnModuleInit { * the input unchanged when no route matches or parsing fails. */ private applyProxyRoute(input: RequestInfo | URL): RequestInfo | URL { + let requestUrl: URL; + try { - const requestUrl = new URL( + requestUrl = new URL( input instanceof Request ? input.url : input.toString() ); + } catch { + return input; + } - const route = this.proxyRoutes.find(({ domain }) => { - return this.hostnameMatchesDomain({ - domain, - hostname: requestUrl.hostname - }); + const route = this.proxyRoutes.find(({ domain }) => { + return this.hostnameMatchesDomain({ + domain, + hostname: requestUrl.hostname }); + }); - if (!route) { - return input; - } + if (!route) { + return input; + } + try { const proxyUrl = new URL(route.url); - requestUrl.protocol = proxyUrl.protocol; + requestUrl.hostname = proxyUrl.hostname; requestUrl.port = proxyUrl.port; - - return input instanceof Request - ? new Request(requestUrl.toString(), input) - : requestUrl.toString(); + requestUrl.protocol = proxyUrl.protocol; } catch { + this.logger.warn( + `Skipping proxy route for "${route.domain}": invalid url "${route.url}"` + ); + return input; } + + return input instanceof Request + ? new Request(requestUrl.toString(), input) + : requestUrl.toString(); } private getMatchingWebFetchRoute(url: string) { diff --git a/apps/api/src/services/fetch/interfaces/proxy-route.interface.ts b/apps/api/src/services/fetch/interfaces/proxy-route.interface.ts index 7236ac8ee..83edba6c0 100644 --- a/apps/api/src/services/fetch/interfaces/proxy-route.interface.ts +++ b/apps/api/src/services/fetch/interfaces/proxy-route.interface.ts @@ -1,9 +1,6 @@ /** * Overrides the origin (protocol, host and port) of outgoing requests for a - * given domain. This lets a self-hosted instance transparently route a - * provider's traffic through a local proxy (e.g. one that solves a bot - * challenge) without changing any call sites — the request path and query are - * preserved. + * given domain. * * Configured via the `PROXY_ROUTES` property as a JSON array, e.g. *