forked from claude-did-this/claude-hub
- Add Gitea webhook provider with signature verification (x-gitea-signature) - Add GiteaApiClient for REST API interactions - Add handlers for issues, PRs, and workflow events (CI failure detection) - Update secure credentials to use GITEA_TOKEN - Add GITEA_TOKEN redaction in logger and sanitize utilities - Remove all GitHub-specific code (provider, routes, controllers, services, types, tests) - Update documentation with Gitea webhook setup instructions 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
168 lines
3.5 KiB
TypeScript
168 lines
3.5 KiB
TypeScript
import type { Request, Response, NextFunction } from 'express';
|
|
import type { StartupMetrics } from './metrics';
|
|
|
|
// Generic webhook payload (provider-agnostic)
|
|
export interface WebhookPayload {
|
|
action?: string;
|
|
repository?: {
|
|
full_name: string;
|
|
name: string;
|
|
owner: {
|
|
login: string;
|
|
};
|
|
};
|
|
sender?: {
|
|
login: string;
|
|
};
|
|
[key: string]: unknown;
|
|
}
|
|
|
|
// Extended Express Request with custom properties
|
|
export interface WebhookRequest extends Request {
|
|
rawBody?: Buffer;
|
|
startupMetrics?: StartupMetrics;
|
|
body: WebhookPayload;
|
|
}
|
|
|
|
export interface ClaudeAPIRequest extends Request {
|
|
body: {
|
|
repoFullName?: string;
|
|
repository?: string;
|
|
issueNumber?: number;
|
|
command: string;
|
|
isPullRequest?: boolean;
|
|
branchName?: string;
|
|
authToken?: string;
|
|
useContainer?: boolean;
|
|
};
|
|
}
|
|
|
|
// Custom response types for our endpoints
|
|
export interface WebhookResponse {
|
|
success?: boolean;
|
|
message: string;
|
|
context?: {
|
|
repo: string;
|
|
issue?: number;
|
|
pr?: number;
|
|
type?: string;
|
|
sender?: string;
|
|
branch?: string;
|
|
};
|
|
claudeResponse?: string;
|
|
errorReference?: string;
|
|
timestamp?: string;
|
|
}
|
|
|
|
export interface HealthCheckResponse {
|
|
status: 'ok' | 'degraded' | 'error';
|
|
timestamp: string;
|
|
startup?: StartupMetrics;
|
|
docker: {
|
|
available: boolean;
|
|
error: string | null;
|
|
checkTime: number | null;
|
|
};
|
|
claudeCodeImage: {
|
|
available: boolean;
|
|
error: string | null;
|
|
checkTime: number | null;
|
|
};
|
|
healthCheckDuration?: number;
|
|
}
|
|
|
|
export interface ErrorResponse {
|
|
error: string;
|
|
message?: string;
|
|
errorReference?: string;
|
|
timestamp?: string;
|
|
context?: Record<string, unknown>;
|
|
}
|
|
|
|
// Middleware types
|
|
export type WebhookHandler = (
|
|
req: WebhookRequest,
|
|
res: Response<WebhookResponse | ErrorResponse>
|
|
) =>
|
|
| Promise<Response<WebhookResponse | ErrorResponse> | void>
|
|
| Response<WebhookResponse | ErrorResponse>
|
|
| void;
|
|
|
|
export type ClaudeAPIHandler = (
|
|
req: ClaudeAPIRequest,
|
|
res: Response,
|
|
next: NextFunction
|
|
) => Promise<Response | void> | Response | void;
|
|
|
|
export type HealthCheckHandler = (
|
|
req: Request,
|
|
res: Response<HealthCheckResponse>,
|
|
next: NextFunction
|
|
) => Promise<void> | void;
|
|
|
|
export type ErrorHandler = (
|
|
err: Error,
|
|
req: Request,
|
|
res: Response<ErrorResponse>,
|
|
next: NextFunction
|
|
) => void;
|
|
|
|
// Request logging types
|
|
export interface RequestLogData {
|
|
method: string;
|
|
url: string;
|
|
statusCode: number;
|
|
responseTime: string;
|
|
}
|
|
|
|
export interface WebhookHeaders {
|
|
// Gitea headers
|
|
'x-gitea-event'?: string;
|
|
'x-gitea-delivery'?: string;
|
|
'x-gitea-signature'?: string;
|
|
// Generic headers
|
|
'user-agent'?: string;
|
|
'content-type'?: string;
|
|
}
|
|
|
|
// Express app configuration
|
|
export interface AppConfig {
|
|
port: number;
|
|
bodyParserLimit?: string;
|
|
requestTimeout?: number;
|
|
rateLimitWindowMs?: number;
|
|
rateLimitMax?: number;
|
|
}
|
|
|
|
// Custom error types for Express handlers
|
|
export interface ValidationError extends Error {
|
|
statusCode: 400;
|
|
field?: string;
|
|
value?: unknown;
|
|
}
|
|
|
|
export interface AuthenticationError extends Error {
|
|
statusCode: 401;
|
|
challenge?: string;
|
|
}
|
|
|
|
export interface AuthorizationError extends Error {
|
|
statusCode: 403;
|
|
requiredPermission?: string;
|
|
}
|
|
|
|
export interface NotFoundError extends Error {
|
|
statusCode: 404;
|
|
resource?: string;
|
|
}
|
|
|
|
export interface WebhookVerificationError extends Error {
|
|
statusCode: 401;
|
|
signature?: string;
|
|
}
|
|
|
|
export interface RateLimitError extends Error {
|
|
statusCode: 429;
|
|
retryAfter?: number;
|
|
}
|