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
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.
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:
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.
async function resolveDependenciesFromYaml(
yamlContent: string,
options?: LaunchpadResolverOptions
): Promise<LaunchpadInstallResult>
Example:
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.
async function resolvePackageDependencies(
packageName: string,
options?: LaunchpadResolverOptions
): Promise<LaunchpadPackage[]>
Example:
const deps = await resolvePackageDependencies('gnu.org/grep')
// Returns: ['gnu.org/grep', 'pcre.org/v2', 'zlib.net', ...]
Response Format
All resolution functions return a LaunchpadInstallResult
:
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
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
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
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
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
// 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
global: true
dependencies:
bun.sh: ^1.2.16
gnu.org/bash: ^5.2.37
gnu.org/grep: ^3.12.0
With Comments
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
dependencies:
openssl.org: ^1.1
linux:gnu.org/gcc: '*'
darwin:apple.com/xcode: '*'
Complex Version Constraints
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:
- Caret constraints (^): Compatible within major version
- Tilde constraints (~): Compatible within minor version
- Range constraints: Uses comparison operators (>=, <=, >, <)
- Exact versions: Takes precedence over ranges
- Latest: Falls back to newest available version
Example conflict resolution:
# 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:
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:
- Parse 7 direct dependencies
- Resolve ~60 total packages (including all transitive dependencies)
- Handle 9 version conflicts automatically
- Generate platform-specific install commands
- 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
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
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:
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:
// Check if package exists
const deps = await resolvePackageDependencies('nonexistent.package')
// Returns empty array if package not found
Version conflicts:
// 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:
// Platform-specific resolution
const result = await resolveDependencies('./deps.yaml', {
targetOs: 'linux',
includeOsSpecific: false // Skip OS-specific deps
})
Next Steps
- See API Reference for complete type definitions
- Check CLI Reference for command-line usage
- View Examples for more integration patterns
- Read Advanced Usage for complex scenarios