diff --git a/src/app/api/[...path]/proxy-ipfs.ts b/src/app/api/[...path]/proxy-ipfs.ts index 31a019a..3c1d3cf 100644 --- a/src/app/api/[...path]/proxy-ipfs.ts +++ b/src/app/api/[...path]/proxy-ipfs.ts @@ -1,7 +1,20 @@ import { NextRequest, NextResponse } from 'next/server'; import { kuboApiUrl, kuboBasicAuth } from '@/lib/config'; +import { localListPins, localAddPin, localRemovePin } from '@/lib/local-pins'; export async function proxyIPFS(path: string, method: string, req: NextRequest): Promise { + // Normalize path + const p = path.replace(/^\/+/, '').replace(/\/+$/, ''); + + // ── Lokale pin opslag (zonder Kubo) ── + // Wanneer KUBO_API_URL niet beschikbaar is, gebruik lokale JSON file + if (p === 'pins' || p.startsWith('pins/')) { + const kuboSvc = kuboApiUrl(); + if (!kuboSvc) { + return handleLocalPins(p, method, req); + } + } + // In dev, the Kubo API is behind nginx with Basic Auth. // If no KUBO_API_URL is configured, return a clear error. const kuboSvc = kuboApiUrl(); @@ -75,6 +88,44 @@ export async function proxyIPFS(path: string, method: string, req: NextRequest): }); } +/** Lokale pin handler — werkt zonder Kubo API */ +async function handleLocalPins(path: string, method: string, req: NextRequest): Promise { + const p = path.replace(/^\/+/, '').replace(/\/+$/, ''); + + // GET /api/pins — lijst alle pins + if (p === 'pins' && method === 'GET') { + const pins = await localListPins(); + // Retourneer in Kubo-formaat voor backwards compatibiliteit + const Keys: Record = {}; + for (const pin of pins) { + Keys[pin.cid] = { Type: pin.created || 'indirect' }; + } + return NextResponse.json({ Keys }); + } + + // POST /api/pins — pin een CID + if (p === 'pins' && method === 'POST') { + try { + const body = await req.json(); + const { cid, name, size } = body; + if (!cid) return NextResponse.json({ error: 'cid required' }, { status: 400 }); + await localAddPin(cid, name, size || 0); + return NextResponse.json({ cid }); + } catch { + return NextResponse.json({ error: 'Invalid request' }, { status: 400 }); + } + } + + // DELETE /api/pins/ — verwijder pin + if (p.startsWith('pins/') && method === 'DELETE') { + const cid = p.slice(5); + await localRemovePin(cid); + return NextResponse.json({ ok: true }); + } + + return NextResponse.json({ error: 'Not found' }, { status: 404 }); +} + export function mapToKuboAPI(path: string, method: string): string { // Normalize: /api/node/info → /api/v0/id, etc. const p = path.replace(/^\/+/, '').replace(/\/+$/, ''); diff --git a/src/lib/local-pins.ts b/src/lib/local-pins.ts new file mode 100644 index 0000000..930d75d --- /dev/null +++ b/src/lib/local-pins.ts @@ -0,0 +1,63 @@ +/** + * Local pin storage — JSON file based + * Gebruikt wanneer KUBO_API_URL niet beschikbaar is (development/local). + */ + +import { readFile, writeFile, mkdir } from 'fs/promises'; +import { join } from 'path'; + +const PIN_FILE = join(process.cwd(), '.data', 'pins.json'); + +interface PinRecord { + cid: string; + name: string; + size: number; + created: string; +} + +async function ensureDir() { + const dir = join(process.cwd(), '.data'); + await mkdir(dir, { recursive: true }); +} + +async function readPins(): Promise> { + try { + const data = await readFile(PIN_FILE, 'utf-8'); + return JSON.parse(data); + } catch { + return {}; + } +} + +async function writePins(pins: Record): Promise { + await ensureDir(); + await writeFile(PIN_FILE, JSON.stringify(pins, null, 2), 'utf-8'); +} + +export async function localListPins(): Promise { + const pins = await readPins(); + return Object.values(pins); +} + +export async function localAddPin(cid: string, name?: string, size: number = 0): Promise<{ cid: string }> { + const pins = await readPins(); + pins[cid] = { + cid, + name: name || '', + size, + created: new Date().toISOString(), + }; + await writePins(pins); + return { cid }; +} + +export async function localRemovePin(cid: string): Promise { + const pins = await readPins(); + delete pins[cid]; + await writePins(pins); +} + +export async function localGetPinCount(): Promise { + const pins = await readPins(); + return Object.keys(pins).length; +}