Skip to main content
API reference for the @enclave-vm/react package - React hooks and components for EnclaveJS.

Installation

npm install @enclave-vm/react @enclave-vm/client

EnclaveProvider

Provider component for the EnclaveJS context.
import { EnclaveProvider } from '@enclave-vm/react';

function App() {
  return (
    <EnclaveProvider
      serverUrl="http://localhost:3001"
      auth={{ type: 'bearer', token: 'your-token' }}
    >
      <YourApp />
    </EnclaveProvider>
  );
}

Props

interface EnclaveProviderProps {
  // Required
  serverUrl: string;

  // Optional
  auth?: AuthOptions;
  reconnection?: ReconnectionOptions;
  encryption?: EncryptionOptions;
  children: ReactNode;
}

useEnclave

Main hook for code execution.
const {
  execute,
  stream,
  isRunning,
  cancel,
} = useEnclave();

Return Value

interface UseEnclaveReturn {
  execute: (code: string, options?: ExecuteOptions) => void;
  stream: AsyncIterable<StreamEvent> | null;
  isRunning: boolean;
  cancel: () => void;
}

Example

import { useEnclave } from '@enclave-vm/react';

function CodeRunner() {
  const { execute, isRunning, cancel } = useEnclave();

  const runCode = () => {
    execute(`
      console.log('Hello');
      return 42;
    `);
  };

  return (
    <div>
      <button onClick={runCode} disabled={isRunning}>
        Run
      </button>
      {isRunning && (
        <button onClick={cancel}>Cancel</button>
      )}
    </div>
  );
}

useExecutionStream

Process stream events with state management.
const {
  status,
  output,
  toolCalls,
  result,
  error,
  stats,
} = useExecutionStream(stream);

Return Value

interface UseExecutionStreamReturn {
  status: 'idle' | 'running' | 'completed' | 'error';
  output: string[];
  toolCalls: ToolCall[];
  result: unknown;
  error: string | null;
  stats: ExecutionStats | null;
}

interface ToolCall {
  id: string;
  tool: string;
  args: Record<string, unknown>;
  status: 'pending' | 'completed' | 'error';
  result?: unknown;
}

Example

import { useEnclave, useExecutionStream } from '@enclave-vm/react';

function CodeExecutor() {
  const { execute, stream, isRunning } = useEnclave();
  const { status, output, result, error } = useExecutionStream(stream);

  return (
    <div>
      <button onClick={() => execute(code)} disabled={isRunning}>
        Execute
      </button>

      <div>Status: {status}</div>

      <div>
        {output.map((line, i) => (
          <div key={i}>{line}</div>
        ))}
      </div>

      {result && <div>Result: {JSON.stringify(result)}</div>}
      {error && <div style={{ color: 'red' }}>{error}</div>}
    </div>
  );
}

useToolHandler

Handle tool calls with a callback.
useToolHandler(stream, async (name, args) => {
  return executeTool(name, args);
});

Parameters

function useToolHandler(
  stream: AsyncIterable<StreamEvent> | null,
  handler: (name: string, args: Record<string, unknown>) => Promise<unknown>
): void;

Example

import { useEnclave, useExecutionStream, useToolHandler } from '@enclave-vm/react';

function App() {
  const { execute, stream } = useEnclave();
  const { result } = useExecutionStream(stream);

  // Handle tool calls
  useToolHandler(stream, async (name, args) => {
    switch (name) {
      case 'users:list':
        return fetch('/api/users').then(r => r.json());
      case 'users:get':
        return fetch(`/api/users/${args.id}`).then(r => r.json());
      default:
        throw new Error(`Unknown tool: ${name}`);
    }
  });

  return (
    <div>
      <button onClick={() => execute(code)}>Run</button>
      {result && <pre>{JSON.stringify(result, null, 2)}</pre>}
    </div>
  );
}

useEnclaveClient

Get direct access to the client instance.
const client = useEnclaveClient();

Example

import { useEnclaveClient } from '@enclave-vm/react';

function HealthCheck() {
  const client = useEnclaveClient();
  const [health, setHealth] = useState(null);

  useEffect(() => {
    client.health().then(setHealth);
  }, [client]);

  return (
    <div>
      Status: {health?.status}
    </div>
  );
}

Components

Console

Pre-built console output component.
import { Console } from '@enclave-vm/react';

<Console
  output={output}
  maxLines={1000}
  autoScroll={true}
  className="my-console"
/>

Props

interface ConsoleProps {
  output: string[];
  maxLines?: number;
  autoScroll?: boolean;
  className?: string;
  style?: CSSProperties;
}

ToolCallList

Display tool call history.
import { ToolCallList } from '@enclave-vm/react';

<ToolCallList
  toolCalls={toolCalls}
  showArgs={true}
  className="my-tool-list"
/>

Props

interface ToolCallListProps {
  toolCalls: ToolCall[];
  showArgs?: boolean;
  className?: string;
  style?: CSSProperties;
}

ExecutionStatus

Show execution status with stats.
import { ExecutionStatus } from '@enclave-vm/react';

<ExecutionStatus
  status={status}
  stats={stats}
  error={error}
/>

Props

interface ExecutionStatusProps {
  status: 'idle' | 'running' | 'completed' | 'error';
  stats?: ExecutionStats | null;
  error?: string | null;
  className?: string;
}

Complete Example

import React, { useState } from 'react';
import {
  EnclaveProvider,
  useEnclave,
  useExecutionStream,
  useToolHandler,
  Console,
  ToolCallList,
  ExecutionStatus,
} from '@enclave-vm/react';

function CodePlayground() {
  const [code, setCode] = useState(`
    const users = await callTool('users:list', { limit: 5 });
    console.log('Found', users.length, 'users');
    return users;
  `);

  const { execute, stream, isRunning, cancel } = useEnclave();
  const {
    status,
    output,
    toolCalls,
    result,
    error,
    stats,
  } = useExecutionStream(stream);

  // Handle tool calls
  useToolHandler(stream, async (name, args) => {
    if (name === 'users:list') {
      return [
        { id: '1', name: 'Alice' },
        { id: '2', name: 'Bob' },
      ].slice(0, args.limit);
    }
    throw new Error(`Unknown tool: ${name}`);
  });

  return (
    <div style={{ padding: '20px' }}>
      <h1>Code Playground</h1>

      {/* Code Editor */}
      <textarea
        value={code}
        onChange={(e) => setCode(e.target.value)}
        style={{ width: '100%', height: '150px', fontFamily: 'monospace' }}
        disabled={isRunning}
      />

      {/* Actions */}
      <div style={{ margin: '10px 0' }}>
        <button onClick={() => execute(code)} disabled={isRunning}>
          {isRunning ? 'Running...' : 'Execute'}
        </button>
        {isRunning && (
          <button onClick={cancel} style={{ marginLeft: '10px' }}>
            Cancel
          </button>
        )}
      </div>

      {/* Status */}
      <ExecutionStatus status={status} stats={stats} error={error} />

      {/* Output */}
      <div style={{ display: 'grid', gridTemplateColumns: '1fr 1fr', gap: '20px' }}>
        <div>
          <h3>Console Output</h3>
          <Console output={output} maxLines={100} />
        </div>

        <div>
          <h3>Tool Calls</h3>
          <ToolCallList toolCalls={toolCalls} showArgs />
        </div>
      </div>

      {/* Result */}
      {result !== null && (
        <div style={{ marginTop: '20px' }}>
          <h3>Result</h3>
          <pre style={{ background: '#f5f5f5', padding: '10px' }}>
            {JSON.stringify(result, null, 2)}
          </pre>
        </div>
      )}
    </div>
  );
}

// App with provider
function App() {
  return (
    <EnclaveProvider serverUrl="http://localhost:3001">
      <CodePlayground />
    </EnclaveProvider>
  );
}

export default App;

TypeScript

All hooks and components are fully typed.
import type {
  UseEnclaveReturn,
  UseExecutionStreamReturn,
  ToolCall,
  ExecutionStats,
  StreamEvent,
} from '@enclave-vm/react';

// Types are exported for use
const handleResult = (result: UseExecutionStreamReturn['result']) => {
  console.log(result);
};