@cnstra/core 1.7.0 → 1.8.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (36) hide show
  1. package/README.md +16 -588
  2. package/dist/CNS.d.ts +12 -83
  3. package/dist/CNS.d.ts.map +1 -1
  4. package/dist/CNSNetwork.d.ts +87 -0
  5. package/dist/CNSNetwork.d.ts.map +1 -0
  6. package/dist/CNSNeuronActivationPump.d.ts +27 -0
  7. package/dist/CNSNeuronActivationPump.d.ts.map +1 -0
  8. package/dist/CNSStimulation.d.ts +27 -6
  9. package/dist/CNSStimulation.d.ts.map +1 -1
  10. package/dist/index.cjs +324 -304
  11. package/dist/index.cjs.map +1 -1
  12. package/dist/index.d.ts +2 -1
  13. package/dist/index.d.ts.map +1 -1
  14. package/dist/index.js +324 -304
  15. package/dist/index.js.map +1 -1
  16. package/dist/interfaces/ICNS.d.ts +12 -24
  17. package/dist/interfaces/ICNS.d.ts.map +1 -1
  18. package/dist/interfaces/ICNSStimulationContextStore.d.ts +3 -2
  19. package/dist/interfaces/ICNSStimulationContextStore.d.ts.map +1 -1
  20. package/dist/types/TCNSDendrite.d.ts +2 -2
  21. package/dist/types/TCNSDendrite.d.ts.map +1 -1
  22. package/dist/types/TCNSNeuronActivationTask.d.ts +8 -0
  23. package/dist/types/TCNSNeuronActivationTask.d.ts.map +1 -0
  24. package/dist/types/TCNSNeuronActivationTaskFailure.d.ts +7 -0
  25. package/dist/types/TCNSNeuronActivationTaskFailure.d.ts.map +1 -0
  26. package/dist/types/TCNSStimulationOptions.d.ts +7 -4
  27. package/dist/types/TCNSStimulationOptions.d.ts.map +1 -1
  28. package/dist/types/TCNSStimulationResponse.d.ts +11 -4
  29. package/dist/types/TCNSStimulationResponse.d.ts.map +1 -1
  30. package/dist/types/TCNSStimulationSerializedContextValue.d.ts +4 -0
  31. package/dist/types/TCNSStimulationSerializedContextValue.d.ts.map +1 -0
  32. package/package.json +1 -1
  33. package/dist/CNSFunctionalQueue.d.ts +0 -26
  34. package/dist/CNSFunctionalQueue.d.ts.map +0 -1
  35. package/dist/types/TCNSSerializedSignal.d.ts +0 -7
  36. package/dist/types/TCNSSerializedSignal.d.ts.map +0 -1
package/README.md CHANGED
@@ -2,49 +2,17 @@
2
2
 
3
3
  **Graph-routed, type-safe orchestration for reactive apps — no global event bus.**
4
4
 
5
- 📚 **[Full Documentation](https://cnstra.org/)** | [Quick Start](https://cnstra.org/docs/core/quick-start) | [API Reference](https://cnstra.org/docs/core/api) | [Recipes](https://cnstra.org/docs/recipes/cancel)
5
+ 📚 **[Full Documentation →](https://cnstra.org/)** | [Quick Start](https://cnstra.org/docs/core/quick-start) | [API Reference](https://cnstra.org/docs/core/api) | [Recipes](https://cnstra.org/docs/recipes)
6
6
 
7
- ## 🧠 What is CNStra?
7
+ ## What is CNStra?
8
8
 
9
- **CNStra (Central Nervous System Orchestrator)** models your app as a **typed neuron graph**.
10
- You explicitly start a run with `cns.stimulate(...)`; CNStra then performs a **deterministic, hop-bounded traversal** from **collateral → dendrite → returned signal**, step by step.
9
+ **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.
11
10
 
12
- > **Zero dependencies:** CNS has no third-party dependencies, making it suitable for any JavaScript/TypeScript environment - browsers, Node.js, serverless, edge functions, React Native, or embedded systems.
11
+ **Zero dependencies** • **No pub/sub** • **CNS approach** (Central Neural Network of your app)
13
12
 
14
- **No pub/sub:** there are no ambient listeners or global `emit`. Only the **signal you return** from a dendrite continues the traversal; returning `null`/`undefined` ends that branch. Hop limits guard against cycles.
13
+ 👉 **[Read the full documentation →](https://cnstra.org/)**
15
14
 
16
- We follow the **IERG approach — Inverted Explicit Reactive Graph**. You explicitly stimulate the graph; reactions are local and deterministic; no background listeners or buses exist.
17
-
18
- ## 💡 Why CNStra
19
-
20
- IERG is our inverted control flow: you start the run, we walk the reaction graph explicitly. This is not Flux and not an event bus.
21
-
22
- - **Deterministic routing**: signals are delivered along an explicit neuron graph, not broadcast to whoever “happens to listen”.
23
- - **Readable, reliable flows**: each step is local and typed; branches are explicit, so debugging feels like reading a storyboard, not a log stream.
24
- - **Backpressure & concurrency**: built‑in per‑stimulation and per‑neuron concurrency limits keep workloads controlled without custom plumbing.
25
- - **Saga‑grade orchestration**: IERG already models long‑running, multi‑step reactions with retries/cancellation hooks (abort), so you rarely need to hand‑roll “sagas”.
26
- - **Safer than ad‑hoc events**: no hidden global listeners, no accidental fan‑out; every continuation must be returned explicitly.
27
-
28
- ## 🏗️ Core Model
29
-
30
- ### Neurons
31
- Units of logic with clear DI and sharp boundaries:
32
- - **ID** — unique name
33
- - **Axon** — the neuron's **output channels** (its collaterals)
34
- - **Dendrites** — **input receptors** (typed reactions bound to specific collaterals)
35
-
36
- ### Collaterals
37
- Typed **output channels** that mint signals:
38
- - **ID** — string identifier (e.g., `'user:created'`)
39
- - **Payload** — the shape carried by the signal
40
- - `createSignal(payload)` → `{ collateral, payload }`
41
-
42
- ### Signals
43
- The data structures that flow through the system:
44
- - **collateral** — reference to the collateral that created this signal
45
- - **payload** — the typed data being transmitted
46
-
47
- ## 🚀 Quick Start
15
+ ## Quick Start
48
16
 
49
17
  ```bash
50
18
  npm install @cnstra/core
@@ -64,14 +32,8 @@ const userService = neuron('user-service', {
64
32
  .dendrite({
65
33
  collateral: userCreated,
66
34
  response: (payload, axon) => {
67
- const userData = payload;
68
-
69
- // Process the user creation
70
- console.log(`Processing user: ${userData.name}`);
71
-
72
- // Return the signal that will be processed by CNS
73
35
  return axon.userRegistered.createSignal({
74
- userId: userData.id,
36
+ userId: payload.id,
75
37
  status: 'completed'
76
38
  });
77
39
  }
@@ -81,555 +43,21 @@ const userService = neuron('user-service', {
81
43
  const cns = new CNS([userService]);
82
44
 
83
45
  // Stimulate the system
84
- await cns.stimulate(userCreated.createSignal({
46
+ const stimulation = cns.stimulate(userCreated.createSignal({
85
47
  id: '123',
86
48
  name: 'John Doe'
87
49
  }));
50
+ await stimulation.waitUntilComplete();
88
51
  ```
89
52
 
90
- ## 📚 API Reference
91
-
92
- ### `collateral<T>(id: string)`
93
-
94
- Creates a new collateral (communication channel).
95
-
96
- ```typescript
97
- const userEvent = collateral<{ userId: string }>('user:event');
98
- const simpleEvent = collateral('simple:event'); // No payload type
99
- ```
100
-
101
- ### `neuron(id: string, axon: Axon)`
102
-
103
- Creates a new neuron with the specified axon (output channels).
104
-
105
- ```typescript
106
- const myNeuron = neuron('my-neuron', {
107
- output: myCollateral
108
- });
109
- ```
110
-
111
- ### `neuron.dendrite(dendrite: Dendrite)`
112
-
113
- Adds a dendrite (input receptor) to a neuron. Returns the neuron for chaining.
114
-
115
- The `response` function can return:
116
- - A single signal: `axon.output.createSignal(data)`
117
- - An array of signals: `[axon.output1.createSignal(data1), axon.output2.createSignal(data2)]`
118
- - A Promise of either
119
- - `undefined`/`void` to end processing
120
-
121
- ```typescript
122
- myNeuron
123
- .dendrite({
124
- collateral: inputCollateral,
125
- response: async (payload, axon, ctx) => {
126
- // ctx: { get, set, abortSignal?, cns? }
127
- if (ctx.abortSignal?.aborted) return; // graceful cancel
128
- const prev = ctx.get();
129
- ctx.set({ ...prev, handled: true });
130
-
131
- // Return single signal or array of signals
132
- return axon.output.createSignal(result);
133
- }
134
- });
135
- ```
136
-
137
- ### `neuron.bind(axon, map)` — exhaustive subscriptions (with shorthand)
138
-
139
- Bind this neuron to every collateral of another neuron's axon in one place. The `map` must be exhaustive: you must provide a handler for each collateral key of `axon`. This gives you compile-time safety: if someone adds a new collateral later, TypeScript will immediately flag missing handlers.
140
-
141
- - You can pass either a full dendrite object per key or just a response function shorthand.
142
- - Payload types are inferred from the followed axon.
143
-
144
- This pattern is especially useful for domain-oriented neurons that must react to every way a record can be created/changed. For example, an email-notifier neuron can safely ensure emails are sent for every creation path; if a new creation collateral is introduced, the build will fail until the notifier adds a corresponding handler.
145
-
146
- ```typescript
147
- import { withCtx, collateral } from '@cnstra/core';
148
-
149
- // Order domain model (axon)
150
- const order = {
151
- created: collateral<{ id: string; amount: number }>('order:created'),
152
- updated: collateral<{ id: string; changes: Record<string, unknown> }>('order:updated'),
153
- cancelled: collateral<{ id: string; reason?: string }>('order:cancelled'),
154
- };
155
-
156
- // Mailer neuron must react to ALL order events
157
- withCtx()
158
- .neuron('order-mailer', { /* your axon if you emit follow-up signals */ })
159
- .bind(order, {
160
- created: (payload) => {
161
- sendEmail(`Order created #${payload.id} for $${payload.amount}`);
162
- return undefined;
163
- },
164
- updated: (payload) => {
165
- sendEmail(`Order updated #${payload.id} (changes: ${Object.keys(payload.changes).join(', ')})`);
166
- return undefined;
167
- },
168
- cancelled: (payload) => {
169
- sendEmail(`Order cancelled #${payload.id}${payload.reason ? `: ${payload.reason}` : ''}`);
170
- return undefined;
171
- },
172
- });
173
-
174
- // If later someone adds a new event variant, e.g. refunds:
175
- // const order = { ...order, refunded: collateral<{ id: string; amount: number }>('order:refunded') };
176
- // TypeScript will now error until you also add a `refunded` handler in the .bind(...) map.
177
- ```
178
-
179
- ### `CNS` Class
180
-
181
- The main orchestrator that manages signal flow between neurons.
182
-
183
- #### Constructor
184
- ```typescript
185
- new CNS(neurons, options?)
186
- ```
187
-
188
- **Parameters:**
189
- - `neurons`: Array of neurons that process signals
190
- - `options`: Optional CNS configuration
191
-
192
- #### Global listeners
193
- ```typescript
194
- const unsubscribe = cns.addResponseListener(r => {
195
- // fires for every stimulation (input + outputs)
196
- });
197
- // unsubscribe();
198
- ```
199
-
200
- #### `stimulate()` Method
201
- ```typescript
202
- cns.stimulate(signal | signal[], options?)
203
- ```
204
-
205
- **Parameters:**
206
- - `signal`: A signal or array of signals created by `collateral.createSignal(payload)`
207
- - `options`: Optional stimulation configuration
208
-
209
- **Returns:** `Promise<void>` that resolves when stimulation completes
210
-
211
- **Example:**
212
- ```typescript
213
- // Single signal
214
- await cns.stimulate(
215
- userCreated.createSignal({ id: '123', name: 'John' })
216
- );
217
-
218
- // Multiple signals at once
219
- await cns.stimulate([
220
- userCreated.createSignal({ id: '123', name: 'John' }),
221
- userCreated.createSignal({ id: '456', name: 'Jane' })
222
- ]);
223
- ```
224
-
225
- ## ⚙️ Stimulation Options
226
-
227
- ### `maxNeuronHops?: number` (default: 1000)
228
- Prevents infinite loops by limiting signal traversal depth.
229
-
230
- ```typescript
231
- await cns.stimulate(signal, {
232
- maxNeuronHops: 50 // Stop after 50 neuron hops
233
- });
234
- ```
235
-
236
- ### `onResponse?: (response) => void`
237
- Real-time callback for monitoring signal flow and completion.
238
-
239
- ```typescript
240
- await cns.stimulate(signal, {
241
- onResponse: (response) => {
242
- console.log(`Signal: ${response.outputSignal?.collateral.id}`);
243
- console.log(`Hops: ${response.hops}`);
244
-
245
- if (response.error) {
246
- console.error('Processing failed:', response.error);
247
- }
248
-
249
- if (response.queueLength === 0) {
250
- console.log('Stimulation completed');
251
- }
252
- }
253
- });
254
- ```
255
-
256
- **Response Object:**
257
- - `outputSignal` — The signal being processed (if any)
258
- - `hops` — Number of neuron hops taken so far
259
- - `queueLength` — Remaining signals in processing queue (0 = complete)
260
- - `error` — Any error that occurred during processing
261
- - `stimulationId` — Unique identifier for this stimulation
262
-
263
- ### `abortSignal?: AbortSignal`
264
- Gracefully stop stimulation using AbortController.
265
-
266
- ```typescript
267
- const controller = new AbortController();
268
-
269
- cns.stimulate(signal, {
270
- abortSignal: controller.signal
271
- });
272
-
273
- // Cancel after 5 seconds
274
- setTimeout(() => controller.abort(), 5000);
275
- ```
276
- Inside dendrites, read it via `ctx.abortSignal`.
277
-
278
- ### `stimulationId?: string`
279
- Custom identifier for this stimulation cascade. Auto-generated if not provided.
280
-
281
- ```typescript
282
- await cns.stimulate(signal, {
283
- stimulationId: 'user-action-' + Date.now()
284
- });
285
- ```
286
-
287
- ### `allowName?: (collateralName: string) => boolean`
288
- Filter which collateral names can be processed.
289
-
290
- ```typescript
291
- await cns.stimulate(signal, {
292
- allowName: (name) => name.startsWith('user:') // Only process user-related signals
293
- });
294
- ```
295
-
296
- ### `concurrency?: number` (default: unlimited)
297
- Limit concurrent operations to prevent resource exhaustion.
298
-
299
- ```typescript
300
- await cns.stimulate(signal, {
301
- concurrency: 10 // Max 10 operations at once
302
- });
303
- ```
304
-
305
- #### Per‑neuron global concurrency
306
- Set a limit per neuron; parallel stimulations share the same gate.
307
- ```typescript
308
- const worker = neuron('worker', { out })
309
- .setConcurrency(2)
310
- .dendrite({ /* ... */ });
311
- ```
312
-
313
- ### `ctx?: ICNSStimulationContextStore`
314
- Provide existing context store for recovery/retry scenarios.
315
-
316
- ```typescript
317
- await cns.stimulate(signal, {
318
- ctx: savedContextStore // Restore previous state
319
- });
320
- ```
321
-
322
- ### `createContextStore?: () => ICNSStimulationContextStore`
323
- Factory for custom context store implementations.
324
-
325
- ```typescript
326
- await cns.stimulate(signal, {
327
- createContextStore: () => new CustomContextStore()
328
- });
329
- ```
330
-
331
- ## 🔄 Signal Flow Patterns
332
-
333
- ### Basic Chain Processing
334
-
335
- ```typescript
336
- const input = collateral<{ value: number }>('input');
337
- const middle = collateral<{ doubled: number }>('middle');
338
- const output = collateral<{ result: string }>('output');
339
-
340
- const step1 = neuron('step1', { middle }).dendrite({
341
- collateral: input,
342
- response: (payload, axon) => {
343
- return axon.middle.createSignal({ doubled: payload.value * 2 });
344
- }
345
- });
346
-
347
- const step2 = neuron('step2', { output }).dendrite({
348
- collateral: middle,
349
- response: (payload, axon) => {
350
- return axon.output.createSignal({ result: `Final: ${payload.doubled}` });
351
- }
352
- });
353
-
354
- const cns = new CNS([step1, step2]);
355
-
356
- await cns.stimulate(input.createSignal({ value: 5 }));
357
- // Flows: input(5) → middle(10) → output("Final: 10")
358
- ```
359
-
360
- ### Context-Aware Processing
361
-
362
- ```typescript
363
- import { withCtx } from '@cnstra/core';
364
-
365
- const input = collateral<{ increment: number }>('input');
366
- const output = collateral<{ count: number }>('output');
367
-
368
- const counter = withCtx<{ total: number }>()
369
- .neuron('counter', { output })
370
- .dendrite({
371
- collateral: input,
372
- response: async (payload, axon, ctx) => {
373
- const current = ctx.get()?.total || 0;
374
- const newTotal = current + payload.increment;
375
-
376
- ctx.set({ total: newTotal });
377
-
378
- return axon.output.createSignal({ count: newTotal });
379
- }
380
- });
381
-
382
- const cns = new CNS([counter]);
383
-
384
- await cns.stimulate(input.createSignal({ increment: 5 })); // count: 5
385
- await cns.stimulate(input.createSignal({ increment: 3 })); // count: 8 (separate context)
386
- ```
387
-
388
- ### Multiple Signals (Fan-out Pattern)
389
-
390
- Neurons can return arrays of signals for parallel processing:
391
-
392
- ```typescript
393
- const orderPlaced = collateral<{ orderId: string; items: string[] }>('order:placed');
394
- const updateInventory = collateral<{ orderId: string; item: string }>('update:inventory');
395
- const sendEmail = collateral<{ orderId: string }>('send:email');
396
- const logAudit = collateral<{ orderId: string }>('log:audit');
397
-
398
- const orderProcessor = neuron('order-processor', {
399
- updateInventory,
400
- sendEmail,
401
- logAudit
402
- }).dendrite({
403
- collateral: orderPlaced,
404
- response: (payload, axon) => {
405
- // Return array of signals - each will be processed independently
406
- return [
407
- // Create signal for each item
408
- ...payload.items.map(item =>
409
- axon.updateInventory.createSignal({ orderId: payload.orderId, item })
410
- ),
411
- // Also send confirmation email
412
- axon.sendEmail.createSignal({ orderId: payload.orderId }),
413
- // And log the action
414
- axon.logAudit.createSignal({ orderId: payload.orderId })
415
- ];
416
- }
417
- });
418
-
419
- // Downstream neurons process each signal independently
420
- const inventoryService = neuron('inventory-service', {}).dendrite({
421
- collateral: updateInventory,
422
- response: (payload) => {
423
- console.log(`Updating inventory for ${payload.item}`);
424
- // Each item gets its own execution
425
- }
426
- });
427
-
428
- const cns = new CNS([orderProcessor, inventoryService /* ... */]);
429
-
430
- // Single order triggers multiple parallel operations
431
- await cns.stimulate(
432
- orderPlaced.createSignal({ orderId: 'ORD-001', items: ['A', 'B', 'C'] })
433
- );
434
- // Flows: orderPlaced → [inventory(A), inventory(B), inventory(C), email, audit]
435
- ```
436
-
437
- **Conditional Arrays:**
438
- ```typescript
439
- const validator = neuron('validator', { success, error, audit }).dendrite({
440
- collateral: input,
441
- response: (payload, axon) => {
442
- const signals = [];
443
-
444
- // Conditionally add signals
445
- if (isValid(payload.data)) {
446
- signals.push(axon.success.createSignal({ validated: payload.data }));
447
- } else {
448
- signals.push(axon.error.createSignal({ error: 'Invalid' }));
449
- }
450
-
451
- // Always audit
452
- signals.push(axon.audit.createSignal({ attempted: true }));
453
-
454
- return signals; // Return empty array to emit nothing
455
- }
456
- });
457
- ```
458
-
459
- **Starting with Multiple Signals:**
460
- ```typescript
461
- // Process multiple orders in parallel
462
- await cns.stimulate([
463
- orderPlaced.createSignal({ orderId: 'ORD-001', items: ['X'] }),
464
- orderPlaced.createSignal({ orderId: 'ORD-002', items: ['Y', 'Z'] })
465
- ]);
466
- ```
467
-
468
- See [Multiple Signals Recipe](https://cnstra.org/docs/recipes/multiple-signals) for more patterns and best practices.
469
-
470
- ## 🧠 Memory & Performance
471
-
472
- ### Memory-Efficient Design
473
- - **Zero dependencies**: No third-party packages
474
- - **No error storage**: Errors delivered via callbacks, not stored
475
- - **Streaming responses**: Signal traces delivered via callbacks
476
- - **Context on-demand**: Context stores created only when needed
477
- - **No global state**: Clean slate between stimulations
478
-
479
- ### Performance Characteristics
480
- - **Sync-first**: Synchronous chains execute in single tick
481
- - **Minimal async overhead**: Promises created only when needed
482
- - **Stack-safe**: Handles deep chains without stack overflow
483
- - **Bounded execution**: `maxNeuronHops` prevents runaway processing
484
-
485
- ### Best Practices
486
- - Keep context data minimal (IDs, counters, flags)
487
- - Use synchronous responses when possible
488
- - Set reasonable `maxNeuronHops` limits
489
- - Implement proper error handling in `onResponse`
490
- - Use array returns for genuine fan-out patterns, not just convenience
491
- - Consider concurrency limits when returning many signals
492
-
493
- ## 🎯 Common Use Cases
494
-
495
- ### HTTP Request Processing
496
- ```typescript
497
- const httpRequest = collateral<{ method: string; url: string }>('http:request');
498
- const requestValidated = collateral<{ method: string; url: string }>('request:validated');
499
- const responseReady = collateral<{ status: number; body: any }>('response:ready');
500
-
501
- const validator = neuron('validator', { requestValidated }).dendrite({
502
- collateral: httpRequest,
503
- response: (payload, axon) => {
504
- if (!payload.url.startsWith('https://')) {
505
- throw new Error('Only HTTPS URLs allowed');
506
- }
507
- return axon.requestValidated.createSignal(payload);
508
- }
509
- });
510
-
511
- const handler = neuron('handler', { responseReady }).dendrite({
512
- collateral: requestValidated,
513
- response: async (payload, axon) => {
514
- const response = await fetch(payload.url, { method: payload.method });
515
- const body = await response.json();
516
- return axon.responseReady.createSignal({ status: response.status, body });
517
- }
518
- });
519
-
520
- const cns = new CNS([validator, handler]);
521
- ```
522
-
523
- ### Event Sourcing
524
- ```typescript
525
- const eventReceived = collateral<{ name: string; data: any }>('event:received');
526
- const eventStored = collateral<{ eventId: string }>('event:stored');
527
- const stateUpdated = collateral<{ aggregateId: string }>('state:updated');
528
-
529
- const eventStore = neuron('event-store', { eventStored }).dendrite({
530
- collateral: eventReceived,
531
- response: async (payload, axon) => {
532
- const eventId = await saveEvent(payload);
533
- return axon.eventStored.createSignal({ eventId });
534
- }
535
- });
536
-
537
- const stateManager = neuron('state-manager', { stateUpdated }).dendrite({
538
- collateral: eventStored,
539
- response: async (payload, axon) => {
540
- const aggregateId = await updateState(payload.eventId);
541
- return axon.stateUpdated.createSignal({ aggregateId });
542
- }
543
- });
544
-
545
- const cns = new CNS([eventStore, stateManager]);
546
- ```
547
-
548
- ## 🚨 Error Handling
549
-
550
- Errors are delivered immediately via `onResponse` callbacks:
551
-
552
- ```typescript
553
- await cns.stimulate(signal, {
554
- onResponse: (response) => {
555
- if (response.error) {
556
- console.error(`Error in neuron processing:`, response.error);
557
-
558
- // Log error details
559
- console.error(`Signal: ${response.outputSignal?.collateral.id}`);
560
- console.error(`Stimulation: ${response.stimulationId}`);
561
-
562
- // Handle specific error types
563
- if (response.error instanceof ValidationError) {
564
- handleValidationError(response.error);
565
- }
566
- }
567
- }
568
- });
569
- ```
570
-
571
- **Error Recovery with Context:**
572
- ```typescript
573
- let savedContext: ICNSStimulationContextStore | undefined;
574
-
575
- await cns.stimulate(signal, {
576
- onResponse: (response) => {
577
- if (response.error) {
578
- // Save context for retry
579
- savedContext = response.contextStore;
580
- }
581
- }
582
- });
583
-
584
- // Retry with preserved context
585
- if (savedContext) {
586
- await cns.stimulate(retrySignal, {
587
- ctx: savedContext
588
- });
589
- }
590
- ```
591
-
592
- ## 🔧 Advanced Configuration
593
-
594
- ### Custom Context Store
595
- ```typescript
596
- class RedisContextStore implements ICNSStimulationContextStore {
597
- constructor(private client: RedisClient, private sessionId: string) {}
598
-
599
- get<T>(): T | undefined {
600
- // Implement Redis-backed context retrieval
601
- }
602
-
603
- set<T>(value: T): void {
604
- // Implement Redis-backed context storage
605
- }
606
- }
607
-
608
- await cns.stimulate(signal, {
609
- createContextStore: () => new RedisContextStore(redisClient, 'session-123')
610
- });
611
- ```
612
-
613
- ### CNS Configuration
614
- ```typescript
615
- const cns = new CNS(neurons, {
616
- autoCleanupContexts: true, // Auto-cleanup unused contexts
617
- defaultConcurrency: 50 // Default concurrency limit
618
- });
619
- ```
620
-
621
- ⚠️ **Performance Warning**: `autoCleanupContexts` adds computational overhead due to:
622
- - **O(V²) initialization cost** - building SCC (Strongly Connected Components) structures
623
- - **O(1 + A) runtime cost** per cleanup check (where A = number of SCC ancestors)
624
- - **Memory overhead** for storing SCC graphs and ancestor relationships
625
-
626
- **Use only when:**
627
- - Memory leaks are a critical issue
628
- - You have a small to medium-sized neuron graph (< 1000 neurons)
629
- - Performance is less critical than memory management
53
+ ## Documentation
630
54
 
631
- **For production systems**, consider manual context cleanup or custom cleanup strategies instead.
55
+ - **[Quick Start Guide](https://cnstra.org/docs/core/quick-start)** — Get up and running in minutes
56
+ - **[API Reference](https://cnstra.org/docs/core/api)** — Complete API documentation
57
+ - **[Concepts](https://cnstra.org/docs/core/concepts)** — Neurons, collaterals, signals, and the CNS model (Central Neural Network of your app)
58
+ - **[Recipes](https://cnstra.org/docs/recipes)** — Common patterns and use cases
59
+ - **[Advanced Topics](https://cnstra.org/docs/advanced)** — Performance, context stores, integrations
632
60
 
633
61
  ---
634
62
 
635
- *CNStra provides deterministic, type-safe orchestration without the complexity of traditional event systems. Build reliable, maintainable reactive applications with clear data flow and predictable behavior.*
63
+ *CNStra provides deterministic, type-safe orchestration without the complexity of traditional event systems.*