@hyperfrontend/versioning/flow/modelsmodels
Type definitions and immutable builders for version flows and their steps.
VersionFlow is the top-level shape carrying steps, configuration, and metadata; FlowStep is the per-step shape carrying an ID, a condition, and an executor. createFlow, addStep, removeStep, insertStep, insertStepAfter, and insertStepBefore are the immutable builders — every operation returns a new VersionFlow rather than mutating in place. FlowConfig, FlowContext, FlowResult, FlowState, FlowStatus, FlowStepResult, and FlowStepResultWithId describe the runtime surface that the executor threads through each step.
API Reference
ƒ Functions
Returns
VersionFlowExample
Adding a custom step to a flow
import { addStep, createConventionalFlow, createNoopStep } from '@hyperfrontend/versioning'
const flow = createConventionalFlow()
const extended = addStep(flow, createNoopStep('custom', 'Custom Step'))
console.log(extended.steps.length)
// => original steps + 1Parameters
Returns
FlowStepResultExample
Handling step execution errors
import { createFailedResult } from '@hyperfrontend/versioning'
// In a step handler:
try {
await doOperation()
} catch (err) {
return createFailedResult(err as Error, 'Operation failed')
}createFlow(id: string, name: string, steps: unknown, options: CreateFlowOptions): VersionFlow
Parameters
Returns
VersionFlowExample
Creating a custom flow
const myFlow = createFlow(
'custom',
'Custom Release Flow',
[fetchStep, analyzeStep, bumpStep],
{ description: 'My custom versioning workflow' }
)Parameters
Returns
FlowStepExample
Creating a placeholder step
import { createNoopStep, executeStep } from '@hyperfrontend/versioning'
const step = createNoopStep('placeholder', 'Placeholder Step')
const result = await executeStep(step, context)
console.log(result.status)
// => 'success'Parameters
| Name | Type | Description |
|---|---|---|
§message | string | Explanation for why the step was skipped |
Returns
FlowStepResultExample
Skipping a step conditionally
import { createSkippedResult } from '@hyperfrontend/versioning'
// In a step handler:
if (!config.enabled) {
return createSkippedResult('Feature disabled in config')
}createStep(id: string, name: string, execute: StepExecutor, options: CreateStepOptions): FlowStep
Parameters
Returns
FlowStepExample
Creating a custom fetch step
const fetchStep = createStep(
'fetch-registry',
'Fetch Registry Version',
async (ctx) => {
const version = await ctx.registry.getLatestVersion(ctx.packageName)
return {
status: 'success',
stateUpdates: { publishedVersion: version },
message: `Found published version: ${version}`
}
}
)Parameters
Returns
FlowStepResultExample
Returning a success result with state updates
import { createSuccessResult } from '@hyperfrontend/versioning'
// In a step handler:
return createSuccessResult('Updated 3 files', {
modifiedFiles: ['/path/a.ts', '/path/b.ts', '/path/c.ts']
})Returns
FlowStepExample
Getting a step by ID
import { getStep, createConventionalFlow } from '@hyperfrontend/versioning'
const flow = createConventionalFlow()
const step = getStep(flow, 'analyze-commits')
console.log(step?.name)
// => 'Analyze Commits'Returns
booleanExample
Checking if a flow has a step
import { hasStep, createConventionalFlow } from '@hyperfrontend/versioning'
const flow = createConventionalFlow()
console.log(hasStep(flow, 'create-commit'))
// => true
console.log(hasStep(flow, 'custom-step'))
// => falseParameters
Returns
VersionFlowExample
Inserting a step at a specific position
import { insertStep, createConventionalFlow, createNoopStep } from '@hyperfrontend/versioning'
const flow = createConventionalFlow()
const modified = insertStep(flow, createNoopStep('early', 'Early Step'), 0)
console.log(modified.steps[0].id)
// => 'early'Parameters
Returns
VersionFlowExample
Inserting a step after another step
import { insertStepAfter, createConventionalFlow, createNoopStep } from '@hyperfrontend/versioning'
const flow = createConventionalFlow()
const modified = insertStepAfter(flow, createNoopStep('validate', 'Validate'), 'analyze-commits'))
// 'validate' step now follows 'analyze-commits'Parameters
Returns
VersionFlowExample
Inserting a step before another step
import { insertStepBefore, createConventionalFlow, createNoopStep } from '@hyperfrontend/versioning'
const flow = createConventionalFlow()
const modified = insertStepBefore(flow, createNoopStep('prep', 'Prepare'), 'create-commit'))
// 'prep' step now runs before 'create-commit'Parameters
Returns
VersionFlowExample
Removing a step from a flow
import { removeStep, createConventionalFlow } from '@hyperfrontend/versioning'
const flow = createConventionalFlow()
const minimal = removeStep(flow, 'generate-changelog')
// Flow no longer has changelog step
console.log(minimal.steps.find(s => s.id === 'generate-changelog'))
// => undefinedParameters
Returns
VersionFlowExample
Replacing a step with a custom implementation
import { replaceStep, createConventionalFlow, createNoopStep } from '@hyperfrontend/versioning'
const flow = createConventionalFlow()
const modified = replaceStep(flow, 'create-tag', createNoopStep('create-tag', 'Custom Tag'))
// 'create-tag' now uses custom implementationParameters
Returns
VersionFlowExample
Updating flow configuration
import { withConfig, createConventionalFlow } from '@hyperfrontend/versioning'
const flow = createConventionalFlow()
const dryRunFlow = withConfig(flow, { dryRun: true })
// Flow now runs in dry-run mode◈ Interfaces
Properties
readonly backupChangelog?:boolean— When enabled:
- Existing
CHANGELOG.mdis renamed toCHANGELOG.backup.md - New changelog is written
- Backup is deleted on success
readonly commitTypeToSection?:Partial<Record<string, ChangelogSectionType | null>>— null to exclude a type from changelog.readonly maxCommitFallback?:number— Set higher if you expect >500 commits between releases.
readonly releaseAs?:"minor" | "patch" | "major"— readonly repository?:RepositoryConfig | "inferred" | "disabled" | RepositoryResolution— Controls how repository information is resolved:
'disabled': No compare URLs generated (default, backward compatible)'inferred': Auto-detect from package.json or git remoteRepositoryResolution: Fine-grained control with explicit mode and optionsRepositoryConfig: Direct repository configuration
readonly scopeFiltering?:ScopeFilteringConfig— By default, hybrid filtering ensures commits are included based on conventional commit scope OR file changes within the project.
Note:
state is mutable within context to allow accumulation, but individual FlowState objects are immutable.Properties
Properties
readonly diffs?:unknown— showDiff: true is passed to executeFlow. Provides unified diff format for programmatic access.Properties
readonly classificationResult?:ClassificationResult— readonly effectiveBaseCommit?:string— publishedCommit if that commit is reachable from HEAD, or null if a fallback was used (e.g., history was rewritten). When null, compare URLs are omitted from the changelog.
readonly isPendingPublication?:boolean— - nextVersion is calculated from publishedVersion (not currentVersion)
- Changelog entries > publishedVersion should be cleaned up
- The correct changelog entry replaces any stacked ones
Steps are pure functions that:
- Read from context (state, config, services)
- Perform work (possibly with side effects via services)
- Return state updates
Properties
Properties
Properties
Flows are immutable configurations that define:
- What steps to execute
- In what order
- With what configuration
◆ Types
type FlowStatus = "success" | "partial" | "failed" | "skipped"type StepCondition = (context: FlowContext) => booleantype StepExecutor = (context: FlowContext) => Promise<FlowStepResult>