npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

@mesantosrai/pipeline-canvas

v1.0.3

Published

Pipeline canvas component library for visual workflow design

Readme

@mesantosrai/pipeline-canvas

A React component library for building visual pipeline/workflow canvases using React Flow.

Installation from Private GitHub Repo

Using SSH (Recommended for Private Repos)

npm install git+ssh://[email protected]:santosrai/pipeline-canvas.git

Using HTTPS with Personal Access Token

npm install git+https://[email protected]/santosrai/pipeline-canvas.git

Using Specific Branch or Tag

npm install git+ssh://[email protected]:santosrai/pipeline-canvas.git#main

Setup

  1. Install dependencies:
npm install
  1. Build the library:
npm run build

Peer Dependencies

Make sure you have these installed in your consuming project:

npm install react react-dom reactflow zustand lucide-react

shadcn/ui Components (Required)

This library uses shadcn/ui components. You need to install the required Radix UI packages and utilities:

npm install @radix-ui/react-dialog @radix-ui/react-dropdown-menu @radix-ui/react-label @radix-ui/react-select @radix-ui/react-slot @radix-ui/react-tooltip class-variance-authority clsx tailwind-merge

Note: The library includes shadcn component implementations in components/ui/, but you must install the peer dependencies above for them to work.

Usage

Basic Example (Standalone - No Dependencies)

The library works completely standalone without any dependencies:

import { PipelineCanvas, PipelineCanvasProvider } from '@mesantosrai/pipeline-canvas';
import '@mesantosrai/pipeline-canvas/style.css';

function App() {
  return (
    <PipelineCanvasProvider>
      <div style={{ width: '100vw', height: '100vh' }}>
        <PipelineCanvas />
      </div>
    </PipelineCanvasProvider>
  );
}

Note: Without dependencies, the library works in "offline mode":

  • Pipelines are saved locally (localStorage)
  • No backend sync
  • No authentication required
  • File uploads work if your API supports unauthenticated requests

With Authentication and API Client

For full functionality (backend sync, authenticated operations):

import { 
  PipelineCanvas, 
  PipelineCanvasProvider,
  type ApiClient,
  type AuthState 
} from '@mesantosrai/pipeline-canvas';
import '@mesantosrai/pipeline-canvas/style.css';

function App() {
  // Your API client (compatible with axios, fetch, or custom)
  const apiClient: ApiClient = {
    get: async (url: string) => {
      const response = await fetch(`/api${url}`, {
        headers: { 'Authorization': `Bearer ${token}` }
      });
      return { data: await response.json() };
    },
    post: async (url: string, data: any) => {
      const response = await fetch(`/api${url}`, {
        method: 'POST',
        headers: { 
          'Content-Type': 'application/json',
          'Authorization': `Bearer ${token}`
        },
        body: JSON.stringify(data)
      });
      return { data: await response.json() };
    },
  };

  // Your auth state
  const authState: AuthState = {
    user: { id: 'user-123', email: '[email protected]' },
    isAuthenticated: true,
    accessToken: token,
  };

  // Session ID for execution context
  const sessionId = 'session-456';

  // Auth headers function for file uploads
  const getAuthHeaders = () => ({
    'Authorization': `Bearer ${token}`
  });

  return (
    <PipelineCanvasProvider
      apiClient={apiClient}
      authState={authState}
      sessionId={sessionId}
      getAuthHeaders={getAuthHeaders}
    >
      <div style={{ width: '100vw', height: '100vh' }}>
        <PipelineCanvas />
      </div>
    </PipelineCanvasProvider>
  );
}

With Axios API Client

If you're using axios:

import axios from 'axios';
import { PipelineCanvasProvider, type ApiClient } from '@mesantosrai/pipeline-canvas';

const apiClient: ApiClient = {
  get: (url: string, config?) => axios.get(url, config),
  post: (url: string, data?: any, config?) => axios.post(url, data, config),
  put: (url: string, data?: any, config?) => axios.put(url, data, config),
  patch: (url: string, data?: any, config?) => axios.patch(url, data, config),
  delete: (url: string, config?) => axios.delete(url, config),
};

function App() {
  return (
    <PipelineCanvasProvider apiClient={apiClient}>
      <PipelineCanvas />
    </PipelineCanvasProvider>
  );
}

Partial Dependencies

You can provide only the dependencies you need:

// Only API client (no auth)
<PipelineCanvasProvider apiClient={myApiClient}>
  <PipelineCanvas />
</PipelineCanvasProvider>

// Only auth state (local operations only)
<PipelineCanvasProvider authState={authState}>
  <PipelineCanvas />
</PipelineCanvasProvider>

// Everything optional - works standalone
<PipelineCanvasProvider>
  <PipelineCanvas />
</PipelineCanvasProvider>

Using the Store

import { usePipelineStore } from '@mesantosrai/pipeline-canvas';

function MyComponent() {
  const { nodes, edges, addNode } = usePipelineStore();
  
  return (
    <div>
      <p>Nodes: {nodes.length}</p>
      <button onClick={() => addNode({ id: '1', type: 'input', data: {} })}>
        Add Node
      </button>
    </div>
  );
}

Using Context Directly

You can also access dependencies directly from context:

import { usePipelineContext } from '@mesantosrai/pipeline-canvas';

function MyComponent() {
  const { apiClient, authState, sessionId, getAuthHeaders } = usePipelineContext();
  
  // Use dependencies as needed
  if (authState?.user) {
    // User is authenticated
  }
  
  return <div>...</div>;
}

Dependency Injection

The library uses dependency injection to remain standalone and flexible. All dependencies are optional:

  • apiClient: For backend operations (save, load, sync pipelines)
  • authState: For user-specific features and authentication
  • sessionId: For execution context and session tracking
  • getAuthHeaders: For authenticated file uploads
  • logger: For structured logging (optional, uses console by default)
  • errorReporter: For error tracking (Sentry, LogRocket, etc.)

Graceful Degradation

When dependencies are not provided:

  • ✅ Pipelines work locally (localStorage)
  • ✅ All UI features work
  • ✅ Pipeline execution works (with provided apiClient or external APIs)
  • ⚠️ Backend sync is skipped
  • ⚠️ User-specific features are disabled
  • ⚠️ File uploads may fail if API requires authentication

Integration Examples

With Zustand Auth Store

import { useAuthStore } from './stores/authStore';
import { PipelineCanvasProvider } from '@mesantosrai/pipeline-canvas';

function App() {
  const user = useAuthStore(state => state.user);
  const token = useAuthStore(state => state.accessToken);
  
  const authState = {
    user,
    isAuthenticated: !!user,
    accessToken: token,
  };
  
  return (
    <PipelineCanvasProvider authState={authState}>
      <PipelineCanvas />
    </PipelineCanvasProvider>
  );
}

With React Context Auth

import { useContext } from 'react';
import { AuthContext } from './AuthContext';
import { PipelineCanvasProvider } from '@mesantosrai/pipeline-canvas';

function App() {
  const { user, token } = useContext(AuthContext);
  
  return (
    <PipelineCanvasProvider
      authState={{ user, isAuthenticated: !!user, accessToken: token }}
    >
      <PipelineCanvas />
    </PipelineCanvasProvider>
  );
}

Logging and Error Tracking

The library supports structured logging and error tracking through dependency injection. This allows you to integrate with your own logging systems (Sentry, LogRocket, Bugsnag, etc.) or use the default console logger.

Basic Usage (Default Logger)

By default, the library uses a console logger that only logs in development mode:

import { PipelineCanvasProvider } from '@mesantosrai/pipeline-canvas';

// No logger needed - uses default console logger (development only)
<PipelineCanvasProvider>
  <PipelineCanvas />
</PipelineCanvasProvider>

Custom Logger

Provide your own logger for structured logging:

import { 
  PipelineCanvasProvider,
  type Logger 
} from '@mesantosrai/pipeline-canvas';

const myLogger: Logger = {
  debug: (message, data) => {
    // Your debug logging logic
    console.debug(`[Pipeline] ${message}`, data);
  },
  info: (message, data) => {
    // Your info logging logic
    console.info(`[Pipeline] ${message}`, data);
  },
  warn: (message, data) => {
    // Your warning logging logic
    console.warn(`[Pipeline] ${message}`, data);
  },
  error: (message, error, data) => {
    // Your error logging logic
    console.error(`[Pipeline] ${message}`, error, data);
  },
};

<PipelineCanvasProvider logger={myLogger}>
  <PipelineCanvas />
</PipelineCanvasProvider>

Error Tracking (Sentry Example)

Integrate with error tracking services:

import * as Sentry from '@sentry/react';
import { 
  PipelineCanvasProvider,
  type ErrorReporter 
} from '@mesantosrai/pipeline-canvas';

const errorReporter: ErrorReporter = {
  captureException: (error, context) => {
    Sentry.captureException(error, {
      extra: context,
      tags: {
        component: 'pipeline-canvas',
      },
    });
  },
  captureMessage: (message, level, context) => {
    Sentry.captureMessage(message, {
      level: level === 'error' ? 'error' : level === 'warning' ? 'warning' : 'info',
      extra: context,
      tags: {
        component: 'pipeline-canvas',
      },
    });
  },
  setUser: (user) => {
    Sentry.setUser({
      id: user.id,
      email: user.email,
    });
  },
  setContext: (key, context) => {
    Sentry.setContext(key, context);
  },
};

<PipelineCanvasProvider errorReporter={errorReporter}>
  <PipelineCanvas />
</PipelineCanvasProvider>

LogRocket Example

import LogRocket from 'logrocket';
import { PipelineCanvasProvider, type ErrorReporter } from '@mesantosrai/pipeline-canvas';

const errorReporter: ErrorReporter = {
  captureException: (error, context) => {
    LogRocket.captureException(error, {
      extra: context,
    });
  },
  captureMessage: (message, level, context) => {
    LogRocket.captureMessage(message, {
      level,
      extra: context,
    });
  },
  setUser: (user) => {
    LogRocket.identify(user.id, {
      email: user.email,
    });
  },
};

<PipelineCanvasProvider errorReporter={errorReporter}>
  <PipelineCanvas />
</PipelineCanvasProvider>

Using Logger in Your Code

You can access the logger from context:

import { usePipelineContext } from '@mesantosrai/pipeline-canvas';

function MyComponent() {
  const { logger } = usePipelineContext();
  
  const handleAction = () => {
    logger?.info('Action performed', { action: 'click' });
  };
  
  return <button onClick={handleAction}>Click me</button>;
}

What Gets Logged

The library logs:

  • Pipeline execution events: Start, completion, errors
  • Node execution: Status changes, errors, results
  • API requests: Request/response details (if enabled)
  • User actions: Pipeline save, load, delete operations
  • Errors: All errors with full context (node ID, pipeline ID, error details)

Privacy and Security

  • No automatic data collection: Logging is opt-in via dependency injection
  • You control what gets logged: Provide your own logger/error reporter
  • No external calls: Default logger only uses console (no network requests)
  • Context-aware: All logs include relevant context (pipeline ID, node ID, etc.)

Theming

The library uses a scoped theming system with CSS variables prefixed with --pc- to avoid conflicts with your parent application's theme. This allows you to integrate the pipeline canvas into any app regardless of its existing styling.

Basic Setup

  1. Import the CSS file in your main entry:
// main.tsx or App.tsx
import '@mesantosrai/pipeline-canvas/style.css';
  1. Configure Tailwind to include the library's classes:
// tailwind.config.js
module.exports = {
  content: [
    './src/**/*.{js,jsx,ts,tsx}',
    './node_modules/@mesantosrai/pipeline-canvas/**/*.{js,jsx,ts,tsx}',
  ],
  theme: {
    extend: {},
  },
};

Using the Theme Wrapper

The PipelineThemeWrapper component provides theme isolation and supports light/dark modes:

import { 
  PipelineCanvas, 
  PipelineThemeWrapper,
  PipelineCanvasProvider 
} from '@mesantosrai/pipeline-canvas';

// Option 1: Follow system preference (default)
<PipelineThemeWrapper>
  <PipelineCanvasProvider {...deps}>
    <PipelineCanvas />
  </PipelineCanvasProvider>
</PipelineThemeWrapper>

// Option 2: Force a specific theme
<PipelineThemeWrapper theme="dark">
  <PipelineCanvasProvider {...deps}>
    <PipelineCanvas />
  </PipelineCanvasProvider>
</PipelineThemeWrapper>

// Option 3: Sync with your app's theme state
const [appTheme, setAppTheme] = useState<'light' | 'dark'>('dark');

<PipelineThemeWrapper externalTheme={appTheme}>
  <PipelineCanvasProvider {...deps}>
    <PipelineCanvas />
  </PipelineCanvasProvider>
</PipelineThemeWrapper>

Default White Theme (Standalone Usage)

For a default light/white theme when using the pipeline canvas in any app:

// Force light theme (default white)
<PipelineThemeWrapper theme="light">
  <PipelineCanvasProvider {...deps}>
    <PipelineCanvas />
  </PipelineCanvasProvider>
</PipelineThemeWrapper>

// Or rely on system preference (if system is light, it will be light)
<PipelineThemeWrapper theme="system">
  <PipelineCanvasProvider {...deps}>
    <PipelineCanvas />
  </PipelineCanvasProvider>
</PipelineThemeWrapper>

Note: The pipeline canvas uses CSS variables at :root (light) and html.dark (dark) for portalled components (dialogs, dropdowns, etc.). For default white in any app, the :root values apply automatically. If your app sets html.dark for dark mode, portalled pipeline UI will follow that.

Portalled Components and Dark Mode

Pipeline UI components that render in portals (dialogs, dropdowns, select menus) are rendered outside .pipeline-canvas-root and rely on CSS variables at :root (light) and html.dark (dark).

For dark mode in portalled components:

  • Option 1: Use externalTheme prop (recommended for apps with theme management):

    const { theme } = useYourAppTheme(); // Your app's theme hook
      
    <PipelineThemeWrapper externalTheme={theme}>
      <PipelineCanvas />
    </PipelineThemeWrapper>

    When your app sets html.dark for dark mode, portalled pipeline UI will automatically use dark theme variables.

  • Option 2: Set html.dark class manually when in dark mode:

    // In your app's theme provider
    useEffect(() => {
      if (isDark) {
        document.documentElement.classList.add('dark');
      } else {
        document.documentElement.classList.remove('dark');
      }
    }, [isDark]);

For default white in any app: The :root CSS variables provide light theme values by default. If the host app never sets html.dark, portalled pipeline UI will remain light (default white).

Theme Toggle Button

Include a theme toggle button using the PipelineThemeToggle component:

import { PipelineThemeToggle, PipelineThemeWrapper } from '@mesantosrai/pipeline-canvas';

<PipelineThemeWrapper>
  <div className="flex justify-end p-2">
    <PipelineThemeToggle />
  </div>
  <PipelineCanvasProvider {...deps}>
    <PipelineCanvas />
  </PipelineCanvasProvider>
</PipelineThemeWrapper>

Using the Theme Hook

Access the current theme programmatically:

import { usePipelineTheme, useIsDarkTheme } from '@mesantosrai/pipeline-canvas';

function MyComponent() {
  const { theme, resolvedTheme, setTheme, toggleTheme } = usePipelineTheme();
  const isDark = useIsDarkTheme();

  return (
    <div>
      <p>Current theme: {resolvedTheme}</p>
      <button onClick={toggleTheme}>Toggle Theme</button>
    </div>
  );
}

Customizing Theme Colors

Override the CSS variables in your own stylesheet to customize colors:

/* Your app's CSS file */
.pipeline-canvas-root {
  /* Light theme overrides */
  --pc-primary: 210 100% 50%;
  --pc-canvas-bg: 0 0% 98%;
}

.pipeline-canvas-root[data-theme="dark"] {
  /* Dark theme overrides */
  --pc-primary: 210 100% 60%;
  --pc-canvas-bg: 220 20% 10%;
}

Available CSS Variables

| Variable | Description | |----------|-------------| | --pc-background | Main background color | | --pc-foreground | Main text color | | --pc-card | Card/panel background | | --pc-primary | Primary accent color | | --pc-secondary | Secondary color | | --pc-muted | Muted/disabled color | | --pc-border | Border color | | --pc-canvas-bg | Canvas background | | --pc-toolbar-bg | Toolbar background | | --pc-sidebar-bg | Sidebar background | | --pc-panel-bg | Panel background | | --pc-text-primary | Primary text | | --pc-text-secondary | Secondary text | | --pc-text-muted | Muted text |

Theme Props Reference

| Prop | Type | Default | Description | |------|------|---------|-------------| | theme | 'light' \| 'dark' \| 'system' | 'system' | Theme preference | | externalTheme | 'light' \| 'dark' | - | External theme override from parent app | | onThemeChange | (theme: 'light' \| 'dark') => void | - | Callback when theme changes | | className | string | - | Additional CSS classes |

Development

# Type check
npm run type-check

# Build
npm run build

Creating New Node Types

When creating a new node type, please read the Node Development Guide first. It covers critical best practices and common pitfalls, including:

  • ✅ Always initialize nodes with default config
  • ✅ Keep execution logs accessible after completion
  • ✅ Don't force navigation during execution
  • ✅ Handle multiple data structures in output extraction
  • ✅ Common pitfalls and how to avoid them

This guide will save you time and prevent common issues!

Project Structure

pipeline-canvas/
├── components/          # React components
│   ├── PipelineCanvas.tsx
│   ├── PipelineNodeConfig.tsx
│   ├── PipelineNodePalette.tsx
│   ├── PipelineExecution.tsx
│   ├── PipelineManager.tsx
│   ├── CustomHandle.tsx
│   ├── ExecutionLogsPanel.tsx
│   ├── PipelineThemeWrapper.tsx  # Theme isolation wrapper
│   └── index.ts
├── context/             # React contexts
│   ├── PipelineContext.tsx
│   └── ThemeContext.tsx          # Theme state management
├── nodes/               # Node type configurations (JSON)
│   ├── input_node/
│   ├── rfdiffusion_node/
│   ├── proteinmpnn_node/
│   └── alphafold_node/
├── store/               # Zustand store
│   └── pipelineStore.ts
├── types/               # TypeScript types
│   └── index.ts
├── utils/               # Utility functions
│   ├── topologicalSort.ts
│   └── nodeLoader.ts
├── dist/                # Build output (generated)
├── index.ts             # Main export file
├── style.css            # CSS styles (scoped --pc- variables)
├── package.json
├── tsconfig.json
└── vite.config.ts

Backend Abstraction

The library supports backend abstraction through adapters, allowing you to integrate with any backend framework. See BACKEND_ABSTRACTION.md for:

  • Adapter pattern implementation
  • Custom adapter examples (FastAPI, Express, Firebase, Supabase)
  • Configuration-based customization
  • Migration guide

License

MIT