From 08de5a40645386b4b2dc7d693bd7600c1fbb4b7c Mon Sep 17 00:00:00 2001 From: josh Date: Sat, 12 Sep 2026 09:28:15 -0400 Subject: [PATCH] Unwrap fetch errors + show URL in Komodo probe result MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The probe surfaced "unreachable: This operation was aborted" — technically correct (an AbortController fired the fetch timeout) but useless for diagnosing whether it's a wrong URL, blocked route, or firewall. Node's fetch also hides real network causes (ECONNREFUSED, ENOTFOUND, EHOSTUNREACH) under `.cause`, and the default message just says "fetch failed". describeFetchError() now unwraps AbortError to "timed out after 10000ms dialing " and pulls `.cause.code/.cause.message` for network failures. KomodoPortResult gains a `url` field, always populated, so the probe panel can surface the exact URL we dialed in a code block — operators can then `curl` it from the container to confirm reachability. komodoRestart benefits from the same unwrapping since it uses the same komodoCall() transport. Co-Authored-By: Claude Opus 4.7 --- src/lib/server/integrations/komodo.ts | 43 ++++++++++++++++++++++---- src/routes/servers/[name]/+page.svelte | 31 +++++++++++++++++++ 2 files changed, 68 insertions(+), 6 deletions(-) diff --git a/src/lib/server/integrations/komodo.ts b/src/lib/server/integrations/komodo.ts index 15d9639..dce4670 100644 --- a/src/lib/server/integrations/komodo.ts +++ b/src/lib/server/integrations/komodo.ts @@ -56,11 +56,13 @@ export async function komodoRestart(serverName: string): Promise + {#if komodoProbe.url} +
+ tried + {komodoProbe.url} +
+ {/if} {#if komodoProbe.reason}
{komodoFixHint(komodoProbe.reason, komodoProbe.httpStatus)}
{/if} @@ -505,6 +512,30 @@ } .probe-detail strong { color: var(--spark-500); } + .probe-url { + display: flex; + align-items: baseline; + gap: 8px; + margin-top: 8px; + padding: 6px 12px; + background: var(--cherry-875); + border-radius: var(--r-sm); + border: 1px solid var(--cherry-700); + font-size: 11px; + } + .probe-url .k { + color: var(--ink-500); + font-family: var(--font-body); + font-size: 10px; + text-transform: uppercase; + letter-spacing: 1px; + } + .probe-url code { + color: var(--cream); + font-family: var(--font-mono); + word-break: break-all; + } + .snippet-details { margin-top: 10px; font-family: var(--font-mono);