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

vindral-composer-connection

v0.2.0

Published

TypeScript Node.js library for connecting to Vindral Composer via WebSocket

Readme

vindral-composer-connection

TypeScript/Node.js library for connecting to a Vindral Composer instance via its WebSocket and HTTP Web APIs.

Designed to be used as the foundation for a TSR (Timeline State Resolver) device integration and potentially useful for others in future.

Features

  • WebSocket connection to Vindral Composer's WS API
  • HTTP Web API integration for controlling Composer (connectors, scenes, media, script engine)
  • Automatic reconnection with exponential backoff; connected is only emitted once both the WebSocket and HTTP API are healthy
  • HTTP keepalive polling (/api/getstatistics) to detect connectivity loss and trigger reconnection
  • Typed state model mirroring Composer's AudioMixerStrips
  • EventEmitter-based API, similar to sofie-atem-connection
  • Manual subscribe/unsubscribe to Composer channels (AudioMixer, etc.)

Installation

npm install vindral-composer-connection
# or
yarn add vindral-composer-connection

Usage

import { VindralComposer } from 'vindral-composer-connection'

const composer = new VindralComposer({
	host: '192.168.1.100',
	wsPort: 8081,
	httpPort: 44433,
})

composer.on('connected', () => {
	// Both WebSocket and HTTP API are healthy
	console.log('Connected to Vindral Composer')
	void composer.subscribeAudioMixer()
})

composer.on('disconnected', () => {
	console.log('Disconnected from Vindral Composer')
})

composer.on('stateChanged', (state, changedPaths) => {
	console.log('State updated:', changedPaths)
	console.log('Audio strips:', state.audioMixer?.strips)
})

composer.on('error', (err) => {
	console.error('Error:', err)
})

await composer.connect()

// WebSocket — set a property on an audio strip by its object ID
await composer.setPropertyValue('strip-abc123', 'Volume', 0.8)

// HTTP API — trigger a Connector by name
await composer.triggerConnector('MyConnector', { scene: 'intro' })

// HTTP API — trigger a Connector by value
await composer.triggerConnectorByValue('42')

// HTTP API — execute a Script Engine function
await composer.executeScriptFunction('MyFunction', { playerId: 'u123' })

// HTTP API — list all Connectors
const connectors = await composer.listConnectors()

// HTTP API — change a scene layer's source
await composer.setLayerSource('MyScene', 'MyLayer', 'MyInput')

// HTTP API — load and play a video file
await composer.playVideoFileInput('MyVideoInput', '/media/clip.mp4')

// Unsubscribe and disconnect when done
await composer.unsubscribeAudioMixer()
composer.disconnect()

API

VindralComposer

Constructor options

| Option | Type | Default | Description | | ------------------- | --------- | ------------- | -------------------------------------------------------------------------------------------------------------------------- | | host | string | 'localhost' | Hostname or IP of the Composer instance | | wsPort | number | 8081 | WebSocket port | | httpPort | number | 44433 | HTTP Web API port | | autoReconnect | boolean | true | Whether to automatically reconnect on disconnect | | reconnectInterval | number | 1000 | Initial reconnect delay in ms (doubles on each attempt, capped at 30s) | | pollInterval | number | 10000 | Interval in ms between HTTP keepalive polls to /api/getstatistics | | pollTimeout | number | 5000 | Timeout in ms for each keepalive poll request | | requestTimeout | number | 10000 | Timeout in ms for HTTP API method calls | | apiKey | string | '' | API key sent as the apikey header on every HTTP request. Required when apikeys.json on the Composer host defines keys. |

WebSocket methods

  • connect(): Promise<void> — Open the WebSocket connection
  • disconnect(): void — Close the connection and stop reconnecting
  • subscribeAudioMixer(): Promise<void> — Subscribe to the AudioMixer channel
  • unsubscribeAudioMixer(): Promise<void> — Unsubscribe from the AudioMixer channel
  • setPropertyValue(objectId: string, propertyName: string, value: string | number | boolean): Promise<void> — Set a writable property on a Composer object

Note: subscribeAudioMixer(), unsubscribeAudioMixer(), and setPropertyValue() are fire-and-forget — the returned promise resolves immediately after sending the message, before the server has processed it. There is no acknowledgement from Composer's WebSocket API.

HTTP API methods

All HTTP methods require the composer to be in the CONNECTED state and throw if it is not. They also throw on non-2xx HTTP responses.

  • triggerConnector(name: string, params?: Record<string, string>): Promise<void> — Trigger a Connector by name. Optional params are appended to the request URL and accessible via @@paramname in Connector commands.
  • triggerConnectorByValue(value: string, params?: Record<string, string>): Promise<void> — Trigger a Connector by value. Optional params are appended as above.
  • executeScriptFunction(functionName: string, parameter?: Record<string, unknown>, signal?: AbortSignal): Promise<void> — Execute a Script Engine function. parameter is JSON-serialised and passed as the parameter query argument.
  • listConnectors(signal?: AbortSignal): Promise<VindralConnector[]> — Return all Connectors configured in Composer.
  • setLayerSource(scene: string, layer: string, source: string, signal?: AbortSignal): Promise<void> — Change the input source of a scene layer. The source must already exist in the Composer Inputs list.
  • playVideoFileInput(inputName: string, sourceUri: string, signal?: AbortSignal): Promise<void> — Load and play a video file in a named Video File Input. Playback starts automatically once the file is parsed.

Events

| Event | Payload | Description | | -------------- | ------------------------ | -------------------------------------------------------------------------------------------------- | | connected | — | WebSocket connected, Welcome received, and HTTP API is reachable | | disconnected | — | Connection closed; state is reset to initial values (consumers should treat cached state as stale) | | error | string | Error message | | stateChanged | VindralState, string[] | State updated; second arg is list of changed paths | | info | string | Informational message | | debug | string | Debug message |

State (VindralState)

interface VindralState {
	info: {
		composerVersion: string
		projectName: string
		composerOS: string
	}
	audioMixer:
		| {
				strips: AudioMixerStrip[]
		  }
		| undefined
}

Note: The connected event is deferred until the first HTTP keepalive poll to /api/getstatistics succeeds. If the HTTP API becomes unreachable after connection, the socket is reconnected and disconnected is emitted.

Types

VindralConnector — shape of each entry returned by listConnectors():

interface VindralConnector {
	Id: string
	Name: string
	IsActive: boolean
	InvokeCount: number
	Description: string
}

API setup notes

WebSocket API

Composer's WebSocket API defaults to port 8081. You must enable it in Composer settings:

  • Desktop: Settings → Web API → Enable WebSockets
  • Runtime: Edit settings.xml:
"EnableWebSockets": true,
"WebSocketsHostName": "localhost",
"WebSocketsPort": 8081

Note: For remote connections, set WebSocketsHostName to the machine's IP address (not localhost).

HTTP Web API

Composer's HTTP Web API defaults to port 44433. You must enable it in Composer settings. Refer to the HTTP Web API docs for the exact configuration keys.

Note: For remote connections, configure the API to bind to the machine's IP address rather than localhost.

Message protocol

All WebSocket messages are JSON with the shape:

{ "Type": "MessageType", "Content": "string or JSON string" }

Key message types:

  • Subscribe / Unsubscribe — Subscribe to a named channel (AudioMixer, LogFile)
  • SetPropertyValueByObjectId — Write a property value on a Composer object
  • AudioMixerSummary (incoming) — Full AudioMixer state (sent after subscribe and on changes)
  • Welcome (incoming) — Sent on connect with Composer version/project info

Development

yarn install
yarn build      # compile TypeScript
yarn test       # lint + unit tests
yarn unit       # unit tests only
yarn watch      # run tests in watch mode

Reference