Skip to main content

CNStra API Reference - Neurons, Signals, Collaterals, Context

collateral<T>(id: string)

Create a typed output channel.

const userEvent = collateral<{ userId: string }>('user:event');
const simpleEvent = collateral('simple:event');

neuron(id: string, axon: Axon)

Create a neuron with the given axon.

const myNeuron = neuron('my-neuron', { output: myCollateral });

Signal ownership

Signal ownership

A neuron may emit only collaterals declared in its own axon. It must not emit another neuron's collaterals. Cross-neuron orchestration is done by having a controller own request collaterals and letting each domain neuron emit its own responses.

Incorrect (emits someone else's collateral):

// DON'T: myNeuron emits otherAxon.some
return otherAxon.some.createSignal(result);

Correct (controller-owned request, domain emits its own):

const controller = neuron('controller', { requestA });
const serviceA = neuron('serviceA', { doneA })
.dendrite({ collateral: requestA, response: (_, axon) => axon.doneA.createSignal(...) });
// controller emits requestA; serviceA emits doneA

neuron.dendrite({...})

Add a dendrite bound to a collateral.

myNeuron.dendrite({
collateral: inputCollateral,
response: async (payload, axon, ctx) => {
if (ctx.abortSignal?.aborted) return;
return axon.output.createSignal(result);
}
});

neuron.bind(axon, map)

Exhaustive bind to every collateral of another neuron's axon (compile-time safety).

withCtx().neuron('order-mailer', {})
.bind(order, {
created: (payload) => { /* ... */ },
updated: (payload) => { /* ... */ },
cancelled: (payload) => { /* ... */ },
});

neuron.setConcurrency(n: number | undefined)

Set per-neuron global concurrency limit (shared across all parallel stimulations).

const worker = neuron('worker', { out })
.setConcurrency(2) // max 2 parallel executions across all runs
.dendrite({ collateral: task, response: async (p, axon) => { /* ... */ } });

This limits how many concurrent executions of this neuron's dendrites can run at the same time, even across different stimulate() calls. Useful for rate-limiting external APIs or heavy I/O operations.

CNS

Main orchestrator. new CNS(neurons, options?)

const unsubscribe = cns.addResponseListener(r => { /* ... */ });

cns.stimulate(signal, options?)

Run a stimulation.

await cns.stimulate(userCreated.createSignal({ id: '123', name: 'John' }));

Single entry point

stimulate(...) is the only entry point that begins execution. Nothing runs until you explicitly stimulate a signal. This is the “inverted” part of IERG: you start the run and each dendrite returns the explicit continuation.

Stimulation options

await cns.stimulate(signal, {
onResponse: (r) => { /* per-stimulation hook */ },
abortSignal, // Abort the whole run cooperatively
concurrency: 4, // Per-stimulation parallelism
maxNeuronHops: undefined, // Disabled by default; set to cap traversal length
allowName: (neuronName) => true, // Filter allowed neurons by name
stimulationId: 'run-123', // Optional id for tracing
ctx, // Pre-supplied context store
createContextStore: () => myStore(), // Custom context store factory
});

Response shape (for listeners)

Both onResponse and global listeners receive the same object:

{
inputSignal?: TCNSSignal; // when a signal is ingested
outputSignal?: TCNSSignal; // when a dendrite returns a continuation
ctx: ICNSStimulationContextStore;
queueLength: number; // current work queue size
error?: Error; // when a dendrite throws
hops?: number; // present if maxNeuronHops is set
}

Global response listeners (middleware‑style)

Use addResponseListener to attach cross‑cutting concerns (logging, metrics, tracing) that run for every stimulation.

const off = cns.addResponseListener((r) => {
if (r.error) {
metrics.count('error', 1);
return;
}
if (r.outputSignal) {
trace.log('out', r.outputSignal.collateralName);
} else if (r.inputSignal) {
trace.log('in', r.inputSignal.collateralName);
}
});

// later
off();

Notes

  • Local onResponse (per stimulation) runs as well as global listeners; both can be async.
  • All listeners run in parallel per response; errors from any listener reject the stimulate(...) Promise.
  • If all listeners are synchronous, no extra async deferrals are introduced.
  • Use allowName/maxNeuronHops to constrain traversal if needed.