Files
IPFS-portal/src/lib/api.ts.bak
T
maikrolf f72b775379 refactor: codebase opschoning — type safety, error handling, central config, page splits
- categorie A: alle catch(e: any) → catch(e: unknown) met instanceof check
- categorie B: stille .catch() logging toegevoegd (SWRegister, admin, upload, auth)
- categorie C: hardcoded 192.168.1.176 IPs vervangen door env var defaults
- categorie D: page files >250L gesplitst (history, settings, explorer, admin/payment,
  ipns, users, upload, dashboard) in helpers/components
- categorie E: eslint-disable vervangen in SearchInput.tsx
- src/lib/config.ts centrale config module (localhost defaults)
- CSP in next.config.ts dynamisch via env var
- deploy.sh: geen hardcoded IP meer (REQUIRED arg)
- lib/api/ lib/auth/ lib/wallet/ lib/search-index/ lib/storage/ gesplitst in modules
- ongebruikte bestanden verwijderd: api.ts, auth.tsx, wallet.ts, search-index.ts,
  PaymentPanel.tsx, SearchBar.tsx, proxy.ts, serve-static.js
2026-07-19 15:35:18 +02:00

231 lines
6.4 KiB
Plaintext

/* ── IPFS Portal API Layer ── */
const API_BASE = ''; // nginx proxy /api/* → backend
export interface IPFSNodeInfo {
version: string;
peerId: string;
peers: number;
storageUsed: string;
storageMax: string;
uptime: string;
}
export interface IPFSPin {
cid: string;
name: string;
size: number;
created: string;
}
export interface IPFSUser {
username: string;
created: string;
active: boolean;
}
/* ── Generic fetch wrapper ── */
async function apiFetch<T>(path: string, options?: RequestInit): Promise<T> {
const res = await fetch(`${API_BASE}/api${path}`, {
headers: { 'Content-Type': 'application/json', ...options?.headers },
...options,
credentials: 'include',
});
if (!res.ok) {
const text = await res.text().catch(() => '');
throw new Error(`${res.status} ${res.statusText}: ${text.slice(0, 200)}`);
}
return res.json();
}
/* ── Node info ── */
export async function getNodeInfo(): Promise<IPFSNodeInfo> {
return apiFetch('/node/info');
}
export async function getPeers(): Promise<{ id: string; addr: string; latency: string }[]> {
const raw = await apiFetch<{ Peers?: { Peer: string; Addr: string; Latency: string }[] }>('/peers');
return (raw.Peers || []).map((p: { Peer: string; Addr: string; Latency: string }) => ({
id: p.Peer,
addr: p.Addr,
latency: p.Latency || '—',
}));
}
/* ── Storage ── */
export async function listPins(): Promise<IPFSPin[]> {
const raw = await apiFetch<{ Keys?: Record<string, { Type: string }> }>('/pins');
if (!raw.Keys) return [];
return Object.entries(raw.Keys).map(([cid, info]) => ({
cid,
name: '',
size: 0,
created: info.Type || '',
}));
}
export async function addPin(cid: string, name?: string): Promise<{ cid: string }> {
return apiFetch('/pins', {
method: 'POST',
body: JSON.stringify({ cid, name }),
});
}
export async function removePin(cid: string): Promise<void> {
await apiFetch(`/pins/${cid}`, { method: 'DELETE' });
}
/* ── Files ── */
export async function uploadFile(file: File): Promise<{ cid: string; size: number }> {
const form = new FormData();
form.append('file', file);
const res = await fetch(`${API_BASE}/api/files/upload`, {
method: 'POST',
body: form,
credentials: 'include',
});
if (!res.ok) {
let errMsg = res.statusText;
try { const d = await res.json(); errMsg = d.error || d.Message || errMsg; } catch {}
throw new Error(`Upload failed: ${errMsg}`);
}
const data = await res.json();
// Kubo API returns { Hash, Size, Name }, normalize to { cid, size }
return {
cid: data.cid || data.Hash || data.hash || '',
size: data.size || data.Size || 0,
};
}
export async function listFiles(): Promise<{ name: string; cid: string; size: number; modified: string }[]> {
return apiFetch('/files');
}
/* ── Users (admin) ── */
export async function listUsers(): Promise<IPFSUser[]> {
const raw = await apiFetch<IPFSUser[] | { users: IPFSUser[] }>('/users');
// Handle both [{...}] and {users: [{...}]} response formats
if (Array.isArray(raw)) return raw;
if (raw && Array.isArray(raw.users)) return raw.users;
return [];
}
export async function createUser(username: string, password: string): Promise<{ username: string }> {
return apiFetch('/users', {
method: 'POST',
body: JSON.stringify({ username, password }),
});
}
export async function deleteUser(username: string): Promise<void> {
await apiFetch(`/users/${encodeURIComponent(username)}`, { method: 'DELETE' });
}
/* ── IPFS Explorer ── */
export interface IPFSEntry {
name: string;
type: 'file' | 'dir';
size: number;
hash: string;
}
export async function explorerLs(cid: string): Promise<IPFSEntry[]> {
return apiFetch(`/explorer/ls/${encodeURIComponent(cid)}`, { method: 'POST' });
}
export async function explorerCat(cid: string): Promise<string> {
const res = await fetch(`${API_BASE}/api/explorer/cat/${encodeURIComponent(cid)}`, {
method: 'POST',
credentials: 'include',
});
if (!res.ok) {
const text = await res.text().catch(() => '');
throw new Error(`${res.status} ${res.statusText}: ${text.slice(0, 200)}`);
}
return res.text();
}
export async function explorerStat(cid: string): Promise<Record<string, unknown>> {
return apiFetch(`/explorer/stat/${encodeURIComponent(cid)}`, { method: 'POST' });
}
/* ── IPNS ── */
export interface IPNSKey {
name: string;
id: string;
}
export async function listIPNSKeys(): Promise<IPNSKey[]> {
const res = await apiFetch<{ Keys: { Name?: string; Id?: string }[] }>('/ipns/keys');
if (!res.Keys) return [];
return res.Keys.map((k: { Name?: string; Id?: string }) => ({
name: k.Name ?? '',
id: k.Id ?? '',
}));
}
export async function ipnsPublish(cid: string, key = 'self'): Promise<{ name: string; value: string }> {
return apiFetch(`/ipns/publish?arg=${encodeURIComponent(cid)}&key=${encodeURIComponent(key)}`, {
method: 'POST',
});
}
export async function ipnsResolve(name: string): Promise<string> {
const res = await apiFetch<{ Path: string }>(`/ipns/resolve/${encodeURIComponent(name)}`);
return res.Path || '';
}
export async function ipnsGenKey(name: string): Promise<IPNSKey> {
return apiFetch(`/ipns/keys/gen/${encodeURIComponent(name)}`, { method: 'POST' });
}
/* ── Repo / Bandwidth Stats ── */
export interface RepoStats {
repoSize: number;
storageMax: number;
numObjects: number;
repoPath: string;
version: string;
}
export interface BWStats {
totalIn: number;
totalOut: number;
rateIn: number;
rateOut: number;
}
export async function getRepoStats(): Promise<RepoStats> {
const raw = await apiFetch<{
RepoSize?: number; StorageMax?: number; NumObjects?: number;
RepoPath?: string; Version?: string;
}>('/repo/stats');
return {
repoSize: raw.RepoSize ?? 0,
storageMax: raw.StorageMax ?? 0,
numObjects: raw.NumObjects ?? 0,
repoPath: raw.RepoPath ?? '',
version: raw.Version ?? '',
};
}
export async function getBWStats(): Promise<BWStats> {
const raw = await apiFetch<{
TotalIn?: number; TotalOut?: number; RateIn?: number; RateOut?: number;
}>('/bw/stats');
return {
totalIn: raw.TotalIn ?? 0,
totalOut: raw.TotalOut ?? 0,
rateIn: raw.RateIn ?? 0,
rateOut: raw.RateOut ?? 0,
};
}
/* ── Health ── */
export async function checkHealth(): Promise<{ status: string; node: string }> {
return apiFetch('/health');
}