CtrlK
BlogDocsLog inGet started
Tessl Logo

tessl/npm-probot

A framework for building GitHub Apps to automate and improve your workflow

Pending

Quality

Pending

Does it follow best practices?

Impact

Pending

No eval scenarios have been run

Overview
Eval results
Files

server-middleware.mddocs/

HTTP Server and Middleware

The Server class provides a built-in HTTP server for receiving GitHub webhooks, serving web interfaces, and handling custom HTTP requests with extensible middleware support.

Capabilities

Server Class

Built-in HTTP server with webhook handling, static file serving, and custom route support.

/**
 * HTTP server for handling webhooks and web requests
 */
class Server {
  /**
   * Create a new server instance
   * @param options - Server configuration options
   */
  constructor(options: ServerOptions = {});
  
  /**
   * Get the Probot framework version
   * @returns Version string
   */
  static get version(): string;
}

Usage Examples:

import { Server, Probot } from "probot";

// Basic server setup
const server = new Server({
  port: 3000,
  host: "localhost",
  Probot: Probot,
});

// Server with custom options
const server = new Server({
  port: process.env.PORT || 3000,
  webhookPath: "/api/github/webhooks",
  enablePing: true,
  enableStaticFiles: true,
  loggingOptions: {
    level: "info",
  },
});

Server Properties

Access to server configuration and runtime properties.

/**
 * Port the server is configured to listen on
 */
get port(): number;

/**
 * Host the server is configured to bind to
 */
get host(): string;

/**
 * Server instance version (same as Probot version)
 */
get version(): string;

Usage Examples:

const server = new Server({ port: 3000, host: "0.0.0.0" });

console.log(`Server will start on ${server.host}:${server.port}`);
console.log(`Server version: ${server.version}`);

Handler Management

Methods for registering custom HTTP request handlers.

/**
 * Add a custom HTTP request handler
 * @param handler - Handler function for processing HTTP requests
 */
addHandler(handler: Handler): void;

/**
 * Load a handler factory function
 * @param appFn - Factory function that returns a handler
 */
async loadHandlerFactory(appFn: HandlerFactory): Promise<void>;

/**
 * Load an application function that may register handlers
 * @param appFn - Application function to load
 */
async load(appFn: ApplicationFunction): Promise<void>;

Usage Examples:

// Add custom handler
server.addHandler((req, res) => {
  if (req.url === "/health") {
    res.writeHead(200, { "Content-Type": "application/json" });
    res.end(JSON.stringify({ status: "ok", timestamp: new Date().toISOString() }));
    return true; // Handler processed the request
  }
  return false; // Pass to next handler
});

// Handler factory
const createAPIHandler = (app: Probot, options) => {
  return (req, res) => {
    if (req.url?.startsWith("/api/v1/")) {
      // Custom API logic
      res.writeHead(200, { "Content-Type": "application/json" });
      res.end(JSON.stringify({ message: "API endpoint" }));
      return true;
    }
    return false;
  };
};

await server.loadHandlerFactory(createAPIHandler);

// Application function that adds handlers
const appWithRoutes = (app: Probot, { addHandler }) => {
  // Register webhook handlers
  app.on("issues.opened", async (context) => {
    // Handle webhook
  });
  
  // Add custom HTTP routes
  addHandler((req, res) => {
    if (req.url === "/dashboard") {
      res.writeHead(200, { "Content-Type": "text/html" });
      res.end("<h1>Dashboard</h1>");
      return true;
    }
    return false;
  });
};

await server.load(appWithRoutes);

Server Lifecycle

Methods for starting and stopping the HTTP server.

/**
 * Start the HTTP server with all configured handlers
 * Sets up default handlers for webhooks, ping, static files, and 404s
 * @returns Promise resolving to Node.js HTTP server instance
 */
async start(): Promise<HttpServer>;

/**
 * Stop the HTTP server and clean up resources
 * Closes webhook proxy connections if configured
 */
async stop(): Promise<void>;

Usage Examples:

import { Server, Probot } from "probot";

const server = new Server({
  port: 3000,
  Probot: Probot,
});

// Load application
await server.load((app) => {
  app.on("push", async (context) => {
    context.log.info("Push received");
  });
});

// Start server
const httpServer = await server.start();
console.log(`Server started on port ${server.port}`);

// Graceful shutdown
process.on("SIGTERM", async () => {
  console.log("Shutting down server...");
  await server.stop();
  process.exit(0);
});

Built-in Handlers

Webhook Handler

Automatically configured to handle GitHub webhook events at the specified webhook path.

// Default webhook path: "/api/github/webhooks"
// Handles POST requests with GitHub webhook payloads
// Verifies webhook signatures using the configured secret
// Parses payloads and triggers registered event handlers

Ping Handler

Optional health check endpoint for monitoring server availability.

// Endpoint: GET /ping
// Response: "PONG" with 200 status
// Enabled with: enablePing: true in ServerOptions

Usage Examples:

const server = new Server({
  enablePing: true,
});

// GET /ping -> "PONG"

Static Files Handler

Optional static file serving for web interfaces and assets.

// Serves files from ./static directory
// Endpoint: GET /static/*
// Enabled with: enableStaticFiles: true in ServerOptions

Usage Examples:

const server = new Server({
  enableStaticFiles: true,
});

// Files in ./static/logo.png -> GET /static/logo.png
// Files in ./static/css/styles.css -> GET /static/css/styles.css

Not Found Handler

Default 404 handler for unmatched requests.

// Returns 404 status for unhandled requests
// Enabled with: enableNotFound: true in ServerOptions (default: true)
// Can be disabled to allow custom 404 handling

Configuration Types

interface ServerOptions {
  /** Current working directory */
  cwd?: string;
  /** Logger instance for server logs */
  log?: Logger;
  /** Port to listen on */
  port?: number;
  /** Host to bind to */
  host?: string;
  /** Webhook endpoint path */
  webhookPath?: string;
  /** Smee.io proxy URL for development */
  webhookProxy?: string;
  /** Enable GET /ping endpoint */
  enablePing?: boolean;
  /** Enable 404 not found handler */
  enableNotFound?: boolean;
  /** Enable static file serving from ./static */
  enableStaticFiles?: boolean;
  /** Probot class to use for app instances */
  Probot: typeof Probot;
  /** HTTP request logging configuration */
  loggingOptions?: LoggingOptions;
  /** Octokit request configuration */
  request?: RequestRequestOptions;
}

type Handler = (
  req: IncomingMessage,
  res: ServerResponse
) => void | boolean | Promise<void | boolean>;

type HandlerFactory = (
  app: Probot,
  options: ApplicationFunctionOptions
) => Handler | Promise<Handler>;

type ApplicationFunction = (
  app: Probot,
  options: ApplicationFunctionOptions
) => void | Promise<void>;

interface LoggingOptions {
  /** Log level for HTTP requests */
  level?: "trace" | "debug" | "info" | "warn" | "error" | "fatal" | "silent";
  /** Custom logger instance */
  logger?: Logger;
  /** Custom serializers for request/response logging */
  serializers?: Record<string, (obj: any) => any>;
}

interface ApplicationFunctionOptions {
  /** Current working directory */
  cwd: string;
  /** Function to register custom HTTP handlers */
  addHandler: (handler: Handler) => void;
  /** Additional options */
  [key: string]: unknown;
}

Middleware Integration

Express Integration

import express from "express";
import { createNodeMiddleware } from "probot";

const app = express();

// Create Probot middleware
const probotMiddleware = await createNodeMiddleware((app) => {
  app.on("issues.opened", async (context) => {
    // Handle GitHub webhooks
  });
});

// Mount Probot middleware
app.use("/github", probotMiddleware);

// Add other Express routes
app.get("/", (req, res) => {
  res.send("Hello World");
});

app.listen(3000);

Fastify Integration

import Fastify from "fastify";
import { createNodeMiddleware } from "probot";

const fastify = Fastify();

// Create Probot handler
const probotHandler = await createNodeMiddleware((app) => {
  app.on("push", async (context) => {
    // Handle webhooks
  });
});

// Register as Fastify plugin
fastify.register(async (fastify) => {
  fastify.all("/webhooks/*", async (request, reply) => {
    return probotHandler(request.raw, reply.raw);
  });
});

await fastify.listen({ port: 3000 });

Custom HTTP Server

import { createServer } from "http";
import { createNodeMiddleware } from "probot";

const middleware = await createNodeMiddleware((app) => {
  app.on("repository.created", async (context) => {
    context.log.info("New repository created");
  });
});

const server = createServer(async (req, res) => {
  // Try Probot middleware first
  const handled = await middleware(req, res);
  
  if (!handled) {
    // Handle other routes
    res.writeHead(404);
    res.end("Not Found");
  }
});

server.listen(3000);

Types

type HandlerFactory = (
  app: Probot,
  options: ApplicationFunctionOptions
) => Handler | Promise<Handler>;

Install with Tessl CLI

npx tessl i tessl/npm-probot

docs

app-creation.md

context-events.md

core-framework.md

github-api.md

index.md

server-middleware.md

tile.json