Unified deployment monitoring across GitHub Actions, Vercel, and Railway
Deployment Monitoring
The DeploymentOverseer provides unified deployment monitoring across GitHub Actions, Vercel, and Railway. It normalizes deployment status, commit tracking, and event callbacks into a single interface.
Installation
import {
DeploymentOverseer,
createDeploymentOverseer,
GitHubActionsWatcher,
VercelDeploymentWatcher,
RailwayDeploymentWatcher,
createGitHubWatcher,
createVercelWatcher,
createGitHubWatcherFromEnv,
createVercelWatcherFromEnv,
createRailwayWatcherFromEnv,
} from "@codmir/overseer";Quick Start
From Environment Variables
The simplest setup reads API tokens from environment variables automatically.
import { createDeploymentOverseer } from "@codmir/overseer";
// Reads GITHUB_TOKEN, VERCEL_TOKEN, RAILWAY_API_TOKEN from env
const overseer = createDeploymentOverseer();
// Watch all providers for a specific commit
const deployments = await overseer.watchCommit("abc1234", {
onSuccess: (d) => console.log(`${d.provider} deployed: ${d.url}`),
onError: (d) => console.error(`${d.provider} failed: ${d.error}`),
onLog: (msg) => console.log(msg),
});Manual Configuration
import {
DeploymentOverseer,
createGitHubWatcher,
createVercelWatcher,
} from "@codmir/overseer";
const github = createGitHubWatcher({
token: process.env.GITHUB_TOKEN!,
owner: "codmir",
repo: "codmir",
});
const vercel = createVercelWatcher({
token: process.env.VERCEL_TOKEN!,
projectId: "prj_abc123",
});
const overseer = new DeploymentOverseer({ github, vercel });DeploymentOverseer
Constructor
new DeploymentOverseer(options: {
github?: GitHubActionsWatcher;
vercel?: VercelDeploymentWatcher;
railway?: RailwayDeploymentWatcher;
})Pass only the watchers you need. Unconfigured providers are skipped.
watchCommit(commitSha, callbacks?): Promise<UnifiedDeployment[]>
Watches a commit SHA across all configured providers simultaneously. Returns when all provider watches complete.
watchCommit(
commitSha: string,
callbacks?: UnifiedWatchCallbacks,
): Promise<UnifiedDeployment[]>const deployments = await overseer.watchCommit("a1b2c3d", {
onStatusChange: (deployment) => {
console.log(`${deployment.provider}: ${deployment.status}`);
},
onSuccess: (deployment) => {
console.log(`Deployed to ${deployment.url}`);
},
onError: (deployment) => {
console.error(`Failed: ${deployment.error}`);
// Trigger incident
},
onLog: (message) => {
process.stdout.write(message);
},
});watch(provider, deploymentId, callbacks?): Promise<UnifiedDeployment>
Watches a specific deployment by provider and deployment ID.
watch(
provider: DeploymentProvider,
deploymentId: string,
callbacks?: UnifiedWatchCallbacks,
): Promise<UnifiedDeployment>const deployment = await overseer.watch("vercel", "dpl_abc123", {
onLog: (msg) => console.log(msg),
});Throws if the requested provider is not configured.
stopAll(): void
Stops all active watches across all providers.
overseer.stopAll();Provider Watchers
GitHubActionsWatcher
Monitors GitHub Actions workflow runs.
import { createGitHubWatcher, createGitHubWatcherFromEnv } from "@codmir/overseer";
// Manual config
const watcher = createGitHubWatcher({
token: "ghp_...",
owner: "codmir",
repo: "codmir",
});
// From GITHUB_TOKEN, GITHUB_REPOSITORY env vars
const watcher = createGitHubWatcherFromEnv();GitHubWatcherConfig
| Property | Type | Description |
|---|---|---|
token | string | GitHub personal access token |
owner | string | Repository owner |
repo | string | Repository name |
VercelDeploymentWatcher
Monitors Vercel deployments.
import { createVercelWatcher, createVercelWatcherFromEnv } from "@codmir/overseer";
// Manual config
const watcher = createVercelWatcher({
token: "vercel_...",
projectId: "prj_abc123",
teamId: "team_xyz",
});
// From VERCEL_TOKEN, VERCEL_PROJECT_ID env vars
const watcher = createVercelWatcherFromEnv();VercelWatcherConfig
| Property | Type | Description |
|---|---|---|
token | string | Vercel API token |
projectId | string | Vercel project ID |
teamId | string | Vercel team ID (optional) |
RailwayDeploymentWatcher
Monitors Railway deployments.
import { createRailwayWatcherFromEnv } from "@codmir/overseer";
// From RAILWAY_API_TOKEN, RAILWAY_PROJECT_ID env vars
const watcher = createRailwayWatcherFromEnv();RailwayWatcherConfig
| Property | Type | Description |
|---|---|---|
token | string | Railway API token |
projectId | string | Railway project ID |
Types
DeploymentProvider
type DeploymentProvider = "github" | "vercel" | "railway";UnifiedDeployment
All deployments are normalized to this shape regardless of provider.
interface UnifiedDeployment {
id: string;
provider: DeploymentProvider;
status: "pending" | "building" | "deploying" | "success" | "failed" | "canceled";
url?: string;
commitSha?: string;
branch?: string;
createdAt: string;
completedAt?: string;
error?: string;
}UnifiedWatchCallbacks
interface UnifiedWatchCallbacks {
onStatusChange?: (deployment: UnifiedDeployment) => void;
onSuccess?: (deployment: UnifiedDeployment) => void;
onError?: (deployment: UnifiedDeployment) => void;
onLog?: (message: string) => void;
}Status Mapping
Provider-specific statuses are mapped to UnifiedDeployment.status:
| Provider | Source Status | Unified Status |
|---|---|---|
| GitHub | queued, in_progress | building |
| GitHub | completed + success | success |
| GitHub | completed + failure | failed |
| GitHub | completed + cancelled | canceled |
| Vercel | QUEUED | pending |
| Vercel | INITIALIZING, BUILDING | building |
| Vercel | READY | success |
| Vercel | ERROR | failed |
| Vercel | CANCELED | canceled |
| Railway | BUILDING | building |
| Railway | DEPLOYING | deploying |
| Railway | SUCCESS | success |
| Railway | FAILED, CRASHED | failed |
| Railway | REMOVED | canceled |
Integration with Incidents
Combine deployment monitoring with incident management to auto-create incidents on deploy failures:
import { createDeploymentOverseer, createIncidentManager } from "@codmir/overseer";
const deployments = createDeploymentOverseer();
const incidents = createIncidentManager({ autoAssignAgent: true });
const results = await deployments.watchCommit(commitSha, {
onError: async (deployment) => {
await incidents.createIncident({
projectId: "proj_abc",
title: `Deploy failed on ${deployment.provider}`,
description: deployment.error || "Unknown error",
source: "build_failure",
severity: "high",
fingerprint: `deploy_fail:${deployment.provider}:${deployment.branch}`,
metadata: {
provider: deployment.provider,
deploymentId: deployment.id,
commitSha: deployment.commitSha,
branch: deployment.branch,
},
});
},
});