Files
p2ns/docs/RESTAPI.md
T

1945 lines
68 KiB
Markdown

# P2NS Admin Backend API
The P2NS (Peer-to-Peer Name System) admin backend API, hosted at `https://p2ns.admin`, provides endpoints for managing the decentralized DNS system programmatically. These endpoints, implemented in `admin.js`, allow interaction with domains, Holesail servers and clients, local DNS records, certificates, virtual interfaces, logs, settings, and system status. All endpoints are accessible via HTTP/HTTPS and do not require authentication (since the domain is local). Responses are typically JSON or plain text, with errors returned as plain text messages. Real-time updates are broadcast via WebSocket at `wss://p2ns.admin/ws`.
## Base URL
`https://p2ns.admin`
## WebSocket Endpoint
- **URL**: `wss://p2ns.admin/ws`
- **Description**: Establishes a WebSocket connection for real-time updates from the server.
- **Client → server messages**:
- `subscribe-stats` / `unsubscribe-stats` / `request-stats-snapshot` — Stats tab live data.
- `subscribe-log``{ "type": "subscribe-log", "channel": "core", "lines": 1000 }` (channels: `core`, `proxy`, `httpProxy`, `dns`, `plugins`, `holesail`).
- `unsubscribe-log` — Stop log tail.
- `request-domains` — Refresh domains list (server replies with `domains-list`).
- **Server → client messages**:
- `stats-snapshot` — Full stats page payload (`stats`, `historical`, `health`, `status`, `minutes`). Includes `stats.core` (invite RPC diagnostics) and `stats.pluginRpc` / `stats.peerChannels` (plugin RPC metrics).
- `update-stats` — Notifies stats subscribers to apply their latest snapshot (does not embed metrics itself).
- `update-health` — Health payload for Diagnostics tab subscribers.
- `file-log``{ "type": "file-log", "channel": "dns", "level": "info", "message": "<line>" }` (live log tail).
- `log-snapshot` — Initial tail after `subscribe-log`: `{ "type": "log-snapshot", "channel": "core", "lines": ["..."] }`.
- `log`**Legacy**; may still map to core. Prefer `file-log` + `subscribe-log`.
- `holesail-log` — Holesail child process logs (`id`, `level`, `message`).
- `plugin-log` — Per-plugin logs (`domain`, `level`, `component`, `message`).
- `domains-list` — Resolved domains array.
- `update-database`, `update-peers`, `update-certs`, `update-interfaces`, `update-local-dns`, `update-holesail`, `update-holesail-clients`, `update-settings`, `update-plugins`, `update-plugin-settings` — Tab refresh hints.
- `system-reset` — Client should reload.
- **Example (`file-log`)**:
```json
{
"type": "file-log",
"channel": "core",
"level": "info",
"message": "2026-05-28T12:00:00.000Z [INFO] [Main] Starting..."
}
```
## Endpoints
### 1. GET /
- **Description**: Serves the admin panel HTML (`includes/admin/admin-frontend/index.html`).
- **Response**: HTML content.
- **Status Codes**:
- `200`: Success.
- `500`: Failed to load admin panel.
- **Example**:
```bash
curl -X GET \
https://p2ns.admin/
```
### 2. GET /styles.css
- **Description**: Serves the admin panel stylesheet (`includes/admin/admin-frontend/styles.css`).
- **Response**: CSS content.
- **Status Codes**:
- `200`: Success.
- `500`: Failed to load styles.
- **Example**:
```bash
curl -X GET \
https://p2ns.admin/styles.css
```
### 3. GET /admin.js
- **Description**: Serves the admin panel JavaScript (`includes/admin/admin-frontend/admin.js`).
- **Response**: JavaScript content.
- **Status Codes**:
- `200`: Success.
- `500`: Failed to load script.
- **Example**:
```bash
curl -X GET \
https://p2ns.admin/admin.js
```
### 4. GET /api/resolved-domains
- **Description**: Retrieves a list of resolved domains with their hashes, local status, ownership, consensus information, and available services.
- **Response**: JSON array of objects with:
- `domain` (string): Domain name
- `hash` (string): Holesail hash or `"internal"` for internal domains
- `isLocal` (boolean): Whether the local writer has a claim for this domain
- `isOwner` (boolean): Whether the local writer is the resolved claimant (owner) of this domain
- `consensusState` (object): Detailed consensus information including status, vote counts, quorum status, etc.
- `consensusStatus` (string): Simplified status that may include `"conflict"` for domains where local peer has a claim but another claimant won
- `services` (array): Array of service objects with `serviceName`, `key`, `port`, and `protocol` fields
- **Status Codes**:
- `200`: Success.
- `500`: Failed to fetch domains.
- **Example**:
```bash
curl -X GET \
https://p2ns.admin/api/resolved-domains
```
```json
[
{
"domain": "example.tld",
"hash": "hs://s00084bf...",
"isLocal": true,
"isOwner": true,
"consensusState": {
"status": "resolved",
"hash": "hs://s00084bf...",
"resolvedClaimant": "a6a6d7ebcc1df8f33410067bf96ad2cc30d5276516f758bb0f34195e914c451f",
"voteCounts": {
"a6a6d7ebcc1df8f33410067bf96ad2cc30d5276516f758bb0f34195e914c451f": 8
},
"activePeers": 5,
"quorumMet": true,
"minVotes": 2,
"totalVotes": 8,
"lastResolution": 1766780982538
},
"consensusStatus": "resolved",
"services": [
{
"serviceName": "web",
"key": "hs://s00084bf...",
"port": 8080,
"protocol": "tcp"
}
]
},
{
"domain": "bm.git",
"hash": "hs://s000f44fb5cfe3fa7f37e9070ea14975a8dbf1e2156689638bc92458118df7a4987b",
"isLocal": true,
"isOwner": false,
"consensusState": {
"status": "resolved",
"hash": "hs://s000f44fb5cfe3fa7f37e9070ea14975a8dbf1e2156689638bc92458118df7a4987b",
"resolvedClaimant": "acbb3b69ee810f4fbe54927a5742530e4cf76b7b462a4c37ddfe27ba5c3060b6",
"voteCounts": {
"a6a6d7ebcc1df8f33410067bf96ad2cc30d5276516f758bb0f34195e914c451f": 1,
"acbb3b69ee810f4fbe54927a5742530e4cf76b7b462a4c37ddfe27ba5c3060b6": 7
},
"activePeers": 5,
"quorumMet": true,
"minVotes": 2,
"totalVotes": 8,
"lastResolution": 1766780982538
},
"consensusStatus": "conflict",
"services": []
},
{
"domain": "peer.directory",
"hash": "internal",
"isLocal": true,
"isOwner": true,
"consensusStatus": "internal",
"services": []
}
]
```
### 5. GET /api/entries
- **Description**: Retrieves all Autopass ledger entries (claims and votes).
- **Response**: JSON array of objects with `key` (string) and `value` (string).
- **Status Codes**:
- `200`: Success.
- `500`: Failed to fetch entries.
- **Example**:
```bash
curl -X GET \
https://p2ns.admin/api/entries
```
```json
[
{ "key": "claim:example.tld:abc123", "value": "hs://s00084bf..." },
{ "key": "vote:example.tld:abc123:def456", "value": "1" }
]
```
### 6. GET /api/peers
- **Description**: Lists connected peers (public keys).
- **Response**: JSON array of peer public keys (strings).
- **Status Codes**:
- `200`: Success.
- `500`: Failed to fetch peers.
- **Example**:
```bash
curl -X GET \
https://p2ns.admin/api/peers
```
```json
["def456", "ghi789"]
```
### 7. GET /api/certs
- **Description**: Lists domains with generated certificates.
- **Response**: JSON array of domain names (strings).
- **Status Codes**:
- `200`: Success.
- `500`: Failed to fetch certs.
- **Example**:
```bash
curl -X GET \
https://p2ns.admin/api/certs
```
```json
["example.tld", "peer.directory"]
```
### 8. GET /api/cert-details?domain=<domain>
- **Description**: Retrieves the certificate content for a specified domain.
- **Query Parameters**:
- `domain`: The domain name (e.g., `example.tld`).
- **Response**: Plain text certificate content (PEM format).
- **Status Codes**:
- `200`: Success.
- `500`: Failed to fetch cert details.
- **Example**:
```bash
curl -X GET \
https://p2ns.admin/api/cert-details?domain=example.tld
```
```text
-----BEGIN CERTIFICATE-----
MIID...
-----END CERTIFICATE-----
```
### 9. GET /api/interfaces
- **Description**: Lists virtual interfaces with domain-to-IP mappings.
- **Response**: JSON array of objects with `domain` (string) and `ip` (string).
- **Status Codes**:
- `200`: Success.
- `500`: Failed to fetch interfaces.
- **Example**:
```bash
curl -X GET \
https://p2ns.admin/api/interfaces
```
```json
[
{ "domain": "example.tld", "ip": "192.168.3.2" },
{ "domain": "peer.directory", "ip": "192.168.3.3" }
]
```
### 10. GET /api/local-dns
- **Description**: Retrieves custom local DNS records and conflicting domains (domains with both P2P and public records).
- **Response**: JSON object with:
- `records`: Array of DNS records with `index` (number), `name` (string), `type` (string), `ttl` (number), `class` (string, usually "IN"), and type-specific fields (e.g., `data` for A, `preference` and `exchange` for MX).
- `conflicts`: Array of objects with `domain` (string), `version` (p2p/public), and `publicIP` (string).
- **Status Codes**:
- `200`: Success.
- `500`: Failed to fetch local DNS and conflicts.
- **Example**:
```bash
curl -X GET \
https://p2ns.admin/api/local-dns
```
```json
{
"records": [
{ "index": 0, "name": "local.example", "type": "A", "class": "IN", "ttl": 3600, "data": "192.168.1.100" },
{ "index": 1, "name": "mail.example", "type": "MX", "class": "IN", "ttl": 3600, "preference": 10, "exchange": "mx.example.com" },
{ "index": 2, "name": "_service._tcp.example", "type": "SRV", "class": "IN", "ttl": 3600, "priority": 0, "weight": 5, "port": 8080, "target": "server.example.com" }
],
"conflicts": [
{ "domain": "myspace.com", "version": "public", "publicIP": "151.101.1.195" },
{ "domain": "example.com", "version": "p2p", "publicIP": "93.184.216.34" }
]
}
```
### 11. GET /api/selector-cache
- **Description**: Retrieves DNS version preferences for domains with both P2P and public records.
- **Response**: JSON object mapping domains to `p2p` or `public`.
- **Status Codes**:
- `200`: Success.
- `500`: Failed to fetch selector cache.
- **Example**:
```bash
curl -X GET \
https://p2ns.admin/api/selector-cache
```
```json
{
"myspace.com": "public",
"example.com": "p2p"
}
```
### 12. GET /api/status
- **Description**: Retrieves system status, including master/joiner mode and peer count.
- **Response**: JSON object with `isMaster` (boolean), `isConnected` (boolean), and `peersCount` (number).
- **Status Codes**:
- `200`: Success.
- `500`: Failed to fetch status.
- **Example**:
```bash
curl -X GET \
https://p2ns.admin/api/status
```
```json
{
"isMaster": true,
"isConnected": true,
"peersCount": 5
}
```
### 13. GET /api/holesail-servers
- **Description**: Lists all Holesail servers with their configurations and status.
- **Response**: JSON array of objects with `id` (string), `opts` (configuration object), and `info` (object including `state`: running/stopped).
- **Status Codes**:
- `200`: Success.
- `500`: Failed to fetch Holesail servers.
- **Example**:
```bash
curl -X GET \
https://p2ns.admin/api/holesail-servers
```
```json
[
{
"id": "abc123",
"opts": { "name": "server1", "port": 8080, "host": "0.0.0.0", "secure": true, "log": 1 },
"info": { "state": "running", "url": "hs://s00084bf..." }
}
]
```
### 14. GET /api/holesail-clients
- **Description**: Lists all Holesail clients with their configurations and status.
- **Response**: JSON array of objects with `id` (string), `opts` (configuration object), and `info` (object including `state`: running/starting/stopped/error).
- **Status Codes**:
- `200`: Success.
- `500`: Failed to fetch Holesail clients.
- **Example**:
```bash
curl -X GET \
https://p2ns.admin/api/holesail-clients
```
```json
[
{
"id": "def456",
"opts": { "domain": "example.tld", "key": "hs://s00084bf...", "port": 8080, "protocol": "tcp" },
"info": { "state": "running" }
}
]
```
### 15. GET /api/settings
- **Description**: Retrieves environment settings (whitelisted variables). Note: `SUBNETS`, `SUBNET_BASE`, and `INITIAL_IP_INDEX` are managed separately via the subnet configurator (see `/api/subnets`).
- **Response**: JSON object with `settings` (object mapping whitelisted keys to values) and `metadata` (object with setting metadata including types, descriptions, and categories).
- **Status Codes**:
- `200`: Success.
- `500`: Failed to fetch settings.
- **Example**:
```bash
curl -X GET \
https://p2ns.admin/api/settings
```
```json
{
"settings": {
"LOG_LEVEL": "1",
"INTERNAL_DOMAINS": "Note: Internal domains are now automatically discovered from plugin-sites/{domain}/config.json files"
},
"metadata": {
"LOG_LEVEL": {
"type": "number",
"category": "Logging & Debugging",
"label": "Log Level",
"description": "...",
"default": "0"
}
}
}
```
### 16. POST /api/add-domain
- **Description**: Adds a domain with its Holesail hash to the P2P network and `domains.json`. Assigns an IP if needed and triggers auto-voting. **Note: Internal domains (automatically discovered from `plugin-sites/{domain}/config.json` files, including `p2ns.admin`) cannot be claimed and will return an error.**
- **Request Body**: JSON with `domain` (string), `hash` (string, e.g., `hs://<hash>`), and optionally `ssl` (boolean). The `ssl` field indicates if the Holesail connection uses SSL/TLS. When `true`, proxy connections will use HTTPS/WSS instead of HTTP/WS. Defaults to `false` if not provided.
- **Response**: Plain text `OK` on success, error message on failure.
- **Status Codes**:
- `200`: Success.
- `500`: Failed to add domain.
- **WebSocket Broadcast**: `update-database`.
- **Example**:
```bash
curl -X POST \
-H "Content-Type: application/json" \
-d '{"domain":"example.tld","hash":"hs://s00084bf...","ssl":true}' \
https://p2ns.admin/api/add-domain
```
```text
OK
```
### 17. POST /api/remove-domain
- **Description**: Removes a domain. Behavior depends on consensus status:
- **Resolved Claimant**: Performs full cleanup removing all claims and votes for the domain, broadcasts `consensus.removeDomain` RPC to trigger other peers to clean up
- **Conflict Claim**: Removes only your own claim and votes, broadcasts `removeConflictDomainClaim:` notification (other peers preserve their claims)
- **Request Body**: JSON with `domain` (string).
- **Response**: Plain text `OK` on success, error message on failure.
- **Status Codes**:
- `200`: Success.
- `403`: No claim found for domain or peer not initialized.
- `500`: Failed to remove domain.
- **WebSocket Broadcast**: `update-database`, `update-holesail-clients`, `update-local-dns`.
- **Note**: Only the peer that created a claim can remove it. Ownership is strictly validated before removal.
- **Example**:
```bash
curl -X POST \
-H "Content-Type: application/json" \
-d '{"domain":"example.tld"}' \
https://p2ns.admin/api/remove-domain
```
```text
OK
```
### 18. POST /api/regenerate-ca
- **Description**: Regenerates the root CA certificate.
- **Request Body**: None.
- **Response**: Plain text `OK` on success, error message on failure.
- **Status Codes**:
- `200`: Success.
- `500`: Failed to regenerate CA.
- **WebSocket Broadcast**: `update-certs`.
- **Example**:
```bash
curl -X POST \
https://p2ns.admin/api/regenerate-ca
```
```text
OK
```
### 19. POST /api/install-ca
- **Description**: Installs the root CA to the system trust store.
- **Request Body**: None.
- **Response**: Plain text `OK` on success, error message on failure.
- **Status Codes**:
- `200`: Success.
- `500`: Failed to install CA.
- **Example**:
```bash
curl -X POST \
https://p2ns.admin/api/install-ca
```
```text
OK
```
### 20. POST /api/generate-cert
- **Description**: Generates a certificate for a specified domain, assigning an IP if needed.
- **Request Body**: JSON with `domain` (string).
- **Response**: Plain text `OK` on success, error message on failure.
- **Status Codes**:
- `200`: Success.
- `500`: Failed to generate cert.
- **WebSocket Broadcast**: `update-certs`.
- **Example**:
```bash
curl -X POST \
-H "Content-Type: application/json" \
-d '{"domain":"example.tld"}' \
https://p2ns.admin/api/generate-cert
```
```text
OK
```
### 21. POST /api/delete-cert
- **Description**: Deletes the certificate for a specified domain.
- **Request Body**: JSON with `domain` (string).
- **Response**: Plain text `OK` on success, error message on failure.
- **Status Codes**:
- `200`: Success.
- `500`: Failed to delete cert.
- **WebSocket Broadcast**: `update-certs`.
- **Example**:
```bash
curl -X POST \
-H "Content-Type: application/json" \
-d '{"domain":"example.tld"}' \
https://p2ns.admin/api/delete-cert
```
```text
OK
```
### 22. POST /api/regenerate-cert
- **Description**: Regenerates the certificate for a specified domain, assigning an IP if needed.
- **Request Body**: JSON with `domain` (string).
- **Response**: Plain text `OK` on success, error message on failure.
- **Status Codes**:
- `200`: Success.
- `500`: Failed to regenerate cert.
- **WebSocket Broadcast**: `update-certs`.
- **Example**:
```bash
curl -X POST \
-H "Content-Type: application/json" \
-d '{"domain":"example.tld"}' \
https://p2ns.admin/api/regenerate-cert
```
```text
OK
```
### 23. POST /api/cleanup-interfaces
- **Description**: Cleans up unused virtual interfaces.
- **Note**: This endpoint is available via the API but is not exposed in the admin UI interface.
- **Request Body**: None.
- **Response**: Plain text `OK` on success, error message on failure.
- **Status Codes**:
- `200`: Success.
- `500`: Failed to cleanup interfaces.
- **WebSocket Broadcast**: `update-interfaces`.
- **Example**:
```bash
curl -X POST \
https://p2ns.admin/api/cleanup-interfaces
```
```text
OK
```
### 24. POST /api/add-local-dns
- **Description**: Adds a custom DNS record to `local_dns.json`. Supports all DNS record types (e.g., A, AAAA, CNAME, MX, TXT, SRV, SOA, CAA, NS, PTR, OTHER) with flexible fields.
- **Request Body**: JSON object with `name` (string), `type` (string), `ttl` (number), `class` (string, optional, defaults to "IN"), and type-specific fields (e.g., `data` for A, `preference` and `exchange` for MX).
- **Response**: Plain text `OK` on success, error message on failure.
- **Status Codes**:
- `200`: Success.
- `500`: Failed to add local DNS record.
- **WebSocket Broadcast**: `update-local-dns`.
- **Example** (A record):
```bash
curl -X POST \
-H "Content-Type: application/json" \
-d '{"name":"local.example","type":"A","ttl":3600,"data":"192.168.1.100"}' \
https://p2ns.admin/api/add-local-dns
```
```text
OK
```
- **Example** (SRV record):
```bash
curl -X POST \
-H "Content-Type: application/json" \
-d '{"name":"_service._tcp.example","type":"SRV","ttl":3600,"priority":0,"weight":5,"port":8080,"target":"server.example.com"}' \
https://p2ns.admin/api/add-local-dns
```
```text
OK
```
### 25. POST /api/update-local-dns
- **Description**: Updates an existing custom DNS record in `local_dns.json` by index. Supports all DNS record types.
- **Request Body**: JSON object with `index` (number) and `record` (object with `name`, `type`, `ttl`, `class` (optional), and type-specific fields).
- **Response**: Plain text `OK` on success, error message on failure.
- **Status Codes**:
- `200`: Success.
- `400`: Invalid index.
- `500`: Failed to update local DNS record.
- **WebSocket Broadcast**: `update-local-dns`.
- **Example**:
```bash
curl -X POST \
-H "Content-Type: application/json" \
-d '{"index":0,"record":{"name":"local.example","type":"A","ttl":7200,"data":"192.168.1.101"}}' \
https://p2ns.admin/api/update-local-dns
```
```text
OK
```
### 26. POST /api/delete-local-dns
- **Description**: Deletes a custom DNS record from `local_dns.json` by index.
- **Request Body**: JSON with `index` (number).
- **Response**: Plain text `OK` on success, error message on failure.
- **Status Codes**:
- `200`: Success.
- `400`: Invalid index.
- `500`: Failed to delete local DNS record.
- **WebSocket Broadcast**: `update-local-dns`.
- **Example**:
```bash
curl -X POST \
-H "Content-Type: application/json" \
-d '{"index":0}' \
https://p2ns.admin/api/delete-local-dns
```
```text
OK
```
### 27. POST /api/update-version-preference
- **Description**: Updates the DNS version preference (p2p or public) for a domain with both P2P and public records, stored in `selector_cache.json`.
- **Request Body**: JSON with `domain` (string) and `version` (string: `p2p` or `public`).
- **Response**: Plain text `OK` on success, error message on failure.
- **Status Codes**:
- `200`: Success.
- `400`: Invalid version.
- `500`: Failed to update version preference.
- **WebSocket Broadcast**: `update-local-dns`.
- **Example**:
```bash
curl -X POST \
-H "Content-Type: application/json" \
-d '{"domain":"myspace.com","version":"public"}' \
https://p2ns.admin/api/update-version-preference
```
```text
OK
```
### 28. GET /api/p2p-domain-conflicts
- **Description**: Retrieves domains with P2P consensus conflicts where the user has a local claim but another claimant won consensus. Used for the P2P Domain Conflicts management interface.
- **Response**: JSON object with `conflicts` array containing objects with:
- `domain` (string): Domain name
- `localHash` (string): User's local claim hash
- `resolvedHash` (string): Consensus-resolved hash
- `resolvedClaimant` (string): Public key of consensus winner
- `localClaimant` (string): User's public key
- `consensusStatus` (string): Current consensus status
- `hashPreference` (string): User's hash preference ('local' or 'resolved')
- **Status Codes**:
- `200`: Success.
- `500`: Failed to fetch P2P domain conflicts.
- **WebSocket Broadcast**: None.
- **Example**:
```bash
curl -X GET \
https://p2ns.admin/api/p2p-domain-conflicts
```
```json
{
"conflicts": [
{
"domain": "example.com",
"localHash": "hs://s0001abc...",
"resolvedHash": "hs://s0001def...",
"resolvedClaimant": "abc123...",
"localClaimant": "def456...",
"consensusStatus": "resolved",
"hashPreference": "resolved"
}
]
}
```
### 29. POST /api/update-hash-preference
- **Description**: Updates the hash preference ('local' or 'resolved') for a domain with P2P consensus conflicts, stored in `selector_cache.json`. When changed, automatically restarts any active Holesail clients for the domain to use the new hash.
- **Request Body**: JSON with `domain` (string) and `preference` (string: `local` or `resolved`).
- **Response**: Plain text `OK` on success, error message on failure.
- **Status Codes**:
- `200`: Success.
- `400`: Invalid preference.
- `500`: Failed to update hash preference.
- **WebSocket Broadcast**: `update-local-dns`.
- **Example**:
```bash
curl -X POST \
-H "Content-Type: application/json" \
-d '{"domain":"example.com","preference":"local"}' \
https://p2ns.admin/api/update-hash-preference
```
```text
OK
```
### 30. POST /api/clear-dns-cache
- **Description**: Clears DNS resolution cache entries for a specific domain to force fresh hash resolution on next DNS query.
- **Request Body**: JSON with `domain` (string).
- **Response**: Plain text `OK` on success, error message on failure.
- **Status Codes**:
- `200`: Success.
- `500`: Failed to clear DNS cache.
- **WebSocket Broadcast**: None.
- **Example**:
```bash
curl -X POST \
-H "Content-Type: application/json" \
-d '{"domain":"example.com"}' \
https://p2ns.admin/api/clear-dns-cache
```
```text
OK
```
### 31. POST /api/restart-holesail-clients-for-domain
- **Description**: Restarts all Holesail clients (both admin-managed and DNS-triggered) for a specific domain to use updated hash preferences. Closes existing connections and creates new ones with correct hashes. Ensures IP assignment exists before creating clients.
- **Request Body**: JSON with `domain` (string).
- **Response**: Plain text `OK` on success, error message on failure.
- **Status Codes**:
- `200`: Success.
- `500`: Failed to restart clients or resolve hash.
- `500`: Failed to restart Holesail clients.
- **WebSocket Broadcast**: `update-holesail-clients`.
- **Example**:
```bash
curl -X POST \
-H "Content-Type: application/json" \
-d '{"domain":"example.com"}' \
https://p2ns.admin/api/restart-holesail-clients-for-domain
```
```text
OK
```
### 32. POST /api/holesail-create
- **Description**: Creates a new Holesail server, optionally assigning it to a domain. Persists to `holesail_servers.json`.
- **Request Body**: JSON with `name` (string, optional), `port` (number), `host` (string, optional), `key` (string, optional), `domain` (string, optional), `secure` (boolean), `udp` (boolean), `log` (number).
- **Response**: JSON with `id` (string) on success, error message on failure.
- **Status Codes**:
- `200`: Success.
- `500`: Failed to create Holesail server.
- **WebSocket Broadcast**: `update-holesail`, `update-database` (if domain assigned).
- **Example**:
```bash
curl -X POST \
-H "Content-Type: application/json" \
-d '{"name":"server1","port":8080,"host":"0.0.0.0","secure":true,"udp":false,"log":1,"domain":"example.tld"}' \
https://p2ns.admin/api/holesail-create
```
```json
{"id":"abc123"}
```
### 33. POST /api/holesail-delete
- **Description**: Deletes a Holesail server by ID and removes it from `holesail_servers.json`.
- **Request Body**: JSON with `id` (string).
- **Response**: Plain text `OK` on success, error message on failure.
- **Status Codes**:
- `200`: Success.
- `500`: Failed to delete Holesail server.
- **WebSocket Broadcast**: `update-holesail`.
- **Example**:
```bash
curl -X POST \
-H "Content-Type: application/json" \
-d '{"id":"abc123"}' \
https://p2ns.admin/api/holesail-delete
```
```text
OK
```
### 34. POST /api/holesail-restart
- **Description**: Restarts a Holesail server by ID, optionally reassigning its domain. Persists to `holesail_servers.json`.
- **Request Body**: JSON with `id` (string).
- **Response**: Plain text `OK` on success, error message on failure.
- **Status Codes**:
- `200`: Success.
- `500`: Failed to restart Holesail server.
- **WebSocket Broadcast**: `update-holesail`, `update-database` (if domain assigned).
- **Example**:
```bash
curl -X POST \
-H "Content-Type: application/json" \
-d '{"id":"abc123"}' \
https://p2ns.admin/api/holesail-restart
```
```text
OK
```
### 35. POST /api/holesail-client-create
- **Description**: Creates a new Holesail client for a domain and port. Persists to `holesail_clients.json`. If `serviceName` is provided, the client ID will be `domain_servicename`; otherwise, a generated ID is used. The client is also added to the domain's claim record `clients` array.
- **Request Body**: JSON with:
- `domain` (string, required): Domain name (must be owned by local writer)
- `key` (string, required): Holesail connection hash (e.g., `hs://s00084bf...`)
- `port` (number, required): Port number
- `serviceName` (string, optional): Service name for naming the client (format: `domain_servicename`)
- `protocol` (string, optional): Protocol type (`tcp` or `udp`, default: `tcp`)
- **Response**: JSON with `id` (string) on success, error message on failure.
- **Status Codes**:
- `200`: Success.
- `400`: Invalid request (missing required fields or domain not owned).
- `500`: Failed to create Holesail client.
- **WebSocket Broadcast**: `update-holesail-clients`.
- **Example**:
```bash
curl -X POST \
-H "Content-Type: application/json" \
-d '{"domain":"example.tld","key":"hs://s00084bf...","port":8080,"serviceName":"web","protocol":"tcp"}' \
https://p2ns.admin/api/holesail-client-create
```
```json
{"id":"example.tld_web"}
```
### 36. POST /api/holesail-client-delete
- **Description**: Deletes a Holesail client by ID, closing connections and removing it from `holesail_clients.json`.
- **Request Body**: JSON with `id` (string).
- **Response**: Plain text `OK` on success, error message on failure.
- **Status Codes**:
- `200`: Success.
- `500`: Failed to delete Holesail client.
- **WebSocket Broadcast**: `update-holesail-clients`.
- **Example**:
```bash
curl -X POST \
-H "Content-Type: application/json" \
-d '{"id":"def456"}' \
https://p2ns.admin/api/holesail-client-delete
```
```text
OK
```
### 37. POST /api/holesail-client-restart
- **Description**: Restarts a Holesail client by ID, ensuring the port is free and connections are closed.
- **Request Body**: JSON with `id` (string).
- **Response**: Plain text `OK` on success, error message on failure.
- **Status Codes**:
- `200`: Success.
- `500`: Failed to restart Holesail client.
- **WebSocket Broadcast**: `update-holesail-clients`.
- **Example**:
```bash
curl -X POST \
-H "Content-Type: application/json" \
-d '{"id":"def456"}' \
https://p2ns.admin/api/holesail-client-restart
```
```text
OK
```
### 38. POST /api/update-settings
- **Description**: Updates environment settings (whitelisted variables) and persists them to `.env`. Note: `SUBNETS` can be updated here, but it's recommended to use `/api/subnets` for subnet management. `SUBNET_BASE` and `INITIAL_IP_INDEX` are deprecated in favor of the subnet configurator.
- **Request Body**: JSON with `settings` (object mapping whitelisted keys to values). For `SUBNETS`, provide a JSON array string.
- **Response**: JSON object with `message` (string), `restartRequired` (boolean), and optionally `restartRequiredSettings` (array of strings).
- **Status Codes**:
- `200`: Success.
- `400`: Validation failed (includes `errors` array).
- `500`: Failed to update settings.
- **WebSocket Broadcast**: `update-settings`.
- **Example**:
```bash
curl -X POST \
-H "Content-Type: application/json" \
-d '{"settings":{"LOG_LEVEL":"1"}}' \
https://p2ns.admin/api/update-settings
```
```json
{
"message": "Settings saved and applied successfully.",
"restartRequired": false
}
```
### 39. GET /api/network-interfaces
- **Description**: Retrieves a list of available network interfaces on the system. Used by the admin interface to populate the Subnet Interface Name dropdown setting.
- **Response**: JSON object with `interfaces` (array of interface objects). Each interface object contains:
- `value` (string): Interface name (e.g., "lo0", "lo", "eth0")
- `label` (string): Display label for the interface (may include "(default)" for OS default)
- **Status Codes**:
- `200`: Success.
- `500`: Failed to fetch network interfaces.
- **Example**:
```bash
curl -X GET \
https://p2ns.admin/api/network-interfaces
```
```json
{
"interfaces": [
{ "value": "lo0", "label": "lo0" },
{ "value": "en0", "label": "en0" },
{ "value": "eth0", "label": "eth0" }
]
}
```
- **Note**: Interfaces are sorted with loopback interfaces (lo, lo0) and OS-specific defaults (lo0 on macOS, lo on Linux, Loopback Pseudo-Interface 1 on Windows) prioritized first.
### 40. GET /api/subnets
- **Description**: Retrieves all configured subnets with capacity information. Returns default subnet from `SUBNET_BASE` if no subnets are configured.
- **Response**: JSON object with `subnets` (array of subnet objects). Each subnet object contains:
- `base` (string): Network base IP address (e.g., "192.168.3.0")
- `cidr` (number): CIDR notation (1-32, e.g., 24)
- `startIndex` (number): First usable IP index (1-254)
- `name` (string): Subnet name/description
- `index` (number): Subnet index in array
- `available` (number): Total available IPs in subnet
- `used` (number): Currently used IPs
- `remaining` (number): Remaining available IPs
- **Status Codes**:
- `200`: Success.
- `500`: Failed to fetch subnets.
- **Example**:
```bash
curl -X GET \
https://p2ns.admin/api/subnets
```
```json
{
"subnets": [
{
"base": "192.168.3.0",
"cidr": 24,
"startIndex": 2,
"name": "Primary Subnet",
"index": 0,
"available": 253,
"used": 5,
"remaining": 248
},
{
"base": "10.0.0.0",
"cidr": 24,
"startIndex": 2,
"name": "Secondary Subnet",
"index": 1,
"available": 253,
"used": 0,
"remaining": 253
}
]
}
```
### 41. POST /api/subnets
- **Description**: Updates subnet configuration. Replaces all existing subnets with the provided array. Changes require a system restart to fully take effect.
- **Request Body**: JSON object with `subnets` (array of subnet objects). Each subnet object must contain:
- `base` (string, required): Network base IP address (e.g., "192.168.3.0")
- `cidr` (number, required): CIDR notation (1-32, typically 24)
- `startIndex` (number, required): First usable IP index (1-254, typically 2)
- `name` (string, optional): Subnet name/description (defaults to "Subnet N" if not provided)
- **Response**: JSON object with `message` (string) and `restartRequired` (boolean, always true).
- **Status Codes**:
- `200`: Success.
- `400`: Validation failed (includes `error` string and `errors` array).
- `500`: Failed to update subnets.
- **WebSocket Broadcast**: `update-settings`.
- **Example**:
```bash
curl -X POST \
-H "Content-Type: application/json" \
-d '{"subnets":[{"base":"192.168.3.0","cidr":24,"startIndex":2,"name":"Primary Subnet"},{"base":"10.0.0.0","cidr":24,"startIndex":2,"name":"Secondary Subnet"}]}' \
https://p2ns.admin/api/subnets
```
```json
{
"message": "Subnets updated. Restart required to fully apply changes.",
"restartRequired": true
}
```
- **Validation Rules**:
- `base` must be a valid IPv4 address (e.g., "192.168.3.0")
- `cidr` must be between 1 and 32
- `startIndex` must be between 1 and 254 (or up to subnet size - 2)
- Subnets must not overlap with each other
### 42. GET /api/health
- **Description**: Health check endpoint supporting liveness and readiness probes.
- **Query Parameters**:
- `probe`: Type of health probe (`liveness` or `readiness`, default: `liveness`).
- **Response**: JSON object with `status` (healthy/degraded/not_ready), `timestamp`, `uptime`, `probe`, `services` (object with DNS, proxy, swarm status), and `dependencies` (object with corestore, hyperswarm status).
- **Status Codes**:
- `200`: System is healthy.
- `503`: System is degraded or not ready.
- **Example**:
```bash
curl -X GET \
https://p2ns.admin/api/health
```
```json
{
"status": "healthy",
"timestamp": "2024-01-01T00:00:00.000Z",
"uptime": 3600000,
"probe": "liveness",
"services": {
"dns": { "enabled": true, "healthy": true, "initialized": true },
"proxy": { "enabled": true, "healthy": true },
"swarm": { "healthy": true }
},
"dependencies": {
"corestore": { "healthy": true },
"hyperswarm": { "healthy": true }
}
}
```
### 43. GET /api/stats
- **Description**: Retrieves a one-shot system metrics snapshot (same data shape as `stats-snapshot` over WebSocket). The admin UI loads this once, then uses `subscribe-stats` for live updates.
- **Response**: JSON object including:
- Request statistics (total, success rate, average response time, failed requests)
- Holesail children (servers, clients, P2P domain connections) with status, PID, uptime, CPU/memory usage
- `core` — Core control-plane / invite RPC diagnostics (`diagnoseInviteIssues`)
- `pluginRpc` and `peerChannels` — Per-plugin protomux-rpc protocol stats (`transport: 'rpc'`, methods, `rpcOpen` counts)
- HyperDB / Hyperdrive sections when available
- **Status Codes**:
- `200`: Success.
- `500`: Failed to fetch stats.
- **Example**:
```bash
curl -X GET \
https://p2ns.admin/api/stats
```
```json
{
"requests": {
"total": 1000,
"successful": 950,
"failed": 50,
"successRate": 0.95,
"avgResponseTime": 45
},
"holesailChildren": [
{
"id": "abc123",
"type": "server",
"status": "running",
"pid": 12345,
"uptime": 3600000,
"cpuUsage": { "percentage": 2.5 },
"memoryUsage": { "rss": 52428800 }
}
]
}
```
### 44. GET /api/logs
- **Description**: Lists available split log channels written under `LOG_DIR` (default `./logs/`).
- **Response**: `{ "channels": [ { "id": "core", "label": "Core", "file": "core.log" }, ... ] }`
- **Status Codes**: `200`, `500`
- **Example**:
```bash
curl -k https://p2ns.admin/api/logs
```
### 45. GET /api/logs/:channel
- **Description**: Returns the tail of a log file (in-memory buffer with file fallback).
- **Path**: `channel` — `core`, `proxy`, `httpProxy`, `dns`, `plugins`, or `holesail`
- **Query**: `lines` — max lines (default `500`, max `5000`)
- **Response**: `{ "channel": "dns", "lines": ["..."] }`
- **Example**:
```bash
curl -k "https://p2ns.admin/api/logs/dns?lines=200"
```
### 46. GET /api/stats/historical
- **Description**: Retrieves historical metrics data for a specified time range.
- **Query Parameters**:
- `minutes`: Time range in minutes (1-1440, default: 60).
- **Response**: JSON object with historical metrics data including request trends, connection statistics, and system performance over time.
- **Status Codes**:
- `200`: Success.
- `500`: Failed to fetch historical data.
- **Example**:
```bash
curl -X GET \
"https://p2ns.admin/api/stats/historical?minutes=1440"
```
### 47. GET /api/backups
- **Description**: Lists all available backups with metadata including name, timestamp, size, and file count.
- **Response**: JSON array of backup objects with `name`, `timestamp`, `size`, `sizeFormatted`, and `fileCount`.
- **Status Codes**:
- `200`: Success.
- `500`: Failed to list backups.
- **Example**:
```bash
curl -X GET \
https://p2ns.admin/api/backups
```
```json
[
{
"name": "backup-20240101-000000",
"timestamp": "2024-01-01T00:00:00.000Z",
"size": 1048576,
"sizeFormatted": "1.00 MB",
"fileCount": 15
}
]
```
### 48. POST /api/backups/create
- **Description**: Creates a manual backup of configuration files, certificates, and cache data. Automatic cleanup of old backups is performed before creation.
- **Request Body**: None.
- **Response**: JSON object with `success` (boolean) and `path` (string, backup file path).
- **Status Codes**:
- `200`: Success.
- `500`: Failed to create backup.
- **Example**:
```bash
curl -X POST \
https://p2ns.admin/api/backups/create
```
```json
{
"success": true,
"path": "./backups/backup-20240101-000000.tar.gz"
}
```
### 49. POST /api/backups/restore
- **Description**: Restores system configuration from a backup. Replaces current configuration files and certificates.
- **Request Body**: JSON with `backupName` (string, backup name to restore).
- **Response**: JSON object with `success` (boolean) and `message` (string).
- **Status Codes**:
- `200`: Success.
- `400`: Invalid request (missing backupName).
- `500`: Failed to restore backup.
- **Example**:
```bash
curl -X POST \
-H "Content-Type: application/json" \
-d '{"backupName":"backup-20240101-000000"}' \
https://p2ns.admin/api/backups/restore
```
```json
{
"success": true,
"message": "Backup restored successfully"
}
```
### 50. DELETE /api/backups/:id
- **Description**: Deletes a backup by name. Supports both directory and tar.gz formats.
- **Path Parameters**:
- `id`: Backup name (e.g., `backup-20240101-000000` or `backup-20240101-000000.tar.gz`).
- **Response**: JSON object with `success` (boolean) and `message` (string).
- **Status Codes**:
- `200`: Success.
- `400`: Invalid backup name.
- `500`: Failed to delete backup.
- **Example**:
```bash
curl -X DELETE \
https://p2ns.admin/api/backups/backup-20240101-000000
```
### 51. GET /api/backups/:id/metadata
- **Description**: Retrieves detailed metadata for a backup including file list, sizes, and timestamps.
- **Path Parameters**:
- `id`: Backup name.
- **Response**: JSON object with backup metadata including `timestamp`, `files` (array with name, size, sizeFormatted, modified), and other metadata.
- **Status Codes**:
- `200`: Success.
- `404`: Backup not found.
- `500`: Failed to get backup metadata.
- **Example**:
```bash
curl -X GET \
https://p2ns.admin/api/backups/backup-20240101-000000/metadata
```
### 52. POST /api/diagnostics/dns-lookup
- **Description**: Performs DNS lookup for a domain with specified record type.
- **Request Body**: JSON with `domain` (string, required) and `type` (string, optional, default: `A`). Supported types: A, AAAA, MX, TXT, NS, CNAME, SRV, PTR, SOA.
- **Response**: JSON object with `success` (boolean), `domain`, `type`, `results` (array), and `responseTime` (number).
- **Status Codes**:
- `200`: Success (includes both successful and failed lookups).
- `400`: Invalid request (missing domain).
- `500`: Server error.
- **Example**:
```bash
curl -X POST \
-H "Content-Type: application/json" \
-d '{"domain":"example.com","type":"A"}' \
https://p2ns.admin/api/diagnostics/dns-lookup
```
```json
{
"success": true,
"domain": "example.com",
"type": "A",
"results": ["93.184.216.34"],
"responseTime": 25
}
```
### 53. POST /api/diagnostics/ping
- **Description**: Tests network connectivity using ping. Supports both streaming and non-streaming modes.
- **Request Body**: JSON with `target` (string, required), `count` (number, optional, default: 4), and `stream` (boolean, optional, default: false).
- **Response**:
- **Non-streaming**: JSON object with `success`, `target`, `count`, `output`, `error`, and `responseTime`.
- **Streaming**: NDJSON stream with `type` (output/error/complete), `data`, `timestamp`, and completion status.
- **Status Codes**:
- `200`: Success.
- `400`: Invalid request (missing target).
- `500`: Server error.
- **Example** (non-streaming):
```bash
curl -X POST \
-H "Content-Type: application/json" \
-d '{"target":"8.8.8.8","count":4}' \
https://p2ns.admin/api/diagnostics/ping
```
- **Example** (streaming):
```bash
curl -X POST \
-H "Content-Type: application/json" \
-d '{"target":"8.8.8.8","count":4,"stream":true}' \
https://p2ns.admin/api/diagnostics/ping
```
### 54. POST /api/diagnostics/traceroute
- **Description**: Traces network path to a target. Supports both streaming and non-streaming modes.
- **Request Body**: JSON with `target` (string, required) and `stream` (boolean, optional, default: false).
- **Response**:
- **Non-streaming**: JSON object with `success`, `target`, `output`, `error`, and `responseTime`.
- **Streaming**: NDJSON stream with `type` (output/error/complete), `data`, `timestamp`, and completion status.
- **Status Codes**:
- `200`: Success.
- `400`: Invalid request (missing target).
- `500`: Server error.
- **Example**:
```bash
curl -X POST \
-H "Content-Type: application/json" \
-d '{"target":"8.8.8.8","stream":true}' \
https://p2ns.admin/api/diagnostics/traceroute
```
### 55. POST /api/diagnostics/connection-test
- **Description**: Tests TCP connectivity to a domain and port combination.
- **Request Body**: JSON with `domain` (string, required) and `port` (number, required).
- **Response**: JSON object with `success` (boolean), `domain`, `ip` (resolved IP), `port`, `latency` (if successful), `error` (if failed), and `responseTime`.
- **Status Codes**:
- `200`: Success (includes both successful and failed tests).
- `400`: Invalid request (missing domain or port).
- `500`: Server error.
- **Example**:
```bash
curl -X POST \
-H "Content-Type: application/json" \
-d '{"domain":"example.com","port":443}' \
https://p2ns.admin/api/diagnostics/connection-test
```
```json
{
"success": true,
"domain": "example.com",
"ip": "93.184.216.34",
"port": 443,
"latency": 45,
"responseTime": 50
}
```
### 56. GET /api/diagnostics/bandwidth
- **Description**: Network interface information and configuration. Real-time throughput stats are not available via Node.js; response is interface layout only.
- **Response**: JSON with `interfaces`, optional `note`, `responseTime`.
- **Status Codes**: `200`, `500`
- **Example**:
```bash
curl -k https://p2ns.admin/api/diagnostics/bandwidth
```
### 57. GET /api/diagnostics/invites
- **Description**: Core invite / control-plane diagnostics over `p2ns.core-request-rpc` (`invite.request`, `invite.deliver`, `invite.ack`, `core.status`). Used by the Stats **Core** section and Invite Diagnostics UI.
- **Response**: JSON with `summary` (dnsPass, rpcOpen, requestChannelOpen, failed peers, …), `peers`, `recommendations`, `connectionIssues`, etc.
- **Status Codes**: `200`, `503` (still initializing), `500`
- **Example**:
```bash
curl -k https://p2ns.admin/api/diagnostics/invites
```
### 58. GET /<tab>
- **Description**: Redirects to the admin panel with the specified tab (e.g., `/domains`, `/host`, `/local-dns`) open.
- **Path Parameters**:
- `tab`: One of `domains`, `host`, `local-dns`, `entries`, `peers`, `certs`, `interfaces`, `logs`, `settings`.
- **Response**: HTTP redirect to `/#<tab>`.
- **Status Codes**:
- `302`: Redirect.
- **Example**:
```bash
curl -X GET \
-L \
https://p2ns.admin/domains
```
### 59. GET /favicon.ico
- **Description**: Returns a 404 response (favicon not implemented).
- **Response**: Plain text `Not Found`.
- **Status Codes**:
- `404`: Not found.
- **Example**:
```bash
curl -X GET \
https://p2ns.admin/favicon.ico
```
```text
Not Found
```
## Consensus Endpoints
### 60. GET /api/consensus/:domain
- **Description**: Retrieves the consensus state for a specific domain, including vote counts, quorum status, and resolution information.
- **Path Parameters**:
- `domain`: The domain name (e.g., `example.tld`).
- **Response**: JSON object with:
- `status` (string): Consensus status (`resolved`, `insufficient_quorum`, `tie`, `no_claims`, `error`).
- `hash` (string|null): Resolved Holesail hash if status is `resolved`, otherwise `null`.
- `resolvedClaimant` (string|null): Public key of the winning claimant if resolved, otherwise `null`.
- `voteCounts` (object): Mapping of claimant public keys to their vote counts.
- `activePeers` (number): Number of active peers in the network (including local node).
- `quorumMet` (boolean): Whether the quorum threshold has been met.
- `minVotes` (number): Minimum votes required to meet quorum.
- `totalVotes` (number): Total number of votes cast for all claimants.
- `lastResolution` (number|null): Timestamp of last resolution, or `null` if never resolved.
- **Status Codes**:
- `200`: Success.
- `500`: Failed to get consensus state.
- **Example**:
```bash
curl -X GET \
https://p2ns.admin/api/consensus/example.tld
```
```json
{
"status": "resolved",
"hash": "hs://s00084bf87dfa89a3048fb081c0e6207eb5a",
"resolvedClaimant": "abc123def456...",
"voteCounts": {
"abc123def456...": 3,
"ghi789jkl012...": 1
},
"activePeers": 5,
"quorumMet": true,
"minVotes": 3,
"totalVotes": 4,
"lastResolution": 1704067200000
}
```
### GET /api/consensus/status
- **Description**: Returns health and progress of the consensus Autobase sidecar (the sole read path for `getConsensusState`).
- **Response**: JSON object with:
- `open` (boolean): Whether the sidecar Autobase instance is open.
- `ready` (boolean): Whether the sidecar has completed opening.
- `writable` (boolean): Whether this node can append sidecar events.
- `bootstrapComplete` (boolean): Whether bootstrap or hydration from dnsPass has finished.
- `eventCount` (number): Total events applied to the in-memory view.
- `domainCount` (number): Domains present in the apply view.
- `lastApplyAt` (number|null): Timestamp of the last applied event.
- `indexedLength` (number): Autobase indexed length.
- `length` (number): Autobase length.
- `key` (string|null): Sidecar public key (hex).
- **Status Codes**:
- `200`: Success.
- `500`: Failed to get consensus status.
- **Example**:
```bash
curl -X GET \
https://p2ns.admin/api/consensus/status
```
```json
{
"open": true,
"ready": true,
"writable": true,
"bootstrapComplete": true,
"eventCount": 142,
"domainCount": 12,
"lastApplyAt": 1704067200000,
"indexedLength": 142,
"length": 142,
"key": "a1b2c3..."
}
```
### 61. GET /api/consensus/metrics
- **Description**: Retrieves overall consensus metrics including resolution statistics, quorum failures, ties, validation failures, and sidecar health.
- **Response**: JSON object with:
- `resolutions` (number): Total number of successful domain resolutions.
- `quorumFailures` (number): Number of times quorum was not met.
- `ties` (number): Number of ties that required tie-breaking.
- `validationFailures` (number): Number of invalid votes that were rejected.
- `totalVotes` (number): Total number of votes cast across all domains.
- `avgVotesPerDomain` (number): Average number of votes per domain.
- `domainResolutions` (array): Per-domain resolution statistics with `domain`, `resolved` count, and `failed` count.
- `sidecar` (object): Same fields as `GET /api/consensus/status`.
- `bootstrapComplete` (boolean): Whether sidecar bootstrap/hydration is complete.
- **Status Codes**:
- `200`: Success.
- `500`: Failed to get consensus metrics.
- **Example**:
```bash
curl -X GET \
https://p2ns.admin/api/consensus/metrics
```
```json
{
"resolutions": 42,
"quorumFailures": 3,
"ties": 2,
"validationFailures": 1,
"totalVotes": 156,
"avgVotesPerDomain": 3.71,
"domainResolutions": [
{
"domain": "example.tld",
"resolved": 5,
"failed": 0
},
{
"domain": "another.tld",
"resolved": 3,
"failed": 1
}
],
"sidecar": {
"open": true,
"ready": true,
"writable": true,
"bootstrapComplete": true,
"eventCount": 142,
"domainCount": 12,
"lastApplyAt": 1704067200000,
"indexedLength": 142,
"length": 142,
"key": "a1b2c3..."
},
"bootstrapComplete": true
}
```
### 62. POST /api/consensus/recalculate
- **Description**: Forces a consensus recalculation for all domains. Invalidates the consensus cache and triggers auto-voting checks.
- **Request Body**: None.
- **Response**: JSON object with `success` (boolean) and `message` (string).
- **Status Codes**:
- `200`: Success.
- `500`: Failed to recalculate consensus.
- **WebSocket Broadcast**: `update-database` (triggers refresh of domains and entries).
- **Example**:
```bash
curl -X POST \
https://p2ns.admin/api/consensus/recalculate
```
```json
{
"success": true,
"message": "Consensus recalculation triggered"
}
```
### 63. POST /api/consensus/recalculate/:domain
- **Description**: Forces a consensus recalculation for a specific domain. Invalidates the consensus cache for that domain and triggers auto-voting.
- **Path Parameters**:
- `domain`: The domain name (e.g., `example.tld`).
- **Request Body**: None.
- **Response**: JSON object with `success` (boolean) and `message` (string).
- **Status Codes**:
- `200`: Success.
- `500`: Failed to recalculate consensus for domain.
- **WebSocket Broadcast**: `update-database` (triggers refresh of domains and entries).
- **Example**:
```bash
curl -X POST \
https://p2ns.admin/api/consensus/recalculate/example.tld
```
```json
{
"success": true,
"message": "Consensus recalculation triggered for example.tld"
}
```
## Service Subscription Endpoints
### 64. GET /api/domain-services
- **Description**: Retrieves all services configured for a specific domain from its claim record.
- **Query Parameters**:
- `domain` (string, required): The domain name to query services for.
- **Response**: JSON array of service objects, each containing:
- `serviceName` (string): Service identifier
- `key` (string): Holesail connection hash
- `port` (number): Port number
- `protocol` (string): Protocol type (`tcp` or `udp`)
- **Status Codes**:
- `200`: Success (returns empty array if domain has no services or is not resolved).
- `400`: Missing domain parameter.
- `500`: Failed to fetch domain services.
- **Example**:
```bash
curl -X GET \
"https://p2ns.admin/api/domain-services?domain=example.tld"
```
```json
[
{
"serviceName": "web",
"key": "hs://s00084bf87dfa89a3048fb081c0e6207eb5a",
"port": 8080,
"protocol": "tcp"
},
{
"serviceName": "api",
"key": "hs://s000bcc379b38f6d3a5cb4cfde23fa52392d",
"port": 9090,
"protocol": "tcp"
}
]
```
### 65. GET /api/service-subscriptions
- **Description**: Lists all service subscriptions configured on this node.
- **Response**: JSON array of subscription objects, each containing:
- `domain` (string): Domain name
- `serviceName` (string): Service identifier
- `key` (string): Holesail connection hash
- `port` (number): Port number
- `protocol` (string): Protocol type (`tcp` or `udp`)
- **Status Codes**:
- `200`: Success.
- `500`: Failed to fetch subscriptions.
- **Example**:
```bash
curl -X GET \
https://p2ns.admin/api/service-subscriptions
```
```json
[
{
"domain": "example.tld",
"serviceName": "web",
"key": "hs://s00084bf87dfa89a3048fb081c0e6207eb5a",
"port": 8080,
"protocol": "tcp"
}
]
```
### 66. GET /api/subscribe-all-domains
- **Description**: Lists all domains for which "subscribe all" is enabled. When enabled, the system automatically subscribes to all services for that domain, including newly added services.
- **Response**: JSON array of domain names (strings).
- **Status Codes**:
- `200`: Success.
- `500`: Failed to fetch subscribe-all domains.
- **Example**:
```bash
curl -X GET \
https://p2ns.admin/api/subscribe-all-domains
```
```json
["example.tld", "another.tld"]
```
### 67. POST /api/service-subscribe
- **Description**: Subscribes to a specific service from a domain. Creates a Holesail client automatically with ID `domain_servicename` and persists the subscription to `subscriptions.json`.
- **Request Body**: JSON with:
- `domain` (string, required): Domain name
- `serviceName` (string, required): Service identifier
- `key` (string, required): Holesail connection hash
- `port` (number, required): Port number
- `protocol` (string, optional): Protocol type (`tcp` or `udp`, default: `tcp`)
- **Response**: JSON with `success` (boolean) on success, error message on failure.
- **Status Codes**:
- `200`: Success.
- `400`: Missing required fields.
- `409`: Already subscribed to this service.
- `500`: Failed to subscribe.
- **WebSocket Broadcast**: `update-holesail-clients`.
- **Example**:
```bash
curl -X POST \
-H "Content-Type: application/json" \
-d '{"domain":"example.tld","serviceName":"web","key":"hs://s00084bf...","port":8080,"protocol":"tcp"}' \
https://p2ns.admin/api/service-subscribe
```
```json
{"success": true}
```
### 68. POST /api/service-unsubscribe
- **Description**: Unsubscribes from a specific service. Deletes the associated Holesail client and removes the subscription from `subscriptions.json`.
- **Request Body**: JSON with:
- `domain` (string, required): Domain name
- `serviceName` (string, required): Service identifier
- **Response**: JSON with `success` (boolean) on success, error message on failure.
- **Status Codes**:
- `200`: Success.
- `400`: Missing required fields.
- `404`: Subscription not found.
- `500`: Failed to unsubscribe.
- **WebSocket Broadcast**: `update-holesail-clients`.
- **Example**:
```bash
curl -X POST \
-H "Content-Type: application/json" \
-d '{"domain":"example.tld","serviceName":"web"}' \
https://p2ns.admin/api/service-unsubscribe
```
```json
{"success": true}
```
### 69. POST /api/subscribe-all
- **Description**: Enables "subscribe all" for a domain. This automatically subscribes to all current services for that domain and will automatically subscribe to any new services added in the future. Creates Holesail clients for all existing services.
- **Request Body**: JSON with:
- `domain` (string, required): Domain name
- **Response**: JSON with `success` (boolean) on success, error message on failure.
- **Status Codes**:
- `200`: Success.
- `400`: Missing domain field.
- `500`: Failed to set subscribe-all.
- **WebSocket Broadcast**: `update-holesail-clients`.
- **Example**:
```bash
curl -X POST \
-H "Content-Type: application/json" \
-d '{"domain":"example.tld"}' \
https://p2ns.admin/api/subscribe-all
```
```json
{"success": true}
```
### 70. POST /api/unsubscribe-all
- **Description**: Disables "subscribe all" for a domain and unsubscribes from all services for that domain. Deletes all associated Holesail clients.
- **Request Body**: JSON with:
- `domain` (string, required): Domain name
- **Response**: JSON with `success` (boolean) on success, error message on failure.
- **Status Codes**:
- `200`: Success.
- `400`: Missing domain field.
- `500`: Failed to clear subscribe-all.
- **WebSocket Broadcast**: `update-holesail-clients`.
- **Example**:
```bash
curl -X POST \
-H "Content-Type: application/json" \
-d '{"domain":"example.tld"}' \
https://p2ns.admin/api/unsubscribe-all
```
```json
{"success": true}
```
## Plugin Management Endpoints
**Note:** For detailed information about the plugin system, see [plugins/README.md](plugins/README.md) and [plugins/PLUGIN_SDK.md](plugins/PLUGIN_SDK.md).
### 71. GET /api/plugins
- **Description**: Lists all plugins with their information, status, actions, and settings. Includes both loaded and stopped plugins.
- **Response**: JSON object with `plugins` (array of plugin objects). Each plugin object contains:
- `domain` (string): Plugin domain name
- `name` (string): Plugin name from config.json
- `version` (string): Plugin version
- `description` (string): Plugin description
- `author` (string): Plugin author
- `homepage` (string): Plugin homepage URL
- `license` (string): Plugin license
- `status` (string): Plugin status (`loaded`, `stopped`, or `static`)
- `hasHandler` (boolean): Whether plugin has a handler function
- `hasWww` (boolean): Whether plugin has a www directory
- `hasDatabase` (boolean): Whether plugin has HyperDB configured
- `actions` (array): Array of registered action objects
- `settings` (object): Map of registered settings with their current values
- **Status Codes**:
- `200`: Success.
- `500`: Failed to list plugins.
- **Example**:
```bash
curl -X GET \
https://p2ns.admin/api/plugins
```
```json
{
"plugins": [
{
"domain": "example.plugin",
"name": "Example Plugin",
"version": "1.0.0",
"description": "A template plugin",
"author": "P2NS",
"homepage": "https://example.com",
"license": "MIT",
"status": "loaded",
"hasHandler": true,
"hasWww": true,
"hasDatabase": false,
"actions": [
{
"name": "testAction",
"label": "Test Action",
"description": "A test action",
"icon": "🧪"
}
],
"settings": {
"maxItems": {
"type": "number",
"label": "Maximum Items",
"description": "Maximum number of items",
"default": 100,
"value": 100
}
}
}
]
}
```
### 72. GET /api/plugins/:domain
- **Description**: Retrieves detailed information for a specific plugin.
- **Path Parameters**:
- `domain`: The plugin domain name (e.g., `example.plugin`).
- **Response**: JSON object with plugin information (same structure as plugin object in GET /api/plugins).
- **Status Codes**:
- `200`: Success.
- `404`: Plugin not found.
- `500`: Failed to get plugin info.
- **Example**:
```bash
curl -X GET \
https://p2ns.admin/api/plugins/example.plugin
```
### 73. POST /api/plugins/:domain/start
- **Description**: Starts a stopped plugin. Loads the plugin handler and initializes resources.
- **Path Parameters**:
- `domain`: The plugin domain name (e.g., `example.plugin`).
- **Request Body**: None.
- **Response**: JSON object with `success` (boolean), `message` (string), and `domain` (string).
- **Status Codes**:
- `200`: Success.
- `400`: Invalid domain parameter.
- `500`: Failed to start plugin.
- **WebSocket Broadcast**: `update-plugins`.
- **Example**:
```bash
curl -X POST \
https://p2ns.admin/api/plugins/example.plugin/start
```
```json
{
"success": true,
"message": "Plugin example.plugin started successfully",
"domain": "example.plugin"
}
```
### 74. POST /api/plugins/:domain/stop
- **Description**: Stops a running plugin. Unloads the plugin handler and cleans up resources.
- **Path Parameters**:
- `domain`: The plugin domain name (e.g., `example.plugin`).
- **Request Body**: None.
- **Response**: JSON object with `success` (boolean), `message` (string), and `domain` (string).
- **Status Codes**:
- `200`: Success.
- `400`: Invalid domain parameter.
- `500`: Failed to stop plugin.
- **WebSocket Broadcast**: `update-plugins`.
- **Example**:
```bash
curl -X POST \
https://p2ns.admin/api/plugins/example.plugin/stop
```
```json
{
"success": true,
"message": "Plugin example.plugin stopped successfully",
"domain": "example.plugin"
}
```
### 75. POST /api/plugins/:domain/reload
- **Description**: Reloads a plugin. Stops the plugin, clears the module cache, and starts it again. Useful for applying code changes without restarting P2NS.
- **Path Parameters**:
- `domain`: The plugin domain name (e.g., `example.plugin`).
- **Request Body**: None.
- **Response**: JSON object with `success` (boolean), `message` (string), and `domain` (string).
- **Status Codes**:
- `200`: Success.
- `400`: Invalid domain parameter.
- `500`: Failed to reload plugin.
- **WebSocket Broadcast**: `update-plugins`.
- **Example**:
```bash
curl -X POST \
https://p2ns.admin/api/plugins/example.plugin/reload
```
```json
{
"success": true,
"message": "Plugin example.plugin reloaded successfully",
"domain": "example.plugin"
}
```
### 76. POST /api/plugins/:domain/actions/:actionName
- **Description**: Executes a registered plugin action. The action handler is called with the provided parameters.
- **Path Parameters**:
- `domain`: The plugin domain name (e.g., `example.plugin`).
- `actionName`: The action name (e.g., `testAction`).
- **Request Body**: JSON object with action parameters (optional).
- **Response**: JSON object with `success` (boolean) and `result` (any) containing the action handler's return value.
- **Status Codes**:
- `200`: Success.
- `400`: Invalid request path.
- `404`: Plugin or action not found.
- `500`: Action execution failed.
- **Example**:
```bash
curl -X POST \
-H "Content-Type: application/json" \
-d '{"value": 10}' \
https://p2ns.admin/api/plugins/example.plugin/actions/testAction
```
```json
{
"success": true,
"result": {
"success": true,
"message": "Test action executed successfully!",
"timestamp": "2025-12-12T10:00:00.000Z"
}
}
```
### 77. POST /api/plugins/:domain/settings
- **Description**: Updates plugin settings. Saves settings to `cache/plugin-settings/{domain}.json` and persists them across plugin restarts.
- **Path Parameters**:
- `domain`: The plugin domain name (e.g., `example.plugin`).
- **Request Body**: JSON object mapping setting keys to values.
- **Response**: JSON object with `success` (boolean) and `message` (string).
- **Status Codes**:
- `200`: Success.
- `400`: Invalid domain parameter.
- `500`: Failed to update settings.
- **WebSocket Broadcast**: `update-plugin-settings`.
- **Example**:
```bash
curl -X POST \
-H "Content-Type: application/json" \
-d '{"maxItems": 200, "enableFeature": true}' \
https://p2ns.admin/api/plugins/example.plugin/settings
```
```json
{
"success": true,
"message": "Settings updated for plugin example.plugin"
}
```
### 78. GET /api/token
- **Description**: Generates a signed Ed25519 authentication token for plugin authentication. Available to all plugins globally.
- **Request Headers**: None required.
- **Response**: JSON object with `token` (string), `expiresAt` (number), and `peerId` (string).
- **Status Codes**:
- `200`: Success.
- `500`: Failed to generate token.
- **Example**:
```bash
curl -X GET \
https://global.profile/api/token
```
```json
{
"token": "eyJwZWVySWQiOiIxMjM0NTY3ODkwYWJjZGVmZ2hpamsuLi4iLCJ0aW1lc3RhbXAiOjE2ODk...",
"expiresAt": 1689123456789,
"peerId": "1234567890abcdef..."
}
```
- **Notes**:
- Tokens expire after 1 hour (3600 seconds) by default.
- Tokens are signed with Ed25519 using the local peer's private key.
- Use the token in the `Authorization: Bearer <token>` header for authenticated requests.
- The `X-Auth-Token` header is also supported as an alternative.
## Authentication
Plugin write operations (POST, PUT, DELETE, PATCH) require authentication using Ed25519-signed tokens.
### Authentication Headers
**Authorization Header (Preferred):**
```
Authorization: Bearer <token>
```
**Alternative Header:**
```
X-Auth-Token: <token>
```
### Error Responses
**401 Unauthorized:**
```json
{
"error": "Authentication required",
"message": "Invalid or missing authentication token"
}
```
**403 Forbidden:**
```json
{
"error": "Forbidden",
"message": "Only the local peer can perform this operation"
}
```
### Token Format
Tokens are base64-encoded JSON objects containing:
- `peerId`: The public key (hex string) of the authenticated peer
- `timestamp`: Token creation timestamp (milliseconds)
- `expiresAt`: Token expiration timestamp (milliseconds)
- `signature`: Ed25519 signature (hex string) of the token payload
### Frontend Integration
Include the authentication utilities script:
```html
<script src="/auth-utils.js"></script>
```
Use `authenticatedFetch()` for write operations:
```javascript
const response = await authenticatedFetch('/api/data', {
method: 'POST',
headers: {
'Content-Type': 'application/json'
},
body: JSON.stringify({ data: 'value' })
});
```
See [plugins/PLUGIN_SDK.md](plugins/PLUGIN_SDK.md#authentication-and-authorization) for complete authentication API documentation.
## Security Notes
- **Plugin Authentication**: Write operations in plugins require Ed25519-signed tokens. See [Authentication](#authentication) section above.
- **No Authentication**: Admin endpoints are unauthenticated, so restrict access to trusted networks or users in production.
- **HTTPS**: Use HTTPS to protect data in transit.
- **Input Validation**: Ensure inputs (e.g., domain names, DNS record fields) are sanitized to prevent injection attacks.
- **Permissions**: `selector_cache.json`, `domains.json`, `local_dns.json`, `holesail_servers.json`, `holesail_clients.json`, and `subscriptions.json` should have restricted permissions to prevent unauthorized modifications.
## Testing
- Use tools like `curl` or Postman to test endpoints.
- Verify WebSocket updates using a WebSocket client (e.g., `wscat`).
- Test DNS record creation with various types (e.g., SRV, SOA) and check `local_dns.json`.
- Monitor logs in the admin **Logs** tab (`subscribe-log` per channel) or `GET /api/logs/:channel`; plugin logs use `plugin-log` WebSocket messages.