From 159b1757748764fb64982fce13b1025b59f7b409 Mon Sep 17 00:00:00 2001 From: Hermes Date: Thu, 9 Apr 2026 21:20:15 -0500 Subject: [PATCH] Replace catch-all proxy with dedicated routes, add 404 page - Dedicated proxy routes for sessions, messages, search, memory, config - Removes [...path] catch-all that conflicted with specific routes - Session detail + delete proxy - Custom 404 page matching design system --- app/api/[...path]/route.ts | 63 ------------------------- app/api/config/route.ts | 17 +++++++ app/api/memory/route.ts | 27 +++++++++++ app/api/sessions/[id]/messages/route.ts | 18 +++++++ app/api/sessions/[id]/route.ts | 31 ++++++++++++ app/api/sessions/route.ts | 14 ++++++ app/api/sessions/search/route.ts | 17 +++++++ app/not-found.tsx | 17 +++++++ 8 files changed, 141 insertions(+), 63 deletions(-) delete mode 100644 app/api/[...path]/route.ts create mode 100644 app/api/config/route.ts create mode 100644 app/api/memory/route.ts create mode 100644 app/api/sessions/[id]/messages/route.ts create mode 100644 app/api/sessions/[id]/route.ts create mode 100644 app/api/sessions/search/route.ts create mode 100644 app/not-found.tsx diff --git a/app/api/[...path]/route.ts b/app/api/[...path]/route.ts deleted file mode 100644 index 30ea081..0000000 --- a/app/api/[...path]/route.ts +++ /dev/null @@ -1,63 +0,0 @@ -import { NextRequest, NextResponse } from "next/server"; - -const BACKEND = process.env.HERMES_BACKEND_URL || "http://127.0.0.1:8643"; - -export async function GET(req: NextRequest, { params }: { params: Promise<{ path: string[] }> }) { - const { path } = await params; - const target = path.join("/"); - const qs = req.nextUrl.search; - const res = await fetch(`${BACKEND}/api/${target}${qs}`); - const data = await res.text(); - return new NextResponse(data, { - status: res.status, - headers: { "content-type": res.headers.get("content-type") || "application/json" }, - }); -} - -export async function POST(req: NextRequest, { params }: { params: Promise<{ path: string[] }> }) { - const { path } = await params; - const target = path.join("/"); - const body = await req.text(); - const res = await fetch(`${BACKEND}/api/${target}`, { - method: "POST", - headers: { "content-type": "application/json" }, - body, - }); - const data = await res.text(); - return new NextResponse(data, { - status: res.status, - headers: { "content-type": res.headers.get("content-type") || "application/json" }, - }); -} - -export async function PATCH(req: NextRequest, { params }: { params: Promise<{ path: string[] }> }) { - const { path } = await params; - const target = path.join("/"); - const body = await req.text(); - const res = await fetch(`${BACKEND}/api/${target}`, { - method: "PATCH", - headers: { "content-type": "application/json" }, - body, - }); - const data = await res.text(); - return new NextResponse(data, { - status: res.status, - headers: { "content-type": res.headers.get("content-type") || "application/json" }, - }); -} - -export async function DELETE(req: NextRequest, { params }: { params: Promise<{ path: string[] }> }) { - const { path } = await params; - const target = path.join("/"); - const body = await req.text(); - const res = await fetch(`${BACKEND}/api/${target}`, { - method: "DELETE", - headers: { "content-type": "application/json" }, - body: body || undefined, - }); - const data = await res.text(); - return new NextResponse(data, { - status: res.status, - headers: { "content-type": res.headers.get("content-type") || "application/json" }, - }); -} diff --git a/app/api/config/route.ts b/app/api/config/route.ts new file mode 100644 index 0000000..7f509cd --- /dev/null +++ b/app/api/config/route.ts @@ -0,0 +1,17 @@ +import { NextRequest, NextResponse } from "next/server"; + +const BACKEND = process.env.HERMES_BACKEND_URL || "http://127.0.0.1:8643"; + +export async function GET(req: NextRequest) { + const qs = req.nextUrl.search; + try { + const res = await fetch(BACKEND + "/api/config" + qs); + const data = await res.text(); + return new NextResponse(data, { + status: res.status, + headers: { "content-type": "application/json" }, + }); + } catch { + return NextResponse.json({ error: "backend unreachable" }, { status: 502 }); + } +} diff --git a/app/api/memory/route.ts b/app/api/memory/route.ts new file mode 100644 index 0000000..b028929 --- /dev/null +++ b/app/api/memory/route.ts @@ -0,0 +1,27 @@ +import { NextRequest, NextResponse } from "next/server"; + +const BACKEND = process.env.HERMES_BACKEND_URL || "http://127.0.0.1:8643"; + +async function proxy(method: string, req: NextRequest) { + const qs = req.nextUrl.search; + const body = method !== "GET" ? await req.text() : undefined; + try { + const res = await fetch(BACKEND + "/api/memory" + qs, { + method, + headers: body ? { "Content-Type": "application/json" } : {}, + body, + }); + const data = await res.text(); + return new NextResponse(data, { + status: res.status, + headers: { "content-type": "application/json" }, + }); + } catch { + return NextResponse.json({ error: "backend unreachable" }, { status: 502 }); + } +} + +export async function GET(req: NextRequest) { return proxy("GET", req); } +export async function POST(req: NextRequest) { return proxy("POST", req); } +export async function PATCH(req: NextRequest) { return proxy("PATCH", req); } +export async function DELETE(req: NextRequest) { return proxy("DELETE", req); } diff --git a/app/api/sessions/[id]/messages/route.ts b/app/api/sessions/[id]/messages/route.ts new file mode 100644 index 0000000..c8573c1 --- /dev/null +++ b/app/api/sessions/[id]/messages/route.ts @@ -0,0 +1,18 @@ +import { NextRequest, NextResponse } from "next/server"; + +const BACKEND = process.env.HERMES_BACKEND_URL || "http://127.0.0.1:8643"; + +export async function GET(req: NextRequest, { params }: { params: Promise<{ id: string }> }) { + const { id } = await params; + const qs = req.nextUrl.search; + try { + const res = await fetch(BACKEND + "/api/sessions/" + id + "/messages" + qs); + const data = await res.text(); + return new NextResponse(data, { + status: res.status, + headers: { "content-type": "application/json" }, + }); + } catch { + return NextResponse.json({ items: [], total: 0 }, { status: 502 }); + } +} diff --git a/app/api/sessions/[id]/route.ts b/app/api/sessions/[id]/route.ts new file mode 100644 index 0000000..0ef41ad --- /dev/null +++ b/app/api/sessions/[id]/route.ts @@ -0,0 +1,31 @@ +import { NextRequest, NextResponse } from "next/server"; + +const BACKEND = process.env.HERMES_BACKEND_URL || "http://127.0.0.1:8643"; + +export async function GET(_req: NextRequest, { params }: { params: Promise<{ id: string }> }) { + const { id } = await params; + try { + const res = await fetch(BACKEND + "/api/sessions/" + id); + const data = await res.text(); + return new NextResponse(data, { + status: res.status, + headers: { "content-type": "application/json" }, + }); + } catch { + return NextResponse.json({ error: "backend unreachable" }, { status: 502 }); + } +} + +export async function DELETE(_req: NextRequest, { params }: { params: Promise<{ id: string }> }) { + const { id } = await params; + try { + const res = await fetch(BACKEND + "/api/sessions/" + id, { method: "DELETE" }); + const data = await res.text(); + return new NextResponse(data, { + status: res.status, + headers: { "content-type": "application/json" }, + }); + } catch { + return NextResponse.json({ error: "backend unreachable" }, { status: 502 }); + } +} diff --git a/app/api/sessions/route.ts b/app/api/sessions/route.ts index 69957e3..80b722a 100644 --- a/app/api/sessions/route.ts +++ b/app/api/sessions/route.ts @@ -2,6 +2,20 @@ import { NextRequest, NextResponse } from "next/server"; const BACKEND = process.env.HERMES_BACKEND_URL || "http://127.0.0.1:8643"; +export async function GET(req: NextRequest) { + const qs = req.nextUrl.search; + try { + const res = await fetch(BACKEND + "/api/sessions" + qs); + const data = await res.text(); + return new NextResponse(data, { + status: res.status, + headers: { "content-type": "application/json" }, + }); + } catch { + return NextResponse.json({ items: [], total: 0 }, { status: 502 }); + } +} + export async function POST(req: NextRequest) { const body = await req.text(); try { diff --git a/app/api/sessions/search/route.ts b/app/api/sessions/search/route.ts new file mode 100644 index 0000000..27f2f87 --- /dev/null +++ b/app/api/sessions/search/route.ts @@ -0,0 +1,17 @@ +import { NextRequest, NextResponse } from "next/server"; + +const BACKEND = process.env.HERMES_BACKEND_URL || "http://127.0.0.1:8643"; + +export async function GET(req: NextRequest) { + const qs = req.nextUrl.search; + try { + const res = await fetch(BACKEND + "/api/sessions/search" + qs); + const data = await res.text(); + return new NextResponse(data, { + status: res.status, + headers: { "content-type": "application/json" }, + }); + } catch { + return NextResponse.json({ query: "", count: 0, results: [] }, { status: 502 }); + } +} diff --git a/app/not-found.tsx b/app/not-found.tsx new file mode 100644 index 0000000..ac90c76 --- /dev/null +++ b/app/not-found.tsx @@ -0,0 +1,17 @@ +import Link from "next/link"; + +export default function NotFound() { + return ( +
+
404
+

Page not found

+ + Back to Pulse + +
+ ); +}