Organise your package versioning and publishing to make both contributors and maintainers happy
—
Quality
Pending
Does it follow best practices?
Impact
Pending
No eval scenarios have been run
Package publishing automates the process of releasing packages to npm registries with support for 2FA, custom tags, git tagging, and multi-package coordination.
The primary function for publishing packages to npm and creating git tags.
/**
* Publishes packages to npm registry and creates git tags
* @param cwd - Working directory path
* @param options.otp - One-time password for 2FA authentication
* @param options.tag - Custom npm dist-tag (defaults to "latest")
* @param options.gitTag - Whether to create git tags (defaults to true)
* @param config - Changesets configuration object
*/
function publish(
cwd: string,
options: {otp?: string, tag?: string, gitTag?: boolean},
config: Config
): Promise<void>;Usage Examples:
import { run } from "@changesets/cli";
// Standard publishing
await run(["publish"], {}, cwd);
// Publishing with 2FA token
await run(["publish"], { otp: "123456" }, cwd);
// Publishing with custom tag
await run(["publish"], { tag: "beta" }, cwd);
// Publishing without git tags
await run(["publish"], { gitTag: false }, cwd);Lower-level function for publishing individual packages with detailed control.
/**
* Core package publishing logic for multiple packages
* @param options.packages - Array of packages to publish
* @param options.access - Package access level (public or restricted)
* @param options.otp - One-time password for 2FA
* @param options.preState - Prerelease state for coordinated prereleases
* @param options.tag - Custom npm dist-tag
* @returns Array of publish results with success/failure status
*/
function publishPackages(options: {
packages: Package[],
access: AccessType,
otp?: string,
preState: PreState | undefined,
tag?: string
}): Promise<PublishedResult[]>;Usage Examples:
import publishPackages from "@changesets/cli/src/commands/publish/publishPackages";
const results = await publishPackages({
packages: packagesToPublish,
access: "public",
otp: process.env.NPM_OTP,
preState: undefined,
tag: "latest"
});
// Check results
results.forEach(result => {
if (result.published) {
console.log(`✓ Published ${result.name}@${result.newVersion}`);
} else {
console.log(`✗ Failed to publish ${result.name}`);
}
});Utilities for handling npm registry configuration and authentication.
/**
* Determines the correct npm registry for a package
* @param packageJson - Package.json object (optional)
* @returns Registry information including scope and URL
*/
function getCorrectRegistry(packageJson?: PackageJSON): RegistryInfo;
/**
* Checks if 2FA token is required for publishing
* @returns Promise resolving to boolean indicating 2FA requirement
*/
function getTokenIsRequired(): Promise<boolean>;
/**
* Gets package information from npm registry
* @param packageJson - Package.json object
* @returns Promise resolving to package registry information
*/
function getPackageInfo(packageJson: PackageJSON): Promise<any>;
/**
* Gets package info from registry, handling 404s gracefully
* @param packageJson - Package.json object
* @returns Promise resolving to publish status and package info
*/
function infoAllow404(
packageJson: PackageJSON
): Promise<{published: boolean, pkgInfo: any}>;Comprehensive 2FA support for secure publishing:
/**
* Gets 2FA token from user input or existing state
* @param twoFactorState - Current 2FA state object
* @returns Promise resolving to OTP token string
*/
function getOtpCode(twoFactorState: TwoFactorState): Promise<string>;
/**
* Publishes a single package to npm with 2FA support
* @param packageJson - Package.json object
* @param opts - Publishing options including registry and access
* @param twoFactorState - 2FA state for token management
* @returns Promise resolving to publish result
*/
function publish(
packageJson: PackageJSON,
opts: PublishOptions,
twoFactorState: TwoFactorState
): Promise<{published: boolean}>;2FA State Management:
interface TwoFactorState {
token: string | null;
isRequired: Promise<boolean>;
}Publishing automatically creates git tags for published versions:
// Default tag format: {packageName}@{version}
// Examples:
// @myorg/ui@1.2.0
// my-package@2.1.0Separate tag creation for packages that were published externally:
/**
* Creates git tags for published packages
* @param cwd - Working directory path
* @param config - Changesets configuration object
*/
function tag(cwd: string, config: Config): Promise<void>;Utility to find packages missing git tags after publishing:
/**
* Finds packages that are missing git tags
* @param packages - Array of package objects
* @param cwd - Working directory path
* @param tool - Package manager tool type
* @returns Promise resolving to array of packages needing tags
*/
function getUntaggedPackages(
packages: Package[],
cwd: string,
tool: Tool
): Promise<PublishedResult[]>;type AccessType = "restricted" | "public";
// Configuration options
interface Config {
access: "restricted" | "public"; // Default access level
privatePackages: {
version: boolean; // Whether to version private packages
tag: boolean; // Whether to tag private packages
};
}Individual packages can override global access settings:
{
"name": "@myorg/public-package",
"publishConfig": {
"access": "public"
}
}Support for publishing scoped packages to custom registries:
interface RegistryInfo {
scope?: string; // Package scope (e.g., "@myorg")
registry: string; // Registry URL
}// .npmrc configuration examples
registry=https://registry.npmjs.org/
@myorg:registry=https://npm.myorg.com/
//npm.myorg.com/:_authToken=${NPM_TOKEN}For packages in prerelease mode:
// Prerelease packages use the prerelease tag
// Example: 1.0.0-beta.1 published with tag "beta"
await publish(cwd, { tag: "beta" }, config);Snapshot releases are published with temporary versions:
// Snapshot versions like 0.0.0-20231201-abc1234
// Published with "snapshot" tag by default
await publish(cwd, { tag: "snapshot" }, config);The publishing system includes built-in retry logic for transient failures:
// Automatic retry for network-related failures
// Manual retry prompts for authentication issues
// Graceful degradation for partial publish failuresWhen publishing multiple packages, the system handles partial failures gracefully:
interface PublishedResult {
name: string;
newVersion: string;
published: boolean;
}
// Results indicate which packages succeeded/failed
// Failed packages can be retried individually
// Git tags are only created for successfully published packages{
"access": "restricted",
"privatePackages": {
"version": true,
"tag": false
}
}Integration with custom publish workflows:
{
"scripts": {
"changeset:publish": "changeset publish",
"changeset:publish:beta": "changeset publish --tag beta",
"changeset:publish:dry": "changeset publish --dry-run"
}
}interface PublishOptions {
registry?: string;
tag?: string;
access?: AccessType;
dryRun?: boolean;
}
interface PublishedResult {
name: string;
newVersion: string;
published: boolean;
}
type Tool = "yarn" | "npm" | "pnpm";
interface PreState {
mode: "pre";
tag: string;
initialVersions: Record<string, string>;
changesets: string[];
}Install with Tessl CLI
npx tessl i tessl/npm-changesets--cli