Skip to content

Launchpad Integration

This guide covers the Launchpad Dependency Resolution API, a powerful feature of ts-pkgx that enables automatic resolution and installation of package dependencies with deep transitive dependency analysis.

Overview

The Launchpad API provides comprehensive dependency resolution for package managers and deployment tools, allowing you to:

  • 🔍 Deep dependency resolution - Automatically resolves all transitive dependencies
  • Version conflict resolution - Intelligently handles conflicting version constraints
  • 🎯 OS-specific dependencies - Supports platform-specific packages
  • 📄 Multiple input formats - Supports YAML files, strings, and individual packages
  • 🔧 Semantic versioning - Proper semver constraint handling (^, ~, >=, etc.)
  • 🚀 Optimized deduplication - Removes duplicate packages and resolves conflicts

Quick Start

typescript
import { resolveDependencies } from 'ts-pkgx'

// Resolve from dependency file
const result = await resolveDependencies('./deps.yaml', {
  targetOs: 'darwin',
  includeOsSpecific: true
})

console.log(`Installing ${result.totalCount} packages...`)

// Install each resolved package
for (const pkg of result.packages) {
  await launchpad.install(pkg.name, pkg.version)
}

API Functions

resolveDependencies()

Resolves all dependencies from a YAML dependency file with complete transitive dependency analysis.

typescript
async function resolveDependencies(
  filePath: string,
  options?: LaunchpadResolverOptions
): Promise<LaunchpadInstallResult>

Parameters:

  • filePath - Path to dependency file (deps.yaml, pkgx.yaml, etc.)
  • options - Optional resolution configuration

Example:

typescript
const result = await resolveDependencies('./project-deps.yaml', {
  targetOs: 'darwin',
  includeOsSpecific: true,
  maxDepth: 10,
  verbose: false
})

// result contains packages, conflicts, commands, etc.

resolveDependenciesFromYaml()

Resolves dependencies directly from a YAML string without requiring a file.

typescript
async function resolveDependenciesFromYaml(
  yamlContent: string,
  options?: LaunchpadResolverOptions
): Promise<LaunchpadInstallResult>

Example:

typescript
const yamlContent = `
global: true
dependencies:
  bun.sh: ^1.2.16
  gnu.org/grep: ^3.12.0
  ffmpeg.org: ^7.1.1
`

const result = await resolveDependenciesFromYaml(yamlContent, {
  targetOs: 'darwin'
})

resolvePackageDependencies()

Resolves all transitive dependencies for a single package.

typescript
async function resolvePackageDependencies(
  packageName: string,
  options?: LaunchpadResolverOptions
): Promise<LaunchpadPackage[]>

Example:

typescript
const deps = await resolvePackageDependencies('gnu.org/grep')
// Returns: ['gnu.org/grep', 'pcre.org/v2', 'zlib.net', ...]

Response Format

All resolution functions return a LaunchpadInstallResult:

typescript
interface LaunchpadInstallResult {
  packages: LaunchpadPackage[] // All packages to install
  directCount: number // Number of direct dependencies
  totalCount: number // Total packages including transitive
  conflicts: Array<{ // Version conflicts resolved
    package: string
    versions: string[]
    resolved: string
  }>
  pkgxCommand: string // Ready-to-use pkgx install command (direct deps only)
  launchpadCommand: string // Ready-to-use launchpad install command (direct deps only)
}

interface LaunchpadPackage {
  name: string // Package domain (e.g., 'bun.sh')
  version: string // Resolved version (e.g., '1.2.19')
  constraint: string // Original constraint (e.g., '^1.2.16')
  isOsSpecific: boolean // Whether OS-specific
  os?: 'linux' | 'darwin' | 'windows'
}

Configuration Options

typescript
interface LaunchpadResolverOptions {
  targetOs?: 'linux' | 'darwin' | 'windows' // Target platform
  includeOsSpecific?: boolean // Include OS-specific deps
  maxDepth?: number // Max recursion depth (default: 10)
  verbose?: boolean // Show detailed output
}

Integration Examples

Basic Launchpad Integration

typescript
import { resolveDependencies } from 'ts-pkgx'

export class LaunchpadInstaller {
  async installFromDepsFile(filePath: string) {
    const result = await resolveDependencies(filePath, {
      targetOs: process.platform === 'darwin' ? 'darwin' : 'linux',
      includeOsSpecific: true
    })

    // Install each package
    for (const pkg of result.packages) {
      console.log(`Installing ${pkg.name}@${pkg.version}...`)
      await this.install(pkg.name, pkg.version)
    }

    return {
      installed: result.totalCount,
      conflicts: result.conflicts.length,
      directDeps: result.directCount
    }
  }

  async installFromYaml(yamlContent: string) {
    const result = await resolveDependenciesFromYaml(yamlContent)
    return this.installFromPackageList(result.packages)
  }

  private async install(packageName: string, version: string) {
    // Your Launchpad installation logic here
    // Note: Launchpad should auto-resolve transitive dependencies
    console.log(`pkgx ${packageName}@${version}`)
  }
}

Batch Installation

typescript
export async function batchInstall(packages: string[]) {
  const allDeps = new Set<string>()

  // Resolve dependencies for each package
  for (const pkg of packages) {
    const deps = await resolvePackageDependencies(pkg)
    deps.forEach(dep => allDeps.add(`${dep.name}@${dep.version}`))
  }

  // Install all unique packages
  for (const pkgSpec of allDeps) {
    const [name, version] = pkgSpec.split('@')
    await launchpad.install(name, version)
  }
}

Error Handling

typescript
export async function safeInstall(depsFile: string) {
  try {
    const result = await resolveDependencies(depsFile, {
      verbose: true
    })

    if (result.conflicts.length > 0) {
      console.warn('Version conflicts resolved:')
      result.conflicts.forEach((conflict) => {
        console.warn(`  ${conflict.package}: [${conflict.versions.join(', ')}] → ${conflict.resolved}`)
      })
    }

    return await this.installPackages(result.packages)
  }
  catch (error) {
    console.error('Dependency resolution failed:', error.message)
    throw new Error(`Failed to resolve dependencies from ${depsFile}`)
  }
}

CI/CD Integration

typescript
// GitHub Actions / CI pipeline integration
export async function ciInstall() {
  const depsFile = process.env.DEPS_FILE || './deps.yaml'
  const targetOs = process.env.RUNNER_OS?.toLowerCase() || 'linux'

  const result = await resolveDependencies(depsFile, {
    targetOs: targetOs as 'linux' | 'darwin' | 'windows',
    includeOsSpecific: true,
    verbose: true
  })

  console.log(`::notice::Resolved ${result.totalCount} packages from ${result.directCount} direct dependencies`)

  if (result.conflicts.length > 0) {
    console.log(`::warning::Resolved ${result.conflicts.length} version conflicts`)
  }

  // Set output for next steps
  console.log(`::set-output name=packages::${result.packages.map(p => p.name).join(' ')}`)
  console.log(`::set-output name=install-command::${result.pkgxCommand}`)

  return result
}

Supported Dependency File Formats

Standard Format

yaml
global: true
dependencies:
  bun.sh: ^1.2.16
  gnu.org/bash: ^5.2.37
  gnu.org/grep: ^3.12.0

With Comments

yaml
global: true
dependencies:
  # Runtime dependencies
  bun.sh: ^1.2.16 # JavaScript runtime
  gnu.org/grep: ^3.12.0 # Text search utility

  # Development tools
  cli.github.com: ^2.73.0 # GitHub CLI

OS-Specific Dependencies

yaml
dependencies:
  openssl.org: ^1.1
  linux:gnu.org/gcc: '*'
  darwin:apple.com/xcode: '*'

Complex Version Constraints

yaml
dependencies:
  # Caret ranges (compatible within major version)
  node.js: ^18.0.0

  # Tilde ranges (compatible within minor version)
  python.org: ~3.11.0

  # Comparison operators
  go.dev: '>=1.20.0'
  rust-lang.org: <1.75.0

  # Exact versions
  bun.sh: 1.2.19

  # Latest available
  deno.land: latest
  cli.github.com: '*'

Version Conflict Resolution

The API automatically resolves version conflicts using semantic versioning rules:

  1. Caret constraints (^): Compatible within major version
  2. Tilde constraints (~): Compatible within minor version
  3. Range constraints: Uses comparison operators (>=, <=, >, <)
  4. Exact versions: Takes precedence over ranges
  5. Latest: Falls back to newest available version

Example conflict resolution:

yaml
# Input dependencies
packageA_deps: somelib ^2.1.0
packageB_deps: somelib ~2.2.0
packageC_deps: somelib >=2.0.0

# Resolved to: somelib@2.2.1 (satisfies all constraints)

Performance Considerations

  • Parallel Resolution: Dependencies are resolved concurrently for speed
  • Caching: Package metadata is cached to avoid repeated API calls
  • Deduplication: Duplicate packages are automatically removed
  • Depth Limiting: Configurable recursion depth to prevent infinite loops
  • Optimized Parsing: YAML parsing is optimized for large dependency files

Real-World Example

Given this dependency file:

yaml
global: true
dependencies:
  bun.sh: ^1.2.16
  gnu.org/bash: ^5.2.37
  gnu.org/grep: ^3.12.0
  crates.io/eza: ^0.21.3
  ffmpeg.org: ^7.1.1
  cli.github.com: ^2.73.0
  starship.rs: ^1.23.0

The resolver will:

  1. Parse 7 direct dependencies
  2. Resolve ~60 total packages (including all transitive dependencies)
  3. Handle 9 version conflicts automatically
  4. Generate platform-specific install commands
  5. Provide complete dependency graph ready for installation

Output includes:

  • All resolved packages with exact versions
  • Version conflict resolutions
  • Ready-to-use install commands:
    • pkgxCommand: Installs only 7 direct dependencies (transitive deps auto-resolved)
    • launchpadCommand: Installs only 7 direct dependencies (transitive deps auto-resolved)
  • OS-specific dependency handling
  • Comprehensive error reporting

Install Commands

Both install commands are optimized for modern package managers that auto-resolve transitive dependencies:

pkgxCommand - pkgx Installation

bash
pkgx install bun.sh gnu.org/bash gnu.org/grep crates.io/eza ffmpeg.org cli.github.com starship.rs
  • Includes only the 7 direct dependencies from your deps file
  • pkgx auto-resolves and installs all transitive dependencies
  • Fast and efficient installation

launchpadCommand - Launchpad Installation

bash
launchpad install bun.sh gnu.org/bash gnu.org/grep crates.io/eza ffmpeg.org cli.github.com starship.rs
  • Includes only the 7 direct dependencies from your deps file
  • Launchpad auto-resolves and installs all transitive dependencies
  • Recommended for Launchpad integrations

Benefits of Direct Dependencies Only

  • Faster installations: Only install what you explicitly need
  • Automatic resolution: Package managers handle transitive dependencies
  • Clean dependency files: Focus on direct requirements
  • Less network overhead: Fewer explicit package downloads

Access to Full Dependency Tree

While the install commands only include direct dependencies, the full resolved dependency tree is still available in the packages array for analysis, conflict resolution, or custom installation logic:

typescript
const result = await resolveDependencies('./deps.yaml')

// Install commands use direct deps only
console.log(result.pkgxCommand) // "pkgx install bun.sh gnu.org/bash gnu.org/grep"

// But full dependency tree is available for analysis
console.log(`Resolved ${result.totalCount} total packages:`)
result.packages.forEach((pkg) => {
  console.log(`${pkg.name}@${pkg.version}`)
})

Troubleshooting

Common Issues

Missing packages:

typescript
// Check if package exists
const deps = await resolvePackageDependencies('nonexistent.package')
// Returns empty array if package not found

Version conflicts:

typescript
// Monitor conflicts
const result = await resolveDependencies('./deps.yaml', { verbose: true })
console.log(`Conflicts: ${result.conflicts.length}`)
result.conflicts.forEach((conflict) => {
  console.log(`${conflict.package}: ${conflict.versions.join(', ')} → ${conflict.resolved}`)
})

OS compatibility:

typescript
// Platform-specific resolution
const result = await resolveDependencies('./deps.yaml', {
  targetOs: 'linux',
  includeOsSpecific: false // Skip OS-specific deps
})

Next Steps

Released under the MIT License.