From 59016a7490c5a77054e8877cc48edeb8eedd8570 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=D0=9D=D0=B8=D0=BA=20=28Claude=29?= Date: Thu, 11 Jun 2026 20:14:40 +0300 Subject: [PATCH] =?UTF-8?q?fix:=20restructure=20inbox=20API=20routes=20?= =?UTF-8?q?=E2=80=94=20channel/=20and=20message/=20namespaces?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Next.js не позволяет [channelId] и [id] на одном уровне. Решение: /api/inbox/channel/[channelId]/* и /api/inbox/message/[id]/* InboxTab: все fetch пути обновлены --- app/api/inbox/[channelId]/route.js | 27 ------------------- app/api/inbox/channel/[channelId]/route.js | 16 +++++++++++ .../[channelId]/setup-webhook/route.js | 0 .../inbox/{ => message}/[id]/reply/route.js | 21 +++++---------- .../inbox/{ => message}/[id]/status/route.js | 6 +---- components/InboxTab.js | 8 +++--- 6 files changed, 27 insertions(+), 51 deletions(-) delete mode 100644 app/api/inbox/[channelId]/route.js create mode 100644 app/api/inbox/channel/[channelId]/route.js rename app/api/inbox/{ => channel}/[channelId]/setup-webhook/route.js (100%) rename app/api/inbox/{ => message}/[id]/reply/route.js (56%) rename app/api/inbox/{ => message}/[id]/status/route.js (81%) diff --git a/app/api/inbox/[channelId]/route.js b/app/api/inbox/[channelId]/route.js deleted file mode 100644 index f4b8e64..0000000 --- a/app/api/inbox/[channelId]/route.js +++ /dev/null @@ -1,27 +0,0 @@ -import { NextResponse } from 'next/server'; -import { requireUser } from '@/lib/session'; - -const ENGINE_URL = process.env.ENGINE_URL || 'http://localhost:3030'; -const ENGINE_SECRET = process.env.ENGINE_SECRET || ''; - -async function engineReq(path, opts = {}) { - const { method = 'GET', body, userId } = opts; - const headers = { 'x-internal-secret': ENGINE_SECRET }; - if (userId) headers['x-user-id'] = String(userId); - if (body) headers['Content-Type'] = 'application/json'; - const res = await fetch(`${ENGINE_URL}${path}`, { - method, headers, body: body ? JSON.stringify(body) : undefined, - }); - return res.json(); -} - -export async function GET(req, { params }) { - const user = await requireUser(); - if (!user) return NextResponse.json({ error: 'Unauthorized' }, { status: 401 }); - const { searchParams } = new URL(req.url); - const data = await engineReq( - `/api/inbox/${params.channelId}?${searchParams.toString()}`, - { userId: user.id } - ); - return NextResponse.json(data); -} diff --git a/app/api/inbox/channel/[channelId]/route.js b/app/api/inbox/channel/[channelId]/route.js new file mode 100644 index 0000000..3fd0eaf --- /dev/null +++ b/app/api/inbox/channel/[channelId]/route.js @@ -0,0 +1,16 @@ +import { NextResponse } from 'next/server'; +import { requireUser } from '@/lib/session'; + +const ENGINE_URL = process.env.ENGINE_URL || 'http://localhost:3030'; +const ENGINE_SECRET = process.env.ENGINE_SECRET || ''; + +export async function GET(req, { params }) { + const user = await requireUser(); + if (!user) return NextResponse.json({ error: 'Unauthorized' }, { status: 401 }); + const { searchParams } = new URL(req.url); + const res = await fetch( + `${ENGINE_URL}/api/inbox/${params.channelId}?${searchParams.toString()}`, + { headers: { 'x-internal-secret': ENGINE_SECRET, 'x-user-id': String(user.id) } } + ); + return NextResponse.json(await res.json()); +} diff --git a/app/api/inbox/[channelId]/setup-webhook/route.js b/app/api/inbox/channel/[channelId]/setup-webhook/route.js similarity index 100% rename from app/api/inbox/[channelId]/setup-webhook/route.js rename to app/api/inbox/channel/[channelId]/setup-webhook/route.js diff --git a/app/api/inbox/[id]/reply/route.js b/app/api/inbox/message/[id]/reply/route.js similarity index 56% rename from app/api/inbox/[id]/reply/route.js rename to app/api/inbox/message/[id]/reply/route.js index a4aa500..260870d 100644 --- a/app/api/inbox/[id]/reply/route.js +++ b/app/api/inbox/message/[id]/reply/route.js @@ -4,23 +4,14 @@ import { requireUser } from '@/lib/session'; const ENGINE_URL = process.env.ENGINE_URL || 'http://localhost:3030'; const ENGINE_SECRET = process.env.ENGINE_SECRET || ''; -async function enginePost(path, userId, body) { - const res = await fetch(`${ENGINE_URL}${path}`, { - method: 'POST', - headers: { - 'Content-Type': 'application/json', - 'x-internal-secret': ENGINE_SECRET, - 'x-user-id': String(userId), - }, - body: JSON.stringify(body), - }); - return res.json(); -} - export async function POST(req, { params }) { const user = await requireUser(); if (!user) return NextResponse.json({ error: 'Unauthorized' }, { status: 401 }); const body = await req.json().catch(() => ({})); - const data = await enginePost(`/api/inbox/${params.id}/reply`, user.id, body); - return NextResponse.json(data); + const res = await fetch(`${ENGINE_URL}/api/inbox/${params.id}/reply`, { + method: 'POST', + headers: { 'Content-Type': 'application/json', 'x-internal-secret': ENGINE_SECRET, 'x-user-id': String(user.id) }, + body: JSON.stringify(body), + }); + return NextResponse.json(await res.json()); } diff --git a/app/api/inbox/[id]/status/route.js b/app/api/inbox/message/[id]/status/route.js similarity index 81% rename from app/api/inbox/[id]/status/route.js rename to app/api/inbox/message/[id]/status/route.js index 717c97f..dd72c73 100644 --- a/app/api/inbox/[id]/status/route.js +++ b/app/api/inbox/message/[id]/status/route.js @@ -10,11 +10,7 @@ export async function POST(req, { params }) { const body = await req.json().catch(() => ({})); const res = await fetch(`${ENGINE_URL}/api/inbox/${params.id}/status`, { method: 'POST', - headers: { - 'Content-Type': 'application/json', - 'x-internal-secret': ENGINE_SECRET, - 'x-user-id': String(user.id), - }, + headers: { 'Content-Type': 'application/json', 'x-internal-secret': ENGINE_SECRET, 'x-user-id': String(user.id) }, body: JSON.stringify(body), }); return NextResponse.json(await res.json()); diff --git a/components/InboxTab.js b/components/InboxTab.js index 02d45c6..0cf358e 100644 --- a/components/InboxTab.js +++ b/components/InboxTab.js @@ -49,7 +49,7 @@ export default function InboxTab({ channel }) { const load = useCallback(async (t = tab) => { setLoading(true); try { - const res = await fetch(`/api/inbox/${channel.id}?status=${t}&limit=40`).then(r => r.json()); + const res = await fetch(`/api/inbox/channel/${channel.id}?status=${t}&limit=40`).then(r => r.json()); setMessages(res.messages || []); setTotal(res.total || 0); } catch {} @@ -61,7 +61,7 @@ export default function InboxTab({ channel }) { async function setupWebhook() { setSetuppping(true); try { - const res = await fetch(`/api/inbox/${channel.id}/setup-webhook`, { method: 'POST' }).then(r => r.json()); + const res = await fetch(`/api/inbox/channel/${channel.id}/setup-webhook`, { method: 'POST' }).then(r => r.json()); if (res.ok) { setWebhookOk(true); load(tab); } else alert(res.error || 'Ошибка'); } catch { alert('Ошибка соединения'); } @@ -72,7 +72,7 @@ export default function InboxTab({ channel }) { if (!replyText.trim()) return; setSending(true); try { - const res = await fetch(`/api/inbox/${msg.id}/reply`, { + const res = await fetch(`/api/inbox/message/${msg.id}/reply`, { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify({ text: replyText }), @@ -87,7 +87,7 @@ export default function InboxTab({ channel }) { } async function setStatus(msgId, status) { - await fetch(`/api/inbox/${msgId}/status`, { + await fetch(`/api/inbox/message/${msgId}/status`, { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify({ status }),