@avataar.ai/varya
v0.1.3
Published
JavaScript/Node client for the Varya video generation API
Maintainers
Readme
@avataar.ai/varya (JavaScript / Node)
JavaScript/Node client for the Varya video generation API. Submit a text (or image) prompt; the client handles the async job lifecycle — submit, poll, and download.
Zero runtime dependencies — uses the built-in fetch and FormData
(Node 18+, modern browsers, and edge runtimes).
Install
npm install @avataar.ai/varyaLocal development (from this folder):
npm linkAuthentication
Create a key in the Varya web app (Account menu → API key). It looks like
sk_live_…. Keep it secret; it draws down your account's credit balance.
export VARYA_API_KEY=sk_live_xxxxxQuick start
import { VaryaClient } from '@avataar.ai/varya';
const client = new VaryaClient({ apiKey: process.env.VARYA_API_KEY });
const result = await client.generateVideo('A snow leopard prowling the Himalayan slopes at dawn', {
resolution: '480p', // '480p' | '720p'
duration: 5, // seconds, 1–5
style: 'none', // 'none' | 'cinematic' | 'anime' | …
aspectRatio: '16:9', // '4:3' | '3:4' | '16:9' (default) | '9:16'
onStatus: (s) => console.log(s),
});
console.log(result.video_url);For a full end-to-end walkthrough (text-to-video and image-to-video, saving the output, error handling), see USAGE.md.
Download in Node:
import { writeFile } from 'node:fs/promises';
const bytes = await client.fetchVideo(result.video_url);
await writeFile('out.mp4', Buffer.from(bytes));Image-to-video — just pass a local imagePath; the client reads the file and
derives the filename + content-type for you:
await client.generateVideo('make it move', { imagePath: 'ref.png' });In a browser (no filesystem) pass a
Blob/Fileinstead viaimage, andimageFilenameto name a bareBlob.
CLI
Installing the package provides a varya command:
# create a new video and download it
varya "a cat surfing a wave" --resolution 720p --output out.mp4
# resume / fetch an existing generation (no prompt, nothing re-charged)
varya --get gen_xxxxxxxx --output out.mp4
varya --helpThe key comes from --key or $VARYA_API_KEY; the base URL from --base-url
or $VARYA_BASE_URL.
API
new VaryaClient({ apiKey, baseUrl?, authScheme?, timeoutMs? })
| Method | Description |
| ------------------------------ | ----------------------------------------------------------------------------------------------------- |
| generateVideo(prompt, opts?) | Submit and wait. Resolves to the final result. The 90% path. |
| submit(prompt, opts?) | POST /api/generations; resolves to { generation_id, status, credits_charged, … } without waiting. |
| status(generationId) | GET /generations/{id}; current status/result. |
| wait(generationId, opts?) | Poll until completed/failed. |
| fetchVideo(url) | Fetch a finished video as an ArrayBuffer. |
Generation options (generateVideo / submit): resolution
('480p' / '720p'), duration (1–5), style, aspectRatio
('4:3' / '3:4' / '16:9' / '9:16', default '16:9'), seed, enhance, and for
image-to-video imagePath (a local file path, Node) or image (Blob/File,
browser) with optional imageFilename. Plus polling options pollIntervalMs,
timeoutMs, onStatus.
Single-clip only: the client targets the streamlined
POST /api/generationsendpoint, so there is no compare / long-form / continuation mode andfpsis fixed server-side.durationmust be 1–5 (out-of-range throwsLONG_FORM_NOT_SUPPORTEDbefore any request is sent). The output is always watermarked.
Result shape
- completed:
{ status: 'completed', video_url: '…' } - failed:
{ status: 'failed', error: '…', error_code: '…' }
Errors
API/business failures reject with VaryaError (.code, .status):
import { VaryaError } from '@avataar.ai/varya';
try {
await client.generateVideo('…');
} catch (err) {
if (err instanceof VaryaError && err.code === 'INSUFFICIENT_CREDITS') {
// prompt the user to top up
} else {
throw err;
}
}TypeScript types ship in index.d.ts.
Notes
- Seed. A
seedis always sent. When you don't pass one it's randomized client-side (in[100, 1_000_000), matching the web app) and returned on the result asseed, so you can reproduce a run by passing that sameseedback. - Async by design. Jobs are queued; the client polls every ~2s — raise
timeoutMsif a job needs longer. - Resilient polling. Idempotent
GETs are retried with backoff and transient network blips don't abort a run.POST /api/generationsis retried only on connection-phase errors (e.g. connect timeout), where the request never reached the server — so a job is never double-charged. Note: Node's built-infetchalso enforces its own ~10s connect timeout; the retries recover from a stalled connect. - Auth header. Defaults to
X-API-Key. If your deployment expectsAuthorization: Bearer, passauthScheme: 'bearer'. - Cost. 1 credit (480p) / 2 (720p). The exact charge is returned as
credits_charged.
Development
npm test # runs node --test (no network; fetch is stubbed)License
MIT
