flow/

Composable versioning workflow system for orchestrating release operations.

Overview

This module provides a declarative flow execution engine for versioning workflows. Flows are sequences of steps that perform operations like fetching registry versions, analyzing commits, calculating bumps, generating changelogs, and creating git commits/tags.

Architecture

API

Factory

Function Description Implementation
createVersionFlow(preset, cfg?) Create a flow from a preset factory.ts
createDryRunFlow(preset, cfg?) Create a dry-run flow factory.ts
getAvailablePresets() List available presets factory.ts
getPresetDescription(preset) Get human-readable preset description factory.ts

Presets

Preset Description Implementation
conventional Standard conventional commits workflow conventional.ts
independent Independent versioning with dependency tracking independent.ts
synced All packages share the same version synced.ts

Executor

Function Description Implementation
executeFlow(flow, project, root, opts) Execute a flow execute.ts
dryRun(flow, project, root, opts) Execute without making changes execute.ts
validateFlow(flow) Validate flow structure execute.ts

FlowExecutionOptions:

Option Default Description
showDiff false Preview changes before committing to VFS
diffFormat 'unified' Diff format: 'unified' or 'simple'
rollbackOnFailure false Discard all VFS changes if any step fails

Models

Type Description Implementation
VersionFlow Complete flow definition with steps and config flow.ts
FlowStep Single step with execute function and conditions step.ts
FlowConfig Flow configuration options types.ts
FlowContext Execution context with services and state types.ts
FlowState Accumulated state during execution types.ts
FlowResult Execution result with status and step results types.ts
FlowStepResult Individual step execution result types.ts

Step Factories

Function Description Implementation
createFetchRegistryStep() Fetch published version from registry fetch-registry.ts
createResolveRepositoryStep() Resolve repository for compare URLs resolve-repository.ts
createAnalyzeCommitsStep() Parse commits since last release analyze-commits.ts
createCalculateBumpStep() Calculate version bump type calculate-bump.ts
createCheckIdempotencyStep() Skip if version already published fetch-registry.ts
createGenerateChangelogStep() Generate changelog entry generate-changelog.ts
createWriteChangelogStep(opts?) Write changelog to file generate-changelog.ts

WriteChangelogStepOptions:

Option Default Description
backupChangelog false Backup existing changelog before writing (uses tree.rename())
createUpdatePackageStep() Update package.json version update-packages.ts
createCascadeDependenciesStep() Update dependent package versions update-packages.ts
createGitCommitStep() Create version commit create-commit.ts
createTagStep() Create git tag create-tag.ts
createPushTagStep() Push tag to remote create-tag.ts

Flow Manipulation

Function Description Implementation
createFlow(id, name, steps, opts?) Create custom flow flow.ts
createStep(id, name, execute, opts?) Create custom step step.ts
addStep(flow, step) Append step to flow flow.ts
removeStep(flow, stepId) Remove step by ID flow.ts
insertStep(flow, step, index) Insert step at position flow.ts
insertStepAfter(flow, step, afterId) Insert after specific step flow.ts
insertStepBefore(flow, step, beforeId) Insert before specific step flow.ts
replaceStep(flow, stepId, newStep) Replace step by ID flow.ts
withConfig(flow, config) Update flow configuration flow.ts
getStep(flow, stepId) Get step by ID flow.ts
hasStep(flow, stepId) Check if step exists flow.ts

Usage

Basic Execution

import { createConventionalFlow, executeFlow } from '@hyperfrontend/versioning/flow'

const flow = createConventionalFlow({ dryRun: true })
const result = await executeFlow(flow, 'lib-utils', '/workspace')

console.log(result.summary)
// "Flow success in 234ms: 8 completed, 0 skipped, 0 failed. Version: 1.2.3 → 1.3.0"

Custom Flow

import {
  createFlow,
  createFetchRegistryStep,
  createAnalyzeCommitsStep,
  createCalculateBumpStep,
  executeFlow,
} from '@hyperfrontend/versioning/flow'

const minimalFlow = createFlow('minimal', 'Minimal Flow', [
  createFetchRegistryStep(),
  createAnalyzeCommitsStep(),
  createCalculateBumpStep(),
])

const result = await executeFlow(minimalFlow, 'lib-utils', '/workspace', {
  dryRun: true,
})

Custom Step

import { createStep, addStep, createConventionalFlow } from '@hyperfrontend/versioning/flow'

const notifyStep = createStep(
  'notify',
  'Send Notification',
  async (ctx) => {
    const { state } = ctx
    console.log(`Released ${state.nextVersion}`)
    return { status: 'success', message: 'Notification sent' }
  },
  { dependsOn: ['create-commit'] }
)

let flow = createConventionalFlow()
flow = addStep(flow, notifyStep)

Flow Execution Lifecycle

Configuration

Option Type Default Description
preset string 'conventional' Flow preset name
releaseTypes string[] ['feat', 'fix', 'perf', 'revert'] Types that trigger releases
minorTypes string[] ['feat'] Types that trigger minor bumps
patchTypes string[] ['fix', 'perf', 'revert'] Types that trigger patch bumps
skipGit boolean false Skip git operations
skipTag boolean true Skip tag creation
skipChangelog boolean false Skip changelog update
dryRun boolean false Preview without changes
commitMessage string 'chore(${projectName}): release...' Commit message template
tagFormat string '${projectName}@${version}' Tag name template
trackDeps boolean false Track dependency bumps
releaseBranch string 'main' Allowed release branch
firstReleaseVersion string '0.1.0' Initial version for new packages
releaseAs string undefined Force bump type: 'major', 'minor', or 'patch'
maxCommitFallback number 500 Max commits to analyze when no base available
repository * undefined Repository config for compare URLs (see below)
changelogFileName string 'CHANGELOG.md' Custom changelog filename
commitTypeToSection object undefined Custom commit type → section mapping (see below)

Repository Configuration

The repository option controls compare URL generation in changelog entries:

// Auto-detect from package.json or git remote
createVersionFlow('conventional', { repository: 'inferred' })

// Disable compare URLs
createVersionFlow('conventional', { repository: 'disabled' })

// Explicit configuration
createVersionFlow('conventional', {
  repository: {
    mode: 'explicit',
    repository: {
      platform: 'github',
      baseUrl: 'https://github.com/owner/repo',
    },
  },
})

// Inferred with custom order
createVersionFlow('conventional', {
  repository: {
    mode: 'inferred',
    inferenceOrder: ['git-remote', 'package-json'], // Try git first
  },
})

When repository is resolved, changelog entries include compare URLs:

## [1.2.0](https://github.com/owner/repo/compare/v1.1.0...v1.2.0) - 2026-03-17

Commit Type to Section Mapping

The commitTypeToSection option customizes how commit types map to changelog sections:

createVersionFlow('conventional', {
  commitTypeToSection: {
    // Override default mapping
    chore: 'other',

    // Add custom commit type
    wip: 'other',

    // Exclude type from changelog
    docs: null,
  },
})

Default mapping:

Commit Type Section
feat features
fix fixes
perf performance
docs documentation
refactor refactoring
revert other
build build
ci ci
test tests
chore chores
style other

Unmapped types fall back to chores. Use null to exclude a type entirely.

Step Dependencies

Steps can declare dependencies using dependsOn:

const tagStep = createStep('create-tag', 'Create Tag', execute, {
  dependsOn: ['create-commit'], // Only runs after create-commit succeeds
})

The executor respects dependencies and skips steps when dependencies fail.

Error Handling

Steps can use continueOnError to allow the flow to continue:

const optionalStep = createStep('optional', 'Optional Step', execute, {
  continueOnError: true, // Flow continues even if this fails
})

Flow results include detailed step-by-step outcomes:

const result = await executeFlow(flow, project, root)

for (const step of result.steps) {
  console.log(`${step.stepName}: ${step.status}`)
  if (step.error) {
    console.error(step.error.message)
  }
}

See Also

  • commits/ — Commit parsing for analyze-commits step
  • semver/ — Version bumping for calculate-bump step
  • changelog/ — Changelog generation step
  • git/ — Git operations for commit/tag steps
  • registry/ — Registry queries for fetch-registry step
  • workspace/ — Workspace operations for batch flows
  • Main README — Package overview and quick start
  • ARCHITECTURE.md — Design principles and data flow