BREAKING: All nodes must upgrade together. Legacy p2ns.core-request string messages are rejected; invite/consensus control plane uses protomux-rpc (invite.request, invite.ack, invite.relay*, consensus.*). Shared Corestore namespaces are the default for plugin DBs and drives; USE_SHARED_CORESTORE_NAMESPACES=false is debug-only. Admin plugin actions with params are validated before run. EXPERIMENTAL: End-to-end RPC invite path reuses existing handlers via adapters; invite wire still ships on the invite channel. Multi-peer invite/relay integration tests are not in CI yet (core-rpc-smoke only). SDK & channels: - channel-rpc.js, sdk.channels.rpc (register/request/event) - core-rpc.js for p2ns.core; action-params + plugin route validation - sdk.db.getCore/reopen, sdk.state.getPeerChannelSnapshot, sdk.metrics.getHolepunchStats (schema v1) Runtime: - p2ns.js: RPC-first core invite/consensus; Hyperswarm firewall/reconnect - channel-manager: required protomux-rpc per peer - db-shared-namespace-migration; drive-manager shared namespaces - proxy-server: invite.request RPC for joiners Plugins: file.drop, global.profile, peer.directory, domain.consensus, peer.visualize, example.plugin (RPC demo); peer.directory UI polish Also: CI/smoke scripts, diagnostics hardening, plugin config schema validation, admin action param modal, docs/RFCS, package-lock + engines.node >= 18
Global Profile Plugin
Status: ✅ Production Ready
The Global Profile plugin provides a universal user identity system for all P2NS plugins with automatic P2P profile replication. It enables users to create, manage, and share their profiles across the entire P2NS network, with real-time updates and seamless integration with other plugins.
Overview
Global Profile is a core identity plugin that stores user profile data in a distributed HyperDB database that automatically replicates across all connected peers. Your profile is available to all P2NS plugins, enabling a unified identity experience across the network.
Key Features
Core Functionality
- HyperDB-Backed Storage: All profile data is stored in HyperDB with automatic P2P replication across the network
- Multi-Size Avatar System: Avatars are automatically resized and stored in multiple sizes (16px, 32px, 64px, 128px, 256px, 512px) for optimal performance
- Real-Time Updates: Profile changes are broadcast in real-time via WebSocket to all connected clients and peers
- Extensible Field System: Plugins can register custom fields that extend the standard profile schema
- Cross-Plugin Integration: Profile data is accessible to all P2NS plugins through the unified API
- Web UI: Complete web interface for managing your profile with an intuitive, modern design
Profile Fields
The plugin supports the following standard profile fields:
peerId- Unique identifier for the peer (required, automatically set)displayName- User's display namebio- Biography/about textemail- Email addresswebsite- Personal or professional website URLxUsername- X (Twitter) usernamegithub- GitHub usernamediscord- Discord usernamelocation- Physical locationavatarHash- Hash of the current avatar imagetags- Array of user-defined tagscustomFields- Object for plugin-specific custom fieldslastUpdated- Timestamp of last profile update
Profile Management Features
- Search & Filter: Search profiles by display name or bio, filter by tags
- Pagination: Efficient pagination with configurable limits (1-1000 per page)
- Sorting: Sort profiles by last updated (newest first) or display name (alphabetical)
- Online Status: Real-time online/offline status for each peer
- Statistics: Network-wide statistics including total profiles, online counts, and recent activity
Architecture
Storage
- HyperDB: All profile data and avatars are stored in HyperDB using base64-encoded data for avatars
- Profile collection (
@profile/profiles): Stores all user profile data - Avatar collection (
@profile/avatars): Stores avatar images in multiple sizes - Fields collection (
@profile/fields): Stores custom field definitions registered by plugins
- Profile collection (
Replication
- Automatic P2P Replication: All data automatically replicates across all connected peers using the global replication topic
- Database Watching: Real-time database change detection broadcasts updates immediately
- Peer Connection Handling: Profile updates are triggered when peers connect or disconnect
Real-Time Communication
- WebSocket Server: Provides real-time updates to connected clients
profile-update: Broadcast when a profile is created or updatedprofile-deleted: Broadcast when a profile is deletedreplication-status: Periodic updates about replication status
- P2P Channels: Uses P2NS channels to broadcast profile updates across the network
Web Interface
The plugin includes a complete web interface accessible at the plugin domain root (/). The interface provides:
- Profile editing form with all standard fields
- Avatar upload with preview
- Tag management with inline editing
- Real-time profile listing with search
- Online/offline status indicators
- Connection status monitoring
API Reference
The plugin provides a comprehensive REST API. For interactive documentation with examples and curl commands, visit /api/docs when the plugin is enabled.
Profile Management
Get Your Profile
GET /api/profile
Returns your local profile. Returns a default empty profile if none exists.
Update Your Profile (Full)
PUT /api/profile
Content-Type: application/json
{
"displayName": "John Doe",
"bio": "Software developer",
"website": "https://example.com",
"email": "[email protected]",
"xUsername": "@johndoe",
"github": "johndoe",
"discord": "johndoe#1234",
"location": "San Francisco, CA",
"tags": ["developer", "opensource"],
"customFields": {}
}
Performs a full update of your profile. All fields must be provided.
Partially Update Your Profile
PATCH /api/profile
Content-Type: application/json
{
"displayName": "John Doe",
"bio": "Updated bio"
}
Updates only the provided fields. Fields not included remain unchanged.
Get Another Peer's Profile
GET /api/profile/:peerId
Returns the profile for the specified peer ID. Returns 404 if not found.
Delete Your Profile
DELETE /api/profile
Deletes your profile and all associated avatars.
Profile Listing
List All Profiles
GET /api/profiles?search=query&tag=tagName&limit=100&offset=0&sort=lastUpdated
Query Parameters:
search(optional): Search term to filter by displayName or bio (case-insensitive)tag(optional): Filter profiles that have this taglimit(optional): Maximum number of results (1-1000, default: 100)offset(optional): Number of results to skip for pagination (default: 0)sort(optional): Sort field -lastUpdated(default, newest first) ordisplayName(alphabetical)
Response:
{
"profiles": [
{
"peerId": "...",
"displayName": "John Doe",
"bio": "...",
"online": true,
"tags": ["developer"],
"customFields": {},
"lastUpdated": 1234567890
}
],
"pagination": {
"total": 150,
"limit": 100,
"offset": 0,
"hasMore": true
}
}
Avatar Management
Upload Avatar
POST /api/profile/avatar
Content-Type: multipart/form-data
avatar: <image file>
Uploads an avatar image. The image is automatically resized to all supported sizes (16px, 32px, 64px, 128px, 256px, 512px) and stored in HyperDB. Requires the sharp library for image processing.
Response:
{
"success": true,
"avatarHash": "md5_hash_of_image"
}
Get Avatar (Default Size)
GET /api/profile/avatar/:peerId
Redirects to the 64px avatar endpoint.
Get Avatar (Specific Size)
GET /api/profile/avatar/:peerId/:size
Returns the avatar image at the specified size. Valid sizes: 16, 32, 64, 128, 256, 512.
If no avatar exists, returns a default SVG placeholder with the first character of the peer ID.
Delete Avatar
DELETE /api/profile/avatar
Deletes all avatar sizes for your profile.
Custom Fields
Get All Registered Fields
GET /api/fields
Returns all custom fields registered by plugins.
Response:
{
"fields": [
{
"fieldKey": "favoriteColor",
"registeredBy": "example.plugin",
"label": "Favorite Color",
"type": "string",
"description": "User's favorite color",
"defaultValue": "blue"
}
]
}
Register a Custom Field
POST /api/fields
Content-Type: application/json
{
"fieldKey": "favoriteColor",
"label": "Favorite Color",
"type": "string",
"description": "User's favorite color",
"defaultValue": "blue"
}
Required Fields:
fieldKey: Unique identifier for the field (string)label: Human-readable label (string)type: Field type - one of:string,number,boolean,array,object
Optional Fields:
description: Field description (string)defaultValue: Default value (any JSON-serializable value)
Note: Custom fields are stored in the customFields object in the profile. Plugins should register their fields on initialization to ensure proper validation and documentation.
Statistics
Get Profile Statistics
GET /api/stats
Response:
{
"total": 150,
"online": 45,
"offline": 105,
"recentActivity": [
{
"peerId": "...",
"displayName": "John Doe",
"hoursAgo": 2.5
}
],
"timestamp": 1234567890
}
Returns:
- Total number of profiles in the network
- Count of online vs offline peers
- Recent activity (profiles updated in the last 24 hours, limited to top 10)
Documentation
Interactive API Documentation
GET /api/docs
Returns an interactive HTML page with complete API documentation, including examples and curl commands for each endpoint.
WebSocket API
The plugin provides WebSocket endpoints for real-time updates. Connect to the WebSocket server to receive:
Message Types
profile-update
Broadcast when a profile is created or updated.
{
"type": "profile-update",
"profile": {
"peerId": "...",
"displayName": "John Doe",
...
},
"timestamp": 1234567890
}
profile-deleted
Broadcast when a profile is deleted.
{
"type": "profile-deleted",
"peerId": "...",
"timestamp": 1234567890
}
replication-status
Periodic updates about replication status (every 2 seconds when status changes).
{
"type": "replication-status",
"data": {
"hyperdb": {
"active": true,
"peers": 5
}
},
"timestamp": 1234567890
}
Client Messages
request-profiles
Request all profiles (for backward compatibility; use REST API /api/profiles instead).
{
"type": "request-profiles"
}
request-replication-status
Request current replication status.
{
"type": "request-replication-status"
}
Configuration
The plugin is enabled by default. Configuration is managed through config.json:
{
"name": "Global Profile",
"version": "1.2.3",
"domain": "global.profile",
"enabled": true,
"description": "Universal user identity system for all P2NS plugins with P2P profile replication"
}
Enabling/Disabling
The plugin can be enabled or disabled through:
- Admin Panel: Navigate to the Plugins tab and toggle the Global Profile plugin status
- Manual Configuration: Edit
plugin-sites/global.profile/config.jsonand change"enabled"totrueorfalse, then restart P2NS
Dependencies
Required
- P2NS core with HyperDB support
- Sharp library for avatar image processing:
npm install sharp
Note: If Sharp is not installed, avatar upload will fail with an error message. The plugin will function normally for all other features.
Database Schema
The plugin uses HyperDB with the following schema:
Profile Schema
peerId(string, required): Unique peer identifier (primary key)displayName(string): Display namebio(string): Biographywebsite(string): Website URLemail(string): Email addressxUsername(string): X/Twitter usernamegithub(string): GitHub usernamediscord(string): Discord usernamelocation(string): LocationavatarHash(string): Avatar hashcustomFields(string): JSON-encoded object for custom fieldstags(string): JSON-encoded array of tagslastUpdated(uint): Timestamp of last update
Avatar Schema
peerId(string, required): Peer identifier (part of composite key)size(string, required): Size identifier - one of:"16","32","64","128","256","512","original"(part of composite key)data(string, required): Base64-encoded image data
Field Definition Schema
fieldKey(string, required): Unique field key (primary key)registeredBy(string, required): Plugin domain that registered the fieldlabel(string): Human-readable labeltype(string): Field typedescription(string): Field descriptiondefaultValue(string): JSON-encoded default value
Indexes
profiles-by-displayName: Case-insensitive search on displayName
Plugin Integration
Other P2NS plugins can integrate with Global Profile in several ways:
Reading Profile Data
Plugins can fetch profile data using the REST API:
// Get a specific peer's profile
const profile = await fetch(`https://global.profile/api/profile/${peerId}`);
const data = await profile.json();
// Access standard fields
console.log(data.displayName, data.bio, data.avatarHash);
// Access custom fields
console.log(data.customFields.myCustomField);
Registering Custom Fields
Plugins can extend the profile schema by registering custom fields:
// Register a custom field on plugin initialization
await fetch('https://global.profile/api/fields', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({
fieldKey: 'myCustomField',
label: 'My Custom Field',
type: 'string',
description: 'Description of my custom field',
defaultValue: 'default'
})
});
Using Avatars
Avatars can be accessed via URL:
<!-- Default size (64px) -->
<img src="https://global.profile/api/profile/avatar/PEER_ID">
<!-- Specific size -->
<img src="https://global.profile/api/profile/avatar/PEER_ID/128">
WebSocket Integration
Plugins can connect to the WebSocket server to receive real-time profile updates:
const ws = new WebSocket('wss://global.profile/ws');
ws.onmessage = (event) => {
const message = JSON.parse(event.data);
if (message.type === 'profile-update') {
// Handle profile update
console.log('Profile updated:', message.profile);
}
};
Performance Considerations
- Avatar Sizes: Avatars are pre-generated in multiple sizes to avoid on-the-fly resizing
- Database Indexes: Indexes on displayName and tags enable efficient searching
- Pagination: Profile listings use pagination to handle large networks efficiently
- Caching: Avatar endpoints include cache headers for optimal performance
- Base64 Storage: Avatars are stored as base64 in HyperDB for seamless replication
Troubleshooting
Avatar Upload Fails
- Ensure the
sharplibrary is installed:npm install sharp - Check that the uploaded file is a valid image format
- Verify file size is reasonable (large files may take time to process)
Profile Updates Not Replicating
- Verify that database replication is active (check
/api/statsor WebSocket replication-status) - Ensure peers are connected and replication is enabled in P2NS
- Check logs for replication errors
Database Not Ready Errors
- The plugin waits up to 30 seconds for database initialization on startup
- If errors persist, restart P2NS to re-initialize the database
- Check that HyperDB is properly configured in P2NS
License
MIT