JavaScript SDK
The Sprites JavaScript SDK (@fly/sprites) provides a Node.js interface for managing Sprites programmatically. The SDK mirrors the Node.js child_process API, making it familiar and easy to use.
Installation
Section titled “Installation”npm install @fly/spritesRequirements:
- Node.js 24.0.0 or later
- No external dependencies (uses Node.js stdlib only)
Quick Start
Section titled “Quick Start”import { SpritesClient } from '@fly/sprites';
const client = new SpritesClient(process.env.SPRITE_TOKEN);
// Create a spriteconst sprite = await client.createSprite('my-sprite');
// Execute a commandconst result = await sprite.execFile('echo', ['Hello, Sprites!']);console.log(result.stdout);
// Clean upawait sprite.delete();Authentication
Section titled “Authentication”Create a token at sprites.dev/account, or use the CLI (sprite org auth).
Using Environment Variables
Section titled “Using Environment Variables”// Uses SPRITE_TOKEN environment variableconst client = new SpritesClient(process.env.SPRITE_TOKEN);With Options
Section titled “With Options”const client = new SpritesClient(token, { baseURL: 'https://api.sprites.dev', // Optional, uses default timeout: 30000, // Request timeout in ms});Generating Tokens
Section titled “Generating Tokens”Generate a Sprites token from Fly.io credentials:
const token = await SpritesClient.createToken( 'FlyV1 <macaroon-token>', // Fly.io macaroon 'personal', // Organization slug 'optional-invite-code' // Optional);Sprite Management
Section titled “Sprite Management”Creating Sprites
Section titled “Creating Sprites”// Simple creationconst sprite = await client.createSprite('my-sprite');
// With configurationconst sprite = await client.createSprite('my-sprite', { cpus: 2, ramMB: 8192, storageGB: 200, region: 'ord',});// Note: config fields are accepted but currently ignored by the API.Getting Sprites
Section titled “Getting Sprites”// Get sprite handle (doesn't verify existence)const sprite = client.sprite('my-sprite');
// Get sprite and verify it existsconst sprite = await client.getSprite('my-sprite');console.log(sprite.url);Note: The API currently returns only id, name, organization, url, url_settings, created_at, and updated_at. Other SpriteInfo fields may be undefined.
Listing Sprites
Section titled “Listing Sprites”// List all sprites (auto-pagination)const sprites = await client.listAllSprites();
// List with prefix filterconst devSprites = await client.listAllSprites('dev-');
// Manual paginationconst page = await client.listSprites({ maxResults: 50 });for (const sprite of page.sprites) { console.log(sprite.name);}
if (page.hasMore) { const nextPage = await client.listSprites({ continuationToken: page.nextContinuationToken, });}Deleting Sprites
Section titled “Deleting Sprites”await sprite.delete();// orawait client.deleteSprite('my-sprite');Upgrading Sprites
Section titled “Upgrading Sprites”await sprite.upgrade();// orawait client.upgradeSprite('my-sprite');Command Execution
Section titled “Command Execution”The SDK provides three methods for executing commands, mirroring Node.js child_process:
spawn() - Event-based Streaming
Section titled “spawn() - Event-based Streaming”Returns a SpriteCommand that emits events. Best for long-running commands or when you need to stream output.
const cmd = sprite.spawn('npm', ['run', 'dev']);
cmd.stdout.on('data', (chunk) => { process.stdout.write(chunk);});
cmd.stderr.on('data', (chunk) => { process.stderr.write(chunk);});
cmd.on('exit', (code) => { console.log(`Exited with code ${code}`);});
// Wait for completionconst exitCode = await cmd.wait();exec() - Promise-based (Direct)
Section titled “exec() - Promise-based (Direct)”Runs a command by splitting on whitespace (no shell). Best for simple commands without shell features.
const { stdout, stderr, exitCode } = await sprite.exec('ls -la');console.log(stdout);With options:
const result = await sprite.exec('npm test', { cwd: '/home/sprite/project', env: { NODE_ENV: 'test' }, maxBuffer: 1024 * 1024, // 1MB});execFile() - Promise-based (Direct)
Section titled “execFile() - Promise-based (Direct)”Executes a file directly without a shell. Use this for specific executables or when you need shell features via bash -lc.
const result = await sprite.execFile('node', ['script.js', '--flag']);console.log(result.stdout);
// Shell features via bashconst result2 = await sprite.execFile('bash', ['-lc', 'ls -la && echo done']);Options
Section titled “Options”SpawnOptions
Section titled “SpawnOptions”Available for spawn(), exec(), and execFile():
interface SpawnOptions { cwd?: string; // Working directory env?: Record<string, string>; // Environment variables tty?: boolean; // Enable TTY mode rows?: number; // TTY rows (default: 24) cols?: number; // TTY columns (default: 80) detachable?: boolean; // Create detachable session sessionId?: string; // Attach to existing session controlMode?: boolean; // Enable control mode}ExecOptions
Section titled “ExecOptions”Additional options for exec() and execFile():
interface ExecOptions extends SpawnOptions { maxBuffer?: number; // Max stdout/stderr buffer size encoding?: string; // Output encoding (default: 'utf8')}TTY Mode
Section titled “TTY Mode”For interactive applications:
const cmd = sprite.spawn('bash', [], { tty: true, rows: 24, cols: 80,});
// Connect to terminalprocess.stdin.pipe(cmd.stdin);cmd.stdout.pipe(process.stdout);
// Handle resizeprocess.stdout.on('resize', () => { cmd.resize(process.stdout.columns, process.stdout.rows);});
await cmd.wait();Detachable Sessions
Section titled “Detachable Sessions”Create sessions that persist after disconnecting:
// Create a detachable sessionconst sessionCmd = sprite.createSession('npm', ['run', 'dev']);let sessionId;
sessionCmd.on('message', (msg) => { if (msg && msg.type === 'session_info') { sessionId = msg.session_id; console.log(`Session ID: ${sessionId}`); }});
// Disconnect (session keeps running)
// Later, attach to the sessionconst cmd = sprite.attachSession(sessionId);cmd.stdout.pipe(process.stdout);await cmd.wait();Listing Sessions
Section titled “Listing Sessions”const sessions = await sprite.listSessions();for (const session of sessions) { console.log(`${session.id}: ${session.command}`);}Port Notifications
Section titled “Port Notifications”Get notified when ports open in the Sprite:
const cmd = sprite.spawn('npm', ['run', 'dev']);
cmd.on('message', (msg) => { if (msg.type === 'port_opened') { console.log(`Port ${msg.port} opened on ${msg.address} by PID ${msg.pid}`); // Could auto-open browser, set up proxy, etc. } else if (msg.type === 'port_closed') { console.log(`Port ${msg.port} closed on ${msg.address}`); }});
await cmd.wait();Error Handling
Section titled “Error Handling”import { ExecError } from '@fly/sprites';
try { await sprite.execFile('bash', ['-lc', 'exit 1']);} catch (error) { if (error instanceof ExecError) { console.log('Exit code:', error.exitCode); console.log('Stdout:', error.stdout); console.log('Stderr:', error.stderr); } else { // Network or other error throw error; }}SpriteCommand API
Section titled “SpriteCommand API”The SpriteCommand class (returned by spawn()) provides:
Properties
Section titled “Properties”cmd.stdin // Writable streamcmd.stdout // Readable streamcmd.stderr // Readable streamMethods
Section titled “Methods”await cmd.wait() // Wait for exit, returns exit codecmd.kill(signal?: string) // Kill the commandcmd.resize(cols, rows) // Resize TTYcmd.exitCode() // Get exit code (after exit)Events
Section titled “Events”cmd.on('exit', (code) => {}) // Command exitedcmd.on('error', (err) => {}) // Error occurredcmd.on('message', (msg) => {}) // Text message (port notifications, session_info)TypeScript Support
Section titled “TypeScript Support”The SDK is written in TypeScript and includes full type definitions:
import { SpritesClient, Sprite, SpriteCommand, SpriteConfig, SpriteInfo, SpawnOptions, ExecOptions, ExecResult, ExecError, Session, PortNotification,} from '@fly/sprites';Complete Example
Section titled “Complete Example”import { SpritesClient, ExecError } from '@fly/sprites';
async function main() { const client = new SpritesClient(process.env.SPRITE_TOKEN);
const sprite = await client.createSprite('ci-runner');
try { // Clone repository await sprite.execFile('git', ['clone', 'https://github.com/user/repo.git', '/home/sprite/repo']);
// Install dependencies await sprite.execFile('npm', ['install'], { cwd: '/home/sprite/repo' });
// Run tests with streaming output const cmd = sprite.spawn('npm', ['test'], { cwd: '/home/sprite/repo' });
cmd.stdout.on('data', (chunk) => process.stdout.write(chunk)); cmd.stderr.on('data', (chunk) => process.stderr.write(chunk));
const exitCode = await cmd.wait(); console.log(`Tests completed with exit code ${exitCode}`);
} catch (error) { if (error instanceof ExecError) { console.error(`Command failed: ${error.stderr}`); process.exit(error.exitCode); } throw error;
} finally { // Always clean up await sprite.delete(); }}
main();Related Documentation
Section titled “Related Documentation”- Sprites Guide - Comprehensive guide
- Go SDK - Go SDK reference
- REST API - HTTP API reference