Development Guide

This comprehensive guide covers everything you need to know about developing with and contributing to the JupyterLab Firefox Launcher extension.

Build Infrastructure, Flow, and Tooling

Build Pipeline Overview

The JupyterLab Firefox Launcher uses a sophisticated multi-stage build pipeline that coordinates both frontend (TypeScript/JavaScript) and backend (Python) components into a single distributable package.

graph TD
    A[./build.sh] --> B[Clean Previous Builds]
    B --> C[uv build --wheel --no-cache --verbose]
    
    C --> D[hatchling Build Backend]
    D --> E[hatch-jupyter-builder]
    
    E --> F[Frontend Build Process]
    E --> G[Backend Build Process]
    
    F --> H[jlpm install]
    H --> I[TypeScript Compiler]
    I --> J[Webpack Bundling]
    J --> K[JupyterLab Extension Build]
    K --> L[Static Assets Generation]
    
    G --> M[Python Package Assembly]
    M --> N[Script Installation Mapping]
    N --> O[Jupyter Config Integration]
    
    L --> P[labextension/static/]
    O --> Q[Wheel Package Assembly]
    P --> Q
    
    Q --> R[dist/jupyterlab_firefox_launcher-*.whl]
    
    style A fill:#e1f5fe
    style C fill:#f3e5f5
    style D fill:#fff3e0
    style E fill:#e8f5e8
    style R fill:#ffebee

Build Toolchain Components

1. Entry Point: build.sh

#!/bin/bash
# Copyright (c) 2025 Vantage Compute Corporation.

rm -rf jupyterlab_firefox_launcher/labextension/static
rm -rf jupyterlab_firefox_launcher/labextension/package.json
rm -rf lib/
rm -rf dist/

uv build --wheel --no-cache --verbose

Purpose:

  • Cleanup: Removes stale build artifacts
  • Orchestration: Triggers the main build process
  • Reproducibility: Ensures clean builds without cached dependencies

2. Package Manager: uv build

uv build --wheel --no-cache --verbose

Purpose:

  • Fast Dependency Resolution: Uses Rust-based resolver for speed
  • Wheel Creation: Generates Python wheel distribution format
  • Cache Management: --no-cache ensures fresh dependency resolution
  • Visibility: --verbose provides detailed build output for debugging

3. Build Backend: hatchling

[build-system]
requires = [
    "hatchling>=1.5.0",
    "jupyterlab>=4.0.0,<5",
    "hatch-jupyter-builder>=0.8.3"
]
build-backend = "hatchling.build"

Purpose:

  • PEP 517 Compliance: Modern Python build system
  • Metadata Management: Handles package metadata and dependencies
  • Build Coordination: Orchestrates the overall build process
  • Hook Integration: Provides hooks for custom build steps

4. JupyterLab Integration: hatch-jupyter-builder

[tool.hatch.build.hooks.jupyter-builder]
dependencies = ["hatch-jupyter-builder>=0.8.3"]
build-function = "hatch_jupyter_builder.npm_builder"
ensured-targets = [
    "jupyterlab_firefox_launcher/labextension/static/style.js",
    "jupyterlab_firefox_launcher/labextension/package.json",
]

Purpose:

  • Dual Build Coordination: Manages both Python and JavaScript builds
  • Asset Management: Ensures frontend assets are built and included
  • Target Validation: Verifies required build artifacts exist
  • JupyterLab Standards: Follows JupyterLab extension conventions

Detailed Build Flow

Phase 1: Cleanup & Preparation

graph LR
    A[build.sh execution] --> B[Remove labextension/static/]
    B --> C[Remove labextension/package.json]
    C --> D[Remove lib/ directory]
    D --> E[Remove dist/ directory]
    E --> F[Clean build environment ready]
    
    style A fill:#e3f2fd
    style F fill:#e8f5e8

Phase 2: Frontend Build Pipeline

graph TD
    A[hatch-jupyter-builder trigger] --> B[jlpm install]
    B --> C[Node.js Dependencies Resolution]
    C --> D[TypeScript Compilation]
    
    D --> E[src/index.ts]
    D --> F[src/firefox-api.ts]
    D --> G[src/svg.d.ts]
    
    E --> H[JavaScript Output]
    F --> H
    G --> H
    
    H --> I[Webpack Bundling]
    I --> J[Asset Optimization]
    J --> K[JupyterLab Extension Build]
    
    K --> L[Static Assets]
    K --> M[Package Metadata]
    
    L --> N[labextension/static/]
    M --> O[labextension/package.json]
    
    style A fill:#f3e5f5
    style N fill:#fff3e0
    style O fill:#fff3e0

Phase 3: Backend Build Pipeline

graph TD
    A[hatchling coordination] --> B[Python Source Processing]
    
    B --> C[jupyterlab_firefox_launcher/__init__.py]
    B --> D[jupyterlab_firefox_launcher/server_extension.py]
    B --> E[jupyterlab_firefox_launcher/firefox_handler.py]
    B --> F[jupyterlab_firefox_launcher/session_cleanup.py]
    B --> G[jupyterlab_firefox_launcher/server_proxy.py]
    B --> H[jupyterlab_firefox_launcher/_version.py]
    
    C --> I[Package Assembly]
    D --> I
    E --> I
    F --> I
    G --> I
    H --> I
    
    I --> J[Script Installation Mapping]
    J --> K[scripts/firefox-xstartup โ†’ bin/firefox-xstartup]
    
    K --> L[Jupyter Configuration]
    L --> M[jupyter-config/ โ†’ etc/jupyter/]
    
    M --> N[Metadata Generation]
    N --> O[Dependency Resolution]
    
    style A fill:#e8f5e8
    style O fill:#ffebee

Phase 4: Package Assembly

graph TD
    A[Frontend Assets] --> C[Wheel Assembly]
    B[Backend Components] --> C
    
    C --> D[WHEEL File]
    C --> E[METADATA File]
    C --> F[RECORD File]
    
    D --> G[dist/jupyterlab_firefox_launcher-0.1.0-py3-none-any.whl]
    E --> G
    F --> G
    
    G --> H[Ready for Distribution]
    
    style A fill:#fff3e0
    style B fill:#e8f5e8
    style G fill:#ffebee
    style H fill:#c8e6c9

Build Configuration Files

pyproject.toml - Master Build Configuration

[tool.hatch.build.targets.wheel.shared-data]
"scripts/firefox-xstartup" = "bin/firefox-xstartup"
"jupyter-config" = "etc/jupyter"

[tool.hatch.build.hooks.jupyter-builder]
dependencies = ["hatch-jupyter-builder>=0.8.3"]
build-function = "hatch_jupyter_builder.npm_builder"
ensured-targets = [
    "jupyterlab_firefox_launcher/labextension/static/style.js",
    "jupyterlab_firefox_launcher/labextension/package.json",
]
skip-if-exists = [
    "jupyterlab_firefox_launcher/labextension/static/style.js",
    "jupyterlab_firefox_launcher/labextension/package.json",
]

package.json - Frontend Build Configuration

{
  "scripts": {
    "build": "jlpm build:lib && jlpm build:labextension:dev",
    "build:prod": "jlpm clean && jlpm build:lib:prod && jlpm build:labextension",
    "build:labextension": "jupyter labextension build .",
    "build:labextension:dev": "jupyter labextension build --development True .",
    "build:lib": "tsc --sourceMap",
    "build:lib:prod": "tsc"
  }
}

tsconfig.json - TypeScript Build Configuration

{
  "compilerOptions": {
    "target": "es2018",
    "lib": ["es2018", "dom"],
    "module": "esnext",
    "moduleResolution": "node",
    "outDir": "./lib",
    "strict": true
  },
  "include": ["src/**/*"]
}

Build Artifacts & Outputs

Generated Directory Structure

dist/
โ””โ”€โ”€ jupyterlab_firefox_launcher-0.1.0-py3-none-any.whl
    โ”œโ”€โ”€ jupyterlab_firefox_launcher/
    โ”‚   โ”œโ”€โ”€ __init__.py
    โ”‚   โ”œโ”€โ”€ server_extension.py
    โ”‚   โ”œโ”€โ”€ firefox_handler.py
    โ”‚   โ””โ”€โ”€ labextension/
    โ”‚       โ”œโ”€โ”€ package.json
    โ”‚       โ””โ”€โ”€ static/
    โ”‚           โ”œโ”€โ”€ style.js
    โ”‚           โ”œโ”€โ”€ remoteEntry.*.js
    โ”‚           โ””โ”€โ”€ *.svg
    โ”œโ”€โ”€ bin/
    โ”‚   โ””โ”€โ”€ firefox-xstartup
    โ””โ”€โ”€ etc/
        โ””โ”€โ”€ jupyter/
            โ””โ”€โ”€ jupyter_server_config.d/
                โ””โ”€โ”€ jupyterlab_firefox_launcher.json

Build Validation & Quality Checks

Asset Verification

graph LR
    A[Build Completion] --> B[Check labextension/static/style.js]
    B --> C[Check labextension/package.json]
    C --> D[Validate Python Package Structure]
    D --> E[Verify Script Installation Paths]
    E --> F[Test Import Statements]
    F --> G[Build Success โœ“]
    
    B --> H[Build Failure โœ—]
    C --> H
    D --> H
    E --> H
    F --> H
    
    style G fill:#c8e6c9
    style H fill:#ffcdd2

Development vs Production Builds

Development Build Flow

# Development setup
jupyter labextension develop . --overwrite
jupyter lab --watch  # Auto-rebuild on changes

Production Build Flow

# Production build
./build.sh  # Clean, optimized build

Troubleshooting Build Issues

Common Build Problems

graph TD
    A[Build Failure] --> B{Error Type?}
    
    B -->|Frontend| C[jlpm install issues]
    B -->|Backend| D[Python dependency issues]
    B -->|Asset| E[Missing build artifacts]
    
    C --> F[Delete node_modules/, run jlpm install]
    D --> G[Check Python version, uv sync]
    E --> H[Clean build: rm -rf lib/ dist/]
    
    F --> I[Retry Build]
    G --> I
    H --> I
    
    style A fill:#ffcdd2
    style I fill:#c8e6c9

This comprehensive build pipeline ensures that both frontend TypeScript code and backend Python code are properly compiled, bundled, and packaged into a single wheel file that can be easily installed and distributed.

Development Setup

Prerequisites

Before starting development, ensure you have the required tools installed:

  • Python: 3.10+ (3.11+ recommended)
  • Node.js: 16+ (18+ recommended)
  • uv: Fast Python package manager (recommended)
  • Git: Version control
  • System packages: Xpra, Firefox, Xvfb (see Dependencies)

Quick Development Setup

# Clone the repository
git clone https://github.com/vantagecompute/jupyterlab-firefox-launcher.git
cd jupyterlab-firefox-launcher

# Install development dependencies
uv pip install -e ".[dev]"

# Install frontend dependencies
uv run jlpm install

# Enable development mode
uv run jupyter labextension develop . --overwrite

# Start development server with watch mode
uv run jupyter lab --watch

Detailed Setup Process

1. Environment Setup

Option A: Using uv (Recommended)

# Create virtual environment
uv venv
source .venv/bin/activate

# Install development dependencies
uv pip install -e ".[dev]"

Option B: Using pip

# Create virtual environment
python -m venv .venv
source .venv/bin/activate

# Upgrade pip and install dependencies
pip install --upgrade pip
pip install -e ".[dev]"

Option C: Using conda

# Create conda environment
conda create -n firefox-launcher-dev python=3.11
conda activate firefox-launcher-dev

# Install dependencies
pip install -e ".[dev]"

2. Frontend Development Setup

# Install Node.js dependencies
jlpm install

# Enable development mode in JupyterLab
jupyter labextension develop . --overwrite

# Verify installation
jupyter labextension list | grep firefox-launcher

Development Workflow

Project Structure

Understanding the project structure is crucial for effective development:

jupyterlab-firefox-launcher/
โ”œโ”€โ”€ src/                          # TypeScript source files
โ”‚   โ”œโ”€โ”€ index.ts                 # Main extension entry point
โ”‚   โ”œโ”€โ”€ firefox-api.ts          # Firefox session API client
โ”‚   โ””โ”€โ”€ svg.d.ts                 # SVG type declarations
โ”œโ”€โ”€ style/                        # CSS and styling
โ”‚   โ”œโ”€โ”€ index.css               # Main stylesheet
โ”‚   โ””โ”€โ”€ icons/                   # Icon assets
โ”‚       โ””โ”€โ”€ firefox.svg         # Firefox icon
โ”œโ”€โ”€ jupyterlab_firefox_launcher/  # Python package
โ”‚   โ”œโ”€โ”€ __init__.py             # Package initialization and entry points
โ”‚   โ”œโ”€โ”€ _version.py             # Version management using importlib.metadata
โ”‚   โ”œโ”€โ”€ server_extension.py     # Jupyter server extension registration
โ”‚   โ”œโ”€โ”€ firefox_handler.py      # Core session management and Xpra integration
โ”‚   โ”œโ”€โ”€ server_proxy.py         # jupyter-server-proxy integration
โ”‚   โ”œโ”€โ”€ session_cleanup.py      # Automatic session cleanup and registry
โ”‚   โ””โ”€โ”€ labextension/           # Built frontend assets
โ”‚       โ”œโ”€โ”€ package.json        # Frontend package metadata
โ”‚       โ””โ”€โ”€ static/             # Compiled JavaScript and assets
โ”œโ”€โ”€ scripts/                      # Executable scripts
โ”‚   โ””โ”€โ”€ firefox-xstartup        # Firefox startup wrapper script
โ”œโ”€โ”€ bin/                          # Script installation directory
โ”‚   โ””โ”€โ”€ firefox-xstartup        # Installed Firefox wrapper
โ”œโ”€โ”€ tests/                        # Test suite
โ”œโ”€โ”€ docs/                         # Documentation site
โ”œโ”€โ”€ jupyter-config/              # Jupyter configuration
โ”‚   โ””โ”€โ”€ jupyter_server_config.d/ # Server extension config
โ”œโ”€โ”€ lib/                          # Compiled TypeScript output
โ”œโ”€โ”€ pyproject.toml               # Python project configuration
โ”œโ”€โ”€ package.json                 # NPM package configuration
โ”œโ”€โ”€ tsconfig.json               # TypeScript configuration
โ””โ”€โ”€ build.sh                    # Production build script

Development Commands

Frontend Development

# Start JupyterLab in watch mode (rebuilds on changes)
jupyter lab --watch

# Manual build during development
jlpm build

# Clean build artifacts
jlpm clean

# Type checking
jlpm run check

# Linting
jlpm run eslint

Backend Development

# Run Python tests
pytest

# Run tests with coverage
pytest --cov=jupyterlab_firefox_launcher

# Type checking
mypy jupyterlab_firefox_launcher/

# Code formatting
black jupyterlab_firefox_launcher/
isort jupyterlab_firefox_launcher/

# Linting
flake8 jupyterlab_firefox_launcher/

Full Build Process

The build.sh script provides a complete production build:

#!/bin/bash

# Clean previous build artifacts
rm -rf jupyterlab_firefox_launcher/labextension/static
rm -rf jupyterlab_firefox_launcher/labextension/package.json
rm -rf lib/
rm -rf dist/

# Build wheel package with verbose output and no cache
uv build --wheel --no-cache --verbose

Build Process Breakdown:

  1. Cleanup Phase: Removes previous build artifacts
    • labextension/static/: Compiled frontend assets
    • labextension/package.json: Frontend package metadata
    • lib/: TypeScript compilation output
    • dist/: Python wheel distribution
  2. Build Phase: Uses uv build for fast, reliable package building
    • --wheel: Creates wheel distribution format
    • --no-cache: Ensures fresh build without cached dependencies
    • --verbose: Provides detailed build output for debugging

Manual Build Steps:

# Frontend build
jlpm install                     # Install Node.js dependencies
jlpm build:prod                 # Build and bundle frontend code

# Backend build  
python -m build --wheel         # Build Python wheel package

# Development installation
uv pip install -e .            # Install in development mode

Code Organization

Frontend Code (src/)

Main Extension (src/index.ts)

  • Widget creation and management
  • JupyterLab integration
  • Lifecycle management
  • Event handling

Key Classes and Functions:

// Main widget class
class FirefoxWidget extends Widget {
  constructor(port: number, processId: number) {
    // Widget initialization
  }
  
  dispose(): void {
    // Cleanup logic
  }
}

// Extension activation
function activate(app: JupyterFrontEnd): void {
  // Extension setup and registration
}

Python Package (jupyterlab_firefox_launcher/)

Package Initialization (__init__.py)

  • Package entry points for Jupyter server extension discovery
  • Version management and module exports
  • Extension metadata and configuration

Version Management (_version.py)

  • Dynamic version detection using importlib.metadata
  • Fallback version for development installations
  • Single source of truth for package version

Server Extension (server_extension.py)

  • Handler registration with Jupyter server
  • URL routing configuration
  • Extension lifecycle management
  • Integration with jupyter-server-proxy

Firefox Handler (firefox_handler.py)

  • Core session management logic
  • Xpra server integration and command generation
  • Process lifecycle management (start, monitor, cleanup)
  • Multi-session support with port allocation
  • Session data persistence and retrieval

Server Proxy Integration (server_proxy.py)

  • jupyter-server-proxy entry point configuration
  • Proxy setup for Xpra HTML5 client access
  • URL mapping and routing

Session Cleanup (session_cleanup.py)

  • Centralized session registry for tracking active sessions
  • Automatic cleanup on server shutdown
  • Process monitoring and zombie process detection
  • Resource cleanup (session directories, temp files)
  • Thread-safe session management

Testing

Running Tests

# Run all Python tests
pytest

# Run specific test file
pytest tests/test_firefox_handler.py

# Run with verbose output
pytest -v

# Run with coverage reporting
pytest --cov=jupyterlab_firefox_launcher --cov-report=html

# Run integration tests
python tests/test_integration.py

Writing Tests

Unit Test Example:

import pytest
from jupyterlab_firefox_launcher.firefox_handler import _find_free_port

def test_find_free_port():
    """Test port allocation functionality."""
    port = _find_free_port()
    assert isinstance(port, int)
    assert 1024 < port < 65535

@pytest.mark.asyncio
async def test_firefox_handler_post():
    """Test Firefox handler POST request."""
    # Test implementation
    pass

Integration Test Example:

def test_full_workflow():
    """Test complete Firefox launch workflow."""
    # Start JupyterLab server
    # Make API request
    # Verify Firefox process
    # Clean up
    pass

Frontend Testing

# Run Jest tests
jlpm test

# Run tests in watch mode
jlpm test --watch

# Generate coverage report
jlpm test --coverage

Debugging

Backend Debugging

Enable Debug Logging:

import logging
logging.basicConfig(level=logging.DEBUG)

# Or set environment variable
export FIREFOX_LAUNCHER_DEBUG=1

Debug Session Management:

# In firefox_handler.py
_logger.debug(f"Active sessions: {FirefoxLauncherHandler._active_sessions}")
_logger.debug(f"Process ID: {process.pid}, Port: {port}")

Process Debugging:

# Monitor processes
ps aux | grep -E "(xpra|firefox)"

# Check session directories
ls -la ~/.firefox-launcher/sessions/

# Monitor system resources
htop

# Check network connections
netstat -tlnp | grep :XXXX  # Replace XXXX with port

Frontend Debugging

Browser Developer Tools:

  • Open browser console in JupyterLab
  • Check Network tab for API requests
  • Monitor JavaScript errors

JupyterLab Console:

// Add debug logging
console.log('Firefox widget created:', this.port);
console.error('Error in widget:', error);

Development Best Practices

Code Style

Python:

  • Follow PEP 8 guidelines
  • Use type hints where appropriate
  • Write descriptive docstrings
  • Use black for formatting
def create_session_directory(port: int) -> Path:
    """Create isolated session directory for Firefox instance.
    
    Args:
        port: Port number for the session
        
    Returns:
        Path to the created session directory
        
    Raises:
        OSError: If directory creation fails
    """
    session_dir = Path.home() / '.firefox-launcher' / 'sessions' / f'session-{port}'
    session_dir.mkdir(parents=True, exist_ok=True)
    return session_dir

TypeScript:

  • Use explicit types
  • Follow JupyterLab coding standards
  • Use meaningful variable names
  • Document complex logic
interface SessionInfo {
  port: number;
  processId: number;
  createdAt: Date;
}

class FirefoxSession {
  constructor(private sessionInfo: SessionInfo) {}
  
  /**
   * Clean up session resources
   */
  async cleanup(): Promise<void> {
    // Implementation
  }
}

Error Handling

Python Error Handling:

try:
    process = subprocess.Popen(xpra_cmd)
    return True, port, process.pid
except subprocess.SubprocessError as e:
    self.log.error(f"Failed to start Xpra: {e}")
    return False, None, None
except Exception as e:
    self.log.error(f"Unexpected error: {e}")
    raise

TypeScript Error Handling:

try {
  const response = await requestAPI<SessionResponse>('firefox', {
    method: 'POST'
  });
  return response;
} catch (error) {
  console.error('Failed to start Firefox session:', error);
  showErrorMessage('Firefox Launcher Error', error.message);
  throw error;
}

Performance Considerations

Memory Management:

  • Clean up resources properly
  • Avoid memory leaks in widgets
  • Monitor process memory usage

Process Management:

  • Limit concurrent sessions
  • Implement proper timeouts
  • Clean up zombie processes

Build System

Build Chain Overview

The extension uses a modern build chain with multiple tools:

Source Files โ†’ TypeScript Compiler โ†’ Webpack โ†’ JupyterLab Builder โ†’ Distribution
Python Files โ†’ Hatch Builder โ†’ Wheel Package โ†’ PyPI

Build Configuration

TypeScript Configuration (tsconfig.json):

{
  "compilerOptions": {
    "target": "es2018",
    "lib": ["es2018", "dom"],
    "module": "esnext",
    "moduleResolution": "node",
    "strict": true,
    "esModuleInterop": true,
    "skipLibCheck": true,
    "forceConsistentCasingInFileNames": true
  },
  "include": ["src/**/*"]
}

Python Build Configuration (pyproject.toml):

[build-system]
requires = [
    "hatchling>=1.5.0",
    "jupyterlab>=4.0.0,<5",
    "hatch-jupyter-builder>=0.8.3"
]
build-backend = "hatchling.build"

[tool.hatch.build.targets.wheel.shared-data]
"scripts/firefox-xstartup" = "bin/firefox-xstartup"
"jupyter-config" = "etc/jupyter"

Custom Build Scripts

Development Build (build.sh):

**Custom Build Scripts (`build.sh`):**
```bash
#!/bin/bash
set -euo pipefail

echo "๐Ÿ”ง Building JupyterLab Firefox Launcher..."

# Clean previous builds
echo "๐Ÿงน Cleaning previous builds..."
jlpm clean:all
rm -rf dist/ build/ *.egg-info/

# Install dependencies
echo "๐Ÿ“ฆ Installing dependencies..."
jlpm install

# Build frontend
echo "๐Ÿ—๏ธ Building frontend..."
jlpm build:prod

# Build Python package
echo "๐Ÿ Building Python package..."
uv build --wheel --no-cache --verbose

echo "โœ… Build complete!"

### Release Process

The project uses a fully automated release workflow with GitHub Actions. The process includes:
- **Automated changelog generation** using git-cliff from conventional commits
- **PyPI trusted publishing** with no manual token management
- **GitHub releases** with auto-generated release notes
- **Version management** across multiple files

#### Prerequisites

For local development and releases, ensure you have:

```bash
# Install git-cliff for changelog generation
curl -L https://github.com/orhun/git-cliff/releases/download/v2.10.0/git-cliff-2.10.0-x86_64-unknown-linux-gnu.tar.gz | tar -xz
sudo cp git-cliff-*/git-cliff /usr/local/bin/

Simply push a version tag to trigger the full release pipeline:

# The automated process will:
# 1. Generate changelog from conventional commits
# 2. Build wheel and source packages  
# 3. Publish to PyPI via trusted publishing
# 4. Create GitHub release with auto-generated notes

git tag 0.2.0
git push origin 0.2.0

Local Release Script

For manual releases, use the included script that automates version management:

# Updates versions, generates changelog, creates tag
./scripts/create_release.sh 0.2.0
git push origin main --tags

Manual Release Steps

If you need to do a completely manual release:

# 1. Update version in multiple files
VERSION="0.2.0"
jq ".version = \"$VERSION\"" package.json > package.json.tmp && mv package.json.tmp package.json
sed -i "s/version = \".*\"/version = \"$VERSION\"/" pyproject.toml

# 2. Generate changelog
git-cliff --tag 0.2.0 -o CHANGELOG.md

# 3. Commit changes
git add package.json pyproject.toml CHANGELOG.md
git commit -m "chore: bump version to $VERSION"

# 4. Create and push tag
git tag 0.2.0
git push origin main 0.2.0

Advanced Development Topics

Custom Firefox Configuration

You can customize Firefox startup behavior by modifying the firefox-xstartup script:

# In bin/firefox-xstartup
# Add custom Firefox preferences
echo 'user_pref("browser.startup.homepage", "about:blank");' >> "$PROFILE_DIR/user.js"
echo 'user_pref("browser.sessionstore.resume_from_crash", false);' >> "$PROFILE_DIR/user.js"

Extending the API

Add new API endpoints by extending the handlers:

class CustomFirefoxHandler(FirefoxLauncherHandler):
    async def patch(self):
        """Custom PATCH endpoint for session updates."""
        data = self.get_json()
        # Custom logic here
        self.write({"status": "success"})

Performance Monitoring

Add performance monitoring to track resource usage:

import psutil
import time

def monitor_session_resources(port: int):
    """Monitor resource usage for a session."""
    # Implementation for resource monitoring
    pass

Next Steps