API Client for use with Scramjet Transform Hub providing typed interfaces for managing sequences, instances, and Hub operations
—
The SequenceClient provides operations for managing sequences (application packages) including starting instances, listing instances, and sequence metadata access.
Create a SequenceClient for managing a specific sequence.
/**
* Creates SequenceClient for a specific sequence
* @param id - Sequence identifier
* @param host - ClientProvider (typically HostClient) for API communication
* @returns New SequenceClient instance
*/
class SequenceClient {
readonly id: string;
static from(id: string, host: ClientProvider): SequenceClient;
private constructor(id: string, host: ClientProvider);
}Usage Example:
import { HostClient } from "@scramjet/api-client";
const host = new HostClient("http://localhost:8000/api/v1");
const sequence = host.getSequenceClient("sequence-id");
// or
const sequence = SequenceClient.from("sequence-id", host);Start new instances from the sequence and manage existing ones.
/**
* Starts a new instance of the sequence
* @param payload - Configuration for starting the sequence
* @param payload.appConfig - Application-specific configuration
* @param payload.args - Command line arguments to pass to the sequence
* @returns Promise resolving to InstanceClient for the started instance
* @throws Error if sequence fails to start
*/
start(payload: STHRestAPI.StartSequencePayload): Promise<InstanceClient>;
/**
* Lists all instances created from this sequence
* @returns Promise resolving to array of instance IDs
*/
listInstances(): Promise<string[]>;
/**
* Gets an InstanceClient for a specific instance
* @param id - Instance identifier
* @param host - Optional ClientProvider (defaults to sequence's host)
* @returns Promise resolving to InstanceClient
*/
getInstance(id: string, host?: ClientProvider): Promise<InstanceClient>;Usage Examples:
// Start a sequence with custom configuration
const instance = await sequence.start({
appConfig: {
environment: "production",
logLevel: "info"
},
args: ["--port", "3000", "--verbose"]
});
// Start a sequence with minimal configuration
const simpleInstance = await sequence.start({});
// List all instances of this sequence
const instanceIds = await sequence.listInstances();
console.log(`Sequence has ${instanceIds.length} instances`);
// Get a specific instance client
const specificInstance = await sequence.getInstance(instanceIds[0]);
await specificInstance.sendInput("Hello from sequence management!");Access and modify sequence metadata and configuration.
/**
* Gets detailed information about the sequence
* @returns Promise resolving to sequence details including configuration and instances
*/
getInfo(): Promise<STHRestAPI.GetSequenceResponse>;
/**
* Overwrites the sequence with new package data
* @param stream - Stream containing the new sequence package
* @returns Promise resolving to new SequenceClient for the updated sequence
*/
overwrite(stream: Readable): Promise<SequenceClient>;Usage Examples:
import { Readable } from "stream";
import fs from "fs";
// Get sequence information
const info = await sequence.getInfo();
console.log(`Sequence: ${info.config.name} v${info.config.version}`);
console.log(`Active instances: ${info.instances.length}`);
// Update sequence with new version
const newPackageStream = fs.createReadStream("./my-app-v2.tar.gz");
const updatedSequence = await sequence.overwrite(newPackageStream);
console.log(`Updated sequence ID: ${updatedSequence.id}`);interface STHRestAPI {
/**
* Configuration payload for starting a sequence instance
*/
StartSequencePayload: {
/** Application-specific configuration object */
appConfig?: {
[key: string]: any;
};
/** Command line arguments to pass to the sequence */
args?: string[];
/** Additional configuration options */
[key: string]: any;
};
/**
* Response containing sequence information
*/
GetSequenceResponse: {
/** Unique sequence identifier */
id: string;
/** Sequence configuration and metadata */
config: {
name: string;
version: string;
description?: string;
main?: string;
engines?: {
node?: string;
[key: string]: any;
};
/** Additional configuration fields */
[key: string]: any;
};
/** List of instance IDs created from this sequence */
instances: string[];
/** Additional sequence metadata */
[key: string]: any;
};
/**
* Response when starting a sequence instance
*/
StartSequenceResponse: {
/** ID of the created instance */
id: string;
/** Instance status */
status: "starting" | "running";
/** Additional response data */
[key: string]: any;
};
}// Start multiple instances in sequence
const instances: InstanceClient[] = [];
for (let i = 0; i < 3; i++) {
const instance = await sequence.start({
appConfig: { workerId: i }
});
instances.push(instance);
// Wait for instance to be ready before starting next
await instance.getNextEvent("ready");
}
console.log(`Started ${instances.length} instances`);// Manage a pool of instances for load balancing
class SequencePool {
private instances: InstanceClient[] = [];
private currentIndex = 0;
constructor(private sequence: SequenceClient, private poolSize: number) {}
async initialize() {
for (let i = 0; i < this.poolSize; i++) {
const instance = await this.sequence.start({
appConfig: { poolIndex: i }
});
this.instances.push(instance);
}
}
getNextInstance(): InstanceClient {
const instance = this.instances[this.currentIndex];
this.currentIndex = (this.currentIndex + 1) % this.instances.length;
return instance;
}
async shutdown() {
await Promise.all(
this.instances.map(instance => instance.stop(5000, false))
);
}
}
// Usage
const pool = new SequencePool(sequence, 3);
await pool.initialize();
// Process requests using round-robin
const instance = pool.getNextInstance();
await instance.sendInput(requestData);// Complete sequence lifecycle from upload to cleanup
async function deployAndRunSequence(packagePath: string, config: any) {
const host = new HostClient("http://localhost:8000/api/v1");
// Upload sequence
const packageStream = fs.createReadStream(packagePath);
const sequence = await host.sendSequence(packageStream);
try {
// Start instance
const instance = await sequence.start(config);
// Wait for completion
const result = await instance.getNextEvent("completed");
console.log("Sequence completed:", result.data);
// Graceful shutdown
await instance.stop(10000, false);
} finally {
// Clean up sequence
await host.deleteSequence(sequence.id, { force: true });
}
}Sequence operations may encounter various error conditions:
try {
const instance = await sequence.start(config);
} catch (error) {
if (error.body?.error?.code === 'INSUFFICIENT_RESOURCES') {
console.log('Not enough resources to start instance');
// Maybe retry later or with different configuration
} else if (error.body?.error?.code === 'INVALID_CONFIG') {
console.log('Invalid configuration provided:', error.body.error.message);
} else {
console.log('Failed to start sequence:', error.message);
}
}
// Handle instance startup monitoring
async function startWithRetry(sequence: SequenceClient, config: any, maxRetries = 3) {
for (let attempt = 1; attempt <= maxRetries; attempt++) {
try {
const instance = await sequence.start(config);
// Wait for instance to be ready or fail
const readyPromise = instance.getNextEvent("ready");
const errorPromise = instance.getNextEvent("error");
const result = await Promise.race([readyPromise, errorPromise]);
if (result.eventName === "error") {
throw new Error(`Instance failed to start: ${result.data}`);
}
return instance;
} catch (error) {
console.log(`Attempt ${attempt} failed:`, error.message);
if (attempt === maxRetries) throw error;
// Wait before retry
await new Promise(resolve => setTimeout(resolve, 1000 * attempt));
}
}
}Install with Tessl CLI
npx tessl i tessl/npm-scramjet--api-client