Buddy Class API
On this page 38
The Buddy class is the main entry point for programmatic dependency management. It provides methods for scanning dependencies across multiple file formats (package.json, Launchpad/pkgx dependency files), creating pull requests, and managing updates.
Constructor
interface BuddyConstructor {
new(config: BuddyConfig, projectPath?: string): Buddy
}
Parameters
- config (
BuddyConfig): Configuration object - projectPath (
string, optional): Project root path (defaults toprocess.cwd())
Example
import { Buddy } from '@buddysh/buddy'
const buddy = new Buddy({
verbose: true,
repository: {
provider: 'github',
owner: 'your-org',
name: 'your-repo'
},
packages: {
strategy: 'patch',
ignore: ['@types/node']
}
}, '/path/to/project')
Core Methods
scanForUpdates()
Scans the project for available dependency updates.
interface BuddyMethods {
scanForUpdates: () => Promise<UpdateScanResult>
}
Returns
UpdateScanResult object containing:
interface UpdateScanResult {
totalPackages: number
updates: PackageUpdate[]
groups: UpdateGroup[]
scannedAt: Date
duration: number
}
Example
const buddy = new Buddy(config)
const scanResult = await buddy.scanForUpdates()
console.log(`Found ${scanResult.updates.length} updates`)
scanResult.groups.forEach((group) => {
console.log(`${group.name}: ${group.updates.length} packages`)
})
createPullRequests()
Creates pull requests for dependency updates.
interface BuddyPRMethods {
createPullRequests: (scanResult: UpdateScanResult) => Promise<void>
}
Parameters
- scanResult (
UpdateScanResult): Result fromscanForUpdates()
Example
const scanResult = await buddy.scanForUpdates()
if (scanResult.updates.length > 0) {
await buddy.createPullRequests(scanResult)
console.log('Pull requests created successfully')
}
run()
Runs the complete update process: scans, then creates pull requests when
pullRequest is configured.
interface BuddyRunMethod {
run: () => Promise<UpdateScanResult>
}
Returns
UpdateScanResult with the scan results
Example
const buddy = new Buddy(config)
const result = await buddy.run()
if (result.updates.length === 0) {
console.log('No updates available!')
}
else {
console.log(`Created PRs for ${result.groups.length} update groups`)
}
checkPackages()
Checks specific packages for updates.
interface BuddyCheckMethods {
checkPackages: (packageNames: string[]) => Promise<PackageUpdate[]>
}
Parameters
- packageNames (
string[]): Array of package names to check
Returns
Array of PackageUpdate objects
Example
const updates = await buddy.checkPackages(['react', 'typescript'])
updates.forEach((update) => {
console.log(`${update.name}: ${update.currentVersion} → ${update.newVersion}`)
})
Utility Methods
generateAllFileUpdates()
Generates file changes for all update types (package.json, dependency files, GitHub Actions).
interface FileChange {
path: string
content: string
type: 'update'
}
interface BuddyUtilityMethods {
generateAllFileUpdates: (updates: PackageUpdate[]) => Promise<FileChange[]>
}
Parameters
- updates (
PackageUpdate[]): Array of package updates
Returns
Array of file change objects
Example
const updates = await buddy.scanForUpdates()
const fileChanges = await buddy.generateAllFileUpdates(updates.updates)
fileChanges.forEach((change) => {
console.log(`Updated ${change.path}`)
// change.content contains the new file content
})
getConfig()
Returns the current configuration.
interface BuddyConfigMethods {
getConfig: () => BuddyConfig
}
Returns
The current BuddyConfig object
Example
const config = buddy.getConfig()
console.log(`Strategy: ${config.packages?.strategy}`)
Types
BuddyConfig
Main configuration interface:
interface BuddyConfig {
verbose?: boolean
repository?: {
/** Only 'github' is implemented; the others are rejected at validation */
provider: 'github' | 'gitlab' | 'bitbucket'
owner: string
name: string
baseBranch?: string
token?: string
}
packages?: {
/** 'all': every update · 'major': majors only · 'minor': minors and patches · 'patch': patches only */
strategy: 'major' | 'minor' | 'patch' | 'all'
/** Package names, matched exactly */
ignore?: string[]
pin?: Record<string, string>
groups?: PackageGroup[]
}
pullRequest?: {
commitMessageFormat?: string
titleFormat?: string
bodyTemplate?: string
autoMerge?: {
enabled: boolean
strategy: 'merge' | 'squash' | 'rebase'
conditions?: string[]
}
reviewers?: string[]
assignees?: string[]
labels?: string[]
}
schedule?: {
cron?: string
timezone?: string
}
}
PackageUpdate
Represents a single package update:
interface PackageUpdate {
name: string
currentVersion: string
newVersion: string
updateType: 'major' | 'minor' | 'patch'
/** 'dependencies' | 'devDependencies' | 'github-actions' | 'docker-image' | … */
dependencyType: Dependency['type']
/** Manifest the dependency was found in */
file: string
metadata?: PackageMetadata
releaseNotesUrl?: string
changelogUrl?: string
homepage?: string
securityAdvisories?: SecurityAdvisory[]
}
UpdateGroup
Groups related package updates:
interface UpdateGroup {
name: string
updates: PackageUpdate[]
updateType: 'major' | 'minor' | 'patch'
title: string
body: string
}
UpdateScanResult
Result of scanning for updates:
interface UpdateScanResult {
totalPackages: number
updates: PackageUpdate[]
groups: UpdateGroup[]
scannedAt: Date
duration: number
}
Error Handling
Configuration Errors
The constructor does not validate. A missing repository is reported when it
is needed — createPullRequests() logs Repository configuration required for PR creation and returns without opening anything — so check the configuration
before you rely on it:
import { Buddy, formatConfigIssues, validateConfig } from '@buddysh/buddy'
const issues = validateConfig(config)
if (issues.length > 0)
throw new Error(formatConfigIssues(issues))
if (!config.repository?.owner || !config.repository?.name)
throw new Error('repository.owner and repository.name are required to open pull requests')
const buddy = new Buddy(config)
GitHub Token Errors
When no token can be resolved — neither repository.token, nor GITHUB_TOKEN,
nor BUDDY_TOKEN — creating the provider throws No token for github. Set one of: GITHUB_TOKEN, BUDDY_TOKEN.
try {
await buddy.createPullRequests(scanResult)
}
catch (error) {
if (error.message.includes('No token for')) {
// Handle missing or invalid GitHub token
}
}
Network Errors
try {
const scanResult = await buddy.scanForUpdates()
}
catch (error) {
if (error.code === 'ENOTFOUND') {
// Handle network connectivity issues
}
}
Advanced Usage
Custom Package Groups
const buddy = new Buddy({
packages: {
strategy: 'all',
groups: [
{
name: 'React Ecosystem',
patterns: ['react', 'react-dom', '@types/react'],
strategy: 'minor'
},
{
name: 'Testing Tools',
patterns: ['jest', '@types/jest', 'testing-library/*'],
strategy: 'patch'
}
]
}
})
Conditional Updates
const scanResult = await buddy.scanForUpdates()
// Only create PRs for patch updates
const patchUpdates = scanResult.updates.filter(u => u.updateType === 'patch')
if (patchUpdates.length > 0) {
const patchScanResult = {
...scanResult,
updates: patchUpdates,
groups: scanResult.groups.map(g => ({
...g,
updates: g.updates.filter(u => u.updateType === 'patch')
})).filter(g => g.updates.length > 0)
}
await buddy.createPullRequests(patchScanResult)
}
Integration with CI/CD
import { Buddy } from '@buddysh/buddy'
async function updateDependencies() {
const buddy = new Buddy({
verbose: process.env.NODE_ENV === 'development',
repository: {
provider: 'github',
owner: process.env.GITHUB_OWNER!,
name: process.env.GITHUB_REPO!,
},
packages: {
strategy: process.env.UPDATE_STRATEGY as any || 'patch'
},
// `run()` only opens pull requests when `pullRequest` is configured
pullRequest: {
labels: ['dependencies']
}
})
try {
const result = await buddy.run()
if (result.updates.length === 0) {
console.log('✅ All dependencies are up to date')
process.exit(0)
}
console.log(`✅ Created ${result.groups.length} PR(s) for ${result.updates.length} updates`)
}
catch (error) {
console.error('❌ Update failed:', error)
process.exit(1)
}
}
// Run in CI environment
if (process.env.CI) {
updateDependencies()
}