Files
BetterDesk/docs/sdk/NODEJS_SDK.md
T
UNITRONIX dd0889e3d6 Add SessionManager; update docs, i18n & CI
Introduce a SessionManager for relay-based remote sessions in the Tauri MGMT client: new SessionCommand API, start/stop/session input routing, clipboard/recording/quality controls, and notification read/dismiss state. Wire AppState with new mutexes and show main window on startup. CI: add SBOM generation (anchore) and Trivy vulnerability scan steps. Misc: change console Docker DB path, large README/CHANGELOG updates (chat E2E, unattended access/WOL, i18n expansion, CDAP/SDK docs), and many web-nodejs assets/locales/routes/views/services and server-side changes.
2026-04-05 13:42:07 +02:00

4.6 KiB

Node.js SDK Reference — betterdesk-cdap

Installation

npm install betterdesk-cdap
# or from source:
npm install ./sdks/nodejs/

Requirements: Node.js 18+, ws ^8.18.0

CDAPBridge

The main class. Extends EventEmitter.

const { CDAPBridge, Widget } = require('betterdesk-cdap');

Constructor

const bridge = new CDAPBridge({
    serverUrl: 'ws://host:21122/cdap',  // WebSocket URL
    deviceId: 'MY-DEVICE',              // Unique device ID
    deviceName: 'My Device',            // Human-readable name
    deviceType: 'custom_agent',         // Device type
    authMethod: 'api_key',              // api_key | device_token | user_password
    apiKey: 'YOUR_KEY',                 // API key
    capabilities: ['telemetry', 'commands'],
    heartbeatSec: 15,                   // Heartbeat interval
    reconnectSec: 5,                    // Base reconnect delay
});

Methods

Method Description
addWidget(widget) Add a Widget to the manifest
connect() Connect to server (auto-reconnects)
disconnect() Gracefully disconnect
updateWidget(id, value) Update a single widget value
bulkUpdate(values) Update multiple widget values { id: value }
sendCommandResponse(cmdId, success, result) Respond to a command
sendAlert(severity, message, source) Send an alert

Events

bridge.on('connected', () => { /* auth + manifest done */ });
bridge.on('disconnected', () => { /* connection lost */ });
bridge.on('command', async (cmdId, command, args) => { /* handle command */ });
bridge.on('collectMetrics', async () => { /* return { id: value } */ });
bridge.on('error', (err) => { /* handle error */ });

Widget

Factory class for creating CDAP widgets.

Factory Methods

Widget.gauge(id, label, { group, unit, min, max, danger, warning })
Widget.toggle(id, label, { group, onCommand, offCommand })
Widget.button(id, label, { group, command, confirm })
Widget.led(id, label, { group, onColor, offColor })
Widget.text(id, label, { group })
Widget.slider(id, label, { group, min, max, step, command })
Widget.select(id, label, { group, options, command })
Widget.chart(id, label, { group, maxPoints })

Example

bridge.addWidget(Widget.gauge('cpu', 'CPU Usage', {
    group: 'System', unit: '%', min: 0, max: 100, danger: 90, warning: 70
}));

bridge.addWidget(Widget.text('hostname', 'Hostname', { group: 'Info' }));

bridge.addWidget(Widget.button('restart', 'Restart Service', {
    group: 'Actions', command: 'restart_svc', confirm: true
}));

Complete Example

const { CDAPBridge, Widget } = require('betterdesk-cdap');
const os = require('os');

const bridge = new CDAPBridge({
    serverUrl: process.env.CDAP_SERVER || 'ws://localhost:21122/cdap',
    deviceId: `NODE-${os.hostname().toUpperCase()}`,
    deviceName: os.hostname(),
    deviceType: 'os_agent',
    authMethod: 'api_key',
    apiKey: process.env.CDAP_API_KEY,
    capabilities: ['telemetry', 'commands']
});

bridge.addWidget(Widget.gauge('cpu', 'CPU', { group: 'System', unit: '%', max: 100, danger: 90 }));
bridge.addWidget(Widget.gauge('mem', 'Memory', { group: 'System', unit: '%', max: 100, danger: 85 }));
bridge.addWidget(Widget.text('uptime', 'Uptime', { group: 'Info' }));

bridge.on('connected', () => console.log('Connected to BetterDesk'));

bridge.on('collectMetrics', () => {
    const cpus = os.cpus();
    const idle = cpus.reduce((sum, c) => sum + c.times.idle, 0) / cpus.length;
    const total = cpus.reduce((sum, c) => sum + Object.values(c.times).reduce((a, b) => a + b), 0) / cpus.length;
    const freeMem = os.freemem();
    const totalMem = os.totalmem();

    return {
        cpu: Math.round((1 - idle / total) * 100),
        mem: Math.round(((totalMem - freeMem) / totalMem) * 100),
        uptime: `${Math.floor(os.uptime() / 3600)}h ${Math.floor((os.uptime() % 3600) / 60)}m`
    };
});

bridge.on('command', (cmdId, command, args) => {
    if (command === 'get_hostname') {
        bridge.sendCommandResponse(cmdId, true, os.hostname());
    } else {
        bridge.sendCommandResponse(cmdId, false, `Unknown command: ${command}`);
    }
});

bridge.connect();

Error Handling

bridge.on('error', (err) => {
    console.error('Bridge error:', err.message);
    // SDK handles reconnection automatically
});

// For unhandled command errors
bridge.on('command', async (cmdId, command, args) => {
    try {
        // ... your logic
    } catch (err) {
        bridge.sendCommandResponse(cmdId, false, err.message);
    }
});