/** * PearData P2P protocol — control plane + metric streaming. * * PROTOCOL_VERSION is negotiated via `handshake`. Bump on breaking RPC shapes. * Additive methods may land without a bump when clients tolerate unknown methods. * * Planes: * - Control/metadata: handshake, info, ACL, invites, jobs, alerts config * - Metrics query: contexts, charts, historical data (hot path) * - Push streams: live samples, anomalies, health events */ export const PROTOCOL = 'peardata/rpc' export const PROTOCOL_VERSION = 1 export const APP_NAME = 'peardata' export const APP_VERSION = '0.1.0' /** Roles for capability ACL. Secure default peer role is viewer. */ export const Roles = Object.freeze({ viewer: 'viewer', operator: 'operator', admin: 'admin', }) const ROLE_RANK = { [Roles.viewer]: 1, [Roles.operator]: 2, [Roles.admin]: 3, } /** * @param {string} role * @param {string} required */ export function roleAllows(role, required) { const have = ROLE_RANK[role] || 0 const need = ROLE_RANK[required] || ROLE_RANK[Roles.admin] return have >= need } /** * Minimum role required per method (default admin for unknown). */ export const MethodRoles = Object.freeze({ // session handshake: Roles.viewer, ping: Roles.viewer, getServerInfo: Roles.viewer, getAuthStatus: Roles.viewer, setDisplayName: Roles.viewer, // agent / node metadata getNodeInfo: Roles.viewer, getHealth: Roles.viewer, // metrics discovery + query listContexts: Roles.viewer, getContext: Roles.viewer, listCharts: Roles.viewer, getChart: Roles.viewer, queryData: Roles.viewer, getAllMetrics: Roles.viewer, getWeights: Roles.viewer, // AI / QVAC tool-friendly composites (viewer read) getHostSnapshot: Roles.viewer, searchCharts: Roles.viewer, summarizeChart: Roles.viewer, investigateHost: Roles.viewer, hotMetrics: Roles.viewer, relatedCharts: Roles.viewer, compareChartWindows: Roles.viewer, summarizeCharts: Roles.viewer, // live subscription control subscribeMetrics: Roles.viewer, unsubscribeMetrics: Roles.viewer, subscribeAnomalies: Roles.viewer, unsubscribeAnomalies: Roles.viewer, // anomalies + alerts (read) listAnomalies: Roles.viewer, listAlerts: Roles.viewer, getAlert: Roles.viewer, /** Anomaly source: viewer; audit/journal enforced admin inside handler */ queryLogs: Roles.viewer, /** Live process table (Linux /proc) */ listProcesses: Roles.viewer, // alerts / thresholds (write) setAlertConfig: Roles.operator, ackAlert: Roles.operator, silenceAlert: Roles.operator, // jobs (on-demand collection / maintenance) listJobs: Roles.viewer, runJob: Roles.operator, cancelJob: Roles.operator, // HyperDB peer links / db info getDbInfo: Roles.viewer, listPeerLinks: Roles.viewer, linkPeer: Roles.admin, unlinkPeer: Roles.admin, // Data Manager — retention + storage getStorageInfo: Roles.viewer, getRetentionConfig: Roles.viewer, setRetentionConfig: Roles.admin, pruneHistory: Roles.admin, // parent / fleet aggregation getFleetHealth: Roles.viewer, listChildPeers: Roles.viewer, // admin / fleet mintInvite: Roles.admin, listPeers: Roles.admin, revokePeer: Roles.admin, exportSnapshot: Roles.admin, }) /** * String method names for typed client calls. */ export const Methods = Object.freeze( Object.fromEntries(Object.keys(MethodRoles).map((k) => [k, k])) ) /** * Server → client push event names (protomux-rpc events). */ export const Pushes = Object.freeze({ metrics: 'push:metrics', anomaly: 'push:anomaly', alert: 'push:alert', health: 'push:health', job: 'push:job', system: 'push:system', }) /** * Map push channel → UI event type. */ export const PushToType = Object.freeze({ [Pushes.metrics]: 'metrics', [Pushes.anomaly]: 'anomaly', [Pushes.alert]: 'alert', [Pushes.health]: 'health', [Pushes.job]: 'job', [Pushes.system]: 'system', }) /** Methods treated as hot-path (skip heavy audit / schema). */ export const HotMethods = Object.freeze( new Set([ Methods.ping, Methods.queryData, Methods.subscribeMetrics, Methods.unsubscribeMetrics, Methods.getAllMetrics, Methods.listProcesses, Methods.getHostSnapshot, Methods.searchCharts, Methods.summarizeChart, Methods.investigateHost, Methods.hotMetrics, Methods.relatedCharts, Methods.compareChartWindows, Methods.summarizeCharts, ]) )