VOLT
Open Source Ecosystem

VoltClient (Node.js)

TypeScript HTTP client for the VOLT REST API.

Overview

@voltstack/voltclient is the official TypeScript HTTP client for the VOLT REST API. It supports both browser and Node.js environments, provides typed response unwrapping, in-flight GET deduplication, RBAC team scoping, and paginated responses.

Installation

npm install @voltstack/voltclient

Quick Start

import { createVoltClient, secretKey } from '@voltstack/voltclient';

const volt = createVoltClient({
  baseUrl: 'https://api.voltcloud.dev',
  credentials: secretKey('your-secret-key'),
});

// Scope requests to a specific team
const team = volt.withTeam('team-id');

// List trajectories
const trajectories = await team.getUnwrapped('/trajectory');

Factory Function

createVoltClient(options)

Creates a new VoltClient instance with the specified configuration.

interface CreateVoltClientOptions {
  baseUrl: string;
  credentials: CredentialProvider;
  // Optional: 'fetch' (default) or 'axios'
  adapter?: 'fetch' | 'axios';
}

Authentication Presets

PresetDescription
staticToken(token)Fixed Bearer token
secretKey(key)API secret key as Bearer token
dynamicToken(fn)Async function that returns a token on each request
import { staticToken, secretKey, dynamicToken } from '@voltstack/voltclient';

// Static token
const creds = staticToken('eyJhbGciOi...');

// Secret key
const creds = secretKey('sk-...');

// Dynamic token (e.g., from a refresh flow)
const creds = dynamicToken(async () => {
  const { token } = await refreshToken();
  return token;
});

HTTP Adapters

The client ships with two HTTP adapters:

AdapterDependencyEnvironment
FetchHttpClientNone (native fetch)Browser, Node.js 18+
AxiosHttpClientaxios >= 1.0.0Browser, Node.js
import { VoltClient, FetchHttpClient, AxiosHttpClient } from '@voltstack/voltclient';

// Using fetch (default)
const http = new FetchHttpClient({ credentials: secretKey('sk-...') });

// Using axios
const http = new AxiosHttpClient({ credentials: secretKey('sk-...') });

Constructor

class VoltClient {
  constructor(
    http: HttpClient,
    basePath: string,
    opts?: VoltClientOptions
  )
}

In most cases, use createVoltClient() instead of calling the constructor directly.

Methods

Team Scoping

withTeam(teamId: string): VoltClient

Returns a new client instance scoped to a team. All subsequent requests will include the team ID in the URL path for RBAC resolution.

const teamClient = volt.withTeam('abc123');

withBasePath(basePath: string, opts?: VoltClientOptions): VoltClient

Returns a new client scoped to a sub-path, reusing the same HTTP adapter.

const trajectoryClient = volt.withBasePath('/trajectory');

Basic Requests

get<T>(path, query?): Promise<T>

Performs a GET request. Identical concurrent requests are deduplicated — the same promise is shared.

const data = await volt.get('/trajectory', { page: 1, limit: 10 });

post<T>(path, body?): Promise<T>

const analysis = await volt.post('/analysis', { trajectoryId, pluginId });

patch<T>(path, body?): Promise<T>

await volt.patch('/trajectory/abc123', { name: 'Updated Name' });

delete<T>(path, query?): Promise<T>

await volt.delete('/trajectory/abc123');

Envelope Unwrappers

The VOLT API wraps responses in a { status, data } envelope. These methods automatically extract the inner data.

getUnwrapped<T>(path, query?): Promise<T>

// Instead of: const { data } = await volt.get('/trajectory');
const trajectories = await volt.getUnwrapped('/trajectory');

postUnwrapped<T>(path, body?): Promise<T>

patchUnwrapped<T>(path, body?): Promise<T>

deleteUnwrapped<T>(path, query?): Promise<T>

Field Extractors

Extract a specific field from the unwrapped response.

getField<T, K>(path, field, query?): Promise<T[K]>

const count = await volt.getField('/trajectory/count', 'count');

postField<T, K>(path, field, body?): Promise<T[K]>

patchField<T, K>(path, field, body?): Promise<T[K]>

Pagination

getPaginated<T>(path, params?): Promise<PaginatedResponse<T>>

Returns a normalized paginated response.

interface PaginatedResponse<T> {
  data: T[];
  totalResults: number;
  page: number;
  limit: number;
  totalPages: number;
}
const page = await volt.getPaginated('/trajectory', { page: 1, limit: 20 });
console.log(page.data, page.totalPages);

File Downloads

exportFile(path, params?): Promise<Blob>

Downloads a file as a Blob.

const blob = await volt.exportFile('/analysis/abc123/export');

Service DSL

The SDK includes a declarative DSL for defining typed API services.

import { createService, get, post, patch, del, paginated } from '@voltstack/voltclient';

const TrajectoryService = createService((volt) => ({
  list: paginated<Trajectory>('/trajectory'),
  getById: get<Trajectory>((id: string) => `/trajectory/${id}`),
  create: post<Trajectory>('/trajectory'),
  update: patch<Trajectory>((id: string) => `/trajectory/${id}`),
  remove: del<void>((id: string) => `/trajectory/${id}`),
}));

// Usage
const service = TrajectoryService(volt);
const trajectories = await service.list({ page: 1 });
const trajectory = await service.getById('abc123');

Error Handling

import { ApiError } from '@voltstack/voltclient';

try {
  await volt.get('/trajectory/invalid');
} catch (err) {
  if (err instanceof ApiError) {
    console.error(err.status, err.message);
  }
}

On this page