CtrlK
BlogDocsLog inGet started
Tessl Logo

tessl/npm-scramjet--api-client

API Client for use with Scramjet Transform Hub providing typed interfaces for managing sequences, instances, and Hub operations

Pending
Overview
Eval results
Files

sequence-client.mddocs/

Sequence Management

The SequenceClient provides operations for managing sequences (application packages) including starting instances, listing instances, and sequence metadata access.

Capabilities

Sequence Client Creation

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);

Instance Management

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!");

Sequence Information

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}`);

Configuration Types

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;
  };
}

Common Patterns

Sequential Instance Management

// 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`);

Instance Pool Management

// 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);

Sequence Lifecycle Management

// 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 });
  }
}

Error Handling

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

docs

host-client.md

index.md

instance-client.md

manager-client.md

sequence-client.md

topics.md

tile.json