Skip to content
GitHubRSS

UI Package

Frontend integration utilities for ComputeSDK - Types, hooks, and utilities for building compute interfaces across any framework.

npm install @computesdk/ui

Complete TypeScript definitions for ComputeSDK API integration:

import type { 
  ComputeRequest, 
  ComputeResponse, 
  ComputeConfig,
  Runtime,
  FrontendSandbox,
  FrontendTerminal
} from '@computesdk/ui'

Framework-agnostic hook for compute operations:

import { useCompute } from '@computesdk/ui'

const compute = useCompute({
  apiEndpoint: '/api/compute',
  defaultRuntime: 'python'
})

// Create sandbox
const sandbox = await compute.sandbox.create()

// Execute code
const result = await sandbox.runCode('print("Hello World!")')

Helper functions for making requests to ComputeSDK APIs:

import { executeComputeRequest, APIError } from '@computesdk/ui'

const response = await executeComputeRequest({
  action: 'compute.sandbox.runCode',
  code: 'print("Hello World!")',
  runtime: 'python'
}, '/api/compute')

Input validation for compute operations:

import { 
  validateCode,
  validateRuntime,
  validateComputeRequest 
} from '@computesdk/ui'

const codeValidation = validateCode('print("hello")')
if (!codeValidation.isValid) {
  console.error(codeValidation.errors)
}

The main hook for compute operations. Returns a ComputeHook object with sandbox management capabilities.

function useCompute(config?: UseComputeConfig): ComputeHook

Configuration:

interface UseComputeConfig {
  apiEndpoint?: string;        // Default: '/api/compute'
  defaultRuntime?: Runtime;    // Default: 'python'
  timeout?: number;            // Request timeout in ms
  retries?: number;            // Number of retry attempts
}

Returns:

interface ComputeHook {
  sandbox: {
    create: (options?: { runtime?: Runtime; timeout?: number }) => Promise<FrontendSandbox>;
    get: (sandboxId: string) => Promise<FrontendSandbox | null>;
    list: () => Promise<FrontendSandbox[]>;
    destroy: (sandboxId: string) => Promise<void>;
  };
}

Mirrors the server-side sandbox API with all operations:

interface FrontendSandbox {
  id: string;
  provider: string;
  
  // Code execution
  runCode: (code: string, runtime?: Runtime) => Promise<ComputeResponse>;
  runCommand: (command: string, args?: string[]) => Promise<ComputeResponse>;
  
  // Sandbox management
  getInfo: () => Promise<ComputeResponse>;
  destroy: () => Promise<ComputeResponse>;
  
  // Filesystem operations
  filesystem: {
    readFile: (path: string) => Promise<ComputeResponse>;
    writeFile: (path: string, content: string) => Promise<ComputeResponse>;
    mkdir: (path: string) => Promise<ComputeResponse>;
    readdir: (path: string) => Promise<ComputeResponse>;
    exists: (path: string) => Promise<ComputeResponse>;
    remove: (path: string) => Promise<ComputeResponse>;
  };
  
  // Terminal operations
  terminal: {
    create: (options?: TerminalOptions) => Promise<FrontendTerminal>;
    getById: (terminalId: string) => Promise<FrontendTerminal | null>;
    list: () => Promise<FrontendTerminal[]>;
    destroy: (terminalId: string) => Promise<void>;
  };
}

Interactive terminal with real-time I/O via Server-Sent Events:

interface FrontendTerminal {
  pid: number;
  command: string;
  status: 'running' | 'exited';
  cols: number;
  rows: number;
  exitCode?: number;
  
  // Terminal operations
  write: (data: Uint8Array | string) => Promise<void>;
  resize: (cols: number, rows: number) => Promise<void>;
  kill: () => Promise<void>;
  
  // Event handlers
  onData?: (data: Uint8Array) => void;    // Auto-starts SSE streaming
  onExit?: (exitCode: number) => void;
}

Request structure for all compute operations:

interface ComputeRequest {
  action: 'compute.sandbox.create' | 'compute.sandbox.runCode' | /* ... */;
  sandboxId?: string;
  code?: string;
  runtime?: Runtime;
  path?: string;
  content?: string;
  // ... more fields for specific operations
}

Response structure from compute operations:

interface ComputeResponse {
  success: boolean;
  error?: string;
  sandboxId: string;
  provider: string;
  result?: ExecutionResult;
  fileContent?: string;
  files?: FileEntry[];
  // ... more fields for specific operations
}

Generic function for any compute operation:

async function executeComputeRequest(
  request: ComputeRequest,
  endpoint?: string
): Promise<ComputeResponse>

Input validation utilities:

function validateCode(code: string): ValidationResult
function validateRuntime(runtime: string): ValidationResult
function validateComputeRequest(request: ComputeRequest): ValidationResult
function validateComputeConfig(config: ComputeConfig): ValidationResult

Display helpers:

function formatExecutionTime(milliseconds: number): string
function formatOutput(output: string): string
function isComputeError(response: ComputeResponse): boolean
function getErrorMessage(response: ComputeResponse): string

This package is framework-agnostic. Use it with any frontend framework:

import React, { useState } from 'react'
import { useCompute, type ComputeResponse } from '@computesdk/ui'

function CodeExecutor() {
  const [code, setCode] = useState('print("Hello World!")')
  const [result, setResult] = useState<ComputeResponse | null>(null)
  const [loading, setLoading] = useState(false)
  
  const compute = useCompute({
    apiEndpoint: '/api/compute',
    defaultRuntime: 'python'
  })
  
  const executeCode = async () => {
    setLoading(true)
    try {
      const sandbox = await compute.sandbox.create()
      const response = await sandbox.runCode(code)
      setResult(response)
      await sandbox.destroy()
    } catch (error) {
      console.error('Execution failed:', error)
    } finally {
      setLoading(false)
    }
  }
  
  return (
    <div>
      <textarea 
        value={code} 
        onChange={(e) => setCode(e.target.value)}
        rows={10}
        cols={50}
      />
      <button onClick={executeCode} disabled={loading}>
        {loading ? 'Executing...' : 'Execute'}
      </button>
      {result && (
        <pre>
          {result.success ? result.result?.stdout : result.error}
        </pre>
      )}
    </div>
  )
}
import { ref, computed } from 'vue'
import { useCompute, type ComputeResponse } from '@computesdk/ui'

export function useCodeExecution() {
  const code = ref('print("Hello World!")')
  const result = ref<ComputeResponse | null>(null)
  const loading = ref(false)
  
  const compute = useCompute({
    apiEndpoint: '/api/compute',
    defaultRuntime: 'python'
  })
  
  const output = computed(() => {
    if (!result.value) return ''
    return result.value.success 
      ? result.value.result?.stdout || ''
      : result.value.error || 'Unknown error'
  })
  
  const execute = async () => {
    loading.value = true
    try {
      const sandbox = await compute.sandbox.create()
      result.value = await sandbox.runCode(code.value)
      await sandbox.destroy()
    } catch (error) {
      console.error('Execution failed:', error)
    } finally {
      loading.value = false
    }
  }
  
  return { code, result, loading, output, execute }
}
import { writable } from 'svelte/store'
import { useCompute, type ComputeResponse } from '@computesdk/ui'

export const code = writable('print("Hello World!")')
export const result = writable<ComputeResponse | null>(null)
export const loading = writable(false)

const compute = useCompute({
  apiEndpoint: '/api/compute',
  defaultRuntime: 'python'
})

export async function execute() {
  loading.set(true)
  try {
    const sandbox = await compute.sandbox.create()
    const response = await sandbox.runCode(get(code))
    result.set(response)
    await sandbox.destroy()
  } catch (error) {
    console.error('Execution failed:', error)
  } finally {
    loading.set(false)
  }
}

Real-time terminal with Server-Sent Events:

import { useCompute } from '@computesdk/ui'

const compute = useCompute()

// Create sandbox and terminal
const sandbox = await compute.sandbox.create()
const terminal = await sandbox.terminal.create({
  command: 'bash',
  cols: 80,
  rows: 24
})

// Set up real-time output handler
terminal.onData = (data: Uint8Array) => {
  const output = new TextDecoder().decode(data)
  console.log('Terminal output:', output)
  // Update your terminal UI here
}

// Send commands
await terminal.write('echo "Hello Terminal!"\n')
await terminal.write('ls -la\n')

// Handle terminal resize
await terminal.resize(120, 30)

// Clean up
await terminal.kill()
await sandbox.destroy()
import { useCompute } from '@computesdk/ui'

const compute = useCompute()
const sandbox = await compute.sandbox.create()

// Create project structure
await sandbox.filesystem.mkdir('/project/data')
await sandbox.filesystem.mkdir('/project/output')

// Write files
await sandbox.filesystem.writeFile('/project/data/input.txt', 'Hello World!')
await sandbox.filesystem.writeFile('/project/script.py', `
with open('/project/data/input.txt', 'r') as f:
    content = f.read()
    
with open('/project/output/result.txt', 'w') as f:
    f.write(f"Processed: {content.upper()}")
    
print("Processing complete!")
`)

// Execute script
const result = await sandbox.runCode(`exec(open('/project/script.py').read())`)
console.log(result.result?.stdout)

// Read results
const output = await sandbox.filesystem.readFile('/project/output/result.txt')
console.log('Result:', output.fileContent)

// List files
const files = await sandbox.filesystem.readdir('/project')
console.log('Project files:', files.files)
import { useCompute, APIError, isComputeError, getErrorMessage } from '@computesdk/ui'

const compute = useCompute()

try {
  const sandbox = await compute.sandbox.create()
  const result = await sandbox.runCode('invalid python code')
  
  if (isComputeError(result)) {
    console.error('Compute error:', getErrorMessage(result))
  } else {
    console.log('Success:', result.result?.stdout)
  }
} catch (error) {
  if (error instanceof APIError) {
    console.error('API Error:', error.message, 'Status:', error.status)
  } else {
    console.error('Unexpected error:', error)
  }
}

Your server should implement the ComputeSDK request handler:

// /api/compute endpoint
import { handleComputeRequest } from 'computesdk'
import { e2b } from '@computesdk/e2b'

export async function GET(request: Request) {
  return handleComputeRequest({
    request,
    provider: e2b({ apiKey: process.env.E2B_API_KEY })
  })
}

export async function POST(request: Request) {
  return handleComputeRequest({
    request,
    provider: e2b({ apiKey: process.env.E2B_API_KEY })
  })
}

See the ComputeSDK examples for complete framework integrations: