TypeScript API Reference
Complete reference for gaji's TypeScript API.
Core Classes
Workflow
Represents a GitHub Actions workflow.
class Workflow {
constructor(config: WorkflowConfig)
addJob(id: string, job: Job | CompositeJob | CallJob): this
static fromObject(def: WorkflowDefinition, id?: string): Workflow
build(filename?: string): void
toJSON(): WorkflowDefinition
}| Method | Description |
|---|---|
addJob(id, job) | Add a job to the workflow. Accepts Job, CompositeJob, or CallJob. |
fromObject(def, id?) | Create a Workflow from a raw WorkflowDefinition object. Useful for wrapping existing YAML-like definitions. |
build(filename?) | Compile and output the workflow as YAML. |
toJSON() | Serialize to a WorkflowDefinition object. |
WorkflowConfig
interface WorkflowConfig {
name: string
on: WorkflowTriggers
env?: Record<string, string>
permissions?: WorkflowPermissions
concurrency?: WorkflowConcurrency
}Example
const workflow = new Workflow({
name: "CI",
on: {
push: { branches: ["main"] },
pull_request: { branches: ["main"] },
},
env: {
NODE_ENV: "production",
},
})
.addJob("test", testJob)
.addJob("build", buildJob);
workflow.build("ci");Workflow.fromObject() Example
const workflow = Workflow.fromObject({
name: "Raw Workflow",
on: { push: {} },
jobs: {
test: {
"runs-on": "ubuntu-latest",
steps: [{ run: "echo hello" }],
},
},
});
workflow.build("raw");Job
Represents a job in a workflow.
class Job {
constructor(runsOn: string | string[], options?: Partial<JobDefinition>)
addStep(step: Step): this
needs(jobs: string | string[]): this
env(variables: Record<string, string>): this
when(condition: string): this
permissions(perms: Permissions): this
outputs(outputs: Record<string, string>): this
strategy(strategy: JobStrategy): this
continueOnError(v: boolean): this
timeoutMinutes(m: number): this
toJSON(): JobDefinition
}| Method | Description |
|---|---|
addStep(step) | Append a step to the job. |
needs(jobs) | Set job dependencies. |
env(variables) | Set environment variables. |
when(condition) | Set the job's if condition (e.g., "github.ref == 'refs/heads/main'"). |
permissions(perms) | Set job-level permissions (e.g., { contents: 'read' }). |
outputs(outputs) | Define job outputs. |
strategy(strategy) | Set matrix strategy. |
continueOnError(v) | Set the continue-on-error flag. |
timeoutMinutes(m) | Set the timeout-minutes value. |
toJSON() | Serialize to a JobDefinition object. |
The optional options parameter in the constructor allows setting all job options at once:
const job = new Job("ubuntu-latest", {
needs: ["test"],
env: { NODE_ENV: "production" },
"timeout-minutes": 30,
});Example
const job = new Job("ubuntu-latest")
.needs(["test"])
.env({
NODE_ENV: "production",
})
.when("github.event_name == 'push'")
.permissions({ contents: "read" })
.strategy({
matrix: {
node: ["18", "20", "22"],
},
})
.outputs({
version: "${{ steps.version.outputs.value }}",
})
.continueOnError(false)
.timeoutMinutes(30)
.addStep(checkout({}))
.addStep({ run: "npm test" });CompositeAction
Create reusable composite actions.
class CompositeAction {
constructor(config: CompositeActionConfig)
addStep(step: Step): this
build(filename: string): void
}CompositeActionConfig
interface CompositeActionConfig {
name: string
description: string
inputs?: Record<string, ActionInput>
outputs?: Record<string, ActionOutput>
}Example
import { CompositeAction } from "../generated/index.js";
const setupEnv = new CompositeAction({
name: "Setup Environment",
description: "Setup Node.js and install dependencies",
inputs: {
"node-version": {
description: "Node.js version",
required: true,
default: "20",
},
},
})
.addStep(checkout({}))
.addStep(setupNode({
with: {
"node-version": "${{ inputs.node-version }}",
},
}))
.addStep({
run: "npm ci",
});
setupEnv.build("setup-env");This generates action.yml that can be used like:
// In another workflow
const setupEnv = getAction("./setup-env");
const job = new Job("ubuntu-latest")
.addStep(setupEnv({
with: {
"node-version": "20",
},
}));JavaScriptAction
Create Node.js-based GitHub Actions.
class JavaScriptAction {
constructor(config: JavaScriptActionConfig, runs: JavaScriptActionRuns)
build(filename: string): void
}JavaScriptActionConfig
interface JavaScriptActionConfig {
name: string
description: string
inputs?: Record<string, ActionInputDefinition>
outputs?: Record<string, ActionOutputDefinition>
}JavaScriptActionRuns
interface JavaScriptActionRuns {
using: 'node12' | 'node16' | 'node20'
main: string
pre?: string
post?: string
'pre-if'?: string
'post-if'?: string
}Example
import { JavaScriptAction } from "../generated/index.js";
const action = new JavaScriptAction(
{
name: "Hello World",
description: "Greet someone and record the time",
inputs: {
"who-to-greet": {
description: "Who to greet",
required: true,
default: "World",
},
},
outputs: {
time: {
description: "The time we greeted you",
},
},
},
{
using: "node20",
main: "dist/index.js",
},
);
action.build("hello-world");This generates .github/actions/hello-world/action.yml.
Use CallAction.from() to reference it in a workflow:
const step = {
id: "hello",
...CallAction.from(action).toJSON(),
with: { "who-to-greet": "Mona the Octocat" },
};CompositeJob
Create reusable job templates via TypeScript class inheritance. CompositeJob extends Job, so all Job methods are available.
class CompositeJob extends Job {
constructor(runsOn: string | string[], options?: Partial<JobDefinition>)
}Unlike Job, CompositeJob is designed to be subclassed with extends to create domain-specific, parameterized job templates. It produces the same YAML output as a regular Job.
CompositeJob vs Job
Use Job directly for one-off jobs. Use CompositeJob when you want to create a reusable class that encapsulates a common job pattern with parameters.
Example
import { CompositeJob } from "../generated/index.js";
// Define a reusable job template
class NodeTestJob extends CompositeJob {
constructor(nodeVersion: string) {
super("ubuntu-latest");
this
.addStep(checkout({}))
.addStep(setupNode({
with: {
"node-version": nodeVersion,
},
}))
.addStep({ run: "npm ci" })
.addStep({ run: "npm test" });
}
}
// Use in workflows
const workflow = new Workflow({
name: "Test Matrix",
on: { push: { branches: ["main"] } },
})
.addJob("test-node-18", new NodeTestJob("18"))
.addJob("test-node-20", new NodeTestJob("20"))
.addJob("test-node-22", new NodeTestJob("22"));You can also create more complex reusable jobs:
class DeployJob extends CompositeJob {
constructor(environment: "staging" | "production") {
super("ubuntu-latest");
this
.env({
ENVIRONMENT: environment,
API_URL: environment === "production"
? "https://api.example.com"
: "https://staging.api.example.com",
})
.addStep(checkout({}))
.addStep(setupNode({ with: { "node-version": "20" } }))
.addStep({
name: "Deploy",
run: `npm run deploy:${environment}`,
env: {
DEPLOY_TOKEN: "${{ secrets.DEPLOY_TOKEN }}",
},
});
}
}
// Use in workflow
const workflow = new Workflow({
name: "Deploy",
on: { push: { tags: ["v*"] } },
})
.addJob("deploy-staging", new DeployJob("staging"))
.addJob("deploy-production", new DeployJob("production").needs(["deploy-staging"]));CallJob
Call a reusable workflow defined in another repository or file. Unlike Job, a CallJob has no steps — it delegates entirely to the referenced workflow via uses.
class CallJob {
constructor(uses: string)
with(inputs: Record<string, unknown>): this
secrets(s: Record<string, unknown> | 'inherit'): this
needs(deps: string | string[]): this
when(condition: string): this
permissions(perms: Permissions): this
toJSON(): object
}| Method | Description |
|---|---|
with(inputs) | Pass inputs to the reusable workflow. |
secrets(s) | Pass secrets explicitly, or use 'inherit' to forward all secrets. |
needs(deps) | Set job dependencies. |
when(condition) | Set the job's if condition. |
permissions(perms) | Set job-level permissions. |
Example
import { CallJob, Workflow } from "../generated/index.js";
const deploy = new CallJob("octo-org/deploy/.github/workflows/deploy.yml@main")
.with({ environment: "production" })
.secrets("inherit")
.needs(["build"]);
const workflow = new Workflow({
name: "Release",
on: { push: { tags: ["v*"] } },
})
.addJob("deploy", deploy);
workflow.build("release");Generated YAML:
jobs:
deploy:
uses: octo-org/deploy/.github/workflows/deploy.yml@main
with:
environment: production
secrets: inherit
needs:
- buildCallAction
Reference a local composite or JavaScript action built by gaji, for use as a step in a job.
class CallAction {
constructor(uses: string)
static from(action: CompositeAction | JavaScriptAction): CallAction
toJSON(): Step
}| Method | Description |
|---|---|
from(action) | Create a CallAction from a CompositeAction or JavaScriptAction instance. Automatically resolves the .github/actions/<id> path. |
Example
import { CompositeAction, CallAction, Job } from "../generated/index.js";
const setupEnv = new CompositeAction({
name: "Setup",
description: "Setup environment",
});
setupEnv.build("setup-env");
const job = new Job("ubuntu-latest")
.addStep({
...CallAction.from(setupEnv).toJSON(),
with: { "node-version": "20" },
});Functions
getAction()
Get a typed action function.
function getAction<T extends string>(
ref: T
): (config?: ActionConfig) => StepExample
const checkout = getAction("actions/checkout@v4");
const setupNode = getAction("actions/setup-node@v4");
// Use with full type safety
const step = checkout({
name: "Checkout code",
with: {
// ✅ Autocomplete available!
repository: "owner/repo",
ref: "main",
"fetch-depth": 0,
},
});Type Definitions
Step
A workflow step.
interface Step {
name?: string
id?: string
if?: string
uses?: string
with?: Record<string, string | number | boolean>
run?: string
env?: Record<string, string>
"continue-on-error"?: boolean
"timeout-minutes"?: number
}WorkflowTriggers
Workflow trigger events.
interface WorkflowTriggers {
push?: PushTrigger
pull_request?: PullRequestTrigger
schedule?: ScheduleTrigger[]
workflow_dispatch?: WorkflowDispatchTrigger
[key: string]: any
}
interface PushTrigger {
branches?: string[]
tags?: string[]
paths?: string[]
}
interface PullRequestTrigger {
branches?: string[]
types?: string[]
paths?: string[]
}
interface ScheduleTrigger {
cron: string
}JobStrategy
Job matrix strategy.
interface JobStrategy {
matrix?: {
[key: string]: string[] | number[]
}
"fail-fast"?: boolean
"max-parallel"?: number
}ActionInput
Action input definition (for CompositeAction).
interface ActionInput {
description: string
required?: boolean
default?: string
}ActionOutput
Action output definition (for CompositeAction).
interface ActionOutput {
description: string
value: string
}Examples
Complete Workflow
import { getAction, Job, Workflow } from "../generated/index.js";
const checkout = getAction("actions/checkout@v4");
const setupNode = getAction("actions/setup-node@v4");
const test = new Job("ubuntu-latest")
.addStep(checkout({}))
.addStep(setupNode({ with: { "node-version": "20" } }))
.addStep({ run: "npm ci" })
.addStep({ run: "npm test" });
const build = new Job("ubuntu-latest")
.needs(["test"])
.addStep(checkout({}))
.addStep(setupNode({ with: { "node-version": "20" } }))
.addStep({ run: "npm ci" })
.addStep({ run: "npm run build" });
const workflow = new Workflow({
name: "CI",
on: {
push: { branches: ["main"] },
pull_request: { branches: ["main"] },
},
})
.addJob("test", test)
.addJob("build", build);
workflow.build("ci");