good forst commit

This commit is contained in:
2026-06-09 02:02:40 +05:30
parent 801c1d7121
commit 249d759e6a
215 changed files with 15425 additions and 1240 deletions
@@ -1,7 +0,0 @@
const API_URL = process.env.API_URL ?? 'http://localhost:3001';
export async function GET(_req: Request, { params }: { params: Promise<{ id: string }> }) {
const { id } = await params;
const res = await fetch(`${API_URL}/accounts/${id}/qr`, { cache: 'no-store' });
return Response.json(await res.json(), { status: res.status });
}
-16
View File
@@ -1,16 +0,0 @@
const API_URL = process.env.API_URL ?? 'http://localhost:3001';
export async function GET() {
const res = await fetch(`${API_URL}/accounts`, { cache: 'no-store' });
return Response.json(await res.json(), { status: res.status });
}
export async function POST(req: Request) {
const body = await req.json();
const res = await fetch(`${API_URL}/accounts`, {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify(body),
});
return Response.json(await res.json(), { status: res.status });
}
@@ -0,0 +1,21 @@
import { getApiBaseUrl, jsonResponse } from '../../../../../_lib/api';
export const dynamic = 'force-dynamic';
export async function POST(req: Request, { params }: { params: Promise<{ id: string }> }): Promise<Response> {
const { id } = await params;
const body = await req.json().catch(() => ({}));
const token = await (await import('next/headers')).cookies().then(c => c.get('tower_super_token')?.value);
const res = await fetch(`${getApiBaseUrl()}/admin/bots/${id}/assign`, {
method: 'POST',
headers: {
'Content-Type': 'application/json',
Accept: 'application/json',
...(token ? { Authorization: `Bearer ${token}` } : {}),
},
body: JSON.stringify(body),
cache: 'no-store',
});
const payload = await res.json();
return jsonResponse(payload, res.status);
}
+18
View File
@@ -0,0 +1,18 @@
import { getApiBaseUrl, jsonResponse } from '../../../../_lib/api';
export const dynamic = 'force-dynamic';
export async function DELETE(_req: Request, { params }: { params: Promise<{ id: string }> }): Promise<Response> {
const { id } = await params;
const token = await (await import('next/headers')).cookies().then(c => c.get('tower_super_token')?.value);
const res = await fetch(`${getApiBaseUrl()}/admin/bots/${id}`, {
method: 'DELETE',
headers: {
Accept: 'application/json',
...(token ? { Authorization: `Bearer ${token}` } : {}),
},
cache: 'no-store',
});
const body = await res.json();
return jsonResponse(body, res.status);
}
@@ -0,0 +1,17 @@
import { getApiBaseUrl, jsonResponse } from '../../../../../_lib/api';
export const dynamic = 'force-dynamic';
export async function GET(_req: Request, { params }: { params: Promise<{ token: string }> }): Promise<Response> {
const { token } = await params;
const tokenCookie = await (await import('next/headers')).cookies().then(c => c.get('tower_super_token')?.value);
const res = await fetch(`${getApiBaseUrl()}/admin/bots/qr/${token}`, {
headers: {
Accept: 'application/json',
...(tokenCookie ? { Authorization: `Bearer ${tokenCookie}` } : {}),
},
cache: 'no-store',
});
const body = await res.json();
return jsonResponse(body, res.status);
}
+33
View File
@@ -0,0 +1,33 @@
import { getApiBaseUrl, jsonResponse } from '../../../_lib/api';
export const dynamic = 'force-dynamic';
export async function GET(): Promise<Response> {
const token = await (await import('next/headers')).cookies().then(c => c.get('tower_super_token')?.value);
const res = await fetch(`${getApiBaseUrl()}/admin/bots`, {
headers: {
Accept: 'application/json',
...(token ? { Authorization: `Bearer ${token}` } : {}),
},
cache: 'no-store',
});
const body = await res.json();
return jsonResponse(body, res.status);
}
export async function POST(req: Request): Promise<Response> {
const body = await req.json().catch(() => ({}));
const token = await (await import('next/headers')).cookies().then(c => c.get('tower_super_token')?.value);
const res = await fetch(`${getApiBaseUrl()}/admin/bots/initiate`, {
method: 'POST',
headers: {
'Content-Type': 'application/json',
Accept: 'application/json',
...(token ? { Authorization: `Bearer ${token}` } : {}),
},
body: JSON.stringify(body),
cache: 'no-store',
});
const payload = await res.json();
return jsonResponse(payload, res.status);
}
@@ -0,0 +1,35 @@
import { getApiBaseUrl, jsonResponse } from '../../../../_lib/api';
export const dynamic = 'force-dynamic';
export async function GET(_req: Request, { params }: { params: Promise<{ id: string }> }): Promise<Response> {
const { id } = await params;
const token = await (await import('next/headers')).cookies().then(c => c.get('tower_super_token')?.value);
const res = await fetch(`${getApiBaseUrl()}/admin/tenants/${id}`, {
headers: {
Accept: 'application/json',
...(token ? { Authorization: `Bearer ${token}` } : {}),
},
cache: 'no-store',
});
const body = await res.json();
return jsonResponse(body, res.status);
}
export async function PATCH(req: Request, { params }: { params: Promise<{ id: string }> }): Promise<Response> {
const { id } = await params;
const body = await req.json().catch(() => ({}));
const token = await (await import('next/headers')).cookies().then(c => c.get('tower_super_token')?.value);
const res = await fetch(`${getApiBaseUrl()}/admin/tenants/${id}`, {
method: 'PATCH',
headers: {
'Content-Type': 'application/json',
Accept: 'application/json',
...(token ? { Authorization: `Bearer ${token}` } : {}),
},
body: JSON.stringify(body),
cache: 'no-store',
});
const payload = await res.json();
return jsonResponse(payload, res.status);
}
+16
View File
@@ -0,0 +1,16 @@
import { getApiBaseUrl, jsonResponse } from '../../../_lib/api';
export const dynamic = 'force-dynamic';
export async function GET(): Promise<Response> {
const token = await (await import('next/headers')).cookies().then(c => c.get('tower_super_token')?.value);
const res = await fetch(`${getApiBaseUrl()}/admin/tenants`, {
headers: {
Accept: 'application/json',
...(token ? { Authorization: `Bearer ${token}` } : {}),
},
cache: 'no-store',
});
const body = await res.json();
return jsonResponse(body, res.status);
}
+19
View File
@@ -0,0 +1,19 @@
import { getApiBaseUrl, jsonResponse } from '../../../_lib/api';
export const dynamic = 'force-dynamic';
export async function POST(req: Request): Promise<Response> {
const body = await req.json();
const upstream = await fetch(`${getApiBaseUrl()}/auth/login`, {
method: 'POST',
headers: { 'Content-Type': 'application/json', Accept: 'application/json' },
body: JSON.stringify(body),
cache: 'no-store',
});
const payload = await upstream.json();
if (!upstream.ok) return jsonResponse(payload, upstream.status);
const token: string | undefined = payload?.token;
if (!token) return jsonResponse({ message: 'Login response missing token' }, 502);
const cookieValue = `tower_token=${token}; Path=/; HttpOnly; SameSite=Lax; Max-Age=${60 * 60 * 24 * 7}`;
return jsonResponse({ admin: payload.admin }, 200, { 'Set-Cookie': cookieValue });
}
+12
View File
@@ -0,0 +1,12 @@
import { TOKEN_COOKIE, jsonResponse } from '../../../_lib/api';
export const dynamic = 'force-dynamic';
export async function POST(): Promise<Response> {
const cookieValue = `${TOKEN_COOKIE}=; Path=/; HttpOnly; SameSite=Lax; Max-Age=0`;
return new Response(null, { status: 204, headers: { 'Set-Cookie': cookieValue } });
}
export function GET(): Response {
return jsonResponse({ message: 'Use POST to log out' }, 405);
}
+9
View File
@@ -0,0 +1,9 @@
import { apiFetch, jsonResponse } from '../../../_lib/api';
export const dynamic = 'force-dynamic';
export async function GET(): Promise<Response> {
const res = await apiFetch('/auth/me');
const body = await res.json();
return jsonResponse(body, res.status);
}
+19
View File
@@ -0,0 +1,19 @@
import { getApiBaseUrl, jsonResponse } from '../../../_lib/api';
export const dynamic = 'force-dynamic';
export async function POST(req: Request): Promise<Response> {
const body = await req.json();
const upstream = await fetch(`${getApiBaseUrl()}/auth/signup`, {
method: 'POST',
headers: { 'Content-Type': 'application/json', Accept: 'application/json' },
body: JSON.stringify(body),
cache: 'no-store',
});
const payload = await upstream.json();
if (!upstream.ok) return jsonResponse(payload, upstream.status);
const token: string | undefined = payload?.token;
if (!token) return jsonResponse({ message: 'Signup response missing token' }, 502);
const cookieValue = `tower_token=${token}; Path=/; HttpOnly; SameSite=Lax; Max-Age=${60 * 60 * 24 * 7}`;
return jsonResponse({ admin: payload.admin }, 200, { 'Set-Cookie': cookieValue });
}
@@ -0,0 +1,19 @@
import { getApiBaseUrl, jsonResponse } from '../../../../_lib/api';
export const dynamic = 'force-dynamic';
export async function POST(req: Request): Promise<Response> {
const body = await req.json().catch(() => ({}));
const res = await fetch(`${getApiBaseUrl()}/auth/super/login`, {
method: 'POST',
headers: { 'Content-Type': 'application/json', Accept: 'application/json' },
body: JSON.stringify(body),
cache: 'no-store',
});
const payload = await res.json();
const headers: Record<string, string> = {};
if (res.ok && payload.token) {
headers['Set-Cookie'] = `tower_super_token=${payload.token}; Path=/; HttpOnly; SameSite=Lax; Max-Age=${7 * 24 * 60 * 60}`;
}
return jsonResponse(payload, res.status, headers);
}
@@ -0,0 +1,9 @@
import { jsonResponse } from '../../../../_lib/api';
export const dynamic = 'force-dynamic';
export async function POST(): Promise<Response> {
return jsonResponse({ ok: true }, 200, {
'Set-Cookie': 'tower_super_token=; Path=/; HttpOnly; SameSite=Lax; Max-Age=0',
});
}
+16
View File
@@ -0,0 +1,16 @@
import { getApiBaseUrl, jsonResponse } from '../../../../_lib/api';
export const dynamic = 'force-dynamic';
export async function GET(): Promise<Response> {
const token = await (await import('next/headers')).cookies().then(c => c.get('tower_super_token')?.value);
const res = await fetch(`${getApiBaseUrl()}/auth/super/me`, {
headers: {
Accept: 'application/json',
...(token ? { Authorization: `Bearer ${token}` } : {}),
},
cache: 'no-store',
});
const body = await res.json();
return jsonResponse(body, res.status);
}
+13
View File
@@ -0,0 +1,13 @@
import { apiFetch, jsonResponse } from '../../../_lib/api';
export const dynamic = 'force-dynamic';
export async function DELETE(
_req: Request,
{ params }: { params: Promise<{ id: string }> },
): Promise<Response> {
const { id } = await params;
const res = await apiFetch(`/admin/bot/${id}`, { method: 'DELETE' });
const payload = await res.json().catch(() => ({}));
return jsonResponse(payload, res.status);
}
+15
View File
@@ -0,0 +1,15 @@
import { apiFetch, jsonResponse } from '../../../_lib/api';
export const dynamic = 'force-dynamic';
export async function POST(req: Request): Promise<Response> {
const body = await req.json();
const res = await apiFetch('/admin/bot/attach', {
method: 'POST',
headers: { 'Content-Type': 'application/json', Accept: 'application/json' },
body: JSON.stringify(body),
}).catch(() => null);
if (!res) return jsonResponse({ message: 'Upstream unavailable' }, 502);
const payload = await res.json();
return jsonResponse(payload, res.status);
}
+20
View File
@@ -0,0 +1,20 @@
import { getApiBaseUrl, getToken, jsonResponse } from '../../../_lib/api';
export const dynamic = 'force-dynamic';
export async function POST(req: Request): Promise<Response> {
const body = await req.json().catch(() => ({}));
const token = await getToken();
const res = await fetch(`${getApiBaseUrl()}/admin/bot/initiate`, {
method: 'POST',
headers: {
'Content-Type': 'application/json',
Accept: 'application/json',
...(token ? { Authorization: `Bearer ${token}` } : {}),
},
body: JSON.stringify(body),
cache: 'no-store',
});
const payload = await res.json();
return jsonResponse(payload, res.status);
}
+13
View File
@@ -0,0 +1,13 @@
import { apiFetch, jsonResponse } from '../../../../_lib/api';
export const dynamic = 'force-dynamic';
export async function GET(
_req: Request,
{ params }: { params: Promise<{ token: string }> },
): Promise<Response> {
const { token } = await params;
const res = await apiFetch(`/admin/bot/qr/${token}`);
const payload = await res.json();
return jsonResponse(payload, res.status);
}
+17
View File
@@ -0,0 +1,17 @@
import { getApiBaseUrl, getToken, jsonResponse } from '../../../_lib/api';
export const dynamic = 'force-dynamic';
export async function POST(): Promise<Response> {
const token = await getToken();
const res = await fetch(`${getApiBaseUrl()}/admin/bot/reveal`, {
method: 'POST',
headers: {
Accept: 'application/json',
...(token ? { Authorization: `Bearer ${token}` } : {}),
},
cache: 'no-store',
});
const payload = await res.json();
return jsonResponse(payload, res.status);
}
+10
View File
@@ -0,0 +1,10 @@
import { apiFetch, jsonResponse } from '../../_lib/api';
export const dynamic = 'force-dynamic';
export async function GET(): Promise<Response> {
const res = await apiFetch('/admin/bot').catch(() => null);
if (!res) return jsonResponse({ message: 'Upstream unavailable' }, 502);
const body = await res.json();
return jsonResponse(body, res.status);
}
@@ -0,0 +1,17 @@
import { apiFetch, jsonResponse } from '../../../../_lib/api';
export const dynamic = 'force-dynamic';
export async function POST(
req: Request,
{ params }: { params: Promise<{ id: string }> },
): Promise<Response> {
const { id } = await params;
const body = await req.json();
const res = await apiFetch(`/admin/groups/${id}/share`, {
method: 'POST',
body: JSON.stringify(body),
});
const payload = await res.json();
return jsonResponse(payload, res.status);
}
@@ -0,0 +1,14 @@
import { apiFetch } from '../../../../../_lib/api';
export const dynamic = 'force-dynamic';
export async function DELETE(
_req: Request,
{ params }: { params: Promise<{ id: string; targetTenantId: string }> },
): Promise<Response> {
const { id, targetTenantId } = await params;
const res = await apiFetch(`/admin/groups/${id}/share/${targetTenantId}`, { method: 'DELETE' });
if (res.status === 204) return new Response(null, { status: 204 });
const body = await res.text();
return new Response(body, { status: res.status, headers: { 'Content-Type': 'application/json' } });
}
@@ -0,0 +1,12 @@
import { apiFetch, jsonResponse } from '../../../_lib/api';
export const dynamic = 'force-dynamic';
export async function GET(req: Request): Promise<Response> {
const { searchParams } = new URL(req.url);
const token = searchParams.get('token');
if (!token) return new Response(JSON.stringify({ message: 'token required' }), { status: 400 });
const res = await apiFetch(`/admin/groups/claim-token-info?token=${encodeURIComponent(token)}`);
const body = await res.json();
return jsonResponse(body, res.status);
}
@@ -0,0 +1,13 @@
import { apiFetch, jsonResponse } from '../../../_lib/api';
export const dynamic = 'force-dynamic';
export async function POST(req: Request): Promise<Response> {
const body = await req.json();
const res = await apiFetch('/admin/groups/claim-with-token', {
method: 'POST',
body: JSON.stringify(body),
});
const payload = await res.json();
return jsonResponse(payload, res.status);
}
@@ -0,0 +1,9 @@
import { apiFetch, jsonResponse } from '../../../_lib/api';
export const dynamic = 'force-dynamic';
export async function GET(): Promise<Response> {
const res = await apiFetch('/groups/shared-by-me');
const body = await res.json();
return jsonResponse(body, res.status);
}
+9
View File
@@ -0,0 +1,9 @@
import { apiFetch, jsonResponse } from '../../../_lib/api';
export const dynamic = 'force-dynamic';
export async function GET(): Promise<Response> {
const res = await apiFetch('/groups/shared');
const body = await res.json();
return jsonResponse(body, res.status);
}
@@ -0,0 +1,19 @@
import { apiFetch, jsonResponse } from '../../../../_lib/api';
export const dynamic = 'force-dynamic';
export async function POST(
_req: Request,
{ params }: { params: Promise<{ id: string }> },
): Promise<Response> {
const { id } = await params;
const res = await apiFetch(`/admin/messages/${id}/approve`, { method: 'POST' });
const body = await res.text();
let payload: unknown = body;
try {
payload = JSON.parse(body);
} catch {
/* keep as text */
}
return jsonResponse(payload, res.status);
}
+13
View File
@@ -0,0 +1,13 @@
import { apiFetch, jsonResponse } from '../../../_lib/api';
export const dynamic = 'force-dynamic';
export async function GET(
_req: Request,
{ params }: { params: Promise<{ id: string }> },
): Promise<Response> {
const { id } = await params;
const res = await apiFetch(`/admin/messages/${id}`);
const body = await res.json();
return jsonResponse(body, res.status);
}
@@ -0,0 +1,9 @@
import { apiFetch, jsonResponse } from '../../../../_lib/api';
export const dynamic = 'force-dynamic';
export async function GET(): Promise<Response> {
const res = await apiFetch('/admin/messages/pending/count');
const body = await res.json();
return jsonResponse(body, res.status);
}
@@ -0,0 +1,9 @@
import { apiFetch, jsonResponse } from '../../../_lib/api';
export const dynamic = 'force-dynamic';
export async function GET(_req: Request): Promise<Response> {
const res = await apiFetch('/admin/messages/pending');
const body = await res.json();
return jsonResponse(body, res.status);
}
+15
View File
@@ -0,0 +1,15 @@
import { clearMemberCookie, jsonResponse, memberApiFetch } from '../../../_lib/api';
export const dynamic = 'force-dynamic';
export async function DELETE(): Promise<Response> {
const res = await memberApiFetch('/my/account', { method: 'DELETE' });
if (res.status === 204) {
return new Response(null, {
status: 204,
headers: { 'Set-Cookie': clearMemberCookie() },
});
}
const body = await res.json().catch(() => ({}));
return jsonResponse(body, res.status, { 'Set-Cookie': clearMemberCookie() });
}
+13
View File
@@ -0,0 +1,13 @@
import { jsonResponse, memberApiFetch } from '../../../../_lib/api';
export const dynamic = 'force-dynamic';
export async function GET(
_req: Request,
{ params }: { params: Promise<{ id: string }> },
): Promise<Response> {
const { id } = await params;
const res = await memberApiFetch(`/my/groups/${id}`);
const body = await res.json();
return jsonResponse(body, res.status);
}
+9
View File
@@ -0,0 +1,9 @@
import { jsonResponse, memberApiFetch } from '../../../_lib/api';
export const dynamic = 'force-dynamic';
export async function GET(): Promise<Response> {
const res = await memberApiFetch('/my/groups');
const body = await res.json();
return jsonResponse(body, res.status);
}
+7
View File
@@ -0,0 +1,7 @@
import { clearMemberCookie } from '../../../_lib/api';
export const dynamic = 'force-dynamic';
export async function POST(): Promise<Response> {
return new Response(null, { status: 204, headers: { 'Set-Cookie': clearMemberCookie() } });
}
+10
View File
@@ -0,0 +1,10 @@
import { jsonResponse, memberApiFetch } from '../../../_lib/api';
export const dynamic = 'force-dynamic';
export async function POST(req: Request): Promise<Response> {
const body = await req.json();
const res = await memberApiFetch('/my/opt-in', { method: 'POST', body: JSON.stringify(body) });
const payload = await res.json();
return jsonResponse(payload, res.status);
}
+10
View File
@@ -0,0 +1,10 @@
import { jsonResponse, memberApiFetch } from '../../../_lib/api';
export const dynamic = 'force-dynamic';
export async function POST(req: Request): Promise<Response> {
const body = await req.json();
const res = await memberApiFetch('/my/opt-out', { method: 'POST', body: JSON.stringify(body) });
const payload = await res.json();
return jsonResponse(payload, res.status);
}
+9
View File
@@ -0,0 +1,9 @@
import { jsonResponse, memberApiFetch } from '../../../_lib/api';
export const dynamic = 'force-dynamic';
export async function GET(): Promise<Response> {
const res = await memberApiFetch('/my/profile');
const body = await res.json();
return jsonResponse(body, res.status);
}
@@ -0,0 +1,30 @@
import { buildMemberCookie, getApiBaseUrl, jsonResponse } from '../../../_lib/api';
export const dynamic = 'force-dynamic';
export async function POST(req: Request): Promise<Response> {
const body = await req.json().catch(() => ({}));
const upstream = await fetch(`${getApiBaseUrl()}/public/auth/verify-otp`, {
method: 'POST',
headers: { 'Content-Type': 'application/json', Accept: 'application/json' },
body: JSON.stringify(body),
cache: 'no-store',
});
const payload = (await upstream.json().catch(() => ({}))) as {
memberToken?: string;
user?: { id: string; tenantId: string; jid: string; displayName: string | null };
consent?: { scopes: string[]; retentionDays: number; policyVersion: string };
message?: string;
};
if (!upstream.ok) {
return jsonResponse(payload, upstream.status);
}
if (!payload.memberToken) {
return jsonResponse({ message: 'Upstream response missing memberToken' }, 502);
}
return jsonResponse(
{ user: payload.user, consent: payload.consent },
200,
{ 'Set-Cookie': buildMemberCookie(payload.memberToken) },
);
}
+7 -4
View File
@@ -1,11 +1,14 @@
const API_URL = process.env.API_URL ?? 'http://localhost:3001';
import { apiFetch } from '../../../_lib/api';
export const dynamic = 'force-dynamic';
export async function DELETE(
_req: Request,
{ params }: { params: Promise<{ id: string }> },
) {
): Promise<Response> {
const { id } = await params;
const res = await fetch(`${API_URL}/routes/${id}`, { method: 'DELETE' });
const res = await apiFetch(`/routes/${id}`, { method: 'DELETE' });
if (res.status === 204) return new Response(null, { status: 204 });
return Response.json(await res.json(), { status: res.status });
const body = await res.text();
return new Response(body, { status: res.status, headers: { 'Content-Type': 'application/json' } });
}
+13
View File
@@ -0,0 +1,13 @@
import { apiFetch, jsonResponse } from '../../../_lib/api';
export const dynamic = 'force-dynamic';
export async function POST(req: Request): Promise<Response> {
const body = await req.json();
const res = await apiFetch('/routes/batch', {
method: 'POST',
body: JSON.stringify(body),
});
const payload = await res.json();
return jsonResponse(payload, res.status);
}
+13 -10
View File
@@ -1,19 +1,22 @@
const API_URL = process.env.API_URL ?? 'http://localhost:3001';
import { apiFetch, jsonResponse } from '../../_lib/api';
export async function GET(req: Request) {
export const dynamic = 'force-dynamic';
export async function GET(req: Request): Promise<Response> {
const { searchParams } = new URL(req.url);
const url = new URL(`${API_URL}/routes`);
searchParams.forEach((v, k) => url.searchParams.set(k, v));
const res = await fetch(url, { cache: 'no-store' });
return Response.json(await res.json(), { status: res.status });
const query = searchParams.toString();
const path = query ? `/routes?${query}` : '/routes';
const res = await apiFetch(path);
const body = await res.json();
return jsonResponse(body, res.status);
}
export async function POST(req: Request) {
export async function POST(req: Request): Promise<Response> {
const body = await req.json();
const res = await fetch(`${API_URL}/routes`, {
const res = await apiFetch('/routes', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify(body),
});
return Response.json(await res.json(), { status: res.status });
const payload = await res.json();
return jsonResponse(payload, res.status);
}
+28
View File
@@ -0,0 +1,28 @@
import { apiFetch, jsonResponse } from '../../../_lib/api';
export const dynamic = 'force-dynamic';
export async function PUT(
req: Request,
{ params }: { params: Promise<{ id: string }> },
): Promise<Response> {
const { id } = await params;
const body = await req.json();
const res = await apiFetch(`/admin/rules/${id}`, {
method: 'PUT',
body: JSON.stringify(body),
});
const payload = await res.json();
return jsonResponse(payload, res.status);
}
export async function DELETE(
_req: Request,
{ params }: { params: Promise<{ id: string }> },
): Promise<Response> {
const { id } = await params;
const res = await apiFetch(`/admin/rules/${id}`, { method: 'DELETE' });
if (res.status === 204) return new Response(null, { status: 204 });
const body = await res.text();
return new Response(body, { status: res.status, headers: { 'Content-Type': 'application/json' } });
}
+19
View File
@@ -0,0 +1,19 @@
import { apiFetch, jsonResponse } from '../../_lib/api';
export const dynamic = 'force-dynamic';
export async function GET(): Promise<Response> {
const res = await apiFetch('/admin/rules');
const body = await res.json();
return jsonResponse(body, res.status);
}
export async function POST(req: Request): Promise<Response> {
const body = await req.json();
const res = await apiFetch('/admin/rules', {
method: 'POST',
body: JSON.stringify(body),
});
const payload = await res.json();
return jsonResponse(payload, res.status);
}