How to Integrate ApraPipes Using the Node.js Addon API: A Complete Guide

You can integrate ApraPipes into Node.js applications by installing the @apra/pipes package, which exposes a native N-API addon that wraps the C++ pipeline engine through the Pipeline and Module JavaScript classes.

The apra-labs/aprapipes repository provides a first-class Node.js addon API that allows developers to control high-performance media processing pipelines directly from JavaScript. By leveraging N-API for binary stability, the addon exposes the full capabilities of the ApraPipes C++ engine—including dynamic module configuration, real-time event streaming, and lifecycle management—without leaving the Node.js ecosystem.

Understanding the ApraPipes Node.js Addon Architecture

The ApraPipes Node.js addon is built on N-API, ensuring compatibility across Node.js versions without recompilation. The addon bridges JavaScript and C++ through a thin wrapper layer that maps JS class methods directly to the underlying pipeline engine.

Core JavaScript Classes and Their C++ Implementations

The addon exposes two primary JavaScript classes that mirror the C++ architecture:

JavaScript Class C++ Implementation File Purpose
Pipeline base/bindings/node/pipeline_wrapper.cpp Creates, configures, and controls processing pipelines
Module base/bindings/node/module_wrapper.cpp Represents individual processing modules within a pipeline
Event Emitter base/bindings/node/event_emitter.cpp Bridges C++ callbacks to JavaScript event listeners
Addon Entry base/bindings/node/addon.cpp Registers classes with N-API and exports the module

When you require('@apra/pipes'), the addon entry point in base/bindings/node/addon.cpp initializes these classes and returns the Pipeline and Module constructors to your JavaScript code.

Setting Up Your Environment

You can obtain the ApraPipes Node.js addon either through the npm registry or by building from the source repository.

Install the prebuilt binary via npm:

npm install @apra/pipes

Alternatively, clone the apra-labs/aprapipes repository and build the addon from source using the provided build scripts. After installation, the native binary aprapipes.node resides alongside the JavaScript entry point, automatically loaded when you import the package.

Creating and Controlling Pipelines with the Node.js Addon API

The Pipeline class constructor accepts a JSON configuration object that follows the same schema used by the C++ command-line interface. This allows you to define modules, connections, and parameters declaratively.

Loading a Pipeline from JSON

The most common integration pattern involves loading a pre-defined pipeline configuration and executing it:

// examples/node/basic_pipeline.js
const { Pipeline } = require('@apra/pipes');
const fs = require('fs');

// Load a declarative pipeline description (same format as CLI)
const json = fs.readFileSync('examples/basic/pipeline.json', 'utf8');
const pipeline = new Pipeline(JSON.parse(json));

// Optional: attach a listener to log status changes
pipeline.on('status', (msg) => console.log('Pipeline status →', msg));

// Initialise internal resources (e.g., allocate buffers)
pipeline.init();

// Start processing
pipeline.run();

// Later … stop gracefully
setTimeout(() => pipeline.stop(), 10000);

In base/bindings/node/pipeline_wrapper.cpp, the constructor parses the JSON and instantiates the corresponding C++ Pipeline object, while the run() method forwards to the native execution engine.

Dynamically Adding Modules at Runtime

For scenarios requiring dynamic configuration, you can instantiate individual Module objects and inject them into a running pipeline structure:

const { Pipeline, Module } = require('@apra/pipes');

// Create an empty pipeline
const pipeline = new Pipeline({ modules: [], connections: [] });

// Define a simple grayscale transform module (C++ side already registered)
const grayModule = new Module('gray', { 
  type: 'ColorConversion', 
  params: { mode: 'GRAY' } 
});

pipeline.addModule(grayModule);
pipeline.connect('source', 'gray');
pipeline.connect('gray', 'sink');

pipeline.run();

The Module class in base/bindings/node/module_wrapper.cpp wraps the C++ module factory, allowing JavaScript to configure parameters that are passed directly to the native implementation.

Handling Real-Time Events

The addon implements an event emitter pattern in base/bindings/node/event_emitter.cpp, bridging C++ callbacks to JavaScript event listeners:

const { Pipeline } = require('@apra/pipes');

const pipeline = new Pipeline(myJson);

// Listen for frame-processed events emitted by a custom module
pipeline.on('myDetector:frame', (frameInfo) => {
  console.log('Detected object at', frameInfo.boundingBox);
});

// Error handling
pipeline.on('error', (err) => {
  console.error('Pipeline error:', err);
});

pipeline.run();

Events follow the naming convention moduleName:eventType, allowing granular subscription to specific module outputs.

Integrating with Express.js

You can embed ApraPipes pipelines within web servers to create real-time media endpoints:

const express = require('express');
const { Pipeline } = require('@apra/pipes');

const app = express();
const pipeline = new Pipeline(streamPipelineJson);

app.get('/video', (req, res) => {
  // Stream raw video frames directly to the response
  pipeline.on('frame', (buf) => res.write(buf));
  pipeline.run();
});

app.listen(3000, () => console.log('Server listening on :3000'));

This pattern leverages the addon's ability to emit raw buffer data, enabling direct streaming to HTTP responses or WebSocket connections.

Graceful Shutdown Handling

To prevent resource leaks, implement signal handlers that invoke the pipeline's stop() method:

const { Pipeline } = require('@apra/pipes');
const pipeline = new Pipeline(myJson);

process.on('SIGINT', async () => {
  console.log('Stopping pipeline …');
  await pipeline.stop();   // returns a promise if the wrapper is async-enabled
  process.exit(0);
});

pipeline.run();

The stop() method in base/bindings/node/pipeline_wrapper.cpp triggers the C++ pipeline's shutdown sequence, ensuring all modules release their resources before the Node.js process exits.

Key Source Files and Implementation Details

Understanding the underlying C++ implementation helps debug integration issues and leverage advanced features.

File Role Link
base/bindings/node/addon.cpp Registers the N-API module and exposes Pipeline & Module classes view
base/bindings/node/pipeline_wrapper.cpp Implements the JavaScript Pipeline class (creation, control, event routing) view
base/bindings/node/module_wrapper.cpp Implements the Module class that mirrors C++ module API view
base/bindings/node/event_emitter.cpp Provides on/off semantics and bridges C++ callbacks to JS view
examples/node/basic_pipeline.js Minimal end-to-end usage example view
examples/node/face_detection_demo.js Shows how to hook custom detection events view
package.json (root) Declares the Node.js package, its binaries, and peer dependencies view

These files together form the public API you’ll use from JavaScript. By importing @apra/pipes and working with the Pipeline class, you get full access to the high-performance, cross-platform media processing capabilities of ApraPipes while staying entirely within the Node.js ecosystem.

Summary

  • Install the addon via npm install @apra/pipes or build from the apra-labs/aprapipes source to obtain the native aprapipes.node binary.
  • Instantiate pipelines using the Pipeline class with JSON configurations that match the C++ CLI schema, or build them dynamically using the Module class.
  • Control execution through methods like run(), stop(), pause(), and step(), which forward directly to the C++ engine via pipeline_wrapper.cpp.
  • Handle events by listening to the EventEmitter interface for pipeline status, errors, and module-specific events bridged through event_emitter.cpp.
  • Integrate seamlessly with Express.js, WebSockets, or Electron apps to build real-time media servers while ensuring graceful shutdown via SIGINT handlers.

Frequently Asked Questions

How do I install the ApraPipes Node.js addon if prebuilt binaries are not available for my platform?

If prebuilt binaries are unavailable, clone the apra-labs/aprapipes repository and build the addon from source using the provided CMake or node-gyp configuration. The build process compiles base/bindings/node/addon.cpp along with its dependencies into aprapipes.node, which the package.json loads via the main entry point. Ensure you have the required system dependencies (C++ compiler, CMake, and Node.js headers) installed before building.

What is the difference between the init() and run() methods in the Pipeline class?

The init() method, implemented in base/bindings/node/pipeline_wrapper.cpp, allocates internal C++ resources such as memory buffers and validates module connections without starting data processing. The run() method begins the actual execution loop, causing data to flow through the pipeline modules. You should call init() once after construction to catch configuration errors early, then invoke run() to start processing. Calling run() without init() may work in some versions but is not guaranteed across all releases.

How can I handle errors that occur inside C++ modules from my JavaScript code?

The addon bridges C++ exceptions and error states to JavaScript through the EventEmitter interface defined in base/bindings/node/event_emitter.cpp. Listen for the 'error' event on your pipeline instance to receive error objects containing message strings and optional error codes. Additionally, synchronous methods like init() may throw JavaScript exceptions immediately if the JSON configuration is malformed. For production applications, always attach both 'error' event listeners and try-catch blocks around initialization calls.

Can I use the ApraPipes Node.js addon with TypeScript?

While the apra-labs/aprapipes repository primarily provides JavaScript examples, you can use the addon with TypeScript by creating type definitions for the Pipeline and Module classes. The classes expose standard JavaScript constructors and methods like run(), stop(), and on(), which map cleanly to TypeScript interfaces. You would typically declare the @apra/pipes module with interfaces matching the JSON configuration schema and the EventEmitter pattern. Community type definitions may be available, or you can generate them from the C++ header files using automated binding generators.

Have a question about this repo?

These articles cover the highlights, but your codebase questions are specific. Give your agent direct access to the source. Share this with your agent to get started:

Share the following with your agent to get started:
curl -s "https://instagit.com/install.md"

Works with
Claude Codex Cursor VS Code OpenClaw Any MCP Client

Maintain an open-source project? Get it listed too →