Remote command execution for Sprites, with an API that mirrors Node.js child_process
.
- Node.js 24.0.0 or later
- No external dependencies (uses only Node.js standard library)
npm install @superfly/sprites
import { SpritesClient } from '@superfly/sprites';
const client = new SpritesClient(process.env.SPRITES_TOKEN!);
const sprite = client.sprite('my-sprite');
// Event-based API (most Node.js-like)
const cmd = sprite.spawn('ls', ['-la']);
cmd.stdout.on('data', (chunk) => {
process.stdout.write(chunk);
});
cmd.on('exit', (code) => {
console.log(`Exited with code ${code}`);
});
// Promise-based API
const { stdout } = await sprite.exec('echo hello');
console.log(stdout); // 'hello\n'
Main client for interacting with the Sprites API.
const client = new SpritesClient(token, options);
Options:
baseURL
: API base URL (default: https://api.sprites.dev)timeout
: HTTP request timeout in ms (default: 30000)
Methods:
sprite(name: string): Sprite
- Get a handle to a spritecreateSprite(name: string, config?: SpriteConfig): Promise<Sprite>
- Create a new spritegetSprite(name: string): Promise<Sprite>
- Get sprite informationlistSprites(options?: ListOptions): Promise<SpriteList>
- List spriteslistAllSprites(prefix?: string): Promise<Sprite[]>
- List all sprites (handles pagination)deleteSprite(name: string): Promise<void>
- Delete a spriteupgradeSprite(name: string): Promise<void>
- Upgrade a spritestatic createToken(flyMacaroon: string, orgSlug: string, inviteCode?: string): Promise<string>
- Create an access token
Represents a sprite instance.
const sprite = client.sprite('my-sprite');
Command Execution Methods:
// Event-based (mirrors child_process.spawn)
spawn(command: string, args?: string[], options?: SpawnOptions): SpriteCommand
// Promise-based (mirrors child_process.exec)
exec(command: string, options?: ExecOptions): Promise<ExecResult>
// Promise-based with separate args (mirrors child_process.execFile)
execFile(file: string, args?: string[], options?: ExecOptions): Promise<ExecResult>
Session Methods:
createSession(command: string, args?: string[], options?: SpawnOptions): SpriteCommand
- Create a detachable sessionattachSession(sessionId: string, options?: SpawnOptions): SpriteCommand
- Attach to a sessionlistSessions(): Promise<Session[]>
- List active sessions
Management Methods:
delete(): Promise<void>
- Delete the spriteupgrade(): Promise<void>
- Upgrade the sprite
Represents a running command. Extends EventEmitter.
Properties:
stdin: Writable
- Standard input streamstdout: Readable
- Standard output streamstderr: Readable
- Standard error stream
Methods:
wait(): Promise<number>
- Wait for exit and return exit codekill(signal?: string): void
- Kill the commandresize(cols: number, rows: number): void
- Resize TTY (if TTY mode enabled)exitCode(): number
- Get exit code (-1 if not exited)
Events:
exit
-(code: number) => void
- Emitted when command exitserror
-(error: Error) => void
- Emitted on errormessage
-(msg: any) => void
- Emitted for text messages (e.g., port notifications)
interface SpawnOptions {
cwd?: string; // Working directory
env?: Record<string, string>; // Environment variables
tty?: boolean; // Enable TTY mode
rows?: number; // TTY rows
cols?: number; // TTY columns
detachable?: boolean; // Create detachable session
sessionId?: string; // Attach to existing session
controlMode?: boolean; // Enable control mode
}
Extends SpawnOptions with:
encoding?: BufferEncoding
- Output encoding (default: 'utf8')maxBuffer?: number
- Maximum buffer size (default: 10MB)
// Streaming output
const cmd = sprite.spawn('ls', ['-la']);
cmd.stdout.pipe(process.stdout);
cmd.stderr.pipe(process.stderr);
await cmd.wait();
// Capture output
const { stdout, stderr } = await sprite.exec('ls -la');
console.log(stdout);
const cmd = sprite.spawn('bash', [], {
tty: true,
rows: 24,
cols: 80,
});
process.stdin.pipe(cmd.stdin);
cmd.stdout.pipe(process.stdout);
// Resize terminal
cmd.resize(100, 30);
const cmd = sprite.spawn('python', ['app.py']);
cmd.on('message', (msg) => {
if (msg.type === 'port_opened') {
console.log(`Port ${msg.port} opened by PID ${msg.pid}`);
// Start local proxy, etc.
}
});
// Create a detachable session
const session = sprite.createSession('bash');
await session.wait();
// List sessions
const sessions = await sprite.listSessions();
console.log(sessions);
// Attach to a session
const attached = sprite.attachSession(sessions[0].id);
import { ExecError } from '@superfly/sprites';
try {
await sprite.exec('false');
} catch (error) {
if (error instanceof ExecError) {
console.log('Exit code:', error.exitCode);
console.log('Stdout:', error.stdout);
console.log('Stderr:', error.stderr);
}
}
// Create a sprite
const sprite = await client.createSprite('my-sprite', {
ramMB: 512,
cpus: 1,
region: 'ord',
});
// List sprites
const sprites = await client.listAllSprites();
// Delete a sprite
await sprite.delete();
MIT