Update docs

This commit is contained in:
Raven Scott
2026-05-28 12:39:38 -04:00
parent 564029af44
commit 343102d4b5
15 changed files with 289 additions and 561 deletions
+5 -3
View File
@@ -144,8 +144,8 @@ Access `https://p2ns.admin` for real-time management:
| **Interfaces** | Domain-to-IP mappings | | **Interfaces** | Domain-to-IP mappings |
| **Backups** | Create/restore backups | | **Backups** | Create/restore backups |
| **Diagnostics** | DNS lookup, ping, traceroute, connection tests | | **Diagnostics** | DNS lookup, ping, traceroute, connection tests |
| **Stats** | Real-time metrics, health status | | **Stats** | Live metrics (`subscribe-stats`), Core RPC invite diagnostics, Plugin RPC protocol stats |
| **Logs** | Live system logs | | **Logs** | Tail split log files (core, proxy, HTTP proxy, DNS, plugins, Holesail) with filter |
| **Settings** | Environment config, subnet management | | **Settings** | Environment config, subnet management |
| **Plugins** | Start/stop plugins, view logs, configure settings | | **Plugins** | Start/stop plugins, view logs, configure settings |
@@ -207,6 +207,8 @@ Configure via `.env` (copy from `default.env`):
| `STORAGE_DIR` | `./my-storage` | Corestore data directory | | `STORAGE_DIR` | `./my-storage` | Corestore data directory |
| `CERTS_DIR` | `./certs` | Certificate storage | | `CERTS_DIR` | `./certs` | Certificate storage |
| `LOG_LEVEL` | `0` | 0=DEBUG, 1=INFO, 2=WARN, 3=ERROR | | `LOG_LEVEL` | `0` | 0=DEBUG, 1=INFO, 2=WARN, 3=ERROR |
| `LOG_DIR` | `./logs` | Split log files (core, proxy, http-proxy, dns, plugins, holesail) |
| `LOG_BUFFER_LINES` | `2000` | In-memory tail size per log channel (admin Logs tab) |
| `TOPIC_SEED` | `p2ns-dns` | Hyperswarm topic seed | | `TOPIC_SEED` | `p2ns-dns` | Hyperswarm topic seed |
### File Paths ### File Paths
@@ -308,7 +310,7 @@ Example multi-subnet config:
- **[REST API](docs/RESTAPI.md)** - Complete API documentation - **[REST API](docs/RESTAPI.md)** - Complete API documentation
- **[Consensus](docs/CONSENSUS.md)** - Domain voting and resolution - **[Consensus](docs/CONSENSUS.md)** - Domain voting and resolution
- **[HyperDB](docs/plugins/HYPERDB.md)** - Database operations - **[HyperDB](docs/plugins/HYPERDB.md)** - Database operations
- **[Plugin Channels](docs/plugins/PLUGIN_CHANNELS.md)** - P2P communication - **[Plugin RPC](docs/plugins/PLUGIN_CHANNELS.md)** - protomux-rpc peer protocols
- **[Hyperdrive](docs/plugins/HYPERDRIVE.md)** - Distributed file system - **[Hyperdrive](docs/plugins/HYPERDRIVE.md)** - Distributed file system
- **[Proxy Server](proxy-server/README.md)** - Standalone proxy configuration - **[Proxy Server](proxy-server/README.md)** - Standalone proxy configuration
+5
View File
@@ -86,7 +86,12 @@ ENABLE_HYPERCORE_STATS=true
# ============================================================================ # ============================================================================
# Logging # Logging
# ============================================================================ # ============================================================================
# 0=DEBUG, 1=INFO, 2=WARN, 3=ERROR
LOG_LEVEL=1 LOG_LEVEL=1
# Split log files directory (core.log, proxy.log, http-proxy.log, dns.log, plugins.log, holesail.log)
# LOG_DIR=./logs
# In-memory tail lines per channel for admin /api/logs and WebSocket tail
# LOG_BUFFER_LINES=2000
# ============================================================================ # ============================================================================
# Backup Configuration # Backup Configuration
+12 -13
View File
@@ -46,21 +46,19 @@ Supports two removal modes:
## Infrastructure Modules ## Infrastructure Modules
### `infrastructure/logger.js` ### `infrastructure/logger.js` + `infrastructure/log-files.js`
Leveled logging system with prefixes: Leveled logging with component prefixes, routed to split files under `logs/` via `log-files.js`:
- `logDebug(prefix, message)` - DEBUG level (0) - `logDebug` / `logInfo` / `logWarn` / `logError`
- `logInfo(prefix, message)` - INFO level (1) - **core** → console + `core.log`; **Internal Proxy**, **HTTP Proxy**, **DNS**, **Plugins**, **Holesail** → dedicated files (no console)
- `logWarn(prefix, message)` - WARN level (2)
- `logError(prefix, message)` - ERROR level (3)
Logs are broadcast to WebSocket clients for real-time admin interface updates. Admin log tail uses `log-websocket.js` (`subscribe-log`, `file-log`, `log-snapshot`). Plugin logs use separate `plugin-log` WebSocket messages and `app.log` per plugin.
### `infrastructure/state.js` ### `infrastructure/state.js`
Global state management including: Global state management including:
- Domain-to-IP mappings - Domain-to-IP mappings
- Holesail connections - Holesail connections
- TLS/HTTP servers - TLS/HTTP servers
- Peer channels and metrics - Swarm peer channels (`peerChannels`), plugin RPC state (`pluginChannels`), and metrics
- Version preferences - Version preferences
- DNS pass instance - DNS pass instance
@@ -313,10 +311,10 @@ Hyperdrive file system management:
- Replication - Replication
### `plugins/channel-manager.js` ### `plugins/channel-manager.js`
Protomux channel management: Plugin protomux-rpc management:
- Channel creation - `registerPluginProtocol` — per-plugin RPC muxes and method handlers
- Message routing - Request/event routing via `channel-rpc.js` and `plugin-rpc-contract.js`
- Peer tracking - Peer RPC session tracking in `state.pluginChannels`
### `plugins/replication-manager.js` ### `plugins/replication-manager.js`
Database replication over Hyperswarm: Database replication over Hyperswarm:
@@ -439,7 +437,8 @@ module.exports = {
httpServers: new Map(), // domain -> HTTP server httpServers: new Map(), // domain -> HTTP server
// Peer management // Peer management
peerChannels: new Map(), // peerId -> channel peerChannels: new Map(), // peerId -> { conn, mux } (swarm); plugin RPC state is in pluginChannels
pluginChannels: new Map(), // pluginDomain -> protocol -> { peerChannels: Map(peerId -> { rpc, ... }) }
peerMetrics: new Map(), // peerId -> metrics peerMetrics: new Map(), // peerId -> metrics
peerHistory: new Map(), // peerId -> history peerHistory: new Map(), // peerId -> history
blockedPeers: new Set(), // blocked peer IDs blockedPeers: new Set(), // blocked peer IDs
+26 -10
View File
@@ -513,19 +513,35 @@ curl -k "https://p2ns.admin/api/stats/historical?minutes=1440"
### JavaScript Stats Monitoring ### JavaScript Stats Monitoring
```javascript ```javascript
async function getStats() { // One-shot HTTP load (admin UI uses this once on tab open)
async function getStatsOnce() {
const response = await fetch('https://p2ns.admin/api/stats'); const response = await fetch('https://p2ns.admin/api/stats');
const stats = await response.json(); return response.json();
console.log('Total requests:', stats.requests?.total);
console.log('Success rate:', stats.requests?.successRate);
console.log('Holesail connections:', stats.holesailChildren?.length);
return stats;
} }
// Get stats every 10 seconds // Live updates via WebSocket (preferred)
setInterval(getStats, 10000); const ws = new WebSocket('wss://p2ns.admin/ws');
ws.onopen = () => ws.send(JSON.stringify({ type: 'subscribe-stats' }));
ws.onmessage = (ev) => {
const msg = JSON.parse(ev.data);
if (msg.type === 'stats-snapshot') {
console.log('Core RPC:', msg.stats?.core?.summary);
console.log('Plugin RPC protocols:', msg.stats?.pluginRpc?.totalProtocols);
}
};
```
### Tail logs over WebSocket
```javascript
const ws = new WebSocket('wss://p2ns.admin/ws');
ws.onopen = () => {
ws.send(JSON.stringify({ type: 'subscribe-log', channel: 'dns', lines: 500 }));
};
ws.onmessage = (ev) => {
const msg = JSON.parse(ev.data);
if (msg.type === 'file-log' && msg.channel === 'dns') console.log(msg.message);
};
``` ```
## Consensus Examples ## Consensus Examples
+8 -2
View File
@@ -79,6 +79,12 @@ A distributed ledger built on Hyperbee used for storing domain claims and votes.
### Corestore ### Corestore
Storage management for multiple Hypercores. Handles persistence, caching, and lifecycle of cores. P2NS uses Corestore to manage storage for Autopass, HyperDB, and Hyperdrive instances. Storage management for multiple Hypercores. Handles persistence, caching, and lifecycle of cores. P2NS uses Corestore to manage storage for Autopass, HyperDB, and Hyperdrive instances.
### Plugin RPC
The only peer-to-peer transport for plugin protocols. Each plugin registers named JSON methods on `{pluginDomain}-{protocol}-rpc`. Distinct from legacy protomux message channels (removed). See [plugins/PLUGIN_CHANNELS.md](plugins/PLUGIN_CHANNELS.md).
### Core request RPC
Control-plane RPC on `p2ns.core-request-rpc` for invites (`invite.request`, `invite.deliver`, `invite.ack`, …) and consensus events. Joiner lifecycle uses `registerPluginProtocol` for the `request` protocol (RPC open triggers invite flow).
--- ---
## Holesail ## Holesail
@@ -129,8 +135,8 @@ A self-contained module that extends P2NS functionality. Plugins are stored in `
### Plugin SDK ### Plugin SDK
The API provided to plugins for accessing P2NS functionality. Includes modules for state access, DNS operations, domain management, Holesail control, peer management, and more. See [plugins/PLUGIN_SDK.md](plugins/PLUGIN_SDK.md). The API provided to plugins for accessing P2NS functionality. Includes modules for state access, DNS operations, domain management, Holesail control, peer management, and more. See [plugins/PLUGIN_SDK.md](plugins/PLUGIN_SDK.md).
### Protomux Channels ### Split logging
P2P communication channels for plugins using the Protomux protocol. Enables plugins to send messages directly between peers without going through HTTP. See [plugins/PLUGIN_CHANNELS.md](plugins/PLUGIN_CHANNELS.md). Core and subsystem logs are written to separate files under `LOG_DIR` (default `./logs/`): `core.log`, `proxy.log`, `http-proxy.log`, `dns.log`, `plugins.log`, `holesail.log`. The admin **Logs** tab tails these via `subscribe-log` / `file-log`. Plugin `sdk.log` output goes to `plugins.log` and per-plugin `app.log`.
### Admin Panel Actions ### Admin Panel Actions
Custom operations that plugins can register to appear in the admin interface. Actions are async functions that can be triggered from the Plugins tab. Registered via `sdk.admin.registerAction()`. Custom operations that plugins can register to appear in the admin interface. Actions are async functions that can be triggered from the Plugins tab. Registered via `sdk.admin.registerAction()`.
+39 -21
View File
@@ -76,7 +76,7 @@ P2NS provides a comprehensive set of features for decentralized networking:
- **Circuit Breaker Pattern**: Automatic failure detection and recovery with exponential backoff retry logic. - **Circuit Breaker Pattern**: Automatic failure detection and recovery with exponential backoff retry logic.
- **Rate Limiting**: Built-in rate limiting for API endpoints to prevent abuse and ensure system stability. - **Rate Limiting**: Built-in rate limiting for API endpoints to prevent abuse and ensure system stability.
- **Enhanced Error Handling**: Comprehensive error handling with retry logic, graceful degradation, and detailed error reporting. - **Enhanced Error Handling**: Comprehensive error handling with retry logic, graceful degradation, and detailed error reporting.
- **Logging**: Leveled logging (DEBUG, INFO, WARN, ERROR) with prefixes for debugging. - **Logging**: Split log files under `logs/` (core, proxy, HTTP proxy, DNS, plugins, Holesail) with live tail in the admin **Logs** tab.
- **Graceful Shutdown**: Cleans up connections, channels, virtual interfaces, and child processes on exit. - **Graceful Shutdown**: Cleans up connections, channels, virtual interfaces, and child processes on exit.
## Architecture Overview ## Architecture Overview
@@ -86,7 +86,7 @@ P2NS is a modular Node.js application with the following components:
- **Core Components**: - **Core Components**:
- **Corestore & Autopass** (`core.js`): Manages decentralized storage and secure writer additions. Stores claims (`claim:domain:claimant`) and votes (`vote:domain:claimant:voter`). - **Corestore & Autopass** (`core.js`): Manages decentralized storage and secure writer additions. Stores claims (`claim:domain:claimant`) and votes (`vote:domain:claimant:voter`).
- **Hyperswarm** (`swarm.js`): Handles peer discovery using a fixed topic (`sha256('p2ns-dns')`). - **Hyperswarm** (`swarm.js`): Handles peer discovery using a fixed topic (`sha256('p2ns-dns')`).
- **Protomux** (`p2ns.js`): Multiplexes channels for invites and requests. - **Protomux / protomux-rpc** (`p2ns.js`, `includes/core/core-rpc.js`): Core invite and consensus on `p2ns.core-request-rpc`; plugin traffic via per-protocol RPC muxes (see [plugins/PLUGIN_CHANNELS.md](plugins/PLUGIN_CHANNELS.md)).
- **DNS Handling** (`dns.js`): - **DNS Handling** (`dns.js`):
- UDP server on port 53 for P2P and public DNS resolution. - UDP server on port 53 for P2P and public DNS resolution.
@@ -423,9 +423,9 @@ P2NS tracks peer connections, metrics, and history to provide visibility into th
When peers connect via Hyperswarm: When peers connect via Hyperswarm:
1. **Connection Established**: Peer connection is detected and tracked 1. **Connection Established**: Peer connection is detected and tracked
2. **Channel Setup**: Protomux channels are created for communication 2. **RPC Setup**: Core `p2ns.core-request-rpc` and plugin RPC muxes attach to the connection
3. **Replication**: Corestore replication begins automatically 3. **Replication**: Corestore replication begins automatically
4. **Invite Exchange**: Peers exchange invites if needed 4. **Invite Exchange**: Joiners receive Autopass invite wire via `invite.deliver` RPC when needed
5. **Metrics Tracking**: Connection metrics are recorded (duration, timestamps) 5. **Metrics Tracking**: Connection metrics are recorded (duration, timestamps)
6. **Disconnection**: On disconnect, metrics are finalized and stored in history 6. **Disconnection**: On disconnect, metrics are finalized and stored in history
@@ -768,11 +768,32 @@ After installation, verify the certificate is trusted by accessing `https://p2ns
## Logging and Debugging ## Logging and Debugging
Logs are prefixed (e.g., `[Main]`, `[DNS]`) and leveled (DEBUG=0, INFO=1, WARN=2, ERROR=3). Set `LOG_LEVEL` in `.env`. Logs are displayed in the admin interface and console. Logging uses leveled, prefixed messages (`[Main]`, `[DNS]`, `[Internal Proxy]`, `[HTTP Proxy]`, etc.). Set `LOG_LEVEL` in `.env` (0=DEBUG … 3=ERROR).
Example: ### Log files (`logs/`)
| File | Prefix / source | Console |
|------|-----------------|--------|
| `core.log` | Most subsystems (Swarm, Admin, Main, …) | Yes |
| `proxy.log` | `[Internal Proxy]` HTTPS plugin proxy | No |
| `http-proxy.log` | `[HTTP Proxy]` HTTP→HTTPS redirect server | No |
| `dns.log` | `[DNS]` | No |
| `plugins.log` | `Plugin:*`, PluginSDK, PluginChannels | No |
| `holesail.log` | `[Holesail]` | No |
Override directory with `LOG_DIR`. In-memory tail size per channel: `LOG_BUFFER_LINES` (default `2000`).
### Admin Logs tab
- Choose a log file from the dropdown.
- **Filter** lines (debounced substring or `/regex/flags`).
- Live tail via WebSocket (`subscribe-log` / `file-log` messages), not the legacy console stream.
Plugin `sdk.log.*` messages still appear in per-plugin terminals (`plugin-log` WebSocket) and `plugin-sites/{domain}/app.log`.
Example core line:
``` ```
[INFO Main] Starting main function... 2026-05-28T12:00:00.000Z [INFO] [Main] Starting main function...
``` ```
## Configuration Options ## Configuration Options
@@ -802,6 +823,8 @@ Configure via `.env` (copy from `default.env`):
- **INTERNAL_PROXY_TIMEOUT_MS**: Timeout for internal HTTP proxy upstream requests to local Holesail endpoints (default: `12000` ms). Prevents long hangs during tunnel failures. - **INTERNAL_PROXY_TIMEOUT_MS**: Timeout for internal HTTP proxy upstream requests to local Holesail endpoints (default: `12000` ms). Prevents long hangs during tunnel failures.
- **PORT_CHECK_TIMEOUT**: Port check timeout in seconds (default: `2` seconds). - **PORT_CHECK_TIMEOUT**: Port check timeout in seconds (default: `2` seconds).
- **LOG_LEVEL**: Logging level (0-3, default: `0`). - **LOG_LEVEL**: Logging level (0-3, default: `0`).
- **LOG_DIR**: Directory for split log files (default: `./logs`).
- **LOG_BUFFER_LINES**: In-memory tail lines per log channel for admin API/WS (default: `2000`).
- **Internal Domains**: Automatically discovered from `plugin-sites/{domain}/config.json` files. `p2ns.admin` is always internal. - **Internal Domains**: Automatically discovered from `plugin-sites/{domain}/config.json` files. `p2ns.admin` is always internal.
- **DNS_PORT**: DNS server port (default: `53`). - **DNS_PORT**: DNS server port (default: `53`).
- **HTTPS_PORT**: HTTPS proxy port (default: `443`). - **HTTPS_PORT**: HTTPS proxy port (default: `443`).
@@ -917,7 +940,7 @@ The resource validation system runs at configurable intervals (default: 5 minute
- **Holesail Connections**: Detects and removes stale Holesail server/client connections - **Holesail Connections**: Detects and removes stale Holesail server/client connections
- **TLS/HTTP Servers**: Identifies and closes inactive TLS and HTTP server instances - **TLS/HTTP Servers**: Identifies and closes inactive TLS and HTTP server instances
- **Peer Channels**: Validates Protomux channels and removes closed or stale channels - **Plugin RPC**: Validates protomux-rpc plugin protocols and recreates stale peer RPC sessions
- **Timeout Handles**: Cleans up orphaned timeout handles that are no longer needed - **Timeout Handles**: Cleans up orphaned timeout handles that are no longer needed
- **State Maps**: Ensures state maps (`holesails`, `tlsServers`, `httpServers`, `holesailClientTimeouts`) are consistent - **State Maps**: Ensures state maps (`holesails`, `tlsServers`, `httpServers`, `holesailClientTimeouts`) are consistent
@@ -925,7 +948,7 @@ The resource validation system runs at configurable intervals (default: 5 minute
1. **Holesail Servers/Clients**: Checks if processes are still running and connections are active 1. **Holesail Servers/Clients**: Checks if processes are still running and connections are active
2. **TLS/HTTP Servers**: Verifies servers are still listening and haven't been closed unexpectedly 2. **TLS/HTTP Servers**: Verifies servers are still listening and haven't been closed unexpectedly
3. **Peer Channels**: Validates that channels are still open and connected 3. **Plugin RPC**: Validates plugin RPC sessions and recreates closed muxes when peers are still connected
4. **Timeouts**: Removes timeout handles for connections that no longer exist 4. **Timeouts**: Removes timeout handles for connections that no longer exist
### Configuration ### Configuration
@@ -955,14 +978,9 @@ P2NS collects comprehensive system metrics for monitoring and troubleshooting.
### Metrics Endpoints ### Metrics Endpoints
- **Current Stats**: `GET /api/stats` - Real-time system metrics including: - **Current Stats**: `GET /api/stats` - One-shot snapshot (used for initial Stats tab load).
- Request statistics (total, success rate, average response time) - **Historical Data**: `GET /api/stats/historical?minutes=N` - Historical metrics (1-1440 minutes).
- Holesail server/client status and resource usage - **Live updates**: Admin Stats tab subscribes over WebSocket with `subscribe-stats` and receives `stats-snapshot` payloads (includes `stats`, `historical`, `health`, `status`, **Core** RPC invite diagnostics, and **Plugin RPC** protocol stats). `update-stats` notifies subscribers only; it does not replace the snapshot stream.
- P2P domain connections
- Process metrics (CPU, memory)
- Peer connection metrics
- **Historical Data**: `GET /api/stats/historical?minutes=N` - Historical metrics for the specified time range (1-1440 minutes).
### Metrics Configuration ### Metrics Configuration
@@ -972,7 +990,7 @@ Configure metrics behavior via environment variables:
- `METRICS_AGGREGATION_INTERVAL`: Aggregation frequency - `METRICS_AGGREGATION_INTERVAL`: Aggregation frequency
- `METRICS_MAX_BUFFER_SIZE`: Maximum samples to buffer - `METRICS_MAX_BUFFER_SIZE`: Maximum samples to buffer
View metrics in the admin interface "Stats" tab with interactive charts and real-time updates. View metrics in the admin **Stats** tab (charts + **Core** / **Plugin RPC** sections). Open the **Diagnostics** tab or `GET /api/diagnostics/invites` for detailed invite RPC diagnostics.
## Subnet Configuration ## Subnet Configuration
@@ -1064,10 +1082,10 @@ For more detailed information on specific topics, see:
- **[Plugin SDK Reference](docs/plugins/PLUGIN_SDK.md)**: Comprehensive API reference for plugin development - **[Plugin SDK Reference](docs/plugins/PLUGIN_SDK.md)**: Comprehensive API reference for plugin development
- **[REST API Documentation](docs/RESTAPI.md)**: Complete API endpoint reference including plugin management endpoints - **[REST API Documentation](docs/RESTAPI.md)**: Complete API endpoint reference including plugin management endpoints
- **[HyperDB Integration](docs/plugins/HYPERDB.md)**: Database operations for plugins - **[HyperDB Integration](docs/plugins/HYPERDB.md)**: Database operations for plugins
- **[Plugin Channels](docs/plugins/PLUGIN_CHANNELS.md)**: P2P communication via Protomux channels - **[Plugin RPC](docs/plugins/PLUGIN_CHANNELS.md)**: Plugin peer protocols via protomux-rpc
- **[Hyperdrive Integration](docs/plugins/HYPERDRIVE.md)**: Distributed file system for plugins - **[Hyperdrive Integration](docs/plugins/HYPERDRIVE.md)**: Distributed file system for plugins
- **[Proxy Server Documentation](proxy-server/README.md)**: Standalone proxy server configuration and usage - **[Proxy Server Documentation](proxy-server/README.md)**: Standalone proxy server configuration and usage
- **[Test Scripts](test-scripts/README.md)**: Smoke validation scripts for `p2ns.admin` and `peer.paste` - **[Test Scripts](test-scripts/README.md)**: Smoke tests and `npm run test:plugin-rpc` for plugin RPC contract
- **[Architecture RFCs](docs/rfcs/README.md)**: Design proposals for consensus, discovery, packaging, and admin security - **[Architecture RFCs](docs/rfcs/README.md)**: Design proposals for consensus, discovery, packaging, and admin security
### Holepunch-Native Defaults ### Holepunch-Native Defaults
@@ -1075,7 +1093,7 @@ For more detailed information on specific topics, see:
The following modernization features are enabled by default: The following modernization features are enabled by default:
- Shared Corestore namespaces for plugin databases (`USE_SHARED_CORESTORE_NAMESPACES=true`) - Shared Corestore namespaces for plugin databases (`USE_SHARED_CORESTORE_NAMESPACES=true`)
- Protomux RPC channel attachment (`ENABLE_PROTOMUX_RPC=true`) - Plugin protomux-rpc (`ENABLE_PROTOMUX_RPC=true`; RPC-only plugin protocols — see [PLUGIN_CHANNELS.md](plugins/PLUGIN_CHANNELS.md))
- Hypercore/Corestore stats collection in `/api/stats` (`ENABLE_HYPERCORE_STATS=true`) - Hypercore/Corestore stats collection in `/api/stats` (`ENABLE_HYPERCORE_STATS=true`)
Each can be explicitly disabled by setting its flag to `false`. Each can be explicitly disabled by setting its flag to `false`.
+104 -92
View File
@@ -8,28 +8,32 @@ The P2NS (Peer-to-Peer Name System) admin backend API, hosted at `https://p2ns.a
## WebSocket Endpoint ## WebSocket Endpoint
- **URL**: `wss://p2ns.admin/ws` - **URL**: `wss://p2ns.admin/ws`
- **Description**: Establishes a WebSocket connection for real-time updates from the server. - **Description**: Establishes a WebSocket connection for real-time updates from the server.
- **Message Types**: - **Client → server messages**:
- `log`: System logs with `level` (info, error) and `message`. - `subscribe-stats` / `unsubscribe-stats` / `request-stats-snapshot` — Stats tab live data.
- `holesail-log`: Holesail server/client logs with `id`, `level`, and `message`. - `subscribe-log``{ "type": "subscribe-log", "channel": "core", "lines": 1000 }` (channels: `core`, `proxy`, `httpProxy`, `dns`, `plugins`, `holesail`).
- `update-database`: Triggers refresh of domains and entries. - `unsubscribe-log` — Stop log tail.
- `update-peers`: Triggers refresh of peers. - `request-domains` — Refresh domains list (server replies with `domains-list`).
- `update-certs`: Triggers refresh of certificates.
- `update-interfaces`: Triggers refresh of virtual interfaces. - **Server → client messages**:
- `update-local-dns`: Triggers refresh of local DNS and conflict selector. - `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-holesail`: Triggers refresh of Holesail servers. - `update-stats` — Notifies stats subscribers to apply their latest snapshot (does not embed metrics itself).
- `update-holesail-clients`: Triggers refresh of Holesail clients. - `update-health` — Health payload for Diagnostics tab subscribers.
- `update-settings`: Triggers refresh of settings and subnets. - `file-log``{ "type": "file-log", "channel": "dns", "level": "info", "message": "<line>" }` (live log tail).
- `update-stats`: Triggers refresh of stats tab. - `log-snapshot` — Initial tail after `subscribe-log`: `{ "type": "log-snapshot", "channel": "core", "lines": ["..."] }`.
- `update-plugins`: Triggers refresh of plugins tab. - `log`**Legacy**; may still map to core. Prefer `file-log` + `subscribe-log`.
- `update-plugin-settings`: Triggers refresh of plugin settings. - `holesail-log` — Holesail child process logs (`id`, `level`, `message`).
- `plugin-log`: Plugin log messages with `domain` (string), `level` (string: debug/info/warn/error), `component` (string), and `message` (string). - `plugin-log` — Per-plugin logs (`domain`, `level`, `component`, `message`).
- `system-reset`: Signals a system reset, requiring a client reload. - `domains-list` — Resolved domains array.
- **Example**: - `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 ```json
{ {
"type": "log", "type": "file-log",
"channel": "core",
"level": "info", "level": "info",
"message": "Starting main function..." "message": "2026-05-28T12:00:00.000Z [INFO] [Main] Starting..."
} }
``` ```
@@ -724,7 +728,7 @@ The P2NS (Peer-to-Peer Name System) admin backend API, hosted at `https://p2ns.a
{"id":"abc123"} {"id":"abc123"}
``` ```
### 29. POST /api/holesail-delete ### 33. POST /api/holesail-delete
- **Description**: Deletes a Holesail server by ID and removes it from `holesail_servers.json`. - **Description**: Deletes a Holesail server by ID and removes it from `holesail_servers.json`.
- **Request Body**: JSON with `id` (string). - **Request Body**: JSON with `id` (string).
- **Response**: Plain text `OK` on success, error message on failure. - **Response**: Plain text `OK` on success, error message on failure.
@@ -743,7 +747,7 @@ The P2NS (Peer-to-Peer Name System) admin backend API, hosted at `https://p2ns.a
OK OK
``` ```
### 30. POST /api/holesail-restart ### 34. POST /api/holesail-restart
- **Description**: Restarts a Holesail server by ID, optionally reassigning its domain. Persists to `holesail_servers.json`. - **Description**: Restarts a Holesail server by ID, optionally reassigning its domain. Persists to `holesail_servers.json`.
- **Request Body**: JSON with `id` (string). - **Request Body**: JSON with `id` (string).
- **Response**: Plain text `OK` on success, error message on failure. - **Response**: Plain text `OK` on success, error message on failure.
@@ -762,7 +766,7 @@ The P2NS (Peer-to-Peer Name System) admin backend API, hosted at `https://p2ns.a
OK OK
``` ```
### 31. POST /api/holesail-client-create ### 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. - **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: - **Request Body**: JSON with:
- `domain` (string, required): Domain name (must be owned by local writer) - `domain` (string, required): Domain name (must be owned by local writer)
@@ -787,7 +791,7 @@ The P2NS (Peer-to-Peer Name System) admin backend API, hosted at `https://p2ns.a
{"id":"example.tld_web"} {"id":"example.tld_web"}
``` ```
### 32. POST /api/holesail-client-delete ### 36. POST /api/holesail-client-delete
- **Description**: Deletes a Holesail client by ID, closing connections and removing it from `holesail_clients.json`. - **Description**: Deletes a Holesail client by ID, closing connections and removing it from `holesail_clients.json`.
- **Request Body**: JSON with `id` (string). - **Request Body**: JSON with `id` (string).
- **Response**: Plain text `OK` on success, error message on failure. - **Response**: Plain text `OK` on success, error message on failure.
@@ -806,7 +810,7 @@ The P2NS (Peer-to-Peer Name System) admin backend API, hosted at `https://p2ns.a
OK OK
``` ```
### 33. POST /api/holesail-client-restart ### 37. POST /api/holesail-client-restart
- **Description**: Restarts a Holesail client by ID, ensuring the port is free and connections are closed. - **Description**: Restarts a Holesail client by ID, ensuring the port is free and connections are closed.
- **Request Body**: JSON with `id` (string). - **Request Body**: JSON with `id` (string).
- **Response**: Plain text `OK` on success, error message on failure. - **Response**: Plain text `OK` on success, error message on failure.
@@ -825,7 +829,7 @@ The P2NS (Peer-to-Peer Name System) admin backend API, hosted at `https://p2ns.a
OK OK
``` ```
### 34. POST /api/update-settings ### 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. - **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. - **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). - **Response**: JSON object with `message` (string), `restartRequired` (boolean), and optionally `restartRequiredSettings` (array of strings).
@@ -848,7 +852,7 @@ The P2NS (Peer-to-Peer Name System) admin backend API, hosted at `https://p2ns.a
} }
``` ```
### 35. GET /api/network-interfaces ### 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. - **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: - **Response**: JSON object with `interfaces` (array of interface objects). Each interface object contains:
- `value` (string): Interface name (e.g., "lo0", "lo", "eth0") - `value` (string): Interface name (e.g., "lo0", "lo", "eth0")
@@ -872,7 +876,7 @@ The P2NS (Peer-to-Peer Name System) admin backend API, hosted at `https://p2ns.a
``` ```
- **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. - **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.
### 36. GET /api/subnets ### 40. GET /api/subnets
- **Description**: Retrieves all configured subnets with capacity information. Returns default subnet from `SUBNET_BASE` if no subnets are configured. - **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: - **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") - `base` (string): Network base IP address (e.g., "192.168.3.0")
@@ -918,7 +922,7 @@ The P2NS (Peer-to-Peer Name System) admin backend API, hosted at `https://p2ns.a
} }
``` ```
### 36. POST /api/subnets ### 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. - **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: - **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") - `base` (string, required): Network base IP address (e.g., "192.168.3.0")
@@ -950,7 +954,7 @@ The P2NS (Peer-to-Peer Name System) admin backend API, hosted at `https://p2ns.a
- `startIndex` must be between 1 and 254 (or up to subnet size - 2) - `startIndex` must be between 1 and 254 (or up to subnet size - 2)
- Subnets must not overlap with each other - Subnets must not overlap with each other
### 37. GET /api/health ### 42. GET /api/health
- **Description**: Health check endpoint supporting liveness and readiness probes. - **Description**: Health check endpoint supporting liveness and readiness probes.
- **Query Parameters**: - **Query Parameters**:
- `probe`: Type of health probe (`liveness` or `readiness`, default: `liveness`). - `probe`: Type of health probe (`liveness` or `readiness`, default: `liveness`).
@@ -981,13 +985,14 @@ The P2NS (Peer-to-Peer Name System) admin backend API, hosted at `https://p2ns.a
} }
``` ```
### 38. GET /api/stats ### 43. GET /api/stats
- **Description**: Retrieves real-time system metrics including request statistics, Holesail connections, process metrics, and peer information. - **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 with comprehensive metrics including: - **Response**: JSON object including:
- Request statistics (total, success rate, average response time, failed requests) - Request statistics (total, success rate, average response time, failed requests)
- Holesail children (servers, clients, P2P domain connections) with status, PID, uptime, CPU/memory usage - Holesail children (servers, clients, P2P domain connections) with status, PID, uptime, CPU/memory usage
- Process metrics - `core` — Core control-plane / invite RPC diagnostics (`diagnoseInviteIssues`)
- Peer connection metrics - `pluginRpc` and `peerChannels` — Per-plugin protomux-rpc protocol stats (`transport: 'rpc'`, methods, `rpcOpen` counts)
- HyperDB / Hyperdrive sections when available
- **Status Codes**: - **Status Codes**:
- `200`: Success. - `200`: Success.
- `500`: Failed to fetch stats. - `500`: Failed to fetch stats.
@@ -1019,7 +1024,26 @@ The P2NS (Peer-to-Peer Name System) admin backend API, hosted at `https://p2ns.a
} }
``` ```
### 39. GET /api/stats/historical ### 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. - **Description**: Retrieves historical metrics data for a specified time range.
- **Query Parameters**: - **Query Parameters**:
- `minutes`: Time range in minutes (1-1440, default: 60). - `minutes`: Time range in minutes (1-1440, default: 60).
@@ -1033,7 +1057,7 @@ The P2NS (Peer-to-Peer Name System) admin backend API, hosted at `https://p2ns.a
"https://p2ns.admin/api/stats/historical?minutes=1440" "https://p2ns.admin/api/stats/historical?minutes=1440"
``` ```
### 40. GET /api/backups ### 47. GET /api/backups
- **Description**: Lists all available backups with metadata including name, timestamp, size, and file count. - **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`. - **Response**: JSON array of backup objects with `name`, `timestamp`, `size`, `sizeFormatted`, and `fileCount`.
- **Status Codes**: - **Status Codes**:
@@ -1056,7 +1080,7 @@ The P2NS (Peer-to-Peer Name System) admin backend API, hosted at `https://p2ns.a
] ]
``` ```
### 41. POST /api/backups/create ### 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. - **Description**: Creates a manual backup of configuration files, certificates, and cache data. Automatic cleanup of old backups is performed before creation.
- **Request Body**: None. - **Request Body**: None.
- **Response**: JSON object with `success` (boolean) and `path` (string, backup file path). - **Response**: JSON object with `success` (boolean) and `path` (string, backup file path).
@@ -1075,7 +1099,7 @@ The P2NS (Peer-to-Peer Name System) admin backend API, hosted at `https://p2ns.a
} }
``` ```
### 42. POST /api/backups/restore ### 49. POST /api/backups/restore
- **Description**: Restores system configuration from a backup. Replaces current configuration files and certificates. - **Description**: Restores system configuration from a backup. Replaces current configuration files and certificates.
- **Request Body**: JSON with `backupName` (string, backup name to restore). - **Request Body**: JSON with `backupName` (string, backup name to restore).
- **Response**: JSON object with `success` (boolean) and `message` (string). - **Response**: JSON object with `success` (boolean) and `message` (string).
@@ -1097,7 +1121,7 @@ The P2NS (Peer-to-Peer Name System) admin backend API, hosted at `https://p2ns.a
} }
``` ```
### 43. DELETE /api/backups/:id ### 50. DELETE /api/backups/:id
- **Description**: Deletes a backup by name. Supports both directory and tar.gz formats. - **Description**: Deletes a backup by name. Supports both directory and tar.gz formats.
- **Path Parameters**: - **Path Parameters**:
- `id`: Backup name (e.g., `backup-20240101-000000` or `backup-20240101-000000.tar.gz`). - `id`: Backup name (e.g., `backup-20240101-000000` or `backup-20240101-000000.tar.gz`).
@@ -1112,7 +1136,7 @@ The P2NS (Peer-to-Peer Name System) admin backend API, hosted at `https://p2ns.a
https://p2ns.admin/api/backups/backup-20240101-000000 https://p2ns.admin/api/backups/backup-20240101-000000
``` ```
### 44. GET /api/backups/:id/metadata ### 51. GET /api/backups/:id/metadata
- **Description**: Retrieves detailed metadata for a backup including file list, sizes, and timestamps. - **Description**: Retrieves detailed metadata for a backup including file list, sizes, and timestamps.
- **Path Parameters**: - **Path Parameters**:
- `id`: Backup name. - `id`: Backup name.
@@ -1127,7 +1151,7 @@ The P2NS (Peer-to-Peer Name System) admin backend API, hosted at `https://p2ns.a
https://p2ns.admin/api/backups/backup-20240101-000000/metadata https://p2ns.admin/api/backups/backup-20240101-000000/metadata
``` ```
### 45. POST /api/diagnostics/dns-lookup ### 52. POST /api/diagnostics/dns-lookup
- **Description**: Performs DNS lookup for a domain with specified record type. - **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. - **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). - **Response**: JSON object with `success` (boolean), `domain`, `type`, `results` (array), and `responseTime` (number).
@@ -1152,7 +1176,7 @@ The P2NS (Peer-to-Peer Name System) admin backend API, hosted at `https://p2ns.a
} }
``` ```
### 46. POST /api/diagnostics/ping ### 53. POST /api/diagnostics/ping
- **Description**: Tests network connectivity using ping. Supports both streaming and non-streaming modes. - **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). - **Request Body**: JSON with `target` (string, required), `count` (number, optional, default: 4), and `stream` (boolean, optional, default: false).
- **Response**: - **Response**:
@@ -1177,7 +1201,7 @@ The P2NS (Peer-to-Peer Name System) admin backend API, hosted at `https://p2ns.a
https://p2ns.admin/api/diagnostics/ping https://p2ns.admin/api/diagnostics/ping
``` ```
### 47. POST /api/diagnostics/traceroute ### 54. POST /api/diagnostics/traceroute
- **Description**: Traces network path to a target. Supports both streaming and non-streaming modes. - **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). - **Request Body**: JSON with `target` (string, required) and `stream` (boolean, optional, default: false).
- **Response**: - **Response**:
@@ -1195,7 +1219,7 @@ The P2NS (Peer-to-Peer Name System) admin backend API, hosted at `https://p2ns.a
https://p2ns.admin/api/diagnostics/traceroute https://p2ns.admin/api/diagnostics/traceroute
``` ```
### 48. POST /api/diagnostics/connection-test ### 55. POST /api/diagnostics/connection-test
- **Description**: Tests TCP connectivity to a domain and port combination. - **Description**: Tests TCP connectivity to a domain and port combination.
- **Request Body**: JSON with `domain` (string, required) and `port` (number, required). - **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`. - **Response**: JSON object with `success` (boolean), `domain`, `ip` (resolved IP), `port`, `latency` (if successful), `error` (if failed), and `responseTime`.
@@ -1221,37 +1245,25 @@ The P2NS (Peer-to-Peer Name System) admin backend API, hosted at `https://p2ns.a
} }
``` ```
### 49. GET /api/diagnostics/bandwidth ### 56. GET /api/diagnostics/bandwidth
- **Description**: Retrieves network interface information and configuration. Note: Real-time bandwidth statistics require system-specific tools and are not available via Node.js. - **Description**: Network interface information and configuration. Real-time throughput stats are not available via Node.js; response is interface layout only.
- **Response**: JSON object with `interfaces` (object mapping interface names to configuration), `note` (string), and `responseTime`. - **Response**: JSON with `interfaces`, optional `note`, `responseTime`.
- **Status Codes**: - **Status Codes**: `200`, `500`
- `200`: Success.
- `500`: Server error.
- **Example**: - **Example**:
```bash ```bash
curl -X GET \ curl -k https://p2ns.admin/api/diagnostics/bandwidth
https://p2ns.admin/api/diagnostics/bandwidth
```
```json
{
"interfaces": {
"eth0": {
"name": "eth0",
"addresses": [
{
"address": "192.168.1.100",
"netmask": "255.255.255.0",
"family": "IPv4"
}
]
}
},
"note": "Bandwidth statistics require system-specific tools. Interface information only.",
"responseTime": 5
}
``` ```
### 50. GET /<tab> ### 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. - **Description**: Redirects to the admin panel with the specified tab (e.g., `/domains`, `/host`, `/local-dns`) open.
- **Path Parameters**: - **Path Parameters**:
- `tab`: One of `domains`, `host`, `local-dns`, `entries`, `peers`, `certs`, `interfaces`, `logs`, `settings`. - `tab`: One of `domains`, `host`, `local-dns`, `entries`, `peers`, `certs`, `interfaces`, `logs`, `settings`.
@@ -1265,7 +1277,7 @@ The P2NS (Peer-to-Peer Name System) admin backend API, hosted at `https://p2ns.a
https://p2ns.admin/domains https://p2ns.admin/domains
``` ```
### 38. GET /favicon.ico ### 59. GET /favicon.ico
- **Description**: Returns a 404 response (favicon not implemented). - **Description**: Returns a 404 response (favicon not implemented).
- **Response**: Plain text `Not Found`. - **Response**: Plain text `Not Found`.
- **Status Codes**: - **Status Codes**:
@@ -1281,7 +1293,7 @@ The P2NS (Peer-to-Peer Name System) admin backend API, hosted at `https://p2ns.a
## Consensus Endpoints ## Consensus Endpoints
### 51. GET /api/consensus/:domain ### 60. GET /api/consensus/:domain
- **Description**: Retrieves the consensus state for a specific domain, including vote counts, quorum status, and resolution information. - **Description**: Retrieves the consensus state for a specific domain, including vote counts, quorum status, and resolution information.
- **Path Parameters**: - **Path Parameters**:
- `domain`: The domain name (e.g., `example.tld`). - `domain`: The domain name (e.g., `example.tld`).
@@ -1320,7 +1332,7 @@ The P2NS (Peer-to-Peer Name System) admin backend API, hosted at `https://p2ns.a
} }
``` ```
### 52. GET /api/consensus/metrics ### 61. GET /api/consensus/metrics
- **Description**: Retrieves overall consensus metrics including resolution statistics, quorum failures, ties, and validation failures. - **Description**: Retrieves overall consensus metrics including resolution statistics, quorum failures, ties, and validation failures.
- **Response**: JSON object with: - **Response**: JSON object with:
- `resolutions` (number): Total number of successful domain resolutions. - `resolutions` (number): Total number of successful domain resolutions.
@@ -1361,7 +1373,7 @@ The P2NS (Peer-to-Peer Name System) admin backend API, hosted at `https://p2ns.a
} }
``` ```
### 53. POST /api/consensus/recalculate ### 62. POST /api/consensus/recalculate
- **Description**: Forces a consensus recalculation for all domains. Invalidates the consensus cache and triggers auto-voting checks. - **Description**: Forces a consensus recalculation for all domains. Invalidates the consensus cache and triggers auto-voting checks.
- **Request Body**: None. - **Request Body**: None.
- **Response**: JSON object with `success` (boolean) and `message` (string). - **Response**: JSON object with `success` (boolean) and `message` (string).
@@ -1381,7 +1393,7 @@ The P2NS (Peer-to-Peer Name System) admin backend API, hosted at `https://p2ns.a
} }
``` ```
### 54. POST /api/consensus/recalculate/:domain ### 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. - **Description**: Forces a consensus recalculation for a specific domain. Invalidates the consensus cache for that domain and triggers auto-voting.
- **Path Parameters**: - **Path Parameters**:
- `domain`: The domain name (e.g., `example.tld`). - `domain`: The domain name (e.g., `example.tld`).
@@ -1405,7 +1417,7 @@ The P2NS (Peer-to-Peer Name System) admin backend API, hosted at `https://p2ns.a
## Service Subscription Endpoints ## Service Subscription Endpoints
### 55. GET /api/domain-services ### 64. GET /api/domain-services
- **Description**: Retrieves all services configured for a specific domain from its claim record. - **Description**: Retrieves all services configured for a specific domain from its claim record.
- **Query Parameters**: - **Query Parameters**:
- `domain` (string, required): The domain name to query services for. - `domain` (string, required): The domain name to query services for.
@@ -1440,7 +1452,7 @@ The P2NS (Peer-to-Peer Name System) admin backend API, hosted at `https://p2ns.a
] ]
``` ```
### 56. GET /api/service-subscriptions ### 65. GET /api/service-subscriptions
- **Description**: Lists all service subscriptions configured on this node. - **Description**: Lists all service subscriptions configured on this node.
- **Response**: JSON array of subscription objects, each containing: - **Response**: JSON array of subscription objects, each containing:
- `domain` (string): Domain name - `domain` (string): Domain name
@@ -1468,7 +1480,7 @@ The P2NS (Peer-to-Peer Name System) admin backend API, hosted at `https://p2ns.a
] ]
``` ```
### 57. GET /api/subscribe-all-domains ### 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. - **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). - **Response**: JSON array of domain names (strings).
- **Status Codes**: - **Status Codes**:
@@ -1483,7 +1495,7 @@ The P2NS (Peer-to-Peer Name System) admin backend API, hosted at `https://p2ns.a
["example.tld", "another.tld"] ["example.tld", "another.tld"]
``` ```
### 58. POST /api/service-subscribe ### 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`. - **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: - **Request Body**: JSON with:
- `domain` (string, required): Domain name - `domain` (string, required): Domain name
@@ -1509,7 +1521,7 @@ The P2NS (Peer-to-Peer Name System) admin backend API, hosted at `https://p2ns.a
{"success": true} {"success": true}
``` ```
### 59. POST /api/service-unsubscribe ### 68. POST /api/service-unsubscribe
- **Description**: Unsubscribes from a specific service. Deletes the associated Holesail client and removes the subscription from `subscriptions.json`. - **Description**: Unsubscribes from a specific service. Deletes the associated Holesail client and removes the subscription from `subscriptions.json`.
- **Request Body**: JSON with: - **Request Body**: JSON with:
- `domain` (string, required): Domain name - `domain` (string, required): Domain name
@@ -1532,7 +1544,7 @@ The P2NS (Peer-to-Peer Name System) admin backend API, hosted at `https://p2ns.a
{"success": true} {"success": true}
``` ```
### 60. POST /api/subscribe-all ### 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. - **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: - **Request Body**: JSON with:
- `domain` (string, required): Domain name - `domain` (string, required): Domain name
@@ -1553,7 +1565,7 @@ The P2NS (Peer-to-Peer Name System) admin backend API, hosted at `https://p2ns.a
{"success": true} {"success": true}
``` ```
### 61. POST /api/unsubscribe-all ### 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. - **Description**: Disables "subscribe all" for a domain and unsubscribes from all services for that domain. Deletes all associated Holesail clients.
- **Request Body**: JSON with: - **Request Body**: JSON with:
- `domain` (string, required): Domain name - `domain` (string, required): Domain name
@@ -1578,7 +1590,7 @@ The P2NS (Peer-to-Peer Name System) admin backend API, hosted at `https://p2ns.a
**Note:** For detailed information about the plugin system, see [plugins/README.md](plugins/README.md) and [plugins/PLUGIN_SDK.md](plugins/PLUGIN_SDK.md). **Note:** For detailed information about the plugin system, see [plugins/README.md](plugins/README.md) and [plugins/PLUGIN_SDK.md](plugins/PLUGIN_SDK.md).
### 62. GET /api/plugins ### 71. GET /api/plugins
- **Description**: Lists all plugins with their information, status, actions, and settings. Includes both loaded and stopped 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: - **Response**: JSON object with `plugins` (array of plugin objects). Each plugin object contains:
- `domain` (string): Plugin domain name - `domain` (string): Plugin domain name
@@ -1639,7 +1651,7 @@ The P2NS (Peer-to-Peer Name System) admin backend API, hosted at `https://p2ns.a
} }
``` ```
### 63. GET /api/plugins/:domain ### 72. GET /api/plugins/:domain
- **Description**: Retrieves detailed information for a specific plugin. - **Description**: Retrieves detailed information for a specific plugin.
- **Path Parameters**: - **Path Parameters**:
- `domain`: The plugin domain name (e.g., `example.plugin`). - `domain`: The plugin domain name (e.g., `example.plugin`).
@@ -1654,7 +1666,7 @@ The P2NS (Peer-to-Peer Name System) admin backend API, hosted at `https://p2ns.a
https://p2ns.admin/api/plugins/example.plugin https://p2ns.admin/api/plugins/example.plugin
``` ```
### 64. POST /api/plugins/:domain/start ### 73. POST /api/plugins/:domain/start
- **Description**: Starts a stopped plugin. Loads the plugin handler and initializes resources. - **Description**: Starts a stopped plugin. Loads the plugin handler and initializes resources.
- **Path Parameters**: - **Path Parameters**:
- `domain`: The plugin domain name (e.g., `example.plugin`). - `domain`: The plugin domain name (e.g., `example.plugin`).
@@ -1678,7 +1690,7 @@ The P2NS (Peer-to-Peer Name System) admin backend API, hosted at `https://p2ns.a
} }
``` ```
### 65. POST /api/plugins/:domain/stop ### 74. POST /api/plugins/:domain/stop
- **Description**: Stops a running plugin. Unloads the plugin handler and cleans up resources. - **Description**: Stops a running plugin. Unloads the plugin handler and cleans up resources.
- **Path Parameters**: - **Path Parameters**:
- `domain`: The plugin domain name (e.g., `example.plugin`). - `domain`: The plugin domain name (e.g., `example.plugin`).
@@ -1702,7 +1714,7 @@ The P2NS (Peer-to-Peer Name System) admin backend API, hosted at `https://p2ns.a
} }
``` ```
### 66. POST /api/plugins/:domain/reload ### 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. - **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**: - **Path Parameters**:
- `domain`: The plugin domain name (e.g., `example.plugin`). - `domain`: The plugin domain name (e.g., `example.plugin`).
@@ -1726,7 +1738,7 @@ The P2NS (Peer-to-Peer Name System) admin backend API, hosted at `https://p2ns.a
} }
``` ```
### 67. POST /api/plugins/:domain/actions/:actionName ### 76. POST /api/plugins/:domain/actions/:actionName
- **Description**: Executes a registered plugin action. The action handler is called with the provided parameters. - **Description**: Executes a registered plugin action. The action handler is called with the provided parameters.
- **Path Parameters**: - **Path Parameters**:
- `domain`: The plugin domain name (e.g., `example.plugin`). - `domain`: The plugin domain name (e.g., `example.plugin`).
@@ -1756,7 +1768,7 @@ The P2NS (Peer-to-Peer Name System) admin backend API, hosted at `https://p2ns.a
} }
``` ```
### 68. POST /api/plugins/:domain/settings ### 77. POST /api/plugins/:domain/settings
- **Description**: Updates plugin settings. Saves settings to `cache/plugin-settings/{domain}.json` and persists them across plugin restarts. - **Description**: Updates plugin settings. Saves settings to `cache/plugin-settings/{domain}.json` and persists them across plugin restarts.
- **Path Parameters**: - **Path Parameters**:
- `domain`: The plugin domain name (e.g., `example.plugin`). - `domain`: The plugin domain name (e.g., `example.plugin`).
@@ -1781,7 +1793,7 @@ The P2NS (Peer-to-Peer Name System) admin backend API, hosted at `https://p2ns.a
} }
``` ```
### 69. GET /api/token ### 78. GET /api/token
- **Description**: Generates a signed Ed25519 authentication token for plugin authentication. Available to all plugins globally. - **Description**: Generates a signed Ed25519 authentication token for plugin authentication. Available to all plugins globally.
- **Request Headers**: None required. - **Request Headers**: None required.
- **Response**: JSON object with `token` (string), `expiresAt` (number), and `peerId` (string). - **Response**: JSON object with `token` (string), `expiresAt` (number), and `peerId` (string).
@@ -1879,4 +1891,4 @@ See [plugins/PLUGIN_SDK.md](plugins/PLUGIN_SDK.md#authentication-and-authorizati
- Use tools like `curl` or Postman to test endpoints. - Use tools like `curl` or Postman to test endpoints.
- Verify WebSocket updates using a WebSocket client (e.g., `wscat`). - 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`. - Test DNS record creation with various types (e.g., SRV, SOA) and check `local_dns.json`.
- Monitor logs via WebSocket or the admin interface for errors. - Monitor logs in the admin **Logs** tab (`subscribe-log` per channel) or `GET /api/logs/:channel`; plugin logs use `plugin-log` WebSocket messages.
+8 -8
View File
@@ -126,7 +126,7 @@ The application layer enables rich functionality through plugins:
- **Internal domains**: Plugins register domains (e.g., "peer.directory") that resolve to localhost - **Internal domains**: Plugins register domains (e.g., "peer.directory") that resolve to localhost
- **HyperDB**: Distributed databases with automatic P2P replication - **HyperDB**: Distributed databases with automatic P2P replication
- **Hyperdrive**: Distributed file systems for content hosting - **Hyperdrive**: Distributed file systems for content hosting
- **Protomux channels**: Custom protocols for real-time peer communication - **Plugin RPC (protomux-rpc)**: Named JSON methods for real-time peer communication between plugins
--- ---
@@ -276,16 +276,16 @@ For file storage, plugins use Hyperdrive:
- **Version history**: Full history of changes preserved - **Version history**: Full history of changes preserved
- **Streaming support**: Large files can be streamed without full download - **Streaming support**: Large files can be streamed without full download
### 6.4 Protomux Channels: Custom Protocols ### 6.4 Plugin RPC: Custom Protocols
For real-time communication, plugins register Protomux channels: For real-time communication, plugins register protomux-rpc protocols via `sdk.channels`:
- **Protocol multiplexing**: Multiple protocols share a single connection - **Protocol multiplexing**: Multiple RPC muxes share a single Hyperswarm connection
- **Typed messages**: JSON, string, or binary encoding - **Named methods**: JSON request/response and fire-and-forget events (e.g. `chat.message`, `profile.updated`)
- **Bidirectional**: Both peers can send and receive - **Bidirectional**: `request`, `event`, and `broadcast` between peers
- **Auto-reconnection**: Channels re-establish when peers reconnect - **Auto-reconnection**: RPC sessions are recreated when peers reconnect (see admin **Plugin RPC** stats)
This enables chat applications, real-time collaboration, gaming, and any protocol requiring low-latency peer communication. This enables chat, collaboration, live profile sync, and other low-latency peer protocols without HTTP. See [plugins/PLUGIN_CHANNELS.md](plugins/PLUGIN_CHANNELS.md).
--- ---
+65 -396
View File
@@ -22,8 +22,9 @@ Upgrade **all nodes and plugins together**. Mixed old (message channel + RPC) an
| `broadcast('x', data)` | `broadcast('x', 'my.event', data)` | | `broadcast('x', data)` | `broadcast('x', 'my.event', data)` |
| `channels.rpc.register` | `channels.register` with `methods` | | `channels.rpc.register` | `channels.register` with `methods` |
| `send('x', peer, data)` | `event('x', peer, 'message', data)` or a named method | | `send('x', peer, data)` | `event('x', peer, 'message', data)` or a named method |
| `closeChannel('x')` | `unregister('x')` |
## Basic Usage ## Basic usage
> **Note:** The SDK is available via `require('../../includes/plugins/sdk')` from `plugin-sites/`. > **Note:** The SDK is available via `require('../../includes/plugins/sdk')` from `plugin-sites/`.
@@ -35,12 +36,14 @@ const sdk = require('../../includes/plugins/sdk');
sdk.channels.register('chat', { sdk.channels.register('chat', {
methods: { methods: {
'chat.message': async (data, { peerId }) => { 'chat.message': async (data, { peerId }) => {
console.log(`Received from ${peerId}:`, data); sdk.log.debug('chat', `From ${peerId}: ${JSON.stringify(data)}`);
return null; return null;
} },
'chat.ping': async (_value, { peerId }) => ({ pong: true, peerId })
}, },
onPeerOpen: (peerId) => console.log(`Peer ${peerId} RPC ready`), onPeerOpen: (peerId) => sdk.log.debug('chat', `RPC ready: ${peerId}`),
onPeerClose: (peerId) => console.log(`Peer ${peerId} disconnected`) onPeerClose: (peerId) => sdk.log.debug('chat', `RPC closed: ${peerId}`),
autoReconnect: true
}); });
``` ```
@@ -57,432 +60,98 @@ const sentCount = sdk.channels.broadcast('chat', 'chat.message', {
Use `sdk.channels.isRpcReady('chat', peerId)` before sending if the peer just connected. Use `sdk.channels.isRpcReady('chat', peerId)` before sending if the peer just connected.
### Getting Channel Information ### Protocol information
```javascript ```javascript
// Get channel info const info = sdk.channels.getProtocol('chat'); // alias: getChannel()
const channelInfo = sdk.channels.getChannel('chat'); const protocols = sdk.channels.listProtocols(); // alias: listChannels()
// List all channels for this plugin
const channels = sdk.channels.listChannels();
// Get connected peers for a channel
const peers = sdk.channels.getConnectedPeers('chat'); const peers = sdk.channels.getConnectedPeers('chat');
const ready = sdk.channels.isRpcReady('chat', peerId);
// Check if a peer is connected
const isConnected = sdk.channels.isPeerConnected('chat', peerId);
``` ```
## Encoding Types `getProtocol()` returns RPC-centric state: `transport: 'rpc'`, `peerChannels` map with `rpc` handles per peer (no legacy message `channel` object).
### JSON Encoding ## Register options
Best for structured data: | Option | Description |
|--------|-------------|
| `methods` | Map of method name → `async (value, { peerId, pluginDomain, protocol }) => result` |
| `onPeerOpen` | Called when RPC is open for a peer |
| `onPeerClose` | Called when RPC closes for a peer |
| `autoReconnect` | Recreate RPC when peer reconnects (default: `true`) |
```javascript Method names must not start with `__p2ns.` (reserved for keepalive).
sdk.channels.createChannel('data', {
encoding: 'json',
onMessage: (data, peerId) => {
// data is automatically parsed as JSON
console.log(data.type, data.payload);
}
});
// Send JSON data ## Complete example: chat plugin
sdk.channels.send('data', peerId, {
type: 'update',
payload: { value: 42 }
});
```
### String Encoding
Best for text messages:
```javascript
sdk.channels.createChannel('text', {
encoding: 'string',
onMessage: (data, peerId) => {
// data is a string
console.log(`Message: ${data}`);
}
});
// Send string
sdk.channels.send('text', peerId, 'Hello, world!');
```
### Binary Encoding
Best for binary data (files, images, etc.):
```javascript
sdk.channels.createChannel('binary', {
encoding: 'binary',
onMessage: (data, peerId) => {
// data is a Buffer
console.log(`Received ${data.length} bytes`);
}
});
// Send binary data
const buffer = Buffer.from('Hello', 'utf8');
sdk.channels.send('binary', peerId, buffer);
```
### Custom Encoding
Use compact-encoding directly:
```javascript
const c = require('compact-encoding');
// Create custom encoding
const customEncoding = {
encode: (state, value) => {
// Custom encode logic
},
decode: (state) => {
// Custom decode logic
}
};
sdk.channels.createChannel('custom', {
encoding: customEncoding,
onMessage: (data, peerId) => {
// Handle custom encoded data
}
});
```
## Channel Options
### `encoding`
- **Type**: `string | Object`
- **Default**: `'string'`
- **Options**: `'json'`, `'string'`, `'binary'`, or custom encoding object
### `onMessage`
- **Type**: `Function(data, peerId, peer)`
- **Required**: No
- **Description**: Callback called when a message is received
```javascript
onMessage: (data, peerId, peer) => {
// data: Decoded message data
// peerId: String peer ID
// peer: Peer object from protomux
}
```
### `onOpen`
- **Type**: `Function(peerId, channel)`
- **Required**: No
- **Description**: Callback called when a peer connects to the channel
```javascript
onOpen: (peerId, channel) => {
// peerId: String peer ID
// channel: Protomux channel object
}
```
### `onClose`
- **Type**: `Function(peerId, channel)`
- **Required**: No
- **Description**: Callback called when a peer disconnects from the channel
```javascript
onClose: (peerId, channel) => {
// peerId: String peer ID
// channel: Protomux channel object
}
```
### `autoReconnect`
- **Type**: `boolean`
- **Default**: `true`
- **Description**: Automatically recreate channels when peers reconnect
## Complete Example: Chat Plugin
```javascript ```javascript
const sdk = require('../../includes/plugins/sdk'); const sdk = require('../../includes/plugins/sdk');
const messages = new Map(); // Store messages per peer
async function onInit() { async function onInit() {
// Create chat channel sdk.channels.register('chat', {
sdk.channels.createChannel('chat', { methods: {
encoding: 'json', 'chat.message': async (data, { peerId }) => {
onMessage: (data, peerId) => { sdk.websocket.broadcast({ type: 'chat', from: peerId, ...data });
if (data.type === 'message' && data.text) { return null;
// Store message
if (!messages.has(peerId)) {
messages.set(peerId, []);
}
messages.get(peerId).push({
timestamp: Date.now(),
peerId,
text: data.text,
direction: 'incoming'
});
} }
}, },
onOpen: (peerId) => { onPeerOpen: (peerId) => {
sdk.log.info('chat', `Peer ${peerId} connected`); sdk.channels.event('chat', peerId, 'chat.sync', { since: Date.now() });
},
onClose: (peerId) => {
sdk.log.info('chat', `Peer ${peerId} disconnected`);
} }
}); });
} }
function sendMessage(peerId, text) {
// Send message
sdk.channels.send('chat', peerId, {
type: 'message',
text: text,
timestamp: Date.now()
});
// Store locally
if (!messages.has(peerId)) {
messages.set(peerId, []);
}
messages.get(peerId).push({
timestamp: Date.now(),
peerId,
text,
direction: 'outgoing'
});
}
async function handler(req, res) {
const { path, query } = sdk.router.parseRequest(req);
if (path === 'api/send' && req.method === 'POST') {
// Handle send message API
let body = '';
req.on('data', chunk => { body += chunk.toString(); });
req.on('end', () => {
const { peerId, message } = JSON.parse(body);
sendMessage(peerId, message);
sdk.router.json(res, { success: true });
});
return true;
}
return false; // Let static files handle other routes
}
module.exports = { handler, onInit };
```
## Best Practices
### 1. Initialize Channels in `onInit`
Always create channels in the `onInit` hook to ensure they're ready when peers connect:
```javascript
async function onInit() {
sdk.channels.createChannel('my-channel', { /* ... */ });
}
```
### 2. Handle Errors Gracefully
Always wrap channel operations in try-catch:
```javascript
try {
sdk.channels.send('chat', peerId, message);
} catch (err) {
sdk.log.error('my-plugin', `Failed to send: ${err.message}`);
}
```
### 3. Clean Up on Shutdown
Channels are automatically cleaned up, but you can clean up local state:
```javascript
async function onShutdown() { async function onShutdown() {
// Channels are cleaned up automatically sdk.channels.unregister('chat');
// Clean up local state
messages.clear();
} }
module.exports = { handler, onInit, onShutdown };
``` ```
### 4. Use Appropriate Encoding ## Best practices
- Use `'json'` for structured data 1. **Register in `onInit`** so RPC is ready before peers attach.
- Use `'string'` for simple text 2. **Use explicit method names** (`domain.action`) instead of opaque blobs.
- Use `'binary'` for files or raw data 3. **Check `isRpcReady`** before `request` on freshly connected peers.
- Use custom encoding for specialized needs 4. **Unregister in `onShutdown`** to release handlers and peer state.
5. **Return JSON-serializable values** from request handlers; use `null` for fire-and-forget handlers.
### 5. Check Peer Connection ## Protocol naming
Before sending, check if peer is connected:
```javascript
if (sdk.channels.isPeerConnected('chat', peerId)) {
sdk.channels.send('chat', peerId, message);
} else {
sdk.log.warn('chat', `Peer ${peerId} not connected`);
}
```
### 6. Handle Reconnections
Channels automatically reconnect, but you may want to resend state:
```javascript
onOpen: (peerId) => {
// Send current state to newly connected peer
sdk.channels.send('chat', peerId, {
type: 'state',
data: getCurrentState()
});
}
```
## Protocol Naming
Channels are automatically scoped to your plugin domain:
- Plugin domain: `peer.chat` - Plugin domain: `peer.chat`
- Protocol: `chat` - Protocol: `chat`
- Full protocol: `peer.chat-chat` - Wire mux: `peer.chat-chat-rpc`
This prevents conflicts between plugins. You don't need to worry about the full protocol name - just use your protocol name in the SDK. Use the short protocol name in the SDK; the manager adds the domain and `-rpc` suffix.
## Limitations
1. **Peer Must Be Connected**: You can only send to peers that are currently connected via Hyperswarm
2. **No Guaranteed Delivery**: Messages are sent over the network without delivery guarantees
3. **No Ordering Guarantees**: Messages may arrive out of order
4. **Size Limits**: Very large messages may be split or fail
## Troubleshooting ## Troubleshooting
### Channel Not Created | Issue | Checks |
|-------|--------|
| RPC not registered | `PLUGIN_DOMAIN` set; `register()` in `onInit`; no reserved method names |
| Peer not receiving | Both nodes upgraded; `isRpcReady`; method name matches on both sides |
| `request` hangs | RPC open timeout; peer disconnected; handler throws |
- Check that `PLUGIN_DOMAIN` is set (should be automatic) ## API reference
- Verify channel creation in `onInit` hook
- Check logs for errors
### Messages Not Received | Method | Description |
|--------|-------------|
| `register(protocol, config)` | Register RPC protocol and handlers |
| `unregister(protocol)` | Tear down protocol |
| `request(protocol, peerId, method, value?, timeoutMs?)` | Request/response |
| `event(protocol, peerId, method, value?)` | Fire-and-forget |
| `broadcast(protocol, method, value)` | Fan-out event to all peers with open RPC |
| `getProtocol(protocol)` | Protocol + per-peer RPC state |
| `listProtocols()` | Registered protocol names |
| `getConnectedPeers(protocol)` | Peer IDs with attached RPC state |
| `isRpcReady(protocol, peerId)` | Whether RPC mux is open |
| `getPeerRpc(protocol, peerId)` | Underlying ProtomuxRPC instance |
- Verify peer is connected: `sdk.channels.isPeerConnected('protocol', peerId)` Deprecated shims (`createChannel`, `send`, `sendAsync`, nested `channels.rpc`) may still exist but should not be used in new code.
- Check encoding matches between sender and receiver
- Verify `onMessage` handler is set correctly
### Channel Not Reconnecting ## See also
- Ensure `autoReconnect: true` (default)
- Check that peer is actually reconnecting
- Verify channel wasn't manually closed
## API Reference
### `sdk.channels.createChannel(protocol, options)`
Create a new channel.
**Parameters:**
- `protocol` (string): Protocol name
- `options` (object): Channel options
**Returns:** `boolean` - Direct `message.send(data)` result (`false` means send was not accepted)
### `sdk.channels.getChannel(protocol)`
Get channel information.
**Parameters:**
- `protocol` (string): Protocol name
**Returns:** `Object | null` - Channel info or null
### `sdk.channels.listChannels()`
List all channels for this plugin.
**Returns:** `Array<string>` - Array of protocol names
### `sdk.channels.closeChannel(protocol)`
Close a channel.
**Parameters:**
- `protocol` (string): Protocol name
**Returns:** `boolean` - Success status
### `sdk.channels.send(protocol, peerId, data)`
Send data to a specific peer.
**Parameters:**
- `protocol` (string): Protocol name
- `peerId` (string): Target peer ID
- `data` (any): Data to send
**Returns:** `boolean` - Success status
### `sdk.channels.sendAsync(protocol, peerId, data, waitTimeout)`
Send data to a specific peer (async version that waits for bidirectional channel opening).
**Parameters:**
- `protocol` (string): Protocol name
- `peerId` (string): Target peer ID
- `data` (any): Data to send
- `waitTimeout` (number): Timeout to wait for channel to open in milliseconds (default: 5000)
**Returns:** `Promise<boolean>` - Direct `message.send(data)` result after waiting for `fullyOpened()`
**Note:** This method waits for the channel to be fully opened before sending, which is useful when you need to ensure the channel is ready. The regular `send()` method returns immediately and may fail if the channel isn't open yet or if backpressure prevents sending.
### `sdk.channels.broadcast(protocol, data)`
Broadcast data to all connected peers.
**Parameters:**
- `protocol` (string): Protocol name
- `data` (any): Data to broadcast
**Returns:** `number` - Number of peers message was sent to
### `sdk.channels.getConnectedPeers(protocol)`
Get list of connected peers for a channel.
**Parameters:**
- `protocol` (string): Protocol name
**Returns:** `Array<string>` - Array of peer IDs
### `sdk.channels.isPeerConnected(protocol, peerId)`
Check if a peer is connected to a channel.
**Parameters:**
- `protocol` (string): Protocol name
- `peerId` (string): Peer ID
**Returns:** `boolean` - True if connected
## See Also
- [Plugin System Documentation](README.md) - Complete plugin system guide
- [Plugin SDK Reference](PLUGIN_SDK.md) - Full SDK documentation
- [Example Plugin](../../plugin-sites/example.plugin/index.js) - Basic plugin example
- [Plugin SDK](PLUGIN_SDK.md)
- [Plugin system](README.md)
- [example.plugin](../../plugin-sites/example.plugin/index.js)
- [global.profile](../../plugin-sites/global.profile/index.js) — `profile.update` broadcast pattern
+4 -4
View File
@@ -31,7 +31,7 @@ The P2NS Plugin SDK provides comprehensive access to P2NS system functionality.
- [Plugin Information](#plugin-information) - [Plugin Information](#plugin-information)
- [Security and Validation](#security-and-validation) - [Security and Validation](#security-and-validation)
- [Authentication and Authorization](#authentication-and-authorization) - [Authentication and Authorization](#authentication-and-authorization)
- [Protomux Channels](#protomux-channels) - [Plugin RPC (protomux-rpc)](#plugin-rpc-protomux-rpc)
- [Database Operations (HyperDB)](#database-operations-hyperdb) - [Database Operations (HyperDB)](#database-operations-hyperdb)
- [Hyperdrive Operations](#hyperdrive-operations) - [Hyperdrive Operations](#hyperdrive-operations)
- [Admin Panel Registration](#admin-panel-registration) - [Admin Panel Registration](#admin-panel-registration)
@@ -62,7 +62,7 @@ const ipMap = sdk.state.domainToIPMap;
// Get all active Holesail connections (returns a new Map) // Get all active Holesail connections (returns a new Map)
const holesails = sdk.state.holesails; const holesails = sdk.state.holesails;
// Get peer channels (returns a new Map) // Get swarm peer channels (returns a new Map; not plugin RPC — use sdk.channels for plugin protocols)
const peerChannels = sdk.state.peerChannels; const peerChannels = sdk.state.peerChannels;
// Get peer metrics (returns a new Map) // Get peer metrics (returns a new Map)
@@ -159,7 +159,7 @@ sdk.log.error('component', 'Error message');
await sdk.log.close(); await sdk.log.close();
``` ```
**Note:** Plugin logs are automatically broadcast to the admin interface and displayed in real-time in the plugin's log terminal. Logs are also written to `app.log` in the plugin directory. **Note:** Plugin logs go to `logs/plugins.log` on the host, `plugin-log` WebSocket messages (per-plugin terminal in the admin UI), and `app.log` in the plugin directory. They are not mixed into the core log stream.
## Core Operations ## Core Operations
@@ -2436,7 +2436,7 @@ module.exports = {
- [PLUGINS.md](PLUGINS.md) - Plugin system overview - [PLUGINS.md](PLUGINS.md) - Plugin system overview
- [RESTAPI.md](RESTAPI.md) - Plugin management API endpoints - [RESTAPI.md](RESTAPI.md) - Plugin management API endpoints
- [plugins/HYPERDB.md](plugins/HYPERDB.md) - HyperDB database integration - [plugins/HYPERDB.md](plugins/HYPERDB.md) - HyperDB database integration
- [plugins/PLUGIN_CHANNELS.md](plugins/PLUGIN_CHANNELS.md) - P2P communication channels - [plugins/PLUGIN_CHANNELS.md](plugins/PLUGIN_CHANNELS.md) - Plugin protomux-rpc protocols
- [plugins/HYPERDRIVE.md](plugins/HYPERDRIVE.md) - Hyperdrive distributed file system - [plugins/HYPERDRIVE.md](plugins/HYPERDRIVE.md) - Hyperdrive distributed file system
- [plugins/README.md](plugins/README.md) - Plugin system documentation (detailed) - [plugins/README.md](plugins/README.md) - Plugin system documentation (detailed)
- [README.md](../README.md) - Main P2NS documentation - [README.md](../README.md) - Main P2NS documentation
+8 -8
View File
@@ -15,7 +15,7 @@ This directory contains comprehensive documentation for the P2NS plugin system:
### SDK Features ### SDK Features
- **[HYPERDB.md](HYPERDB.md)** - HyperDB database integration for plugins - **[HYPERDB.md](HYPERDB.md)** - HyperDB database integration for plugins
- **[HYPERDRIVE.md](HYPERDRIVE.md)** - Hyperdrive distributed file system for plugins - **[HYPERDRIVE.md](HYPERDRIVE.md)** - Hyperdrive distributed file system for plugins
- **[PLUGIN_CHANNELS.md](PLUGIN_CHANNELS.md)** - P2P communication channels via Protomux - **[PLUGIN_CHANNELS.md](PLUGIN_CHANNELS.md)** - Plugin peer protocols via protomux-rpc
### Example Plugins ### Example Plugins
- **[example.plugin.md](example.plugin.md)** - Example Plugin template documentation - **[example.plugin.md](example.plugin.md)** - Example Plugin template documentation
@@ -225,7 +225,7 @@ const ip = sdk.state.getIPForDomain('example.tld');
// Get all active Holesail connections // Get all active Holesail connections
const holesails = sdk.state.holesails; const holesails = sdk.state.holesails;
// Get peer channels // Get swarm peer channels (plugin P2P uses sdk.channels, not this map)
const peerChannels = sdk.state.peerChannels; const peerChannels = sdk.state.peerChannels;
// Get peer metrics // Get peer metrics
@@ -279,7 +279,7 @@ sdk.log.warn('my-plugin', 'Warning message');
sdk.log.error('my-plugin', 'Error message'); sdk.log.error('my-plugin', 'Error message');
``` ```
**Note:** Plugin logs are automatically broadcast to the admin interface and displayed in real-time in the plugin's log terminal. Logs are also written to `app.log` in the plugin directory. **Note:** Plugin logs are written to `logs/plugins.log`, broadcast as `plugin-log` WebSocket messages (per-plugin terminal in admin), and appended to `plugin-sites/{domain}/app.log`.
### Core Operations ### Core Operations
@@ -945,7 +945,7 @@ The SDK provides comprehensive access to all P2NS functionality:
- **`sdk.router`** - HTTP request parsing and response helpers - **`sdk.router`** - HTTP request parsing and response helpers
- **`sdk.admin`** - Admin panel registration (actions, settings) - **`sdk.admin`** - Admin panel registration (actions, settings)
- **`sdk.db`** - HyperDB database operations (see [HYPERDB.md](HYPERDB.md)) - **`sdk.db`** - HyperDB database operations (see [HYPERDB.md](HYPERDB.md))
- **`sdk.channels`** - P2P communication channels (see [PLUGIN_CHANNELS.md](PLUGIN_CHANNELS.md)) - **`sdk.channels`** - Plugin protomux-rpc protocols (see [PLUGIN_CHANNELS.md](PLUGIN_CHANNELS.md))
- **`sdk.drives`** - Hyperdrive distributed file system (see [HYPERDRIVE.md](HYPERDRIVE.md)) - **`sdk.drives`** - Hyperdrive distributed file system (see [HYPERDRIVE.md](HYPERDRIVE.md))
### Admin Panel Registration ### Admin Panel Registration
@@ -1030,7 +1030,7 @@ async handler(req, res) {
## Best Practices ## Best Practices
1. **Error Handling**: Always wrap async operations in try-catch blocks 1. **Error Handling**: Always wrap async operations in try-catch blocks
2. **Logging**: Use the SDK logging functions instead of console.log (logs appear in admin interface) 2. **Logging**: Use `sdk.log` instead of `console.log` (admin Plugins tab + `logs/plugins.log` and per-plugin `app.log`)
3. **Resource Cleanup**: Implement `onShutdown()` to clean up resources 3. **Resource Cleanup**: Implement `onShutdown()` to clean up resources
4. **Security**: Validate and sanitize user input using `sdk.security` 4. **Security**: Validate and sanitize user input using `sdk.security`
5. **Performance**: Cache expensive operations when possible 5. **Performance**: Cache expensive operations when possible
@@ -1059,10 +1059,10 @@ Plugins can be managed via the admin interface at `https://p2ns.admin` in the Pl
- **Static**: Plugin only serves static files (no handler) - **Static**: Plugin only serves static files (no handler)
**Logs:** **Logs:**
- Plugin logs are displayed in real-time in the plugin's log terminal - Plugin logs appear in the Plugins tab terminal and in `logs/plugins.log` (all plugins) plus `plugin-sites/{domain}/app.log`
- Logs are automatically captured from `sdk.log` calls - Logs are captured from `sdk.log` calls only (not `console.log`)
- Logs are also written to `app.log` in the plugin directory
- Log terminals are hidden by default and appear when you start/stop/restart a plugin - Log terminals are hidden by default and appear when you start/stop/restart a plugin
- System-wide split logs (core, proxy, HTTP proxy, DNS, Holesail) are in the admin **Logs** tab — see [README_LONGFORM.md](../README_LONGFORM.md#logging-and-debugging)
## Troubleshooting ## Troubleshooting
+1 -1
View File
@@ -10,7 +10,7 @@ async function handleLogsRoutes(req, res) {
return true; return true;
} }
const match = urlPath.match(/^\/api\/logs\/([a-z]+)$/); const match = urlPath.match(/^\/api\/logs\/([a-zA-Z]+)$/);
if (method === 'GET' && match) { if (method === 'GET' && match) {
const channelId = match[1]; const channelId = match[1];
const channels = listLogChannels(); const channels = listLogChannels();
+1 -1
View File
@@ -16,7 +16,7 @@
- **[HyperDB Integration](../docs/plugins/HYPERDB.md)** - Database operations - **[HyperDB Integration](../docs/plugins/HYPERDB.md)** - Database operations
- **[Hyperdrive Integration](../docs/plugins/HYPERDRIVE.md)** - Distributed file system - **[Hyperdrive Integration](../docs/plugins/HYPERDRIVE.md)** - Distributed file system
- **[Plugin Channels](../docs/plugins/PLUGIN_CHANNELS.md)** - P2P communication - **[Plugin RPC](../docs/plugins/PLUGIN_CHANNELS.md)** - protomux-rpc peer protocols
## Example Plugins ## Example Plugins
+1 -1
View File
@@ -66,7 +66,7 @@ The plugin supports the following standard profile fields:
- `profile-update`: Broadcast when a profile is created or updated - `profile-update`: Broadcast when a profile is created or updated
- `profile-deleted`: Broadcast when a profile is deleted - `profile-deleted`: Broadcast when a profile is deleted
- `replication-status`: Periodic updates about replication status - `replication-status`: Periodic updates about replication status
- **P2P Channels**: Uses P2NS channels to broadcast profile updates across the network - **Plugin RPC**: Uses `sdk.channels` to broadcast profile updates to peers (`profile-updates` protocol)
## Web Interface ## Web Interface
+2 -1
View File
@@ -13,7 +13,8 @@ These scripts validate core HTTP surfaces on a running P2NS instance.
- `npm run test:admin` checks `p2ns.admin` health/status/stats endpoints. - `npm run test:admin` checks `p2ns.admin` health/status/stats endpoints.
- `npm run test:peer-paste` checks `peer.paste` health/stats/OpenAPI endpoints. - `npm run test:peer-paste` checks `peer.paste` health/stats/OpenAPI endpoints.
- `npm run test:plugins` checks `peer.directory`, `global.profile`, and `file.drop` API endpoints. - `npm run test:plugins` checks `peer.directory`, `global.profile`, and `file.drop` API endpoints.
- `npm test` runs all smoke scripts in sequence. - `npm run test:plugin-rpc` runs `plugin-channel-rpc.test.js` (offline contract tests for protomux-rpc plugin channels; no running node required).
- `npm test` runs admin, peer-paste, and plugins smoke scripts in sequence (does not include `test:plugin-rpc`).
## Custom target URL ## Custom target URL