jste-framework
v1.0.4
Published
A framework for defining and running composable tasks. Tasks are plain classes; the framework handles data piping, parallel execution, YAML-based configuration, and dynamic module loading.
Readme
JavaScript Task Executor
A framework for defining and running composable tasks. Tasks are plain classes; the framework handles data piping, parallel execution, YAML-based configuration, and dynamic module loading.
Requires Node.js 18 or later for ESM consumers. If you load the package via require() (CommonJS), Node.js 22.12 or later is required — that is when Node.js added support for require()-ing ES modules.
Install
npm install jste-frameworkCore concepts
Task is the basic unit of work — an abstract class with a single execute(data) method. Each task instance carries three key-value containers:
| Container | Purpose |
|---|---|
| TaskData | Input/output data. Piped between tasks in a pipeline. |
| Config | Static settings loaded from the YAML config: block. |
| TaskInfo | Metadata (name, description, etc.). |
Job runs a set of tasks concurrently, each with its own data; outputs are discarded. If any task throws, all are still allowed to finish and errors are aggregated into one.
Pipeline (extends Job) runs tasks sequentially, forwarding each task's output TaskData as the next task's input.
Writing a task
import { Task, TaskData } from 'jste-framework';
export class Greet extends Task {
async execute(data: TaskData): Promise<TaskData> {
const name = data.get('name') ?? 'world';
data.set('message', `Hello, ${name}!`);
return data;
}
}Compile to .js, then point your config or CLI at the output file.
CLI
Install globally or link the package, then:
# Run a single task — argument is <path/to/file.js>.<ClassName>
npx jste execute task ./dist/tasks/Greet.Greet
# Run a pipeline — tasks execute left-to-right, data piped between them
npx jste execute pipeline ./dist/tasks/Fetch.Fetch ./dist/tasks/Transform.Transform
# Pass initial data with -d (repeatable)
npx jste execute task ./dist/tasks/Greet.Greet -d name=Alice
# Use a YAML config — tasks can then be referenced by their registered name
${env:JSTE_TASKS}='absolute/path/to/config.jste.yaml'
npx jste execute task greetJSTE_TASKS accepts semicolon-separated paths to YAML files or folders.
YAML configuration
Name your config file config.jste.yaml:
version: 1
basePath: ./tasks # Base directory for resolving relative module paths
tasks:
- name: greet
module: ./Greet.js
className: Greet
config: # Passed to the task as its Config object
greeting: Hello
data: # Pre-loaded into the task's TaskData
name: world
- name: transform
module: ./Transform.js
className: Transform
pipelines:
- name: full-run
tasks:
- greet
- transform
data:
name: Alice # Initial data for the first task in the pipelineSet the env var and the CLI (or TaskManager) picks it up:
${env:JSTE_TASKS}='absolute/path/to/config.jste.yaml'
npx jste execute task greet
npx jste execute pipeline full-runProgrammatic API
import { TaskManager } from 'jste-framework';
const manager = new TaskManager();
await manager.loadConfigFile('./config.jste.yaml');
// By registered name (from YAML)
const task = await manager.getTask('greet');
await task?.call();
// By module path (no YAML needed)
const adhoc = await manager.getTask('./dist/tasks/Greet.Greet');
await adhoc?.call();
// Pipeline by registered name, or by assembling task names on the fly
const pipeline = await manager.getTaskPipeline(['greet', 'transform']);
await pipeline?.call();Building a pipeline manually
import { Pipeline, TaskData } from 'jste-framework';
const pipeline = new Pipeline();
pipeline.addTask(new StepOne());
pipeline.addTask(new StepTwo());
const output = await pipeline.execute(new TaskData({ input: 'start' }));
console.log(output.get('result'));Dual package (ESM + CJS)
The package ships both ESM (dist/index.js) and CJS (index.cjs). Node.js resolves the right one automatically depending on the caller's module system. TypeScript consumers get .d.ts declarations from the ESM build.
