velora-node-sdk
v1.1.0
Published
Node.js SDK for Velora local API with registration, HTTP endpoints, and WebSocket support
Maintainers
Readme
Velora SDK
Node.js SDK for the Velora local API, providing easy access to the Velora Electron app's playback controls, state queries, and real-time event streaming.
Features
- HTTP & WebSocket Support — Read current track, playback state, and playback queue; control playback (play, pause, skip, seek)
- App Registration — Secure request-based authorization with user consent
- Token Management — Automatic token polling and permission checking
- Real-time Events — Connect to WebSocket for track changes and playback state updates
- Auto-reconnection — Exponential backoff reconnection on WebSocket disconnect
- TypeScript Ready — Full type definitions for all APIs
- Error Classification — Specific error types for easier error handling
Installation
npm install velora-node-sdkQuick Start
1. Register Your App
import { VeloraClient } from 'velora-node-sdk';
const client = new VeloraClient();
const registrationConfig = {
app: {
name: 'My awesome app',
description: 'An application that is awesome!',
developer: 'ItsMeDev',
website: 'https://example.com',
icon: 'https://example.com/icon.png',
},
permissions: ['read', 'write'],
};
const requestId = await client.registerApp(registrationConfig);
console.log('Registration request ID:', requestId);2. Poll for User Approval
const maxWaitMs = 5 * 60 * 1000;
await client.requestAccessToken(requestId, maxWaitMs);
console.log('User approved! Token acquired.');3. Use HTTP Endpoints
const health = await client.getHealth();
console.log('Velora is running on port:', health.port);
const track = await client.getCurrentTrack();
console.log(`Now playing: ${track.track.title} by ${track.track.artist}`);
const playbackState = await client.getPlaybackState();
console.log('Is playing:', playbackState.is_playing);
const queue = await client.getPlaybackQueue();
console.log('Queue size:', queue.queue.length);
const user = await client.getUserPublic();
console.log('User:', user.user.name);4. Control Playback
await client.play('OrZoMJcXje2');
await client.pause();
await client.next();
await client.seek(60000);
await client.toggle();5. Listen to Real-time Events
await client.connectWebSocket();
client.on('track_changed', (data) => {
console.log(`Track changed: ${data.title} by ${data.artist}`);
});
client.on('playback_state_changed', (data) => {
console.log('Playing:', data.is_playing);
});
client.on('ws:connected', () => {
console.log('WebSocket connected');
});
client.on('ws:disconnected', () => {
console.log('WebSocket disconnected');
});
client.on('ws:error', (error) => {
console.error('WebSocket error:', error);
});API Reference
VeloraClient
Constructor
new VeloraClient(config?: ClientConfig)Options:
host(string, default:127.0.0.1) — Velora server hostport(number, default:39031) — Velora server porttoken(string, optional) — Pre-existing access tokenrequestedPermissions(array, optional) — Permissions for pre-existing tokenhttpOptions(object, optional) — HTTP client options (timeout, maxRetries)wsOptions(object, optional) — WebSocket options
Authentication Methods
registerApp(appConfig: RegisterAppRequest): Promise<string>
Register your app and request permissions. Returns a request_id to poll.
const requestId = await client.registerApp({
app: {
name: 'My App',
description: 'Optional description',
developer: 'Developer name',
website: 'https://example.com',
icon: 'https://example.com/icon.png',
},
permissions: ['read', 'write'],
});requestAccessToken(requestId: string, maxWaitMs?: number): Promise<void>
Poll for user approval. Waits up to maxWaitMs (default 5 minutes).
await client.requestAccessToken(requestId);isAuthenticated(): boolean
Check if client has a valid token.
if (client.isAuthenticated()) {
console.log('Ready to use API');
}getToken(): string | null
Get the current access token.
setToken(token: string, permissions?: PermissionType[]): void
Manually set a token (e.g., from storage).
client.setToken('velora_...', ['read', 'write']);clearCredentials(): void
Clear token and permissions.
client.clearCredentials();Read Endpoints
All read endpoints require read permission.
getHealth(): Promise<HealthResponse>
Check Velora server status.
const health = await client.getHealth();getCurrentTrack(): Promise<CurrentTrackResponse>
Get the current playing track.
const response = await client.getCurrentTrack();
console.log(response.track.title);getPlaybackState(): Promise<PlaybackStateResponse>
Get playback flags (is_playing, shuffle, repeat).
const state = await client.getPlaybackState();getPlaybackQueue(): Promise<PlaybackQueueResponse>
Get the current playback queue and metadata.
const queue = await client.getPlaybackQueue();getUserPublic(): Promise<UserPublicResponse>
Get the signed-in user's public profile snapshot.
const user = await client.getUserPublic();Write Endpoints
All write endpoints require write permission.
play(trackId?: string): Promise<PlayResponse>
Start playback or resume. Optionally specify a track ID.
await client.play();
await client.play('OrZoMJcXje2');pause(): Promise<PauseResponse>
Pause playback.
await client.pause();next(): Promise<NextResponse>
Skip to next track.
await client.next();seek(position: number): Promise<SeekResponse>
Seek to a position in milliseconds.
await client.seek(60000);toggle(): Promise<ToggleResponse>
Toggle between play and pause.
await client.toggle();WebSocket Methods
connectWebSocket(): Promise<void>
Establish WebSocket connection to receive real-time events.
await client.connectWebSocket();disconnectWebSocket(): Promise<void>
Close WebSocket connection.
await client.disconnectWebSocket();isWSConnected(): boolean
Check if WebSocket is connected.
if (client.isWSConnected()) {
console.log('Receiving real-time updates');
}WebSocket Events
track_changed
Emitted when the track changes.
client.on('track_changed', (data: TrackChangedData) => {
console.log(data.id, data.title, data.artist);
});playback_state_changed
Emitted when playback state changes.
client.on('playback_state_changed', (data: PlaybackStateChangedData) => {
console.log('is_playing:', data.is_playing);
console.log('shuffle:', data.shuffle);
console.log('repeat:', data.repeat);
});ws:connected
Emitted when WebSocket connects.
client.on('ws:connected', () => {
console.log('WebSocket connected');
});ws:disconnected
Emitted when WebSocket disconnects.
client.on('ws:disconnected', () => {
console.log('WebSocket disconnected');
});ws:connecting
Emitted before each connection attempt.
client.on('ws:connecting', () => {
console.log('Attempting to connect...');
});ws:error
Emitted on WebSocket errors.
client.on('ws:error', (error: Error) => {
console.error('WebSocket error:', error.message);
});Error Handling
The SDK provides specific error classes to help identify issues:
import {
VeloraError,
AuthError,
NetworkError,
ValidationError,
TimeoutError,
} from 'velora-node-sdk';
try {
await client.getCurrentTrack();
} catch (error) {
if (error instanceof AuthError) {
console.error('Permission denied or invalid token');
} else if (error instanceof NetworkError) {
console.error('Network issue:', error.message);
} else if (error instanceof ValidationError) {
console.error('Invalid input:', error.message);
} else if (error instanceof TimeoutError) {
console.error('Request timed out');
} else if (error instanceof VeloraError) {
console.error('Velora error:', error.message, error.code);
}
}Error Classes
- VeloraError — Base error class; all Velora errors extend this
- AuthError — Authentication or authorization failure (401/403)
- NetworkError — Network or connection issue
- ValidationError — Invalid input or request body
- TimeoutError — Request timeout
- RateLimitError — Rate limit exceeded (429)
- RequestError — HTTP error (4xx or 5xx)
Configuration
HTTP Options
const client = new VeloraClient({
httpOptions: {
timeout: 30000,
maxRetries: 3,
},
});timeout— Request timeout in milliseconds (default: 30000)maxRetries— Max retry attempts for 5xx errors (default: 3)
WebSocket Options
const client = new VeloraClient({
wsOptions: {
initialBackoffMs: 1000,
maxBackoffMs: 60000,
},
});initialBackoffMs— Initial reconnect backoff (default: 1000ms)maxBackoffMs— Max reconnect backoff (default: 60000ms)
Connection Lifecycle
Basic Flow
- Create client
- Register app (or use pre-existing token)
- Poll for user approval (if registering)
- Call
connect()to verify health and optionally start WebSocket - Use HTTP or WebSocket APIs
- Call
disconnect()when done
With Pre-existing Token
const client = new VeloraClient({
token: 'velora_...',
requestedPermissions: ['read', 'write'],
});
const track = await client.getCurrentTrack();Error Recovery
HTTP client automatically retries on 5xx errors with exponential backoff. WebSocket client auto-reconnects on disconnect with backoff.
client.on('ws:error', (error) => {
console.log('Disconnected, will attempt to reconnect...');
});TypeScript Support
The SDK is written in TypeScript and includes full type definitions. All APIs are strictly typed:
import { VeloraClient, CurrentTrackResponse, TrackChangedData } from 'velora-node-sdk';
const client = new VeloraClient();
const response: CurrentTrackResponse = await client.getCurrentTrack();
client.on('track_changed', (data: TrackChangedData) => {
console.log(data.title);
});Permissions
read— Access to all GET endpoints and WebSocketwrite— Access to all POST endpoints (play, pause, seek, etc.)
Check permissions at runtime:
if (client.getPermissions().includes('write')) {
await client.play();
}Localhost only
The Velora local API only accepts connections from 127.0.0.1 or ::1. The SDK enforces this at the client level.
