@fly/sprites
Version:
JavaScript/TypeScript SDK for Sprites - remote command execution
191 lines • 6.46 kB
JavaScript
/**
* Sprites client implementation
*/
import { Sprite } from './sprite.js';
/**
* Main client for interacting with the Sprites API
*/
export class SpritesClient {
baseURL;
token;
timeout;
constructor(token, options = {}) {
this.token = token;
this.baseURL = (options.baseURL || 'https://api.sprites.dev').replace(/\/+$/, '');
this.timeout = options.timeout || 30000;
}
/**
* Get a handle to a sprite (doesn't create it on the server)
*/
sprite(name) {
return new Sprite(name, this);
}
/**
* Create a new sprite
*/
async createSprite(name, config) {
const request = { name, config };
const response = await this.fetch(`${this.baseURL}/v1/sprites`, {
method: 'POST',
headers: {
'Authorization': `Bearer ${this.token}`,
'Content-Type': 'application/json',
},
body: JSON.stringify(request),
signal: AbortSignal.timeout(120000), // 2 minute timeout for creation
});
if (!response.ok) {
const body = await response.text();
throw new Error(`Failed to create sprite (status ${response.status}): ${body}`);
}
const result = await response.json();
return new Sprite(result.name, this);
}
/**
* Get information about a sprite
*/
async getSprite(name) {
const response = await this.fetch(`${this.baseURL}/v1/sprites/${name}`, {
method: 'GET',
headers: {
'Authorization': `Bearer ${this.token}`,
},
signal: AbortSignal.timeout(this.timeout),
});
if (response.status === 404) {
throw new Error(`Sprite not found: ${name}`);
}
if (!response.ok) {
const body = await response.text();
throw new Error(`Failed to get sprite (status ${response.status}): ${body}`);
}
const info = await response.json();
const sprite = new Sprite(info.name, this);
Object.assign(sprite, info);
return sprite;
}
/**
* List sprites with optional filtering and pagination
*/
async listSprites(options = {}) {
const params = new URLSearchParams();
if (options.maxResults)
params.set('max_results', options.maxResults.toString());
if (options.continuationToken)
params.set('continuation_token', options.continuationToken);
if (options.prefix)
params.set('prefix', options.prefix);
const url = `${this.baseURL}/v1/sprites?${params}`;
const response = await this.fetch(url, {
method: 'GET',
headers: {
'Authorization': `Bearer ${this.token}`,
},
signal: AbortSignal.timeout(this.timeout),
});
if (!response.ok) {
const body = await response.text();
throw new Error(`Failed to list sprites (status ${response.status}): ${body}`);
}
return await response.json();
}
/**
* List all sprites, handling pagination automatically
*/
async listAllSprites(prefix) {
const allSprites = [];
let continuationToken;
do {
const result = await this.listSprites({
prefix,
maxResults: 100,
continuationToken,
});
for (const info of result.sprites) {
const sprite = new Sprite(info.name, this);
Object.assign(sprite, info);
allSprites.push(sprite);
}
continuationToken = result.hasMore ? result.nextContinuationToken : undefined;
} while (continuationToken);
return allSprites;
}
/**
* Delete a sprite
*/
async deleteSprite(name) {
const response = await this.fetch(`${this.baseURL}/v1/sprites/${name}`, {
method: 'DELETE',
headers: {
'Authorization': `Bearer ${this.token}`,
},
signal: AbortSignal.timeout(this.timeout),
});
if (!response.ok && response.status !== 204) {
const body = await response.text();
throw new Error(`Failed to delete sprite (status ${response.status}): ${body}`);
}
}
/**
* Upgrade a sprite to the latest version
*/
async upgradeSprite(name) {
const response = await this.fetch(`${this.baseURL}/v1/sprites/${name}/upgrade`, {
method: 'POST',
headers: {
'Authorization': `Bearer ${this.token}`,
},
signal: AbortSignal.timeout(60000),
});
if (!response.ok && response.status !== 204) {
const body = await response.text();
throw new Error(`Failed to upgrade sprite (status ${response.status}): ${body}`);
}
}
/**
* Create a sprite access token using a Fly.io macaroon token
*/
static async createToken(flyMacaroon, orgSlug, inviteCode) {
const apiURL = 'https://api.sprites.dev';
const url = `${apiURL}/v1/organizations/${orgSlug}/tokens`;
const body = {
description: 'Sprite SDK Token',
};
if (inviteCode) {
body.invite_code = inviteCode;
}
const response = await fetch(url, {
method: 'POST',
headers: {
'Authorization': `FlyV1 ${flyMacaroon}`,
'Content-Type': 'application/json',
},
body: JSON.stringify(body),
signal: AbortSignal.timeout(30000),
});
if (!response.ok) {
const text = await response.text();
throw new Error(`API returned status ${response.status}: ${text}`);
}
const result = await response.json();
if (!result.token) {
throw new Error('No token returned in response');
}
return result.token;
}
/**
* Wrapper around fetch for consistent error handling
*/
async fetch(url, init) {
try {
return await fetch(url, init);
}
catch (error) {
if (error instanceof Error) {
throw new Error(`Network error: ${error.message}`);
}
throw error;
}
}
}
//# sourceMappingURL=client.js.map