Organizing your composition
A flat chain of .step(...) works for a small app. Once it grows, the layout stops reflecting the structure:
compose() .step(createWire({ from: literal("https://api"), to: apiUrl })) .step([auth, loadTranslations]) .step([fetchUser, fetchPermissions]) .step(dashboard) .run()The shape carries order — nothing about what belongs to what. The Wire for apiUrl and the auth Task that reads it are in different steps. auth shares its step with loadTranslations, which isn’t part of auth. The auth chain spreads across three steps; reusing it elsewhere means copying lines.
Nesting
Section titled “Nesting”A .step(...) also accepts another compose() — group related work into a block, mix sequential and parallel in one step, name reusable parts of your app.
compose() .step([ loadTranslations, compose() .step(createWire({ from: literal("https://api"), to: apiUrl })) .step(auth) .step([fetchUser, fetchPermissions]), ]) .step(dashboard) .run()Only the outer compose() calls .run() — it runs everything inside.
Presets
Section titled “Presets”A preset is a named compose() — a variable when no arguments are needed, a function when they are.
import { compose, createTask, tag, createWire, literal } from "@grlt-hub/app-compose"
/** preset */
const apiUrl = tag<string>("api-url")
const auth = createTask({ name: "auth", run: { context: { url: apiUrl.value }, fn: () => ({ id: 1 }), },})
const fetchUser = createTask({ name: "fetch-user", run: { context: { id: auth.result.id }, fn: (ctx) => { console.log(`User: id=${ctx.id}; name="John"`) }, },})
const fetchPermissions = createTask({ name: "fetch-permissions", run: { context: { id: auth.result.id }, fn: () => { console.log(`Permissions fetched`) }, },})
// or as a function: (url: string) => compose()...const authPreset = compose() .step(createWire({ from: literal("https://api"), to: apiUrl })) .step(auth) .step([fetchUser, fetchPermissions])
/** composition */
const loadTranslations = createTask({ name: "load-translations", run: { fn: () => console.log(`Translations fetched`), },})
const dashboard = createTask({ name: "dashboard", run: { fn: () => console.log("Dashboard ready") },})
compose().step([loadTranslations, authPreset]).step(dashboard).run()