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

hypha-core

v0.20.85

Published

Hypha Core

Readme

Hypha Core

A lightweight, browser-based runtime for executing Hypha Apps and ImJoy Plugins with full workspace management, RPC communication, and service orchestration capabilities.

What is Hypha Core?

Hypha Core is a client-side JavaScript library that creates a complete Hypha server environment directly in the browser. It enables you to:

  • Run Hypha Apps and ImJoy Plugins without requiring a dedicated server
  • Manage workspaces with isolated execution environments
  • Handle RPC communication between services and plugins
  • Orchestrate services with automatic discovery and registration
  • Support multiple connection types including WebSocket and Redis-like connections
  • Manage authentication with token-based access control

Architecture Overview

Core Components

  1. HyphaCore Server: Main orchestrator that manages connections, workspaces, and message routing
  2. Workspace Manager: Handles service registration, discovery, and workspace isolation
  3. Connection Management: Supports multiple connection types (WebSocket, PostMessage, Redis RPC)
  4. Service Registry: Automatic registration and discovery of services across workspaces
  5. Authentication System: Token-based authentication with support for both anonymous and authenticated users

How It Works

┌─────────────────┐    ┌─────────────────┐    ┌─────────────────┐
│   Browser Tab   │    │   Hypha Core    │    │   Workspace     │
│                 │    │    Server       │    │   Manager       │
│  ┌───────────┐  │    │                 │    │                 │
│  │ Plugin A  │  │◄──►│  ┌───────────┐  │◄──►│  ┌───────────┐  │
│  └───────────┘  │    │  │Connection │  │    │  │Service    │  │
│  ┌───────────┐  │    │  │ Manager   │  │    │  │Registry   │  │
│  │ Plugin B  │  │◄──►│  └───────────┘  │    │  └───────────┘  │
│  └───────────┘  │    │                 │    │                 │
└─────────────────┘    └─────────────────┘    └─────────────────┘

✅ Quality Assurance & Testing

Hypha Core maintains exceptional quality through comprehensive testing:

🛡️ Enhanced Security Features Tested

  • JWT HS256 Authentication with signature verification and expiration handling
  • Cross-Workspace Access Control with token-based permission enforcement
  • Anonymous User Security with automatic workspace assignment and access restrictions
  • Service Registration Security - Only root users can register services in default/public workspaces
  • Workspace Isolation with proper service visibility and permission management
  • Multi-Client Authentication Workflows demonstrating provider/consumer/restricted user patterns

🚀 Advanced Integration Features

  • Custom Web Worker Script Loading - Direct loading of worker scripts via HTTP, blob, and file URLs
  • Full Hypha RPC Integration - Custom workers with complete service registration and communication
  • Performance Optimized Workers - CPU-intensive computations in dedicated worker threads
  • Multiple URL Support - HTTP/HTTPS, blob URLs, and local file loading for maximum flexibility

🌐 Cross-Browser Compatibility Verified

  • Chromium ✅ - All 117 tests passing
  • Firefox ✅ - All 117 tests passing
  • WebKit ✅ - All 117 tests passing

Performance Verified

  • Unit tests complete in ~200ms
  • Full integration test suite in ~35 seconds 🔄
  • Real browser testing with actual WebSocket connections
  • JWT token generation and verification tested in all browsers

🔒 Security Tests Mirror Deno Example

The integration tests now include comprehensive permission and security validation similar to the TypeScript Deno example:

  • JWT Token Generation with proper access control
  • Workspace Access Control for cross-workspace token generation
  • Service Registration Security ensuring only authorized users can register in protected workspaces
  • Multi-Client Authentication Workflows with proper token validation
  • Error Handling for unauthorized access attempts
  • Service Listing with workspace isolation verification

🛠 Development Quality

  • ES6 module compatibility verified
  • Modern JavaScript features tested
  • Error handling and resilience validated
  • UI responsiveness across screen sizes
  • Network interruption recovery tested

Installation & Basic Usage

CDN Import (Recommended)

<!DOCTYPE html>
<html>
<head>
    <title>My Hypha App</title>
</head>
<body>
    <script type="module">
        import { HyphaCore } from "https://cdn.jsdelivr.net/npm/[email protected]/dist/hypha-core.mjs";
        
        // Create and start Hypha Core
        const hyphaCore = new HyphaCore();
        
        // Expose globally for external access (important!)
        window.hyphaCore = hyphaCore;
        
        // Start and wait for API to be ready
        const api = await hyphaCore.start();
        
        console.log("Hypha Core started successfully!");
        console.log("API available:", api);
    </script>
</body>
</html>

NPM Installation

npm install hypha-core
import { HyphaCore } from 'hypha-core';

const hyphaCore = new HyphaCore();
window.hyphaCore = hyphaCore; // Expose globally if needed

const api = await hyphaCore.start();

🌐 Deno/Node.js Compatibility

HyphaCore now supports server environments (Deno and Node.js) with automatic environment detection and graceful feature degradation.

📚 TypeScript Support 🎯

HyphaCore provides comprehensive TypeScript definitions with full type safety:

  • Complete Type Definitions: index.d.ts with all HyphaCore APIs typed
  • Deno/Node.js/Browser Support: Environment-aware type definitions
  • JWT Authentication Types: JWTPayload, TokenConfig, UserInfo
  • Service Management Types: ServiceConfig, ServiceQuery, ServiceOptions
  • API Types: HyphaAPI, HyphaCoreConfig, workspace management
  • ES Module Compatible: Works seamlessly with modern TypeScript projects

TypeScript Usage Example

import { HyphaCore, type HyphaCoreConfig, type TokenConfig } from 'hypha-core';

const config: HyphaCoreConfig = {
    port: 9527,
    jwtSecret: 'your-secure-secret',
    baseUrl: 'http://localhost:9527/'
};

const hyphaCore = new HyphaCore(config);
const api = await hyphaCore.start();

// Type-safe token generation
const tokenConfig: TokenConfig = {
    user_id: 'typescript-user',
    workspace: 'typed-workspace',
    expires_in: 3600
};

const token: string = await api.generateToken(tokenConfig);

See examples/deno-example.ts for a complete TypeScript implementation demonstrating all features.

Deno WebSocket Server Implementation 🦕

HyphaCore now supports real WebSocket connections in Deno through the DenoWebSocketServer wrapper, enabling production-grade server deployments with full compatibility with hypha-rpc clients.

Key Features

  • Real WebSocket Connections: Native Deno HTTP server with WebSocket upgrade
  • Full hypha-rpc Compatibility: Python and JavaScript clients can connect seamlessly
  • Production Ready: Proper error handling, graceful shutdown, and health endpoints
  • Built-in Services: Default services like echo, hello, and get_time work out of the box
  • Service Registration: Register services as :built-in for system-level access
  • Authentication Flow: Complete JWT-based authentication with reconnection tokens

Quick Start

# Clone the repository
git clone https://github.com/amun-ai/hypha-core
cd hypha-core

# Run the Deno server example
deno run --allow-net --allow-env examples/deno-server-example.js

Server Implementation

#!/usr/bin/env -S deno run --allow-net --allow-env
import { HyphaCore } from '../src/hypha-core.js';
import { DenoWebSocketServer, DenoWebSocketClient } from '../src/deno-websocket-server.js';

const hyphaCore = new HyphaCore({
    url: "http://localhost:9527",
    ServerClass: DenoWebSocketServer,      // Use real WebSocket server
    WebSocketClass: DenoWebSocketClient,   // Use real WebSocket client
    jwtSecret: "deno-hypha-secret-key",
    defaultService: {
        // Services with context for authentication and workspace info
        hello: (name, context) => {
            name = name || "World";
            const greeting = `Hello, ${name}! Greetings from Deno Hypha Server 🦕`;
            console.log(`Hello service called: ${greeting}`, context ? `from ${context.from}` : '');
            return greeting;
        },
        
        get_time: (context) => {
            const now = new Date().toISOString();
            console.log(`Time service called: ${now}`, context ? `from ${context.from}` : '');
            return now;
        }
    }
});

// Start the server with proper connection handling
const api = await hyphaCore.start();
console.log(`🚀 Hypha Core server started at ${hyphaCore.url}`);
console.log(`🔌 WebSocket URL: ${hyphaCore.wsUrl}`);

Client Connection Examples

Python Client (hypha-rpc)

from hypha_rpc import connect_to_server

# Connect to the Deno server
server = await connect_to_server("ws://localhost:9527/ws")

# Use built-in services
result = await server.hello("Python Client")
print(result)  # "Hello, Python Client! Greetings from Deno Hypha Server 🦕"

time = await server.get_time()
print(f"Server time: {time}")

# Get server info
info = await server.get_server_info()
print(f"Running on: {info['platform']} {info['version']}")

JavaScript Client

import { hyphaWebsocketClient } from 'hypha-rpc';

const server = await hyphaWebsocketClient.connectToServer({
    server_url: "ws://localhost:9527/ws"
});

const greeting = await server.hello("JavaScript Client");
console.log(greeting);

const serverInfo = await server.get_server_info();
console.log("Server info:", serverInfo);

DenoWebSocketServer Features

Real WebSocket Upgrade

  • Uses Deno's native HTTP server with WebSocket upgrade
  • Proper Upgrade: websocket header handling
  • Binary and text message support with automatic ArrayBuffer conversion

Health Monitoring

# Check server health
curl http://localhost:9527/health
# Returns: OK

Graceful Shutdown

// Handles SIGINT and SIGTERM for clean shutdown
Deno.addSignalListener("SIGINT", () => {
    console.log('🛑 Shutting down server...');
    hyphaCore.close();
    Deno.exit(0);
});

Client Connection Management

  • Automatic client tracking and cleanup
  • Proper error handling for connection failures
  • Support for multiple concurrent connections

Service Registration Security

The Deno server properly handles service registration with workspace security:

// Built-in services are registered with :built-in suffix
// This bypasses workspace security for system services
await hyphaCore.workspaceManager.setup({
    client_id: hyphaCore.workspaceManagerId,
    defaultService: {
        // These become accessible as server.hello(), server.get_time(), etc.
        hello: (name, context) => `Hello, ${name || "World"}!`,
        get_time: (context) => new Date().toISOString(),
        get_server_info: (context) => ({
            platform: "Deno",
            version: Deno.version.deno,
            server: "hypha-core-deno"
        })
    }
});

Production Deployment

Docker Container

FROM denoland/deno:1.40.0

WORKDIR /app
COPY . .

EXPOSE 9527

CMD ["run", "--allow-net", "--allow-env", "examples/deno-server-example.js"]

Performance & Compatibility

Tested Compatibility

  • Python hypha-rpc clients - Full compatibility
  • JavaScript hypha-rpc clients - Complete feature support
  • Browser WebSocket clients - Direct WebSocket connections
  • Node.js clients - Cross-platform compatibility

Performance Characteristics

  • Concurrent Connections: Supports multiple simultaneous clients
  • Message Throughput: High-performance binary and text message handling
  • Memory Efficiency: Automatic cleanup of disconnected clients
  • Error Recovery: Robust error handling without server crashes

Complete Example Files

This implementation provides a complete bridge between Deno's native capabilities and the hypha-core ecosystem, enabling deployment of production-grade WebSocket servers with full compatibility with existing hypha-rpc clients.

Deno/Node.js Compatibility 🦕

HyphaCore provides cross-platform compatibility for server environments with environment-aware feature degradation:

Supported Features in Server Environments

  • JWT Authentication: Full HS256 token generation and verification
  • Service Registration: Register and discover services across workspaces
  • RPC Communication: Real-time service-to-service communication
  • Workspace Management: Multi-tenant workspace isolation
  • Multi-Client Connections: Support multiple concurrent clients
  • Anonymous User Security: Automatic workspace assignment with access control
  • PostMessage (Deno only): Web API compatibility for message passing
  • Event Listeners (Deno only): Web API compatibility for event handling

Browser-Only Features

Features that require DOM/Window APIs throw clear errors in server environments:

  • Window/iframe creation: Environment.requireBrowser() throws error
  • WebWorker integration: Browser-specific worker management
  • DOM manipulation: Document/element operations
  • PostMessage (Node.js only): Not available without polyfills

🦕 Deno Usage

import { HyphaCore } from "https://cdn.jsdelivr.net/npm/[email protected]/dist/hypha-core.mjs";

const hyphaCore = new HyphaCore({
    port: 9527,
    jwtSecret: 'your-secure-secret-key',
    baseUrl: 'http://localhost:9527/',  // Explicit base URL for server
});

// Start server
const api = await hyphaCore.start();
console.log('🚀 HyphaCore server running on Deno!');

// Generate JWT tokens
const token = await api.generateToken({
    user_id: 'deno-user',
    workspace: 'compute-workspace',
    expires_in: 3600
});

// Register computational services
await api.registerService({
    id: 'math-service',
    name: 'Math Service',
    config: { require_context: true, visibility: 'public' },
    
    fibonacci: (n, context) => {
        console.log(`Computing fibonacci(${n}) from ${context.from}`);
        if (n <= 1) return n;
        let a = 0, b = 1;
        for (let i = 2; i <= n; i++) [a, b] = [b, a + b];
        return b;
    }
});

🟢 Node.js Usage

import { HyphaCore } from 'hypha-core';

const hyphaCore = new HyphaCore({
    port: 9527,
    jwtSecret: process.env.HYPHA_JWT_SECRET,
    baseUrl: 'http://localhost:9527/',
});

// Environment detection
console.log(`Running in: ${hyphaCore.environment}`); // 'node'

const api = await hyphaCore.start();
console.log('🚀 HyphaCore server running on Node.js!');

// Connect clients with JWT authentication
const clientApi = await hyphaCore.connect({
    token: await api.generateToken({ user_id: 'node-client' }),
    workspace: 'data-processing'
});

🛡️ Environment-Safe Code Examples

The library automatically detects the environment and provides helpful error messages:

import { HyphaCore } from 'hypha-core';

const hyphaCore = new HyphaCore();
const api = await hyphaCore.start();

try {
    // This will work in all environments
    await api.registerService({
        id: 'data-processor',
        process: (data) => data.map(x => x * 2)
    });
    
    // This will throw clear error in server environments
    await api.createWindow({ src: 'https://example.com' });
} catch (error) {
    if (error.message.includes('requires browser environment')) {
        console.log('🔍 Browser-only feature attempted in server environment');
        console.log('💡 Use only core HyphaCore features in Deno/Node.js');
    }
}

📚 Complete Server Example

See examples/deno-example.js for a full working example demonstrating:

  • 🔐 JWT authentication with secure token generation
  • ⚡ Service registration and cross-service communication
  • 🏗️ Workspace management and client connections
  • 🧮 Computational services (prime number checking, fibonacci)
  • 📊 Environment detection and feature availability

Configuration Options

Constructor Options

const hyphaCore = new HyphaCore({
    port: 8080,                    // Server port (default: 8080)
    baseUrl: "https://myapp.com/", // Base URL for serving template files (must end with /)
    url: "wss://myserver.com/ws",  // Direct WebSocket URL (alternative to port)
    defaultService: {             // Default services to register
        myService: async () => { /* implementation */ }
    }
});

Important Notes:

  • baseUrl must end with a forward slash (/)
  • Cannot specify both url and port - choose one
  • If using url, it must end with /ws

Start Options

const api = await hyphaCore.start({
    workspace: "my-workspace",     // Workspace identifier (default: "default")
    client_id: "my-client",        // Client identifier (default: auto-generated)
    server: hyphaCore             // Reference to the server instance
});

🚀 Cluster Setup & Horizontal Scaling

Hypha Core supports clustered deployments for horizontal scalability, high availability, and production workloads. The cluster mode enables multiple server instances to work together, sharing workspaces and services through Redis coordination.

Quick Start

Option 1: Mock Redis Cluster (Development)

Perfect for development and testing without external dependencies:

# Clone the repository
git clone https://github.com/amun-ai/hypha-core
cd hypha-core/cluster-examples

# Start mock Redis cluster (3 servers: 8080, 8081, 8082)
deno run --allow-all cluster-example.js

Features:

  • ✅ 3 server instances with simulated clustering behavior
  • ✅ No external Redis required - uses built-in mock
  • ✅ Local development friendly
  • ✅ Perfect for testing load balancing logic

Option 2: Real Redis Cluster (Production)

Production-ready clustering with real Redis coordination:

# 1. Start Redis container
docker run -d --name hypha-redis -p 6379:6379 redis:7-alpine

# 2. Start real Redis cluster
deno run --allow-all cluster-example.js --real-redis

Features:

  • ✅ Real Redis pub/sub messaging for true distributed coordination
  • ✅ Horizontal scalability across multiple machines
  • ✅ Production performance and reliability
  • ✅ Fault tolerance and automatic failover

Option 3: Docker Deployment (Recommended for Production)

Full containerized deployment with load balancer:

# Clone and navigate to cluster examples
git clone https://github.com/amun-ai/hypha-core
cd hypha-core/cluster-examples

# Start full containerized cluster
docker compose up -d

# Check cluster status
docker compose ps

# View logs
docker compose logs -f

# Stop cluster
docker compose down

Components:

  • ✅ Redis server for coordination
  • ✅ 3 clustered Hypha-Core servers (auto-scaling ready)
  • ✅ Nginx load balancer with health checks
  • ✅ Health monitoring and automatic recovery

Architecture Overview

┌─────────────────┐    ┌─────────────────┐    ┌─────────────────┐
│ Load Balancer   │    │   Server 1      │    │   Server 2      │
│ (Nginx:80)      │    │   (Port 8080)   │    │   (Port 8081)   │
│                 │    │                 │    │                 │
│  Health Checks  │◄──►│  Hypha Core     │◄──►│  Hypha Core     │
│  Round Robin    │    │  WebSocket      │    │  WebSocket      │
│  Failover       │    │  HTTP API       │    │  HTTP API       │
└─────────────────┘    └─────────────────┘    └─────────────────┘
         │                       │                       │
         │                       ▼                       ▼
         │              ┌─────────────────┐    ┌─────────────────┐
         │              │   Server 3      │    │     Redis       │
         │              │   (Port 8082)   │    │   (Port 6379)   │
         │              │                 │    │                 │
         └─────────────►│  Hypha Core     │◄──►│  Pub/Sub        │
                        │  WebSocket      │    │  Coordination   │
                        │  HTTP API       │    │  Shared State   │
                        └─────────────────┘    └─────────────────┘

Testing Your Cluster

Load Balancing Test

# Test cluster load distribution
cd hypha-core/cluster-examples
deno run --allow-all test-full-cluster.js

Performance Benchmarks

# Run comprehensive performance tests
deno run --allow-all performance-test.js

Sample results (3-server cluster):

  • Throughput: 8,000-11,000 req/s per server
  • Latency: <1ms average response time
  • Memory: ~60MB per server instance
  • Coordination overhead: <5ms for Redis operations

Configuration

Server Ports (Default)

  • Server 1: 8080 - Primary instance
  • Server 2: 8081 - Secondary instance
  • Server 3: 8082 - Tertiary instance
  • Redis: 6379 - Coordination layer
  • Load Balancer: 80 - Entry point (Docker only)

Environment Variables

# Redis connection
REDIS_URL=redis://localhost:6379

# Server identification
SERVER_ID=server-1

# Cluster mode
CLUSTER_MODE=real  # or 'mock' for development

Custom Configuration

// cluster-config.js
export const clusterConfig = {
    redis: {
        url: process.env.REDIS_URL || 'redis://localhost:6379',
        channel: 'hypha-cluster',
        connectionTimeout: 5000
    },
    servers: [
        { id: 'server-1', port: 8080, weight: 1 },
        { id: 'server-2', port: 8081, weight: 1 },
        { id: 'server-3', port: 8082, weight: 1 }
    ],
    loadBalancer: {
        strategy: 'round-robin', // 'round-robin', 'least-connections', 'weighted'
        healthCheck: {
            interval: 10000,
            timeout: 3000,
            retries: 3
        }
    }
};

API Endpoints

All cluster servers expose the same API endpoints:

Health Check

# Check individual server health
curl http://localhost:8080/health
curl http://localhost:8081/health  
curl http://localhost:8082/health

# Through load balancer (Docker)
curl http://localhost/health

Services API

# List services in workspace (returns array of service objects)
curl http://localhost:8080/default/services
# Returns: [{"id": "service1", "name": "My Service", ...}, ...]

# Get specific service info
curl http://localhost:8080/default/services/my-service
# Returns: {"id": "my-service", "name": "My Service", "config": {...}}

# Register service (distributed automatically)
curl -X POST http://localhost:8080/default/services \
  -H "Content-Type: application/json" \
  -d '{"name": "my-service", "config": {...}}'

# Call service function via HTTP
curl http://localhost:8080/default/services/my-service/my-function \
  -H "Content-Type: application/json" \
  -d '{"param1": "value1"}'

Important: The /default/services endpoint returns a list of services in the workspace, not the workspace API object itself.

WebSocket Connections

// Connect to any server in the cluster
const ws1 = new WebSocket('ws://localhost:8080/ws');
const ws2 = new WebSocket('ws://localhost:8081/ws');
const ws3 = new WebSocket('ws://localhost:8082/ws');

// Or through load balancer
const ws = new WebSocket('ws://localhost/ws');

Production Deployment

Docker Compose (Recommended)

# docker-compose.yml
version: '3.8'
services:
  redis:
    image: redis:7-alpine
    ports:
      - "6379:6379"
    command: redis-server --appendonly yes
    volumes:
      - redis-data:/data

  hypha-server-1:
    build: .
    environment:
      - SERVER_ID=server-1
      - REDIS_URL=redis://redis:6379
    depends_on:
      - redis
    ports:
      - "8080:8080"

  hypha-server-2:
    build: .
    environment:
      - SERVER_ID=server-2
      - REDIS_URL=redis://redis:6379
    depends_on:
      - redis
    ports:
      - "8081:8080"

  hypha-server-3:
    build: .
    environment:
      - SERVER_ID=server-3
      - REDIS_URL=redis://redis:6379
    depends_on:
      - redis
    ports:
      - "8082:8080"

  nginx:
    image: nginx:alpine
    ports:
      - "80:80"
    volumes:
      - ./nginx.conf:/etc/nginx/nginx.conf
    depends_on:
      - hypha-server-1
      - hypha-server-2
      - hypha-server-3

volumes:
  redis-data:

Kubernetes Deployment

# k8s-cluster.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
  name: hypha-cluster
spec:
  replicas: 3
  selector:
    matchLabels:
      app: hypha-core
  template:
    metadata:
      labels:
        app: hypha-core
    spec:
      containers:
      - name: hypha-core
        image: hypha-core:latest
        ports:
        - containerPort: 8080
        env:
        - name: REDIS_URL
          value: "redis://redis-service:6379"
        - name: CLUSTER_MODE
          value: "real"
---
apiVersion: v1
kind: Service
metadata:
  name: hypha-service
spec:
  selector:
    app: hypha-core
  ports:
  - port: 80
    targetPort: 8080
  type: LoadBalancer

Troubleshooting

Common Issues

  1. Port Conflicts

    # Stop existing containers
    docker stop hypha-redis
    docker compose down
       
    # Check port usage
    lsof -i :8080
  2. Redis Connection Issues

    # Test Redis connectivity
    redis-cli -h localhost -p 6379 ping
       
    # Check Redis logs
    docker logs hypha-redis
  3. Load Balancer Issues

    # Check Nginx configuration
    docker exec nginx-container nginx -t
       
    # Reload configuration
    docker exec nginx-container nginx -s reload

Debug Mode

Enable comprehensive logging:

# Debug cluster coordination
RUST_LOG=debug deno run --allow-all cluster-example.js --real-redis

# Debug specific components
DEBUG=hypha:cluster,hypha:redis deno run --allow-all cluster-example.js

Monitoring

# Real-time cluster status
watch 'curl -s http://localhost:8080/health && curl -s http://localhost:8081/health'

# Redis monitoring
redis-cli monitor

# Docker cluster monitoring
docker stats

Performance Optimization

Scaling Guidelines

  • Small workload: 1-2 servers sufficient
  • Medium workload: 3-5 servers recommended
  • Large workload: 5+ servers with dedicated Redis
  • High availability: Minimum 3 servers across availability zones

Redis Optimization

# redis.conf optimizations for cluster
maxmemory 2gb
maxmemory-policy allkeys-lru
tcp-keepalive 60
timeout 0

Load Balancer Tuning

# nginx.conf optimizations
upstream hypha_cluster {
    least_conn;
    server hypha-server-1:8080 weight=1 max_fails=3 fail_timeout=30s;
    server hypha-server-2:8080 weight=1 max_fails=3 fail_timeout=30s;
    server hypha-server-3:8080 weight=1 max_fails=3 fail_timeout=30s;
}

location / {
    proxy_pass http://hypha_cluster;
    proxy_set_header X-Real-IP $remote_addr;
    proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
    
    # WebSocket support
    proxy_http_version 1.1;
    proxy_set_header Upgrade $http_upgrade;
    proxy_set_header Connection "upgrade";
}

For complete examples and configuration files, see the cluster-examples/ directory.

Advanced Usage Examples

1. Complete Application with Window Management

<!DOCTYPE html>
<html>
<head>
    <title>Hypha Lite Application</title>
<script src="https://rawcdn.githack.com/nextapps-de/winbox/0.2.82/dist/winbox.bundle.min.js"></script>
    <style>
        .icon-container {
            position: fixed;
            top: 10px;
            right: 10px;
            z-index: 1000;
        }
        .icon {
            width: 40px;
            height: 40px;
            cursor: pointer;
        }
        .dropdown {
            display: none;
            position: absolute;
            top: 50px;
            width: 120px;
            right: 0;
            background-color: white;
            box-shadow: 0 2px 5px rgba(0, 0, 0, 0.2);
            z-index: 1001;
            font-family: Arial, sans-serif;
        }
        .dropdown a {
            display: block;
            padding: 10px;
            text-decoration: none;
            color: black;
        }
        .dropdown a:hover {
            background-color: #f0f0f0;
        }
    </style>
</head>
<body>
    <div class="icon-container">
        <img
            alt="Hypha Logo"
            src="https://raw.githubusercontent.com/amun-ai/hypha/main/docs/img/hypha-icon-black.svg"
            class="icon"
            onclick="toggleDropdown()"
        />
        <div class="dropdown" id="dropdownMenu">
            <a href="#" onclick="promptLoadApp()">+ Load Plugin</a>
            <a href="#" onclick="loadApp('https://if.imjoy.io')">ImJoy Fiddle</a>
        </div>
    </div>
    
<script type="module">
        import { HyphaCore } from "https://cdn.jsdelivr.net/npm/[email protected]/dist/hypha-core.mjs";
        
    const hyphaCore = new HyphaCore();
        
        // Expose hyphaCore globally for tests and external access
        window.hyphaCore = hyphaCore;
        
        // Handle window creation for plugins
    hyphaCore.on("add_window", (config) => {
        const wb = new WinBox(config.name || config.src.slice(0, 128), {
            background: "#448aff",
        });
        wb.body.innerHTML = `<iframe src="${config.src}" id="${config.window_id}" style="width: 100%; height: 100%; border: none;"></iframe>`;
    });
        
        // Start Hypha Core and wait for API
        await hyphaCore.start();
        const api = hyphaCore.api;
        
        // Function to handle loading and running a plugin
        async function loadAppFromUrl(url) {
            try {
                const plugin = await api.loadApp({ src: url });
                await plugin.run({ config: {}, data: {} });
                console.log("Loaded and ran plugin from URL:", url);
            } catch (error) {
                console.error("Failed to load plugin:", error);
            }
        }
        
        // Expose functions globally
        window.loadApp = loadAppFromUrl;
        
        // Handle URL parameters for auto-loading plugins
        const urlParams = new URLSearchParams(window.location.search);
        const pluginUrls = urlParams.getAll("plugin");
        for (const url of pluginUrls) {
            await window.loadApp(url);
        }
        
        // UI Functions
        window.toggleDropdown = function () {
            const dropdown = document.getElementById("dropdownMenu");
            dropdown.style.display =
                dropdown.style.display === "block" ? "none" : "block";
        };

        window.promptLoadApp = async function () {
            const url = prompt("Enter the plugin URL:");
            if (url) {
                await loadAppFromUrl(url);
            }
        };
        
        // Close dropdown when clicking outside
        window.onclick = function (event) {
            if (!event.target.matches(".icon")) {
                const dropdown = document.getElementById("dropdownMenu");
                if (dropdown.style.display === "block") {
                    dropdown.style.display = "none";
                }
            }
        };
        
        // Initialize dropdown display style
        const dropdown = document.getElementById("dropdownMenu");
        if (dropdown) {
            dropdown.style.display = "none";
        }
</script>
</body>
</html>

2. Multiple Workspace Management

Hypha Core supports multiple isolated workspaces for security and organization. Each workspace operates independently with its own service registry and access controls.

// Create and start the core server
const hyphaCore = new HyphaCore();
await hyphaCore.start();

// Connect to different workspaces
const workspace1 = await hyphaCore.connect({
    workspace: "analysis-workspace",
    client_id: "analysis-client"
});

const workspace2 = await hyphaCore.connect({
    workspace: "visualization-workspace", 
    client_id: "viz-client"
});

// Each workspace operates independently
await workspace1.registerService({
    name: "data-processor",
    config: {
        require_context: true,
        visibility: "public",
    },
    process: async (data, context) => {
        // context.ws === "analysis-workspace"
        console.log(`Processing data in workspace: ${context.ws}`);
        return data.map(x => x * 2);
    }
});

await workspace2.registerService({
    name: "chart-renderer",
    config: {
        require_context: true,
        visibility: "public",
    },
    render: async (data, context) => {
        // context.ws === "visualization-workspace"
        console.log(`Rendering chart in workspace: ${context.ws}`);
        return { chart: "rendered", workspace: context.ws };
    }
});

3. Python Integration - Creating Interactive Windows

Hypha Core enables seamless integration between Python (via Pyodide or server-side Python with hypha-rpc) and browser-based JavaScript applications. This example shows how to create an interactive todo list application where Python code controls a JavaScript UI running in a browser window.

# Python code (can run in Pyodide or server-side with hypha-rpc)
import asyncio
from hypha_rpc import connect_to_server

# Connect to Hypha Core server
server = await connect_to_server({
    "server_url": "http://localhost:9527",
    "workspace": "default",
    "client_id": "python-controller"
})

# Define the HTML/JavaScript application as a string
src = '''
<!DOCTYPE html>
<html>
<head>
    <title>Todo List</title>
    <style>
        body {
            font-family: Arial, sans-serif;
            max-width: 600px;
            margin: 50px auto;
            padding: 20px;
        }
        h1 {
            color: #333;
        }
        #todo-list {
            list-style-type: none;
            padding: 0;
        }
        #todo-list li {
            padding: 10px;
            margin: 5px 0;
            background: #f4f4f4;
            border-radius: 4px;
        }
    </style>
    <script type="module">
        import * as hyphaWebsocketClient from 'https://cdn.jsdelivr.net/npm/[email protected]/dist/hypha-rpc-websocket.mjs';

        // Setup local client to communicate with Hypha Core
        const server = await hyphaWebsocketClient.setupLocalClient();

        // Export functions that Python can call
        await server.export({
            // Get all todos from the list
            getTodos: () => {
                const listItems = document.querySelectorAll('#todo-list li');
                return Array.from(listItems).map(li => li.textContent);
            },

            // Add a new todo to the list
            addTodo: (todoText) => {
                const list = document.getElementById('todo-list');
                const li = document.createElement('li');
                li.textContent = todoText;
                list.appendChild(li);
                return `Added: ${todoText}`;
            },

            // Clear all todos
            clearTodos: () => {
                const list = document.getElementById('todo-list');
                list.innerHTML = '';
                return 'Cleared all todos';
            }
        });

        console.log('Todo app ready - services exported');
    </script>
</head>
<body>
    <h1>📝 My Todo List</h1>
    <ul id="todo-list">
        <li>Learn Hypha RPC</li>
        <li>Build awesome apps</li>
    </ul>
</body>
</html>
'''

# Create a window with the HTML content
# This returns a service proxy that can call the exported JavaScript functions
todo_app = await server.create_window(src=src, name='My Todo List')

# Now we can control the JavaScript application from Python!
# Add new todos
result = await todo_app.addTodo('Buy groceries')
print(result)  # Output: Added: Buy groceries

result = await todo_app.addTodo('Call dentist')
print(result)  # Output: Added: Call dentist

# Get all todos
todos = await todo_app.getTodos()
print('Current todos:', todos)
# Output: Current todos: ['Learn Hypha RPC', 'Build awesome apps', 'Buy groceries', 'Call dentist']

# Clear the list
result = await todo_app.clearTodos()
print(result)  # Output: Cleared all todos

Key Features Demonstrated:

  1. Bidirectional RPC: Python can call JavaScript functions, and JavaScript can call Python functions
  2. HTML String Loading: The entire application is defined as a string and loaded directly
  3. Service Export: JavaScript exports an API that Python can invoke
  4. Type Safety: Return values are automatically serialized/deserialized
  5. Async/Await: Seamless async communication between Python and JavaScript

Use Cases:

  • Building data visualization dashboards controlled from Python
  • Creating interactive UI for Python data science workflows
  • Automating browser-based applications from Python scripts
  • Building Jupyter notebook-like experiences with custom UIs

Server-Side Python Example:

# Run this on a Python server that can reach your Hypha Core instance
from hypha_rpc import connect_to_server
import asyncio

async def main():
    # Connect to remote Hypha Core server
    server = await connect_to_server({
        "server_url": "https://your-hypha-server.com",
        "workspace": "my-workspace",
        "client_id": "python-backend",
        "token": "your-auth-token"  # If authentication is enabled
    })

    # Create window and interact with it
    app = await server.create_window(src=html_content, name='Data Dashboard')

    # Update dashboard with computed data
    data = compute_heavy_analysis()
    await app.updateChart(data)

    print("Dashboard updated successfully!")

asyncio.run(main())

Iframe and WebWorker Integration

Hypha Core supports loading and communicating with applications in iframes and web workers. This enables you to create distributed applications where different components run in isolated environments while still communicating through the Hypha RPC system.

Two Approaches for Integration

1. Hypha App Format (ImJoy Plugin Style)

You can create applications using the ImJoy plugin format with embedded configuration and code:

<docs lang="markdown">
# My Hypha App
This is a sample Hypha application that runs in an iframe.
</docs>

<config lang="json">
{
  "name": "My Hypha App",
  "type": "iframe",
  "version": "0.1.0",
  "description": "A sample application running in an iframe",
  "tags": [],
  "ui": "",
  "cover": "",
  "inputs": null,
  "outputs": null,
  "flags": [],
  "icon": "extension",
  "api_version": "0.1.7",
  "env": "",
  "permissions": [],
  "requirements": [],
  "dependencies": []
}
</config>

<script lang="javascript">
// This code runs in the iframe
api.export({
    name: "My App Service",
    
    async setup() {
        await api.log("App initialized in iframe");
    },
    
    async processData(data) {
        // Process data and return results
        return data.map(x => x * 2);
    },
    
    async showMessage(message) {
        alert(`Message from parent: ${message}`);
        return "Message displayed";
    }
});
</script>

Load and use the app:

// Load app from URL (e.g., GitHub raw URL)
const app = await api.loadApp({
    src: "https://raw.githubusercontent.com/myuser/myrepo/main/my-app.imjoy.html"
});

// Run and interact with the app
await app.run();
const result = await app.processData([1, 2, 3, 4]);
console.log(result); // [2, 4, 6, 8]

2. Standalone Web Application

You can also create standalone web applications using any framework (React, Vue, vanilla JavaScript, etc.) and connect them to Hypha Core using the WebSocket client.

Standalone App Example (my-standalone-app.html):

<!DOCTYPE html>
<html>
<head>
    <title>My Standalone App</title>
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <style>
        body {
            font-family: Arial, sans-serif;
            margin: 20px;
            background-color: #f5f5f5;
        }
        .container {
            max-width: 600px;
            margin: 0 auto;
            background: white;
            padding: 20px;
            border-radius: 8px;
            box-shadow: 0 2px 4px rgba(0,0,0,0.1);
        }
        button {
            background: #007bff;
            color: white;
            border: none;
            padding: 10px 20px;
            border-radius: 4px;
            cursor: pointer;
            margin: 5px;
        }
        button:hover {
            background: #0056b3;
        }
        .status {
            padding: 10px;
            margin: 10px 0;
            border-radius: 4px;
            background: #d4edda;
            border: 1px solid #c3e6cb;
            color: #155724;
        }
    </style>
    <script src="https://cdn.jsdelivr.net/npm/[email protected]/dist/hypha-rpc-websocket.min.js"></script>
</head>
<body>
    <div class="container">
        <h1>My Standalone Hypha App</h1>
        <div class="status" id="status">Initializing...</div>
        
        <button onclick="performCalculation()">Perform Calculation</button>
        <button onclick="sendNotification()">Send Notification</button>
        <button onclick="getSystemInfo()">Get System Info</button>
        
        <div id="output"></div>
    </div>

    <script>
        let api = null;
        
        // Connect to Hypha Core
        hyphaWebsocketClient.setupLocalClient({enable_execution: true}).then(async (hyphaApi) => {
            api = hyphaApi;
            console.log("Connected to Hypha Core", api);
            
            // Export services that the parent can call
            await api.export({
                name: "Standalone App Services",
                
                async processData(data) {
                    console.log("Processing data:", data);
                    const result = data.map(x => x * x); // Square the numbers
                    updateOutput(`Processed data: ${JSON.stringify(result)}`);
                    return result;
                },
                
                async updateUI(config) {
                    console.log("Updating UI:", config);
                    if (config.title) {
                        document.querySelector('h1').textContent = config.title;
                    }
                    if (config.message) {
                        updateOutput(`UI Update: ${config.message}`);
                    }
                    return "UI updated successfully";
                },
                
                async getAppState() {
                    return {
                        title: document.querySelector('h1').textContent,
                        timestamp: new Date().toISOString(),
                        status: "running"
                    };
                }
            });
            
            document.getElementById('status').textContent = 'Connected to Hypha Core ✓';
            
        }).catch(error => {
            console.error("Failed to connect to Hypha Core:", error);
            document.getElementById('status').textContent = `Connection failed: ${error.message}`;
            document.getElementById('status').style.background = '#f8d7da';
            document.getElementById('status').style.borderColor = '#f5c6cb';
            document.getElementById('status').style.color = '#721c24';
        });
        
        // Functions called by the UI
        async function performCalculation() {
            if (!api) return;
            
            try {
                // Call a service from the parent Hypha Core
                const numbers = [1, 2, 3, 4, 5];
                const result = await api.echo(`Calculation request: ${numbers.join(', ')}`);
                updateOutput(`Echo result: ${result}`);
            } catch (error) {
                updateOutput(`Error: ${error.message}`);
            }
        }
        
        async function sendNotification() {
            if (!api) return;
            
            try {
                await api.log("Notification sent from standalone app");
                updateOutput("Notification sent to parent");
            } catch (error) {
                updateOutput(`Error: ${error.message}`);
            }
        }
        
        async function getSystemInfo() {
            if (!api) return;
            
            try {
                // Try to get server info if available
                const info = {
                    userAgent: navigator.userAgent,
                    timestamp: new Date().toISOString(),
                    url: window.location.href
                };
                updateOutput(`System Info: ${JSON.stringify(info, null, 2)}`);
            } catch (error) {
                updateOutput(`Error: ${error.message}`);
            }
        }
        
        function updateOutput(message) {
            const output = document.getElementById('output');
            output.innerHTML += `<div style="margin: 10px 0; padding: 8px; background: #e9ecef; border-radius: 4px;">${message}</div>`;
            output.scrollTop = output.scrollHeight;
        }
    </script>
</body>
</html>

Using the Standalone App:

// Create a window with your standalone app
const appWindow = await api.createWindow({
    src: "/path/to/my-standalone-app.html",  // or full URL
    name: "My Standalone App",
    pos: "main"  // or "side"
});

// Wait a moment for the app to initialize
await new Promise(resolve => setTimeout(resolve, 1000));

// Interact with the app's exported services
const result = await appWindow.processData([1, 2, 3, 4, 5]);
console.log("App result:", result); // [1, 4, 9, 16, 25]

await appWindow.updateUI({
    title: "Updated App Title",
    message: "Hello from parent!"
});

const appState = await appWindow.getAppState();
console.log("App state:", appState);

WebWorker Support

Hypha Core supports two approaches for web worker integration:

1. Traditional ImJoy Plugin Format

Load workers using the ImJoy plugin format with embedded configuration:

// Load worker with ImJoy plugin format (.imjoy.html files)
const worker = await api.loadApp({
    src: "https://example.com/my-plugin.imjoy.html"
});

2. Custom Web Worker Scripts (New!)

🚀 Direct Custom Worker Script Loading

You can now load custom web worker scripts directly using any URL (HTTP, HTTPS, blob, or file URLs):

// Load custom worker script directly
const customWorker = await api.loadApp({
    type: 'web-worker',                    // Specify worker type
    src: 'https://example.com/my-custom-worker.js',  // Direct script URL
    name: 'My Custom Worker',
    description: 'Custom computational worker'
});

// Works with different URL types:
// HTTP/HTTPS URLs
const httpWorker = await api.loadApp({
    type: 'web-worker',
    src: 'https://cdn.example.com/workers/math-worker.js'
});

// Blob URLs (for dynamically generated scripts)
const blob = new Blob([workerCode], { type: 'application/javascript' });
const blobUrl = URL.createObjectURL(blob);
const blobWorker = await api.loadApp({
    type: 'web-worker', 
    src: blobUrl
});

// Local file URLs
const fileWorker = await api.loadApp({
    type: 'web-worker',
    src: '/static/workers/data-processor.js'
});

Custom Worker Script Structure

Complete Custom Worker Example (computational-worker.js):

// Import Hypha RPC client in the worker
importScripts('https://cdn.jsdelivr.net/npm/[email protected]/dist/hypha-rpc-websocket.min.js');

console.log('🔧 Custom Computational Worker: Starting...');

// Connect to Hypha Core from the worker
hyphaWebsocketClient.setupLocalClient({
    enable_execution: true,
    workspace: "worker-workspace",
    client_id: "computational-worker-001"
}).then(async (api) => {
    console.log('✅ Worker connected to Hypha Core');
    
    // Export comprehensive worker services
    const exportedServices = await api.export({
        id: 'computational-services',
        name: 'Computational Services',
        description: 'CPU-intensive computations optimized for WebWorker environment',
        
        // Mathematical computations
        fibonacci: function(n) {
            console.log(`🔢 Worker: Computing fibonacci(${n})`);
            if (n <= 1) return n;
            let a = 0, b = 1;
            for (let i = 2; i <= n; i++) {
                [a, b] = [b, a + b];
            }
            return b;
        },
        
        factorial: function(n) {
            console.log(`🔢 Worker: Computing factorial(${n})`);
            if (n <= 1) return 1;
            let result = 1;
            for (let i = 2; i <= n; i++) {
                result *= i;
            }
            return result;
        },
        
        // Prime number operations
        isPrime: function(n) {
            if (n <= 1) return false;
            if (n <= 3) return true;
            if (n % 2 === 0 || n % 3 === 0) return false;
            for (let i = 5; i * i <= n; i += 6) {
                if (n % i === 0 || n % (i + 2) === 0) return false;
            }
            return true;
        },
        
        // Array processing operations
        processArray: function(arr, operation) {
            const operations = {
                sum: () => arr.reduce((a, b) => a + b, 0),
                product: () => arr.reduce((a, b) => a * b, 1),
                average: () => arr.reduce((a, b) => a + b, 0) / arr.length,
                max: () => Math.max(...arr),
                min: () => Math.min(...arr),
                sort: () => [...arr].sort((a, b) => a - b),
                reverse: () => [...arr].reverse()
            };
            
            if (!operations[operation]) {
                throw new Error(`Unknown operation: ${operation}`);
            }
            
            return operations[operation]();
        },
        
        // Heavy computation simulation
        heavyComputation: function(iterations = 1000000) {
            console.log(`⚡ Worker: Running heavy computation with ${iterations} iterations`);
            const startTime = Date.now();
            let result = 0;
            
            for (let i = 0; i < iterations; i++) {
                result += Math.sin(i) * Math.cos(i) * Math.tan(i / 1000);
            }
            
            const endTime = Date.now();
            const duration = endTime - startTime;
            
            return {
                result: result,
                iterations: iterations,
                duration: duration,
                performance: `${iterations / duration} ops/ms`
            };
        },
        
        // Worker info and capabilities
        getWorkerInfo: function() {
            return {
                type: 'webworker',
                environment: 'dedicated-worker',
                timestamp: new Date().toISOString(),
                capabilities: [
                    'fibonacci', 'factorial', 'isPrime', 
                    'processArray', 'heavyComputation'
                ],
                userAgent: navigator.userAgent,
                hardwareConcurrency: navigator.hardwareConcurrency
            };
        }
    });
    
    console.log('✅ Custom Worker: All services registered successfully');
    
    // Notify main thread that worker is ready
    self.postMessage({ 
        type: 'worker_ready', 
        message: 'Custom worker services registered successfully',
        services: Object.keys(exportedServices).filter(key => typeof exportedServices[key] === 'function')
    });
    
}).catch(error => {
    console.error('❌ Custom Worker: Failed to setup Hypha client:', error);
    self.postMessage({ 
        type: 'worker_error', 
        error: error.message 
    });
});

// Handle messages from main thread
self.onmessage = function(event) {
    const { type, data } = event.data;
    
    switch (type) {
        case 'ping':
            self.postMessage({ 
                type: 'pong', 
                message: 'Custom worker is operational',
                timestamp: new Date().toISOString()
            });
            break;
            
        case 'shutdown':
            console.log('🛑 Custom Worker: Shutdown requested');
            self.postMessage({ type: 'shutdown_acknowledged' });
            self.close();
            break;
            
        default:
            console.warn('⚠️ Custom Worker: Unknown message type:', type);
    }
};

// Error handling
self.onerror = function(error) {
    console.error('💥 Custom Worker: Unhandled error:', error);
    self.postMessage({ 
        type: 'worker_error', 
        error: error.message 
    });
};

console.log('🚀 Custom Worker: Initialization complete');

Loading and Using Custom Workers

// Load the custom computational worker
const computeWorker = await api.loadApp({
    type: 'web-worker',
    src: '/workers/computational-worker.js',
    name: 'Computational Worker',
    description: 'High-performance mathematical computations'
});

console.log('Worker loaded:', computeWorker.id);

// Use computational services
const fibResult = await computeWorker.fibonacci(20);
console.log('Fibonacci(20):', fibResult);  // 6765

const factResult = await computeWorker.factorial(5);
console.log('Factorial(5):', factResult);  // 120

const primeCheck = await computeWorker.isPrime(97);
console.log('Is 97 prime?:', primeCheck);  // true

const arraySum = await computeWorker.processArray([1, 2, 3, 4, 5], 'sum');
console.log('Array sum:', arraySum);  // 15

// Heavy computation in background
const heavyResult = await computeWorker.heavyComputation(500000);
console.log('Heavy computation result:', heavyResult);
// { result: 1234.567, iterations: 500000, duration: 89, performance: "5617 ops/ms" }

// Get worker capabilities
const workerInfo = await computeWorker.getWorkerInfo();
console.log('Worker info:', workerInfo);

Key Features of Custom Worker Scripts

Direct Script Loading

  • Support for HTTP/HTTPS URLs, blob URLs, and file URLs
  • Bypasses ImJoy plugin parsing for faster loading
  • Full control over worker implementation

Full Hypha RPC Integration

  • Complete access to Hypha RPC WebSocket client
  • Service registration with api.export()
  • Context-aware service calls with workspace isolation

Performance Optimized

  • Dedicated worker threads for CPU-intensive tasks
  • Non-blocking main thread execution
  • Efficient memory management

Production Ready

  • Error handling and graceful degradation
  • Worker lifecycle management
  • Comprehensive logging and debugging

Custom vs Traditional Workers

| Feature | Custom Worker Scripts | Traditional ImJoy Plugins | |---------|----------------------|---------------------------| | Loading | Direct URL loading | Plugin code parsing required | | Performance | Faster initialization | Additional parsing overhead | | Flexibility | Full control over implementation | ImJoy plugin format constraints | | Integration | Full Hypha RPC access | Full Hypha RPC access | | Use Cases | Custom algorithms, existing workers | ImJoy ecosystem plugins |

Complete Working Example

See public/test-worker.js for a complete example featuring:

  • ✅ Full Hypha RPC WebSocket integration
  • ✅ Mathematical computation services (fibonacci, factorial, prime checking)
  • ✅ Array processing operations with multiple algorithms
  • ✅ Performance benchmarking capabilities
  • ✅ Matrix operations and text processing
  • ✅ Worker status monitoring and error handling
  • ✅ Production-ready architecture patterns

This example demonstrates how to create sophisticated custom workers that integrate seamlessly with the Hypha Core ecosystem while providing high-performance computational capabilities.

Key Points for Integration

Connection Setup

All standalone apps and workers must include this connection code:

hyphaWebsocketClient.setupLocalClient({enable_execution: true}).then(async (api) => {
    // Your app code here
    await api.export({
        // Your exported services
    });
}).catch(console.error);

Important Notes

  1. Script Loading: Always load the Hypha RPC WebSocket client:

    <script src="https://cdn.jsdelivr.net/npm/[email protected]/dist/hypha-rpc-websocket.min.js"></script>
  2. Enable Execution: Use {enable_execution: true} when setting up the local client to allow service exports.

  3. Error Handling: Always include proper error handling for connection failures.

  4. Service Export: Use await api.export({...}) to make your app's functions available to the parent.

  5. Async/Await: Most Hypha API calls are asynchronous, so use async/await or Promises.

  6. Viewport Meta Tag: For mobile compatibility, include the viewport meta tag in your HTML.

This integration system allows you to create complex, distributed applications where different components can run in isolation while maintaining seamless communication through the Hypha RPC system.

Mounting Existing Workers and Iframes

Hypha Core provides simple, direct APIs for mounting existing web workers and iframes without needing the ImJoy plugin format. This is perfect for integrating notebook environments (like Pyodide), custom workers, or existing web applications.

mountWorker(worker, config) - Mount a Web Worker

Mount an existing Web Worker instance to Hypha Core with automatic RPC setup and bidirectional communication.

Basic Usage

import { HyphaCore } from 'hypha-core';

// Start Hypha Core
const server = new HyphaCore({ port: 9527 });
await server.start();

// Create a web worker
const worker = new Worker('my-worker.js');

// Mount it to Hypha Core
await server.mountWorker(worker, {
    workspace: 'default',           // Optional: defaults to 'default'
    client_id: 'my-worker',         // Optional: auto-generated if not provided
    timeout: 60000                  // Optional: connection timeout (default: 60s)
});

// Worker is now connected and ready for RPC communication!

Pyodide/Python Worker Example

// Mount a Pyodide worker with Python code to execute
const worker = new Worker('pyodide-worker.js');

await server.mountWorker(worker, {
    workspace: 'default',
    client_id: 'python-notebook',
    config: {
        name: 'My Notebook',
        scripts: [{
            lang: 'python',
            content: `
print("Hello from Python!")

# Access Hypha services from Python
services = await api.list_services({})
print(f"Found {len(services)} services")

# Get a JavaScript service and call it
demo = await api.get_service("demo-service")
result = await demo.greet("Python")
print(f"Response: {result}")
`
        }]
    }
});

Worker Script Structure

Your worker script should use hypha-rpc to connect:

// my-worker.js
importScripts("https://cdn.jsdelivr.net/npm/[email protected]/dist/hypha-rpc-websocket.min.js");

// Start Pyodide or other environment
loadPyodide().then(async (pyodide) => {
    // Install hypha-rpc
    await pyodide.loadPackage("micropip");
    const micropip = pyodide.pyimport("micropip");
    await micropip.install('hypha-rpc==0.20.84');

    // Signal ready to receive initialization
    self.postMessage({ type: "hyphaClientReady" });

    // Set up the local client (will block until initializeHyphaClient arrives)
    await pyodide.runPythonAsync(`
from hypha_rpc import setup_local_client

async def execute(server, config):
    # Your Python code execution logic
    print('Executing:', config["name"])
    for script in config["scripts"]:
        exec(script["content"], {'api': server})

server = await setup_local_client(enable_execution=False, on_ready=execute)
    `);
});

mountIframe(iframe, config) - Mount an Iframe

Mount an existing iframe element to Hypha Core for bidirectional RPC communication.

Basic Usage

// Create an iframe element
const iframe = document.createElement('iframe');
iframe.src = 'my-app.html';
document.body.appendChild(iframe);

// Wait for iframe to load
await new Promise(resolve => iframe.onload = resolve);

// Mount it to Hypha Core
await server.mountIframe(iframe, {
    workspace: 'default',
    client_id: 'my-iframe-app'
});

// Iframe is now connected!

Example: Mounting an Existing Div with Iframe

// Mount an iframe inside an existing div
const container = document.getElementById('app-container');

// Create iframe programmatically
const iframe = document.createElement('iframe');
iframe.src = '/apps/data-viewer.html';
iframe.style.width = '100%';
iframe.style.height = '600px';
container.appendChild(iframe);

// Mount to Hypha Core
const result = await server.mountIframe(iframe, {
    workspace: 'visualization',
    client_id: 'data-viewer'
});

console.log('Iframe mounted:', result.client_id);

// Get the iframe's service and interact with it
const viewerService = await server.api.getService('data-viewer:default');
await viewerService.loadData({ dataset: 'my-data.csv' });

Configuration Options

Both mountWorker and mountIframe accept these configuration options:

{
    workspace: 'workspace-name',    // Workspace to connect to (default: 'default')
    client_id: 'unique-client-id',  // Client identifier (default: auto-generated)
    user_info: {                    // User information (default: anonymous)
        id: 'user-123',
        email: '[email protected]',
        roles: ['user'],
        scopes: []
    },
    config: {},                     // Configuration passed to the worker/iframe
    timeout: 60000,                 // Connection timeout in ms (default: 60000)
    passive: false                  // Skip waiting for service registration (default: false)
}

Passive Mode

When passive: true, the mount methods return immediately after sending the initialization message without waiting for the worker/iframe to register a service. This is useful when:

  • You don't need to interact with the worker/iframe immediately
  • The worker/iframe may take a long time to initialize
  • You want to mount multiple workers/iframes in parallel without blocking
// Mount worker in passive mode
const result = await server.mountWorker(worker, {
    workspace: 'default',
    passive: true  // Returns immediately, service will be null
});

console.log(result.service);  // null - no service yet

// Later, get the service when needed
const service = await server.api.getService(`${result.client_id}:default`);

Return Value

Both methods return a result object:

{
    workspace: 'workspace-name',
    client_id: 'client-id',
    connection: { /* connection object */ },
    service: { /* registered service object */ }  // null if passive: true
}

Note: When passive: true, the service field will be null since the method returns without waiting for service registration.

Complete Working Example

See examples/pyodide-adhoc-client.html for a complete example demonstrating:

  • ✅ Mounting a Pyodide worker to run Python code
  • ✅ Registering JavaScript services callable from Python
  • ✅ Bidirectional RPC communication
  • ✅ Real-time output display
  • ✅ Error handling

Example Output:

Python/Pyodide Worker Started
==================================================

Found 2 services:
  - default/root:default: Default workspace management service
  - default/root:demo-service: JavaScript Demo Service

Calling demo.greet('Python')...
Response: Hello Python from JavaScript!

Calling demo.add(42, 58)...
Result: 100

All RPC calls successful!
==================================================

Key Features

✅ Simple API

  • No ImJoy plugin format required
  • Mount any existing worker or iframe
  • Automatic RPC connection setup

✅ Flexible Integration

  • Works with Pyodide, custom workers, React apps, etc.
  • Pass configuration during mounting
  • Full access to Hypha services

✅ Bidirectional Communication

  • Workers/iframes can call Hypha services
  • Hypha can call worker/iframe services
  • Automatic message forwarding

✅ Production Ready

  • Timeout handling
  • Error detection
  • Connection state management
  • Proper cleanup

Comparison: Mount vs LoadApp

| Feature | mountWorker/mountIframe | loadApp | |---------|---------------------------|-----------| | Input | Existing Worker/Iframe instance | URL to load | | Format | Any format | ImJoy plugin format |