From 01f2c166cb43b9730d86fb6a1aa1e4ab6e220c46 Mon Sep 17 00:00:00 2001 From: Claude Date: Wed, 14 Jan 2026 13:04:01 +0000 Subject: [PATCH] fix: Improve error handling for NIP-86 network/CORS errors - Add Nip86NetworkError class to detect CORS and network failures - Provide helpful error message when fetch fails due to CORS - Update RelayAdminViewer to show specific CORS error messaging --- src/components/RelayAdminViewer.tsx | 8 +++++ src/lib/nip86-client.ts | 47 ++++++++++++++++++++++++----- 2 files changed, 47 insertions(+), 8 deletions(-) diff --git a/src/components/RelayAdminViewer.tsx b/src/components/RelayAdminViewer.tsx index 9283d8d..b3c3c6c 100644 --- a/src/components/RelayAdminViewer.tsx +++ b/src/components/RelayAdminViewer.tsx @@ -31,6 +31,7 @@ import { import { Nip86Client, Nip86AuthError, + Nip86NetworkError, categoryHasMethods, } from "@/lib/nip86-client"; import accountManager from "@/services/accounts"; @@ -92,6 +93,13 @@ export function RelayAdminViewer({ url }: RelayAdminViewerProps) { } catch (error) { if (error instanceof Nip86AuthError) { setMethodsError("Unauthorized - you may not have admin access"); + } else if (error instanceof Nip86NetworkError) { + // Network/CORS error - provide helpful messaging + setMethodsError( + error.isCorsLikely + ? "Cannot connect to relay API. The relay may not support NIP-86, or CORS is blocking the request." + : error.message, + ); } else { setMethodsError( error instanceof Error ? error.message : "Failed to fetch methods", diff --git a/src/lib/nip86-client.ts b/src/lib/nip86-client.ts index 34f0f49..31e291d 100644 --- a/src/lib/nip86-client.ts +++ b/src/lib/nip86-client.ts @@ -52,6 +52,17 @@ export class Nip86AuthError extends Nip86Error { } } +/** NIP-86 network/CORS error */ +export class Nip86NetworkError extends Nip86Error { + constructor( + message: string = "Network error", + public readonly isCorsLikely: boolean = false, + ) { + super(message); + this.name = "Nip86NetworkError"; + } +} + /** * NIP-86 Relay Management API Client * @@ -93,14 +104,34 @@ export class Nip86Client { this.sign, ); - const response = await fetch(this.httpUrl, { - method: "POST", - headers: { - "Content-Type": CONTENT_TYPE, - Authorization: authHeader, - }, - body, - }); + let response: Response; + try { + response = await fetch(this.httpUrl, { + method: "POST", + headers: { + "Content-Type": CONTENT_TYPE, + Authorization: authHeader, + }, + body, + }); + } catch (error) { + // Network errors (including CORS) throw TypeError with "Failed to fetch" + const message = + error instanceof Error ? error.message : "Network request failed"; + + // "Failed to fetch" is the typical CORS or network error message + const isCorsLikely = + message.toLowerCase().includes("failed to fetch") || + message.toLowerCase().includes("network") || + message.toLowerCase().includes("cors"); + + throw new Nip86NetworkError( + isCorsLikely + ? "Network error - relay may not support CORS or NIP-86" + : message, + isCorsLikely, + ); + } if (response.status === 401) { throw new Nip86AuthError();