A comprehensive cross-platform package management abstraction library that enables developers to programmatically install, manage, and find packages across multiple package managers including npm, yarn, pnpm, bun for Node.js projects, and CocoaPods for iOS projects.
—
Pending
Does it follow best practices?
Impact
Pending
No eval scenarios have been run
Pending
The risk profile of this skill
Workspace detection, offline support, environment detection, and advanced promise utilities for package management operations.
Utilities for detecting and working with monorepo/workspace configurations.
/**
* Resolves the workspace root directory if the project is part of a monorepo
* Uses the resolve-workspace-root package to detect various workspace configurations
*
* @param projectRoot - The current project directory
* @returns Workspace root path or null if not in a workspace
*/
function resolveWorkspaceRoot(projectRoot: string): string | null;Usage Examples:
import { resolveWorkspaceRoot, createForProject } from '@expo/package-manager';
const workspaceRoot = resolveWorkspaceRoot('/path/to/nested/package');
if (workspaceRoot) {
console.log(`Found workspace at: ${workspaceRoot}`);
// Create manager for workspace root
const rootManager = createForProject(workspaceRoot);
// Install dependencies at workspace level
await rootManager.installAsync();
} else {
console.log('Not in a workspace');
}Utilities for detecting when Yarn should run in offline mode.
/**
* Determine if you should use yarn offline or not by checking network connectivity
* and proxy configuration
*
* @returns Promise resolving to true if Yarn should run in offline mode
*/
function isYarnOfflineAsync(): Promise<boolean>;
/**
* Get the npm proxy configuration from environment or npm config
* Exposed for testing
*
* @returns Proxy URL string or null if no proxy configured
*/
function getNpmProxy(): string | null;Usage Examples:
import { isYarnOfflineAsync } from '@expo/package-manager';
// Check if Yarn should run offline
const offline = await isYarnOfflineAsync();
console.log(`Yarn offline mode: ${offline}`);
// This is automatically used by YarnPackageManager internally
const yarn = new YarnPackageManager({ cwd: projectRoot });
await yarn.installAsync(); // Automatically adds --offline flag if neededUtilities for detecting CI environments and other execution contexts.
class Env {
/** Determine if the package manager is running in a CI environment */
get CI(): boolean;
}
// Singleton instance
declare const env: Env;Usage Examples:
import env from '@expo/package-manager/build/utils/env';
if (env.CI) {
console.log('Running in CI environment');
// PNPM automatically adds --no-frozen-lockfile in CI
}Special promise types and utilities for handling delayed spawn operations.
/**
* The pending spawn promise is similar to the spawn promise from @expo/spawn-async.
* Instead of the child process being available immediately, the child is behind another promise.
* We need this to perform async tasks before running the actual spawn promise.
*/
interface PendingSpawnPromise<T> extends Promise<T> {
/**
* The child process from the delayed spawn.
* This is null whenever the promise before the spawn promise is rejected.
*/
child: Promise<SpawnPromise<T>['child'] | null>;
}
/**
* Create a pending spawn promise that performs an async action before spawning a process
*
* @param actionAsync - Async action to perform before spawning
* @param spawnAsync - Function that creates the spawn promise
* @returns PendingSpawnPromise that resolves to the spawn result
*/
function createPendingSpawnAsync<V, T>(
actionAsync: () => Promise<V>,
spawnAsync: (result: V) => SpawnPromise<T>
): PendingSpawnPromise<T>;Usage Examples:
import { createPendingSpawnAsync } from '@expo/package-manager';
// This is used internally by package managers for operations like:
// 1. Check if should run offline (async)
// 2. Then run the actual command (spawn)
const pendingOperation = createPendingSpawnAsync(
async () => {
// Perform async setup
const shouldUseOffline = await isYarnOfflineAsync();
return shouldUseOffline ? ['install', '--offline'] : ['install'];
},
(args) => spawnAsync('yarn', args)
);
// Access the result
const result = await pendingOperation;
// Access the child process (after async setup completes)
const child = await pendingOperation.child;
if (child) {
// child.pid, child.kill(), etc.
}Lower-level utilities for process spawning and management.
/**
* Environment variables automatically set by BasePackageManager
*/
interface DefaultEnvironment {
/** Disable advertisements in package manager output */
ADBLOCK: '1';
/** Disable OpenCollective messages */
DISABLE_OPENCOLLECTIVE: '1';
}Usage Examples:
// These environment variables are automatically set by all package managers
// to reduce noise in output:
const manager = new NpmPackageManager({ cwd: projectRoot });
// Automatically sets ADBLOCK=1 and DISABLE_OPENCOLLECTIVE=1Constants used throughout the package management system.
// Lockfile names
const NPM_LOCK_FILE = 'package-lock.json';
const YARN_LOCK_FILE = 'yarn.lock';
const PNPM_LOCK_FILE = 'pnpm-lock.yaml';
const BUN_LOCK_FILE = 'bun.lockb';
const BUN_TEXT_LOCK_FILE = 'bun.lock';
// Resolution order for automatic package manager detection
const RESOLUTION_ORDER: NodePackageManager['name'][] = ['bun', 'yarn', 'npm', 'pnpm'];Usage Examples:
import {
NPM_LOCK_FILE,
YARN_LOCK_FILE,
RESOLUTION_ORDER
} from '@expo/package-manager';
import fs from 'fs';
import path from 'path';
// Check for specific lockfiles
const hasNpmLock = fs.existsSync(path.join(projectRoot, NPM_LOCK_FILE));
const hasYarnLock = fs.existsSync(path.join(projectRoot, YARN_LOCK_FILE));
// Understand resolution priority
console.log('Package managers checked in order:', RESOLUTION_ORDER);
// ['bun', 'yarn', 'npm', 'pnpm']Network-related utilities used by package managers.
/**
* Check if a URL/hostname is reachable via DNS lookup
* Used internally by isYarnOfflineAsync
*/
function isUrlAvailableAsync(url: string): Promise<boolean>;This function is used internally but not exported. The Yarn offline detection works as follows:
registry.yarnpkg.com is reachabletrue (use offline) if network/proxy is not availableUtilities for improving error messages and debugging package manager operations.
Silent Mode Support:
// All package managers support silent mode
const silentManager = createForProject(projectRoot, {
silent: true,
log: console.debug // Custom logging function
});
// Silent mode:
// - Sets stdio to undefined instead of 'inherit'
// - Disables automatic console.log for commands
// - Allows custom log function for debuggingCommand Logging:
// By default, all package managers log executed commands
const manager = createForProject(projectRoot);
await manager.runAsync(['audit']);
// Logs: "> npm audit" (or yarn, pnpm, bun equivalent)
// Custom logging
const customManager = createForProject(projectRoot, {
log: (message) => console.log(`[PKG] ${message}`)
});
await customManager.runAsync(['install']);
// Logs: "[PKG] > npm install"