Package Exports
- @cnstra/core
Readme
@cnstra/core
Graph-routed, type-safe orchestration for reactive apps β no global event bus.
π§ What is CNStra?
CNStra (Central Nervous System Orchestrator) models your app as a typed neuron graph.
You explicitly start a run with cns.stimulate(...); CNStra then performs a deterministic, hop-bounded traversal from collateral β dendrite β returned signal, step by step.
Not pub/sub: there are no ambient listeners or global
emit. Only the signal you return from a dendrite continues the traversal; returningnull/undefinedends that branch.maxHopsguards against cycles.
ποΈ Core Model
Neurons
Units of logic with clear DI and sharp boundaries:
- ID β unique name
- Axon β the neuronβs output channels (its collaterals)
- Dendrites β input receptors (typed reactions bound to specific collaterals)
Collaterals
Typed output channels that mint signals:
- ID β string identifier (e.g.,
'user:created') - Payload β the shape carried by the signal
createSignal(payload)β{ type, payload }
Afferent axon: the object of collaterals you expose publicly. Its keys (e.g.,
userCreated) are what you pass tocns.stimulate(...), not the string IDs.
π Quick Start
npm install @cnstra/coreimport { CNS, collateral, neuron } from '@cnstra/core';
// Define collaterals (communication channels)
const userCreated = collateral<{ id: string; name: string }>('user:created');
const userRegistered = collateral<{ userId: string; status: string }>('user:registered');
// Create a neuron
const userService = neuron('user-service', {
userRegistered
})
.dendrite({
collateral: userCreated,
reaction: async (payload, axon) => {
const userData = payload as { id: string; name: string };
// Process the user creation
console.log(`Processing user: ${userData.name}`);
// Return the signal that will be processed by CNS
return axon.userRegistered.createSignal({
userId: userData.id,
status: 'completed'
});
}
});
// Create the CNS system
const cns = new CNS({ userCreated }, [userService]);
// Stimulate the system
await cns.stimulate('userCreated', {
id: '123',
name: 'John Doe'
});π API Reference
collateral<T>(id: string)
Creates a new collateral (communication channel).
const userEvent = collateral<{ userId: string }>('user:event');
const simpleEvent = collateral('simple:event'); // No payload typeneuron(id: string, axon: Axon)
Creates a new neuron with the specified axon (output channels).
const myNeuron = neuron('my-neuron', {
output: myCollateral
});neuron.dendrite(dendrite: Dendrite)
Adds a dendrite (input receptor) to a neuron. Returns the neuron for chaining.
myNeuron
.dendrite({
collateral: inputCollateral,
reaction: async (payload, axon) => {
// Process input and return output signal
return axon.output.createSignal(result);
}
});CNS Class
The main orchestrator that manages signal flow between neurons.
Constructor
new CNS(afferentAxon, neurons)Parameters:
afferentAxon: Object containing collaterals that can be used as input triggersneurons: Array of neurons that process signals
stimulate() Method
await cns.stimulate(axonKey, payload, options?)Parameters:
axonKey: Key from the afferent axon to triggerpayload: Signal payload with type and dataoptions: Optional configuration object
Options:
maxHops: Maximum number of signal hops (default: 1000)onTrace: Callback for tracing signal flowabortSignal: AbortController signal for cancellation
π Key Behavior
Only Returned Signals Are Processed
Important: In CNS, only the signal returned from the reaction function is processed and propagated to other neurons. Signals created with axon.collateral.createSignal() but not returned are NOT processed by the system.
const processor = neuron('processor', {
output: outputCollateral
})
.dendrite({
collateral: inputCollateral,
reaction: async (payload, axon) => {
// This signal is created but NOT processed
axon.output.createSignal({ message: 'Hello' });
// Only this returned signal is processed
return axon.output.createSignal({ message: 'World' });
}
});Multiple Neurons on Same Collateral
Multiple neurons can listen to the same collateral:
const emailService = neuron('email-service', { emailSent })
.dendrite({
collateral: userCreated,
reaction: async (payload, axon) => {
return axon.emailSent.createSignal({ to: 'user@example.com' });
}
});
const notificationService = neuron('notification-service', { notificationSent })
.dendrite({
collateral: userCreated,
reaction: async (payload, axon) => {
return axon.notificationSent.createSignal({ message: 'User created' });
}
});
// Both neurons will process the userCreated signal
const cns = new CNS({ userCreated }, [emailService, notificationService]);Conditional Logic
const router = neuron('router', {
success: successCollateral,
error: errorCollateral
})
.dendrite({
collateral: requestCollateral,
reaction: async (payload, axon) => {
try {
const result = await processRequest(payload);
return axon.success.createSignal(result);
} catch (error) {
return axon.error.createSignal({ error: error.message });
}
}
});π§ͺ Testing
npm test
npm run test:typesπ¦ Build
npm run buildπ Examples
Run the examples to see CNS in action:
npm run examplesπ€ Contributing
Contributions are welcome! Please feel free to submit a Pull Request.
π License
MIT