Foundations
Blueprint as a pipeline
The Blueprint does not spring into existence complete. It is produced by a pipeline that runs once, before any event: a sequence of steps, each handed the manifest so far and free to add to or refine it. This is the build phase, and it is where extensibility lives.
#Setup is a chain of responsibility
The principle
A configuration built by one monolithic function is closed: to change it, you edit that function. A configuration built by a pipeline is open: to change it, you insert a step. Composition replaces modification.
In Stone.js
The BlueprintBuilder runs a pipeline of blueprint middleware. Every adapter and extension contributes steps that read the current manifest and write their own stone.* keys. The order is deterministic; later steps refine earlier ones.
The manifest is not configured. It is composed, one step at a time, before the first event.
#A step in the build
A blueprint step is a pipe: it receives the build context (the manifest under construction) and calls next to pass it on. It can inspect what previous steps decided and contribute accordingly.
import { defineBlueprintMiddleware } from '@stone-js/core'
export const withDefaults = defineBlueprintMiddleware((context, next) => {
const { blueprint } = context
if (!blueprint.has('stone.tasks.pageSize')) {
blueprint.set('stone.tasks.pageSize', 20) // refine the manifest
}
return next(context) // hand it to the next step
})#Why this matters for the ecosystem
Because setup is a pipeline, the core never has to know about the packages that extend it. An adapter adds its steps; an extension adds its steps; a community package adds its steps, all by insertion, none by editing the kernel. The micro-kernel stays tiny while the ecosystem grows around it.