@linx-systems/pihole-api-client
v0.1.2
Published
Type-safe TypeScript client for the Pi-hole v6 REST API
Maintainers
Readme
pihole-api-client
Type-safe TypeScript client for the Pi-hole v6 REST API.
Features
- Complete coverage of Pi-hole v6 API (~80 endpoints)
- Type-safe with full TypeScript support
- Result type for explicit error handling (no exceptions)
- Automatic session management with auto-refresh
- Retry with exponential backoff
- Zero runtime dependencies
- Works in Node.js 18+ and browsers
Installation
npm (recommended)
npm install @linx-systems/pihole-api-client
# or
bun add @linx-systems/pihole-api-clientGitHub Packages (alternative)
npm install @linx-systems/pihole-api-client --registry=https://npm.pkg.github.comQuick Start
import { PiholeClient, isOk, isErr } from "@linx-systems/pihole-api-client";
const client = new PiholeClient({
baseUrl: "http://pi.hole",
password: "your-password",
});
// Get statistics
const statsResult = await client.stats.getSummary();
if (isOk(statsResult)) {
console.log("Blocked queries:", statsResult.data.queries.blocked);
}
// Disable blocking for 5 minutes
const blockingResult = await client.dns.disable(300);
if (isErr(blockingResult)) {
console.error("Failed to disable:", blockingResult.error.message);
}
// Add domain to denylist
await client.domains.deny("ads.example.com");
// Get query log
const queries = await client.queries.list({ length: 100 });API Reference
Client Configuration
const client = new PiholeClient({
// Required
baseUrl: "http://pi.hole", // Pi-hole server URL
// Authentication (one of these)
password: "your-password", // Plain password (auto-authenticates)
// or provide session tokens directly
sid: "session-id",
csrf: "csrf-token",
// Optional
timeout: 10000, // Request timeout in ms (default: 10000)
maxRetries: 3, // Max retry attempts (default: 3)
autoRefresh: true, // Auto-refresh sessions (default: true)
});Result Type
All methods return Result<T, PiholeError>:
type Result<T, E = PiholeError> =
| { ok: true; data: T }
| { ok: false; error: E };
// Helper functions
isOk(result); // Type guard for success
isErr(result); // Type guard for error
unwrap(result); // Returns data or throws
unwrapOr(result, defaultValue); // Returns data or defaultAvailable Endpoints
Authentication (client.auth)
await client.auth.login(password, totp?);
await client.auth.logout();
await client.auth.check();
await client.auth.getSessions();
await client.auth.deleteSession(id);
await client.auth.generateTotp();
await client.auth.createAppPassword();DNS Control (client.dns)
await client.dns.getStatus();
await client.dns.enable();
await client.dns.disable(seconds?);
await client.dns.setBlocking(enabled, timer?);Statistics (client.stats)
await client.stats.getSummary();
await client.stats.getUpstreams();
await client.stats.getTopDomains(count?, blocked?);
await client.stats.getTopClients(count?, blocked?);
await client.stats.getQueryTypes();
await client.stats.getRecentBlocked();
// Database variants available with .database prefixHistory (client.history)
await client.history.get(from?, until?);
await client.history.getClients(from?, until?);
// Database variants availableQueries (client.queries)
await client.queries.list({ length, from, until, client, domain, type, status });
await client.queries.getSuggestions();Domain Management (client.domains)
// Denylist
await client.domains.deny(domain, comment?);
await client.domains.undeny(domain);
await client.domains.getDenylist();
// Allowlist
await client.domains.allow(domain, comment?);
await client.domains.unallow(domain);
await client.domains.getAllowlist();
// Regex variants
await client.domains.denyRegex(pattern);
await client.domains.allowRegex(pattern);
// Generic CRUD
await client.domains.list(type, kind);
await client.domains.add(type, kind, domain, options?);
await client.domains.update(type, kind, domain, options);
await client.domains.remove(type, kind, domain);
await client.domains.batchDelete(items);
// Search
await client.domains.search(domain);Groups (client.groups)
await client.groups.list();
await client.groups.create(name, options?);
await client.groups.update(name, options);
await client.groups.delete(name);
await client.groups.batchDelete(names);Clients (client.clients)
await client.clients.list();
await client.clients.create(client, options?);
await client.clients.update(client, options);
await client.clients.delete(client);
await client.clients.getSuggestions();
await client.clients.batchDelete(clients);Lists/Adlists (client.lists)
await client.lists.list();
await client.lists.add(address, options?);
await client.lists.update(id, options);
await client.lists.delete(id);
await client.lists.batchDelete(ids);DHCP (client.dhcp)
await client.dhcp.getLeases();
await client.dhcp.deleteLease(ip);Configuration (client.config)
await client.config.get();
await client.config.getSection(element);
await client.config.update(changes);
await client.config.addArrayItem(element, value);
await client.config.removeArrayItem(element, value);System Info (client.info)
await client.info.getClient();
await client.info.getSystem();
await client.info.getHost();
await client.info.getFtl();
await client.info.getSensors();
await client.info.getDatabase();
await client.info.getVersion();
await client.info.getMetrics();
await client.info.getLogin();
await client.info.getMessages();
await client.info.getMessageCount();
await client.info.deleteMessage(id);Network (client.network)
await client.network.getGateway();
await client.network.getRoutes();
await client.network.getInterfaces();
await client.network.getDevices();
await client.network.deleteDevice(id);Actions (client.actions)
await client.actions.updateGravity();
await client.actions.restartDns();
await client.actions.flushLogs();
await client.actions.flushArp();
await client.actions.flushNetwork();Logs (client.logs)
await client.logs.getDnsmasq(lines?);
await client.logs.getFtl(lines?);
await client.logs.getWebserver(lines?);Teleporter (client.teleporter)
await client.teleporter.export();
await client.teleporter.import(data);Other
await client.getEndpoints();Error Handling
import { PiholeErrorCode } from "@linx-systems/pihole-api-client";
const result = await client.dns.disable();
if (isErr(result)) {
switch (result.error.code) {
case PiholeErrorCode.Unauthorized:
// Handle auth error
break;
case PiholeErrorCode.NetworkError:
// Handle network error
break;
case PiholeErrorCode.Timeout:
// Handle timeout
break;
default:
console.error(result.error.message);
}
}License
MIT
