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 to process.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 from scanForUpdates()

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()
}
Suggest a change to this page

Last updated: