FLOW MASON

React Hooks SDK

Build React applications powered by FlowMason pipelines with type-safe hooks and real-time streaming.

FlowMason provides React hooks for seamless integration with React applications, including real-time streaming, loading states, and error handling.

Installation

npm install @flowmason/react

Setup Provider

Wrap your app with the FlowMason provider:

import { FlowMasonProvider } from '@flowmason/react';

function App() {
  return (
    <FlowMasonProvider
      studioUrl="http://localhost:8999/api/v1"
      apiKey={process.env.REACT_APP_FLOWMASON_API_KEY}
    >
      <YourApp />
    </FlowMasonProvider>
  );
}

usePipeline Hook

The primary hook for running pipelines:

import { usePipeline } from '@flowmason/react';

function ContentGenerator() {
  const { run, result, loading, error, progress } = usePipeline('content-generator');

  const handleGenerate = async () => {
    await run({ topic: 'AI trends in 2024' });
  };

  return (
    <div>
      <button onClick={handleGenerate} disabled={loading}>
        {loading ? 'Generating...' : 'Generate Content'}
      </button>

      {progress && (
        <div className="progress-bar">
          <div style={{ width: `${progress.percentComplete}%` }} />
          <span>Stage: {progress.currentStage}</span>
        </div>
      )}

      {error && <div className="error">{error.message}</div>}

      {result && (
        <div className="result">
          <h3>Generated Content</h3>
          <p>{result.output.content}</p>
          <small>Tokens: {result.usage?.totalTokens}</small>
        </div>
      )}
    </div>
  );
}

useStreamingPipeline Hook

For real-time streaming updates:

import { useStreamingPipeline } from '@flowmason/react';

function StreamingChat() {
  const {
    run,
    stages,
    currentStage,
    isStreaming,
    partialOutput,
    finalResult,
  } = useStreamingPipeline('chat-pipeline');

  return (
    <div>
      <button onClick={() => run({ message: 'Hello!' })}>
        Send Message
      </button>

      {/* Show stage progress */}
      <div className="stages">
        {stages.map(stage => (
          <div
            key={stage.id}
            className={`stage ${stage.status}`}
          >
            {stage.name}: {stage.status}
            {stage.durationMs && ` (${stage.durationMs}ms)`}
          </div>
        ))}
      </div>

      {/* Show streaming output */}
      {isStreaming && (
        <div className="streaming">
          <span className="typing-indicator" />
          {partialOutput}
        </div>
      )}

      {/* Show final result */}
      {finalResult && (
        <div className="response">
          {finalResult.output.response}
        </div>
      )}
    </div>
  );
}

usePipelineList Hook

Fetch and display available pipelines:

import { usePipelineList } from '@flowmason/react';

function PipelineSelector({ onSelect }) {
  const { pipelines, loading, error, refetch } = usePipelineList({
    status: 'published',
    category: 'content',
  });

  if (loading) return <div>Loading pipelines...</div>;
  if (error) return <div>Error: {error.message}</div>;

  return (
    <select onChange={(e) => onSelect(e.target.value)}>
      <option value="">Select a pipeline</option>
      {pipelines.map(p => (
        <option key={p.id} value={p.id}>
          {p.name} v{p.version}
        </option>
      ))}
    </select>
  );
}

useRunHistory Hook

Access pipeline execution history:

import { useRunHistory } from '@flowmason/react';

function RunHistory({ pipelineId }) {
  const { runs, loading, hasMore, loadMore } = useRunHistory({
    pipelineId,
    limit: 10,
  });

  return (
    <div>
      <h3>Recent Runs</h3>
      <ul>
        {runs.map(run => (
          <li key={run.runId}>
            {run.status} - {new Date(run.startedAt).toLocaleString()}
            <span className={run.success ? 'success' : 'failed'}>
              {run.success ? '✓' : '✗'}
            </span>
          </li>
        ))}
      </ul>
      {hasMore && (
        <button onClick={loadMore} disabled={loading}>
          Load More
        </button>
      )}
    </div>
  );
}

useFlowMason Hook

Access the underlying FlowMason client:

import { useFlowMason } from '@flowmason/react';

function CustomComponent() {
  const fm = useFlowMason();

  const customAction = async () => {
    // Direct access to all SDK methods
    const pipeline = await fm.getPipeline('my-pipeline');
    const components = await fm.listComponents({ category: 'ai' });
    // ...
  };

  return <button onClick={customAction}>Custom Action</button>;
}

TypeScript Support

Full type inference for pipeline inputs and outputs:

import { usePipeline } from '@flowmason/react';

// Define your pipeline types
interface ContentInput {
  topic: string;
  style?: 'formal' | 'casual';
  maxLength?: number;
}

interface ContentOutput {
  title: string;
  content: string;
  tags: string[];
}

function TypedComponent() {
  const { run, result } = usePipeline<ContentInput, ContentOutput>(
    'content-generator'
  );

  const handleRun = () => {
    // TypeScript validates input
    run({
      topic: 'AI',
      style: 'formal',
      maxLength: 500,
    });
  };

  // result.output is typed as ContentOutput
  return result ? <div>{result.output.title}</div> : null;
}

Error Boundaries

Handle pipeline errors gracefully:

import { PipelineErrorBoundary } from '@flowmason/react';

function App() {
  return (
    <PipelineErrorBoundary
      fallback={({ error, reset }) => (
        <div className="error-container">
          <h2>Pipeline Error</h2>
          <p>{error.message}</p>
          <button onClick={reset}>Try Again</button>
        </div>
      )}
    >
      <ContentGenerator />
    </PipelineErrorBoundary>
  );
}

Configuration Options

<FlowMasonProvider
  studioUrl="https://api.flowmason.com/v1"
  apiKey="sk-..."
  orgId="org-123"
  defaultTimeout={60000}
  onError={(error) => {
    // Global error handler
    console.error('Pipeline error:', error);
    Sentry.captureException(error);
  }}
  onSuccess={(result) => {
    // Global success handler
    analytics.track('pipeline_completed', {
      pipelineId: result.pipelineId,
      duration: result.durationMs,
    });
  }}
>
  <App />
</FlowMasonProvider>

Server-Side Rendering (Next.js)

For Next.js applications:

// app/providers.tsx
'use client';

import { FlowMasonProvider } from '@flowmason/react';

export function Providers({ children }) {
  return (
    <FlowMasonProvider
      studioUrl={process.env.NEXT_PUBLIC_FLOWMASON_URL}
      apiKey={process.env.NEXT_PUBLIC_FLOWMASON_API_KEY}
    >
      {children}
    </FlowMasonProvider>
  );
}

// app/layout.tsx
import { Providers } from './providers';

export default function RootLayout({ children }) {
  return (
    <html>
      <body>
        <Providers>{children}</Providers>
      </body>
    </html>
  );
}

Best Practices

  1. Use streaming for long-running pipelines - Provides better UX with progress updates
  2. Implement error boundaries - Gracefully handle pipeline failures
  3. Cache pipeline metadata - Use usePipelineList to avoid repeated fetches
  4. Type your inputs/outputs - Leverage TypeScript for safer code
  5. Handle loading states - Always show feedback during execution