S10 (a1): public ledger profiles v1
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
@@ -0,0 +1,31 @@
|
||||
import { NextRequest, NextResponse } from 'next/server';
|
||||
|
||||
export const dynamic = 'force-dynamic';
|
||||
|
||||
const BACKEND_URL = process.env.BACKEND_URL || 'http://localhost:3000';
|
||||
|
||||
/**
|
||||
* Public profile proxy (A1 Session 10) — forwards GET /api/profiles/:handle.
|
||||
* Express owns the privacy rules: unpublished and unknown handles come back
|
||||
* as the SAME 404 body (no existence leak) — this proxy passes it through
|
||||
* untouched.
|
||||
*/
|
||||
export async function GET(
|
||||
req: NextRequest,
|
||||
{ params }: { params: Promise<{ handle: string }> },
|
||||
) {
|
||||
const { handle } = await params;
|
||||
try {
|
||||
const upstream = await fetch(`${BACKEND_URL}/api/profiles/${encodeURIComponent(handle)}`, {
|
||||
headers: { Accept: 'application/json' },
|
||||
cache: 'no-store',
|
||||
});
|
||||
const data = await upstream.json().catch(() => ({ error: 'Profile not found' }));
|
||||
return NextResponse.json(data, {
|
||||
status: upstream.status,
|
||||
headers: upstream.ok ? { 'Cache-Control': 'public, s-maxage=60, stale-while-revalidate=120' } : undefined,
|
||||
});
|
||||
} catch {
|
||||
return NextResponse.json({ error: 'Profile not found' }, { status: 404 });
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,37 @@
|
||||
import { NextRequest, NextResponse } from 'next/server';
|
||||
|
||||
export const dynamic = 'force-dynamic';
|
||||
|
||||
const BACKEND_URL = process.env.BACKEND_URL || 'http://localhost:3000';
|
||||
|
||||
/**
|
||||
* Own-profile proxy (A1 Session 10) — forwards GET/POST /api/profiles/me
|
||||
* with the caller's Authorization header (Express requireAuth resolves the
|
||||
* user; the publish toggle + handle claim live behind it).
|
||||
*/
|
||||
function authHeaders(req: NextRequest): HeadersInit {
|
||||
const auth = req.headers.get('authorization');
|
||||
return { Accept: 'application/json', 'Content-Type': 'application/json', ...(auth ? { Authorization: auth } : {}) };
|
||||
}
|
||||
|
||||
export async function GET(req: NextRequest) {
|
||||
if (!req.headers.get('authorization')) return NextResponse.json({ profile: null }, { status: 401 });
|
||||
try {
|
||||
const upstream = await fetch(`${BACKEND_URL}/api/profiles/me`, { headers: authHeaders(req), cache: 'no-store' });
|
||||
const data = await upstream.json().catch(() => ({ profile: null }));
|
||||
return NextResponse.json(data, { status: upstream.status });
|
||||
} catch {
|
||||
return NextResponse.json({ profile: null }, { status: 200 });
|
||||
}
|
||||
}
|
||||
|
||||
export async function POST(req: NextRequest) {
|
||||
const body = await req.text();
|
||||
try {
|
||||
const upstream = await fetch(`${BACKEND_URL}/api/profiles/me`, { method: 'POST', headers: authHeaders(req), body });
|
||||
const data = await upstream.json().catch(() => ({}));
|
||||
return NextResponse.json(data, { status: upstream.status });
|
||||
} catch {
|
||||
return NextResponse.json({ error: 'Profile service unreachable.' }, { status: 502 });
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user