@fly/sprites
Version:
JavaScript/TypeScript SDK for Sprites - remote command execution
230 lines (170 loc) • 5.82 kB
Markdown
# Sprites JavaScript/TypeScript SDK
Remote command execution for Sprites, with an API that mirrors Node.js `child_process`.
## Requirements
- Node.js 24.0.0 or later
- No external dependencies (uses only Node.js standard library)
## Installation
```bash
npm install @fly/sprites
```
## Quick Start
```typescript
import { SpritesClient } from '@fly/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'
```
## API Reference
### SpritesClient
Main client for interacting with the Sprites API.
```typescript
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 sprite
- `createSprite(name: string, config?: SpriteConfig): Promise<Sprite>` - Create a new sprite
- `getSprite(name: string): Promise<Sprite>` - Get sprite information
- `listSprites(options?: ListOptions): Promise<SpriteList>` - List sprites
- `listAllSprites(prefix?: string): Promise<Sprite[]>` - List all sprites (handles pagination)
- `deleteSprite(name: string): Promise<void>` - Delete a sprite
- `upgradeSprite(name: string): Promise<void>` - Upgrade a sprite
- `static createToken(flyMacaroon: string, orgSlug: string, inviteCode?: string): Promise<string>` - Create an access token
### Sprite
Represents a sprite instance.
```typescript
const sprite = client.sprite('my-sprite');
```
**Command Execution Methods:**
```typescript
// 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 session
- `attachSession(sessionId: string, options?: SpawnOptions): SpriteCommand` - Attach to a session
- `listSessions(): Promise<Session[]>` - List active sessions
**Management Methods:**
- `delete(): Promise<void>` - Delete the sprite
- `upgrade(): Promise<void>` - Upgrade the sprite
### SpriteCommand
Represents a running command. Extends EventEmitter.
**Properties:**
- `stdin: Writable` - Standard input stream
- `stdout: Readable` - Standard output stream
- `stderr: Readable` - Standard error stream
**Methods:**
- `wait(): Promise<number>` - Wait for exit and return exit code
- `kill(signal?: string): void` - Kill the command
- `resize(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 exits
- `error` - `(error: Error) => void` - Emitted on error
- `message` - `(msg: any) => void` - Emitted for text messages (e.g., port notifications)
### Spawn Options
```typescript
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
}
```
### Exec Options
Extends SpawnOptions with:
- `encoding?: BufferEncoding` - Output encoding (default: 'utf8')
- `maxBuffer?: number` - Maximum buffer size (default: 10MB)
## Examples
### Basic Command Execution
```typescript
// 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);
```
### TTY Mode
```typescript
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);
```
### Port Notifications
```typescript
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.
}
});
```
### Detachable Sessions
```typescript
// 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);
```
### Error Handling
```typescript
import { ExecError } from '@fly/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);
}
}
```
### Sprite Management
```typescript
// 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();
```
## License
MIT