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"