From 20f9c8a35fa2369e7d4025517ab2980e83590ee3 Mon Sep 17 00:00:00 2001 From: Uri Date: Sat, 11 Apr 2026 13:07:29 +0300 Subject: [PATCH] fix: authedFetch URL resolution breaks when DENO_DEPLOY_ENDPOINT contains a path --- auth.ts | 2 +- tests/url_resolution.test.ts | 40 ++++++++++++++++++++++++++++++++++++ util.ts | 4 +++- 3 files changed, 44 insertions(+), 2 deletions(-) create mode 100644 tests/url_resolution.test.ts diff --git a/auth.ts b/auth.ts index 5b185e5..b436813 100644 --- a/auth.ts +++ b/auth.ts @@ -355,7 +355,7 @@ export async function authedFetch( `token=${auth}; deno_auth_ghid=force`, ); - const url = new URL(endpoint, context.endpoint); + const url = new URL(`${context.endpoint}/${endpoint}`); let fallbackBody: ReadableStream | undefined; if (init.body instanceof ReadableStream) { diff --git a/tests/url_resolution.test.ts b/tests/url_resolution.test.ts new file mode 100644 index 0000000..57d86df --- /dev/null +++ b/tests/url_resolution.test.ts @@ -0,0 +1,40 @@ +import { assertEquals } from "@std/assert"; + +// Reproduces the URL resolution behavior in authedFetch. +// Before the fix: new URL(endpoint, base) drops path segments from the base. +// After the fix: string concatenation preserves the full base path. + +Deno.test("new URL() two-arg drops base path segments", () => { + // This is the OLD (broken) behavior that motivates the fix. + // When the endpoint is a proxy URL with a path, the path-based + // target host segment gets silently dropped. + const base = "https://proxy.example.com/target-host"; + const endpoint = "api/diffsync/org/app/rev123"; + + const broken = new URL(endpoint, base); + // new URL resolves relative to the parent of "target-host", losing it: + assertEquals(broken.pathname, "/api/diffsync/org/app/rev123"); + // "target-host" is gone — the proxy can no longer route the request. +}); + +Deno.test("string concatenation preserves base path segments", () => { + // This is the FIXED behavior: concatenation keeps the full base path. + const base = "https://proxy.example.com/target-host"; + const endpoint = "api/diffsync/org/app/rev123"; + + const fixed = new URL(`${base}/${endpoint}`); + assertEquals( + fixed.pathname, + "/target-host/api/diffsync/org/app/rev123", + ); +}); + +Deno.test("string concatenation works for standard endpoint too", () => { + // Ensure the fix doesn't regress the normal (non-proxy) case. + const base = "https://console.deno.com"; + const endpoint = "api/diffsync/org/app/rev123"; + + const fixed = new URL(`${base}/${endpoint}`); + assertEquals(fixed.pathname, "/api/diffsync/org/app/rev123"); + assertEquals(fixed.hostname, "console.deno.com"); +}); diff --git a/util.ts b/util.ts index 4cd65d3..fa2f430 100644 --- a/util.ts +++ b/util.ts @@ -102,7 +102,9 @@ export function error( } else { console.error(); console.error(`${red("✗")} An error occurred:`); - console.error(` ${message.replaceAll("\n", "\n ")}`); + console.error( + ` ${String(message ?? "Unknown error").replaceAll("\n", "\n ")}`, + ); if (opts.hint) { console.error(` hint: ${opts.hint.replaceAll("\n", "\n ")}`); }