Use Cases
This page starts from the command a user wants to type, then maps it to the
smallest func model that keeps the CLI predictable. The examples assume
the executable name is saas.
Static Command
The user needs a quick health check for the SaaS service, such as whether the
API, database, and background workers are available. status is a stable
top-level verb, so model it as a normal @Command with one default
@Handler. This keeps command discovery, help output, and future
options attached to the right scope.
import { Command, Handler } from 'func'
@Command({
name: 'status',
description: 'Print service status',
})
export class StatusCommand {
@Handler()
run() {
console.log('All systems operational')
}
}Command With a Path
The user needs to manage domains, and adding a domain is one fixed action under
that domain workflow. domain is the command, and add is a
static action under that command. Use @Handler({ path: ['add'] })
when the action is a fixed path inside an already selected command.
import { Command, Handler } from 'func'
@Command({
name: 'domain',
description: 'Manage custom domains',
})
export class DomainCommand {
@Handler({ path: ['add'] })
add() {
console.log('Adding domain')
}
}Command With Flags and a Value
The user needs to register a domain and optionally create an issue or run DNS
checks during the same operation. register is still a static command.
Boolean switches become @Flag fields, and the domain becomes a required
@Value. This lets func parse, assign, and validate the options
before the handler runs.
import { Command, Flag, Handler, Required, Value } from 'func'
@Command({
name: 'register',
description: 'Register a domain and optional checks',
})
export class RegisterCommand {
@Flag({ description: 'Create an issue after registration' })
issue = false
@Flag({ description: 'Run DNS checks' })
dns = false
@Required()
@Value({ type: String })
domain?: string
@Handler()
run() {
console.log(this.domain, {
issue: this.issue,
dns: this.dns,
})
}
}Fallback Search Input
The user needs to fuzzy-search users by several possible names or aliases, then
shape the returned users by requesting profile details and limiting results to
verified accounts. Here the first token is not a fixed command; it is part of the
search input. Use @CommandMissing as a first-class fallback command, then
keep the result filters as typed flags.
import { Args, CommandMissing, Flag, FuncArgs, Handler } from 'func'
@CommandMissing()
export class UserSearchFallback {
@Flag({ description: 'Include profile details' })
includeProfile = false
@Flag({ description: 'Only return verified users' })
verified = false
@Handler()
async search(@Args() args: FuncArgs) {
const [username, ...aliases] = args.inputs
console.log('Searching user:', {
username,
aliases,
includeProfile: this.includeProfile,
verified: this.verified,
})
}
}Repeated Values With an Enum
The user needs to resize the deployment to multiple machines in one command, and
each machine must use a supported size. scale is a static command, but
--machine can be repeated. Use @ArrayValue for repeated input
and @Enum to reject machine types outside the allowed set.
import { ArrayValue, Command, Enum, Handler } from 'func'
const MACHINES = ['1x-1024m', '1x-2048m', '2x-1024m', '2x-2048m']
@Command({
name: 'scale',
description: 'Scale machines',
})
export class ScaleCommand {
@Enum(MACHINES)
@ArrayValue({ name: 'machine' })
machines: string[] = []
@Handler()
run() {
console.log('Scaling to:', this.machines)
}
}