1
0
forked from maik/IPFS-portal
Files
IPFS-portal-deploy/src/lib/api.ts
T

218 lines
6.0 KiB
TypeScript
Raw Normal View History

/* ── 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) throw new Error(`Upload failed: ${res.statusText}`);
return res.json();
}
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: IPNSKey[] }>('/ipns/keys');
return res.Keys || [];
}
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');
}