npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

merging-ravenna

v0.3.0

Published

Standalone client for Merging Technologies RAVENNA devices (Hapi / Horus / Anubis) over their CometD/WebSocket control protocol. Unofficial; not affiliated with Merging Technologies.

Readme

merging-ravenna

A small, standalone Node.js client for Merging Technologies RAVENNA devices (Hapi, Horus, Anubis) that speaks their web-UI control protocol — CometD/Bayeux over WebSocket — directly. No Node-RED, no browser, no extra services.

Unofficial. This library was built by observing the device's own web interface traffic. It is not affiliated with or endorsed by Merging Technologies, and the protocol is undocumented and may change between firmware versions. Use at your own risk; always keep a way to restore settings.

Install

npm install merging-ravenna

Quick start

const { RavennaEngine } = require('merging-ravenna');

const eng = new RavennaEngine({ host: '192.168.0.146' });

eng.on('online',  () => console.log('device up; catalog:', eng.catalog.length, 'params'));
eng.on('offline', (reason) => console.log('device down:', reason));
eng.on('param',   (p) => console.log('changed', p.moduleId, p.key, '=', p.value));

eng.connect();

// Set D/A (module 60) output gain to -20 dB. Value is dB; clamped to device range.
eng.setParam(60, 'attenuation', -20);

Why it is resilient

The engine handles two failure modes differently:

  • Socket drop / device powered off → exponential-backoff reconnect (2s, 5s, 15s, 30s capped), retrying forever.
  • Device wedged but socket still open → a data-liveness watchdog: the device emits /ravenna/status about every 2s, so if no frame arrives within livenessMs (default 7s) the connection is declared stale, torn down, and re-established.

online / offline are edge-triggered (emitted once per transition), and every successful (re)connect re-runs the handshake and full state fetch — so after a power-cycle (which rotates the device's clientId), state is always re-read from the device rather than assumed.

Discovery

On every full state update the engine builds a flat catalog of settable parameters by reading the device's own capability metadata — so it enumerates whatever modules/cards a given Hapi/Horus/Anubis actually has:

eng.on('catalog', (cat) => {
  // [{ moduleId, moduleName, section, key, value, unit, min, max, step, enum, settable, confidence }, ...]
});

confidence is confirmed (set-frame verified on a real device), inferred (derived from the state shape; very likely correct), or unknown.

Enum parameters (e.g. roll_off_filter, out_max_level) accept either a label string or the raw integersetParam(60, 'out_max_level', '+24 dBu') and setParam(60, 'out_max_level', 1) are equivalent (label match is case-insensitive).

System domain (clock, PTP, sync, health)

Beyond the per-module audio controls, the engine also models the device-wide system domain — sample rate, frame size, clock source, PTP, temperature, uptime, and assorted device flags — read from the parts of the state tree the audio catalog doesn't cover:

eng.on('system', (snap) => {
  // [{ key, label, group, unit, value, raw, enum, settable, readonly, note }, ...]
  // e.g. { key:'sample_rate', value:'44.1 kHz', raw:44100, enum:{'48 kHz':48000,...}, settable:true }
});

eng.getSystem();                       // current snapshot (groups: Clock/Sync/PTP/Device/Health/Advanced)
eng.getSystemValue('sample_rate');     // one entry by key

// Set a system param by label or raw value. Clock/rate changes RE-CLOCK the device,
// so do these with audio off:
eng.setSystem('sample_rate', '48 kHz');    // or 48000
eng.setSystem('sync_source', 'Internal');  // or the raw input id
eng.setSystem('frame_size', 32);

// Generic raw access to any part of the tree:
eng.getTree();                         // last full settings tree
eng.getSubtree('network.PTP.Status');  // any subtree by dotted / $ path

Settable system params are hardware-confirmed by scripts/probe-system.js (set → re-read → restore, behind a meter-silence gate). Pure telemetry (PTP lock, temperature, uptime) is marked readonly and never settable. Some params carry a note describing a dependency (e.g. PTP priorities apply only in manual-grandmaster mode). Use scripts/discover-system.js (read-only) to dump the system tree on unfamiliar firmware.

API (summary)

  • new RavennaEngine({ host, path?, livenessMs?, backoff? })
  • .connect(), .close()
  • .setParam(moduleId, key, value, { channelIndex? }) — high-level, unit-aware, clamped; enums accept a label or int
  • .setModuleOuts(moduleId, valueObj) — mid-level
  • .publishSettings(path, value) — raw escape hatch
  • .setSystem(key, value) — set a system-domain param (clock/PTP/sync/flags) by label or raw value
  • .getSystem(), .getSystemValue(key) — modeled system snapshot
  • .getTree(), .getSubtree(path) — raw last tree / any subtree by dotted-or-$ path
  • .catalog, .tree, .capabilities, .online
  • events: online, offline, status, settings, statusmsg, errors, tree, catalog, param, system, error

Testing

npm test            # hermetic: catalog + watchdog + meter + feedback logic, no device needed
MERGING_HOST=192.168.0.150 npm run validate                       # read-only: discover catalog + write a JSON report
MERGING_HOST=192.168.0.150 MERGING_I_UNDERSTAND=1 npm run validate # write-validate (audio OFF): set->re-read every param, restore

The hermetic suite includes a fake-clock watchdog test that simulates a power cycle and asserts the backoff schedule and the single online/offline transitions. npm run validate (scripts/validate-device.js) discovers every settable parameter, and — with MERGING_I_UNDERSTAND=1, audio off — validates each by SET→RE-READ: it sets the value, re-reads the device to confirm it applied, restores the original, and writes a JSON report (device fingerprint, per-param verdicts, unmodeled leaves) you can share. A meter pre-flight gate aborts if any output is passing audio.

Extending to new parameters / devices

Confirmed and inferred set-frame shapes for the audio params live in src/paths.js. To add one (or support an Anubis monitor control), capture a set frame from the device web UI and add a descriptor there — no engine changes needed. System-domain descriptors (their read path, unit, enum source, and confirmed write shape) live in src/system.js; use scripts/discover-system.js to dump an unfamiliar device's tree and scripts/probe-system.js to confirm new write shapes.

License

MIT