Declarative workflow DSL for orchestrating complex business operations in Node.js / TypeScript.
Documentation · npm · Package README
npm install @celom/proseimport { createFlow, ValidationError } from '@celom/prose';
const checkout = createFlow<{ userId: string; cart: CartItem[]; coupon?: string }>('checkout')
.validate('inputs', (ctx) => {
if (ctx.input.cart.length === 0)
throw ValidationError.single('cart', 'Cart is empty');
})
.parallel('hydrate', 'shallow',
async (ctx) => ({ user: await db.users.find(ctx.input.userId) }),
async (ctx) => ({ stock: await inventory.check(ctx.input.cart, { signal: ctx.signal }) }),
)
.breakIf(
(ctx) => ctx.state.stock.outOfStock.length > 0,
(ctx) => ({ status: 'out_of_stock' as const, items: ctx.state.stock.outOfStock }),
)
.stepIf('applyCoupon', (ctx) => !!ctx.input.coupon, async (ctx) => {
const discount = await pricing.redeem(ctx.input.coupon!, ctx.state.user.id);
return { discount };
})
.step('chargeCard', async (ctx) => {
const receipt = await stripe.charge({
userId: ctx.state.user.id,
amount: total(ctx.input.cart, ctx.state.discount),
signal: ctx.signal,
});
return { receipt };
})
.withRetry({
maxAttempts: 3,
delayMs: 200,
backoffMultiplier: 2,
shouldRetry: (e) => e.code !== 'card_declined',
})
.transaction('persist', async (ctx, tx) => {
const order = await tx.orders.insert({
userId: ctx.state.user.id,
items: ctx.input.cart,
receiptId: ctx.state.receipt.id,
});
await tx.inventory.decrement(ctx.input.cart);
return { order };
})
.events('outbox', [
(ctx) => ({ eventType: 'order.placed', orderId: ctx.state.order.id }),
(ctx) => ({ eventType: 'payment.succeeded', receiptId: ctx.state.receipt.id }),
])
.map((_, state) => ({ status: 'placed' as const, orderId: state.order.id }))
.build();
await checkout.execute(
{ userId: 'u_42', cart, coupon: 'WELCOME10' },
{ db, stripe, inventory, pricing, eventPublisher },
{ timeout: 15_000, observer: pinoObserver, correlationId: req.id },
);One flow declaration captures fail-fast validation, parallel hydration, idempotent early exit, conditional branching, retried external calls, transactional persistence, multi-event publishing, and a typed output shape — with full type-safe state threading and cooperative cancellation via ctx.signal. Add an opt-in durability store and the same flow survives a process crash without re-running completed steps.
The full guide lives at celom.github.io/prose:
- Getting started and core concepts
- API reference:
createFlow, flow builder, execution options, error types, observers, durability store - Guides: retries, timeouts & cancellation, transactions, events, parallel execution, conditional steps, sub-flows, durability, error handling, observability
- Runnable examples: order processing, order processing with durability, user onboarding
- Comparison — when to reach for Prose versus Temporal, Inngest, Effect, or XState
| Package | Description |
|---|---|
@celom/prose |
Core workflow library — see the package README |
Prose ships with a built-in Model Context Protocol server that helps AI assistants write correct flow code. Add to your MCP client config:
{
"mcpServers": {
"prose": {
"command": "npx",
"args": ["-y", "@celom/prose", "mcp"]
}
}
}See the MCP guide for the tools, resources, and prompts the server exposes.
This is an Nx monorepo.
# install dependencies
npm install
# run tests
npx nx test prose
# build the library
npx nx build prose
# run the docs site locally
npx nx dev docsCreated and maintained by Carlos Mimoso.
MIT