A framework for building GitHub Apps to automate and improve your workflow
—
Quality
Pending
Does it follow best practices?
Impact
Pending
No eval scenarios have been run
ProbotOctokit is an enhanced Octokit client pre-configured with Probot-specific plugins for authentication, throttling, retries, and configuration management, providing seamless GitHub API access.
Enhanced Octokit client with Probot-specific plugins and authentication strategies.
/**
* Enhanced Octokit client with Probot plugins
* Extends the standard Octokit client with additional functionality
*/
class ProbotOctokit extends Octokit {
// Inherits all standard Octokit functionality
// Plus additional Probot-specific plugins and configuration
}Usage Examples:
import { ProbotOctokit } from "probot";
// Create authenticated instance (usually done automatically by Probot)
const octokit = new ProbotOctokit({
auth: {
appId: process.env.APP_ID,
privateKey: process.env.PRIVATE_KEY,
installationId: 12345,
},
});
// Access GitHub API
const { data: user } = await octokit.users.getByUsername({
username: "octocat",
});
const { data: repos } = await octokit.repos.listForOrg({
org: "github",
type: "public",
});Automatic GitHub App authentication with JWT and installation token management.
// Uses octokit-auth-probot for GitHub App authentication
// Automatically handles:
// - JWT generation for app-level requests
// - Installation token acquisition and refresh
// - Token caching and expiration managementUsage Examples:
// App-level authentication (in event handlers, authentication is automatic)
app.on("installation.created", async (context) => {
// context.octokit is automatically authenticated for the installation
const { data: repos } = await context.octokit.apps.listReposAccessibleToInstallation();
context.log.info(`Installation has access to ${repos.repositories.length} repositories`);
});
// Manual authentication (when creating Octokit instances outside event handlers)
const appOctokit = await app.auth(); // App-level auth
const installationOctokit = await app.auth(12345); // Installation-level authAutomatic request throttling and rate limit handling with cluster support.
// Default throttling configuration:
// - Primary rate limit: Automatic backoff when approaching limits
// - Secondary rate limit: Exponential backoff for abuse detection
// - Redis cluster support: Coordinate rate limiting across multiple instancesUsage Examples:
// Throttling happens automatically, but can be customized
const octokit = new ProbotOctokit({
throttle: {
enabled: true,
// Custom rate limit handler
onRateLimit: (retryAfter, options, octokit) => {
octokit.log.warn(`Rate limit hit, retrying after ${retryAfter} seconds`);
return true; // Retry the request
},
// Custom secondary rate limit handler
onSecondaryRateLimit: (retryAfter, options, octokit) => {
octokit.log.warn(`Secondary rate limit hit, retrying after ${retryAfter} seconds`);
return true; // Retry the request
},
},
});
// Redis cluster support for distributed rate limiting
const clusteredOctokit = new ProbotOctokit({
throttle: {
enabled: true,
// Redis connection details from environment
connection: new Redis(process.env.REDIS_URL),
},
});Automatic request retries for network errors and temporary failures.
// Default retry configuration:
// - Network errors: Exponential backoff with jitter
// - Server errors (5xx): Automatic retry with limits
// - Rate limit errors: Handled by throttling pluginUsage Examples:
// Retries happen automatically, but can be customized
const octokit = new ProbotOctokit({
retry: {
enabled: true,
retries: 3, // Maximum retry attempts
retryAfter: 2, // Base retry delay in seconds
// Custom retry condition
doNotRetry: ["400", "401", "403", "404", "422"],
},
});
// Disable retries for specific requests
const { data } = await octokit.request("GET /user", {
request: {
retries: 0,
},
});Simplified pagination for GitHub API endpoints that return multiple pages.
/**
* Paginate through all results of a GitHub API endpoint
* @param endpoint - GitHub API endpoint method
* @param parameters - Request parameters
* @returns AsyncIterator of all results
*/
paginate: {
(endpoint: string, parameters?: any): AsyncIterable<any>;
iterator: (endpoint: string, parameters?: any) => AsyncIterableIterator<any>;
};Usage Examples:
// Get all repositories for an organization
const allRepos = await octokit.paginate("GET /orgs/{org}/repos", {
org: "github",
type: "public",
});
console.log(`Found ${allRepos.length} repositories`);
// Iterate through results with custom processing
for await (const { data: repos } of octokit.paginate.iterator("GET /orgs/{org}/repos", {
org: "github",
})) {
for (const repo of repos) {
console.log(`Processing ${repo.name}`);
// Process each repository
}
}
// Paginate with additional parameters
const issues = await octokit.paginate("GET /repos/{owner}/{repo}/issues", {
owner: "octocat",
repo: "Hello-World",
state: "open",
labels: "bug",
per_page: 100,
});Typed GitHub API methods with full parameter and response type safety.
// Provides typed methods for all GitHub REST API endpoints
// - octokit.repos.* for repository operations
// - octokit.issues.* for issue operations
// - octokit.pulls.* for pull request operations
// - octokit.apps.* for GitHub App operations
// - And many more...Usage Examples:
// Typed repository operations
const { data: repo } = await octokit.repos.get({
owner: "octocat",
repo: "Hello-World",
});
const { data: contents } = await octokit.repos.getContent({
owner: "octocat",
repo: "Hello-World",
path: "README.md",
});
// Typed issue operations
const { data: issue } = await octokit.issues.create({
owner: "octocat",
repo: "Hello-World",
title: "Bug report",
body: "Something is broken",
labels: ["bug", "triage"],
assignees: ["maintainer1"],
});
const { data: comment } = await octokit.issues.createComment({
owner: "octocat",
repo: "Hello-World",
issue_number: 1,
body: "Thanks for reporting this!",
});
// Typed pull request operations
const { data: pr } = await octokit.pulls.create({
owner: "octocat",
repo: "Hello-World",
title: "Fix bug",
head: "fix-branch",
base: "main",
body: "This fixes the bug reported in #1",
});Support for GitHub Enterprise Server with custom base URLs and configurations.
// Automatic compatibility with GitHub Enterprise Server
// - Custom API base URLs
// - Enterprise-specific endpoints
// - Version compatibility handlingUsage Examples:
// GitHub Enterprise Server configuration
const enterpriseOctokit = new ProbotOctokit({
baseUrl: "https://github.mycompany.com/api/v3",
auth: {
appId: process.env.APP_ID,
privateKey: process.env.PRIVATE_KEY,
installationId: 12345,
},
});
// Works with all standard GitHub API methods
const { data: user } = await enterpriseOctokit.users.getByUsername({
username: "employee",
});Read YAML configuration files from repository .github directories.
/**
* Read configuration file from .github directory
* @param options - Configuration options
* @returns Parsed configuration object
*/
config: {
get<T>(options: {
owner: string;
repo: string;
path: string;
defaults?: T;
}): Promise<T | null>;
};Usage Examples:
// Read .github/myapp.yml configuration
const config = await octokit.config.get({
owner: "octocat",
repo: "Hello-World",
path: "myapp.yml",
defaults: {
enabled: true,
threshold: 10,
},
});
if (config && config.enabled) {
// Use configuration
console.log(`Threshold: ${config.threshold}`);
}Automatic logging of GitHub API requests with correlation IDs.
// Automatic request/response logging
// - Request details (method, URL, parameters)
// - Response details (status, timing)
// - GitHub delivery ID correlation
// - Rate limit informationUsage Examples:
// Logging happens automatically with context
app.on("issues.opened", async (context) => {
// This request will be logged with the event delivery ID
await context.octokit.issues.createComment(
context.issue({ body: "Welcome!" })
);
// Logs will include:
// - Request: POST /repos/octocat/Hello-World/issues/1/comments
// - Response: 201 Created (timing information)
// - GitHub delivery ID: abc123-def456-ghi789
});// Default ProbotOctokit configuration
const defaultOptions = {
authStrategy: createProbotAuth,
throttle: {
enabled: true,
onSecondaryRateLimit: (retryAfter, options, octokit) => {
octokit.log.warn(`Secondary rate limit triggered, retrying after ${retryAfter} seconds`);
return true;
},
onRateLimit: (retryAfter, options, octokit) => {
octokit.log.warn(`Rate limit triggered, retrying after ${retryAfter} seconds`);
return true;
},
},
userAgent: `probot/${VERSION}`,
retry: {
enabled: true,
},
paginate: {
enabled: true,
},
restEndpointMethods: {
enabled: true,
},
enterpriseCompatibility: {
enabled: true,
},
};interface ProbotAuthOptions {
/** GitHub App ID */
appId: number | string;
/** GitHub App private key in PEM format */
privateKey: string;
/** Installation ID for installation-level auth */
installationId?: number;
/** GitHub API base URL (for Enterprise) */
baseUrl?: string;
/** Request options */
request?: RequestRequestOptions;
}
interface AuthResult {
/** Authentication type */
type: "app" | "installation";
/** Access token */
token: string;
/** Token expiration date */
expiresAt?: string;
/** Permissions granted to token */
permissions?: Record<string, string>;
/** Repository IDs accessible (for installation tokens) */
repositoryIds?: number[];
}// Get repository information
const { data: repo } = await octokit.repos.get({
owner: "octocat",
repo: "Hello-World",
});
// List repository contents
const { data: contents } = await octokit.repos.getContent({
owner: "octocat",
repo: "Hello-World",
path: "src",
});
// Create/update files
await octokit.repos.createOrUpdateFileContents({
owner: "octocat",
repo: "Hello-World",
path: "README.md",
message: "Update README",
content: Buffer.from("# Hello World").toString("base64"),
sha: existingFileSha, // Required for updates
});// Create issue
const { data: issue } = await octokit.issues.create({
owner: "octocat",
repo: "Hello-World",
title: "Feature request",
body: "Please add this feature",
labels: ["enhancement"],
});
// Add labels
await octokit.issues.addLabels({
owner: "octocat",
repo: "Hello-World",
issue_number: issue.number,
labels: ["priority:high"],
});
// Create pull request
const { data: pr } = await octokit.pulls.create({
owner: "octocat",
repo: "Hello-World",
title: "Add new feature",
head: "feature-branch",
base: "main",
body: "Implements the requested feature from #123",
});// List installations
const { data: installations } = await appOctokit.apps.listInstallations();
// Get installation repositories
const { data: repos } = await installationOctokit.apps.listReposAccessibleToInstallation();
// Create installation access token
const { data: token } = await appOctokit.apps.createInstallationAccessToken({
installation_id: 12345,
permissions: {
issues: "write",
contents: "read",
},
});Install with Tessl CLI
npx tessl i tessl/npm-probot