@cnstra/core 2.4.0 → 2.6.0
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.
- package/dist/CNS.d.ts +32 -10
- package/dist/CNS.d.ts.map +1 -1
- package/dist/CNSCollateral.d.ts +2 -2
- package/dist/CNSCollateral.d.ts.map +1 -1
- package/dist/CNSNetwork.d.ts +7 -7
- package/dist/CNSNetwork.d.ts.map +1 -1
- package/dist/CNSStimulation.d.ts +55 -15
- package/dist/CNSStimulation.d.ts.map +1 -1
- package/dist/CNSStimulationContextStore.d.ts +1 -1
- package/dist/CNSStimulationContextStore.d.ts.map +1 -1
- package/dist/factory/index.d.ts +26 -82
- package/dist/factory/index.d.ts.map +1 -1
- package/dist/index.cjs +235 -136
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.ts +1 -14
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +236 -134
- package/dist/index.js.map +1 -1
- package/dist/utils/CNSStimulationGate.d.ts +7 -7
- package/dist/utils/CNSStimulationGate.d.ts.map +1 -1
- package/package.json +4 -1
- package/dist/CNSPersistOptionsRegistry.d.ts +0 -28
- package/dist/CNSPersistOptionsRegistry.d.ts.map +0 -1
- package/dist/interfaces/ICNS.d.ts +0 -20
- package/dist/interfaces/ICNS.d.ts.map +0 -1
- package/dist/interfaces/ICNSCollateral.d.ts +0 -6
- package/dist/interfaces/ICNSCollateral.d.ts.map +0 -1
- package/dist/interfaces/ICNSStimulationContextStore.d.ts +0 -8
- package/dist/interfaces/ICNSStimulationContextStore.d.ts.map +0 -1
- package/dist/types/TCNSAfferentPath.d.ts +0 -4
- package/dist/types/TCNSAfferentPath.d.ts.map +0 -1
- package/dist/types/TCNSAxon.d.ts +0 -26
- package/dist/types/TCNSAxon.d.ts.map +0 -1
- package/dist/types/TCNSDendrite.d.ts +0 -9
- package/dist/types/TCNSDendrite.d.ts.map +0 -1
- package/dist/types/TCNSHandlerContext.d.ts +0 -24
- package/dist/types/TCNSHandlerContext.d.ts.map +0 -1
- package/dist/types/TCNSLocalContextValueStore.d.ts +0 -6
- package/dist/types/TCNSLocalContextValueStore.d.ts.map +0 -1
- package/dist/types/TCNSModality.d.ts +0 -5
- package/dist/types/TCNSModality.d.ts.map +0 -1
- package/dist/types/TCNSNeuron.d.ts +0 -12
- package/dist/types/TCNSNeuron.d.ts.map +0 -1
- package/dist/types/TCNSNeuronActivationTask.d.ts +0 -8
- package/dist/types/TCNSNeuronActivationTask.d.ts.map +0 -1
- package/dist/types/TCNSNeuronActivationTaskFailure.d.ts +0 -7
- package/dist/types/TCNSNeuronActivationTaskFailure.d.ts.map +0 -1
- package/dist/types/TCNSNeuronResponseReturn.d.ts +0 -9
- package/dist/types/TCNSNeuronResponseReturn.d.ts.map +0 -1
- package/dist/types/TCNSOptions.d.ts +0 -11
- package/dist/types/TCNSOptions.d.ts.map +0 -1
- package/dist/types/TCNSPersist.d.ts +0 -16
- package/dist/types/TCNSPersist.d.ts.map +0 -1
- package/dist/types/TCNSSignal.d.ts +0 -6
- package/dist/types/TCNSSignal.d.ts.map +0 -1
- package/dist/types/TCNSStimulationOptions.d.ts +0 -14
- package/dist/types/TCNSStimulationOptions.d.ts.map +0 -1
- package/dist/types/TCNSStimulationQueueItem.d.ts +0 -11
- package/dist/types/TCNSStimulationQueueItem.d.ts.map +0 -1
- package/dist/types/TCNSStimulationResponse.d.ts +0 -17
- package/dist/types/TCNSStimulationResponse.d.ts.map +0 -1
- package/dist/types/TCNSStimulationSerializedContextValue.d.ts +0 -4
- package/dist/types/TCNSStimulationSerializedContextValue.d.ts.map +0 -1
- package/dist/types/TCNSSubscriber.d.ts +0 -7
- package/dist/types/TCNSSubscriber.d.ts.map +0 -1
package/dist/index.d.ts
CHANGED
|
@@ -1,21 +1,8 @@
|
|
|
1
1
|
export { CNS } from './CNS';
|
|
2
|
-
export { CNSPersistOptionsRegistry } from './CNSPersistOptionsRegistry';
|
|
3
2
|
export { CNSCollateral } from './CNSCollateral';
|
|
4
3
|
export { CNSStimulationContextStore } from './CNSStimulationContextStore';
|
|
5
4
|
export { CNSStimulationGate } from './utils/CNSStimulationGate';
|
|
6
|
-
export type { ICNS } from './interfaces/ICNS';
|
|
7
|
-
export type { TCNSNeuron } from './types/TCNSNeuron';
|
|
8
|
-
export type { TCNSAxon } from './types/TCNSAxon';
|
|
9
|
-
export type { TCNSDendrite } from './types/TCNSDendrite';
|
|
10
|
-
export type { TCNSHandlerContext } from './types/TCNSHandlerContext';
|
|
11
|
-
export type { TCNSSignal } from './types/TCNSSignal';
|
|
12
|
-
export type { TCNSNeuronActivationTask } from './types/TCNSNeuronActivationTask';
|
|
13
|
-
export type { TCNSStimulationOptions } from './types/TCNSStimulationOptions';
|
|
14
|
-
export type { TCNSModality } from './types/TCNSModality';
|
|
15
|
-
export type { TCNSAfferentPath } from './types/TCNSAfferentPath';
|
|
16
|
-
export type { TCNSNeuronActivationTaskFailure } from './types/TCNSNeuronActivationTaskFailure';
|
|
17
|
-
export type { TCNSNeuronPersistOptions, TCNSCollateralPersistOptions, TCNSStimulationPersistOptions } from './types/TCNSPersist';
|
|
18
5
|
export type { TCNSStimulationGateOptions, TCNSStimulationGateSignal } from './utils/CNSStimulationGate';
|
|
19
|
-
export { collateral, neuron, neuronFactory, withCtx, withGlobal, afferentPath, modality,
|
|
6
|
+
export { collateral, neuron, neuronFactory, withCtx, withGlobal, afferentPath, modality, } from './factory/index';
|
|
20
7
|
export type { TNeuronFactory } from './factory/index';
|
|
21
8
|
//# sourceMappingURL=index.d.ts.map
|
package/dist/index.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,GAAG,EAAE,MAAM,OAAO,CAAC;
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,GAAG,EAAE,MAAM,OAAO,CAAC;AAG5B,OAAO,EAAE,aAAa,EAAE,MAAM,iBAAiB,CAAC;AAChD,OAAO,EAAE,0BAA0B,EAAE,MAAM,8BAA8B,CAAC;AAC1E,OAAO,EAAE,kBAAkB,EAAE,MAAM,4BAA4B,CAAC;AAKhE,YAAY,EAAE,0BAA0B,EAAE,yBAAyB,EAAE,MAAM,4BAA4B,CAAC;AAGxG,OAAO,EACH,UAAU,EACV,MAAM,EACN,aAAa,EACb,OAAO,EACP,UAAU,EACV,YAAY,EACZ,QAAQ,GACX,MAAM,iBAAiB,CAAC;AACzB,YAAY,EAAE,cAAc,EAAE,MAAM,iBAAiB,CAAC"}
|
package/dist/index.js
CHANGED
|
@@ -37,6 +37,13 @@ var CNSDendriteContext = class {
|
|
|
37
37
|
get global() {
|
|
38
38
|
return this.cns.global;
|
|
39
39
|
}
|
|
40
|
+
// The caller-supplied per-stimulation context (`stimulate(sig, {stimulationContext})`),
|
|
41
|
+
// the same value on every hop — the environment-agnostic way to correlate logs to a
|
|
42
|
+
// run (pass `{ stimulationId, attemptNumber }`). Prototype getter like `global`:
|
|
43
|
+
// zero extra allocation, read only where a handler reaches for it.
|
|
44
|
+
get stimulationContext() {
|
|
45
|
+
return this.stimulation.options?.stimulationContext;
|
|
46
|
+
}
|
|
40
47
|
get() {
|
|
41
48
|
return this.stimulation.getContext().get(this.neuron);
|
|
42
49
|
}
|
|
@@ -48,21 +55,24 @@ var CNSDendriteContext = class {
|
|
|
48
55
|
}
|
|
49
56
|
};
|
|
50
57
|
var CNSStimulationResponseImpl = class {
|
|
51
|
-
constructor(stimulation, store, inputSignal, outputSignal, queueLength, hops, error) {
|
|
58
|
+
constructor(stimulation, store, inputSignal, outputSignal, queueLength, pendingActivations, activeActivations, hops, error, neuron2) {
|
|
52
59
|
this.stimulation = stimulation;
|
|
53
60
|
this.store = store;
|
|
54
61
|
this.inputSignal = inputSignal;
|
|
55
62
|
this.outputSignal = outputSignal;
|
|
56
63
|
this.queueLength = queueLength;
|
|
64
|
+
this.pendingActivations = pendingActivations;
|
|
65
|
+
this.activeActivations = activeActivations;
|
|
57
66
|
this.hops = hops;
|
|
58
67
|
this.error = error;
|
|
68
|
+
this.neuron = neuron2;
|
|
59
69
|
}
|
|
60
70
|
get contextValue() {
|
|
61
71
|
return this.store ? this.store.getAll() : /* @__PURE__ */ new Map();
|
|
62
72
|
}
|
|
63
73
|
};
|
|
64
74
|
var CNSStimulation = class {
|
|
65
|
-
constructor(cns, instanceNeuronQueue, options, onResponse) {
|
|
75
|
+
constructor(cns, instanceNeuronQueue, options, onResponse, onDrain) {
|
|
66
76
|
this.cns = cns;
|
|
67
77
|
this.options = options;
|
|
68
78
|
this.qHead = 0;
|
|
@@ -73,9 +83,20 @@ var CNSStimulation = class {
|
|
|
73
83
|
// Re-entrancy guard for the pump loop.
|
|
74
84
|
this.pumping = false;
|
|
75
85
|
this.needsPump = false;
|
|
86
|
+
// Nesting depth of the current synchronous turn. Only the outermost close
|
|
87
|
+
// announces a drain - see beginTurn/endTurn.
|
|
88
|
+
this.turnDepth = 0;
|
|
76
89
|
this.scheduledCount = 0;
|
|
90
|
+
// Activations belonging to signals of an in-progress array fan-out that have
|
|
91
|
+
// not been handed to processResponse yet, so the task objects do not exist.
|
|
92
|
+
// processResponse enqueues synchronously, so the first signal's whole subtree
|
|
93
|
+
// drains before the second signal is even looked at; without this counter
|
|
94
|
+
// that subtree's leaf sees an empty queue and reads as "all work done".
|
|
95
|
+
// Counted in activations, not signals, so every public counter shares a unit.
|
|
96
|
+
this.reservedActivations = 0;
|
|
77
97
|
this.isCompleted = false;
|
|
78
98
|
this.completionRejected = false;
|
|
99
|
+
this.onDrain = onDrain;
|
|
79
100
|
this.ctxStore = options?.ctx;
|
|
80
101
|
this.instanceNeuronQueue = instanceNeuronQueue;
|
|
81
102
|
this.onResponse = onResponse;
|
|
@@ -172,18 +193,28 @@ var CNSStimulation = class {
|
|
|
172
193
|
(cb) => {
|
|
173
194
|
this.activeOperations--;
|
|
174
195
|
this.activeTasks.delete(task);
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
if (
|
|
178
|
-
|
|
196
|
+
this.beginTurn();
|
|
197
|
+
try {
|
|
198
|
+
if (typeof cb === "function") cb();
|
|
199
|
+
if (this.qSize > 0 && this.canStartOperation) {
|
|
200
|
+
if (this.pumping) this.needsPump = true;
|
|
201
|
+
else this.pump();
|
|
202
|
+
}
|
|
203
|
+
} finally {
|
|
204
|
+
this.endTurn();
|
|
179
205
|
}
|
|
180
206
|
},
|
|
181
207
|
(err) => {
|
|
182
208
|
this.activeOperations--;
|
|
183
209
|
this.activeTasks.delete(task);
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
210
|
+
this.beginTurn();
|
|
211
|
+
try {
|
|
212
|
+
if (this.qSize > 0 && this.canStartOperation) {
|
|
213
|
+
if (this.pumping) this.needsPump = true;
|
|
214
|
+
else this.pump();
|
|
215
|
+
}
|
|
216
|
+
} finally {
|
|
217
|
+
this.endTurn();
|
|
187
218
|
}
|
|
188
219
|
throw err;
|
|
189
220
|
}
|
|
@@ -199,10 +230,54 @@ var CNSStimulation = class {
|
|
|
199
230
|
this.pump();
|
|
200
231
|
}
|
|
201
232
|
}
|
|
233
|
+
/**
|
|
234
|
+
* Open a synchronous turn. Turns nest: a drain is announced only when the
|
|
235
|
+
* outermost one closes, so an enqueue that happens while the pump is already
|
|
236
|
+
* running does not produce its own boundary.
|
|
237
|
+
*/
|
|
238
|
+
beginTurn() {
|
|
239
|
+
this.turnDepth++;
|
|
240
|
+
}
|
|
241
|
+
/**
|
|
242
|
+
* Close a synchronous turn and, if it was the outermost and nothing more can
|
|
243
|
+
* run without yielding to the event loop, announce the drain.
|
|
244
|
+
*
|
|
245
|
+
* This is the only place the synchronous frontier is observable. A response
|
|
246
|
+
* cannot serve the purpose: responses are emitted when an activation
|
|
247
|
+
* *finishes*, but a turn just as often ends when one *starts* and returns a
|
|
248
|
+
* promise - at which point there is nothing left to emit a response from.
|
|
249
|
+
*/
|
|
250
|
+
endTurn() {
|
|
251
|
+
if (--this.turnDepth > 0) return;
|
|
252
|
+
const onDrain = this.onDrain;
|
|
253
|
+
if (!onDrain) return;
|
|
254
|
+
if (this.pumping) return;
|
|
255
|
+
if (this.qSize > 0 && this.canStartOperation) return;
|
|
256
|
+
this.turnDepth++;
|
|
257
|
+
try {
|
|
258
|
+
onDrain({
|
|
259
|
+
stimulation: this,
|
|
260
|
+
queueLength: this.pendingActivations + this.activeOperations,
|
|
261
|
+
pendingActivations: this.pendingActivations,
|
|
262
|
+
activeActivations: this.activeOperations
|
|
263
|
+
});
|
|
264
|
+
} finally {
|
|
265
|
+
this.turnDepth--;
|
|
266
|
+
}
|
|
267
|
+
}
|
|
268
|
+
/**
|
|
269
|
+
* Activations that exist (or are reserved) but whose dendrite body has not
|
|
270
|
+
* been invoked yet: sitting in the ring buffer, created and held in
|
|
271
|
+
* pendingTasks, or reserved by an array fan-out mid-dispatch. Subscribers
|
|
272
|
+
* parked behind an async onResponse land here too - their body has not run.
|
|
273
|
+
*/
|
|
274
|
+
get pendingActivations() {
|
|
275
|
+
return this.qSize + this.scheduledCount + this.reservedActivations;
|
|
276
|
+
}
|
|
202
277
|
tryResolveCompleted() {
|
|
203
278
|
if (this.isCompleted) return;
|
|
204
279
|
const noActive = this.activeOperations === 0;
|
|
205
|
-
const noPending = this.
|
|
280
|
+
const noPending = this.pendingActivations === 0;
|
|
206
281
|
const aborted = !!this.options?.abortSignal?.aborted;
|
|
207
282
|
if (noPending && noActive || aborted && noActive && !noPending) {
|
|
208
283
|
if (aborted) {
|
|
@@ -264,6 +339,19 @@ var CNSStimulation = class {
|
|
|
264
339
|
getFailedTasks() {
|
|
265
340
|
return this.failedTasks ? [...this.failedTasks] : [];
|
|
266
341
|
}
|
|
342
|
+
/**
|
|
343
|
+
* The current outstanding frontier — every task that has not completed:
|
|
344
|
+
* queued, active, and pending (awaiting an async onResponse), plus any
|
|
345
|
+
* failed/aborted tasks. This is the set to persist for resume: re-activating
|
|
346
|
+
* it re-runs exactly the not-yet-done work. Safe to call at any point during
|
|
347
|
+
* a run (for progress) or after it fails.
|
|
348
|
+
*/
|
|
349
|
+
getOutstandingTasks() {
|
|
350
|
+
return [
|
|
351
|
+
...this.getAllActivationTasks(),
|
|
352
|
+
...this.getFailedTasks().map((f) => f.task)
|
|
353
|
+
];
|
|
354
|
+
}
|
|
267
355
|
/**
|
|
268
356
|
* Get the context store for this stimulation
|
|
269
357
|
*/
|
|
@@ -274,10 +362,15 @@ var CNSStimulation = class {
|
|
|
274
362
|
* Enqueue activation tasks directly into the stimulation queue
|
|
275
363
|
*/
|
|
276
364
|
enqueueTasks(tasks) {
|
|
277
|
-
|
|
278
|
-
|
|
365
|
+
this.beginTurn();
|
|
366
|
+
try {
|
|
367
|
+
for (const task of tasks) {
|
|
368
|
+
this.qEnqueue(task);
|
|
369
|
+
}
|
|
370
|
+
this.tryResolveCompleted();
|
|
371
|
+
} finally {
|
|
372
|
+
this.endTurn();
|
|
279
373
|
}
|
|
280
|
-
this.tryResolveCompleted();
|
|
281
374
|
}
|
|
282
375
|
get concurrencyEnabled() {
|
|
283
376
|
return this.options?.concurrency !== void 0 && this.options?.concurrency > 0;
|
|
@@ -378,14 +471,19 @@ var CNSStimulation = class {
|
|
|
378
471
|
}
|
|
379
472
|
}
|
|
380
473
|
if (!subscriber) {
|
|
474
|
+
const error = new Error(`Subscriber not found for activation task`);
|
|
381
475
|
this.pushFailedTask({
|
|
382
476
|
task: neuronActivationTask,
|
|
383
|
-
error
|
|
384
|
-
`Subscriber not found for activation task`
|
|
385
|
-
),
|
|
477
|
+
error,
|
|
386
478
|
aborted: false
|
|
387
479
|
});
|
|
388
480
|
return () => {
|
|
481
|
+
this.processResponseOrResponses(
|
|
482
|
+
void 0,
|
|
483
|
+
neuronActivationTask.input,
|
|
484
|
+
void 0,
|
|
485
|
+
error
|
|
486
|
+
);
|
|
389
487
|
};
|
|
390
488
|
}
|
|
391
489
|
const neuron2 = subscriber.neuron;
|
|
@@ -432,13 +530,13 @@ var CNSStimulation = class {
|
|
|
432
530
|
error: error instanceof Error ? error : new Error(String(error)),
|
|
433
531
|
aborted: isAborted
|
|
434
532
|
});
|
|
435
|
-
this.processResponseOrResponses(
|
|
436
|
-
neuron2,
|
|
437
|
-
inputSignal,
|
|
438
|
-
void 0,
|
|
439
|
-
error
|
|
440
|
-
);
|
|
441
533
|
return () => {
|
|
534
|
+
this.processResponseOrResponses(
|
|
535
|
+
neuron2,
|
|
536
|
+
inputSignal,
|
|
537
|
+
void 0,
|
|
538
|
+
error
|
|
539
|
+
);
|
|
442
540
|
};
|
|
443
541
|
}
|
|
444
542
|
const maxDuration = neuron2.maxDuration;
|
|
@@ -508,8 +606,26 @@ var CNSStimulation = class {
|
|
|
508
606
|
this.processResponse(emitter, inputSignal, void 0, error);
|
|
509
607
|
return;
|
|
510
608
|
}
|
|
511
|
-
|
|
512
|
-
|
|
609
|
+
let perSignal;
|
|
610
|
+
if (!error) {
|
|
611
|
+
perSignal = new Array(outputSignalOrSignals.length);
|
|
612
|
+
let reserved = 0;
|
|
613
|
+
for (let i = 0; i < outputSignalOrSignals.length; i++) {
|
|
614
|
+
const c = outputSignalOrSignals[i]?.collateral;
|
|
615
|
+
const n = c ? this.cns.network.getSubscribers(c).length : 0;
|
|
616
|
+
perSignal[i] = n;
|
|
617
|
+
reserved += n;
|
|
618
|
+
}
|
|
619
|
+
this.reservedActivations += reserved;
|
|
620
|
+
}
|
|
621
|
+
for (let i = 0; i < outputSignalOrSignals.length; i++) {
|
|
622
|
+
if (perSignal) this.reservedActivations -= perSignal[i];
|
|
623
|
+
this.processResponse(
|
|
624
|
+
emitter,
|
|
625
|
+
inputSignal,
|
|
626
|
+
outputSignalOrSignals[i],
|
|
627
|
+
error
|
|
628
|
+
);
|
|
513
629
|
}
|
|
514
630
|
return;
|
|
515
631
|
}
|
|
@@ -563,9 +679,12 @@ var CNSStimulation = class {
|
|
|
563
679
|
this.ctxStore,
|
|
564
680
|
inputSignal,
|
|
565
681
|
outputSignal,
|
|
566
|
-
this.
|
|
682
|
+
this.pendingActivations + this.activeOperations,
|
|
683
|
+
this.pendingActivations,
|
|
684
|
+
this.activeOperations,
|
|
567
685
|
this.options?.maxNeuronHops && emitter ? this.neuronVisitMap?.get(emitter) ?? 0 : void 0,
|
|
568
|
-
error
|
|
686
|
+
error,
|
|
687
|
+
emitter
|
|
569
688
|
)
|
|
570
689
|
);
|
|
571
690
|
} catch (e) {
|
|
@@ -581,21 +700,35 @@ var CNSStimulation = class {
|
|
|
581
700
|
if (maybePromise && typeof maybePromise.then === "function") {
|
|
582
701
|
maybePromise.then(
|
|
583
702
|
() => {
|
|
584
|
-
|
|
585
|
-
|
|
586
|
-
|
|
587
|
-
|
|
703
|
+
this.beginTurn();
|
|
704
|
+
try {
|
|
705
|
+
for (let i = 0; i < subscriberActivationTasks.length; i++) {
|
|
706
|
+
this.scheduledCount--;
|
|
707
|
+
this.pendingTasks?.delete(
|
|
708
|
+
subscriberActivationTasks[i]
|
|
709
|
+
);
|
|
710
|
+
this.qEnqueue(subscriberActivationTasks[i]);
|
|
711
|
+
}
|
|
712
|
+
this.tryResolveCompleted();
|
|
713
|
+
} finally {
|
|
714
|
+
this.endTurn();
|
|
588
715
|
}
|
|
589
|
-
this.tryResolveCompleted();
|
|
590
716
|
},
|
|
591
717
|
(error2) => {
|
|
592
718
|
this.onResponseError = error2 instanceof Error ? error2 : new Error(String(error2));
|
|
593
|
-
|
|
594
|
-
|
|
595
|
-
|
|
596
|
-
|
|
719
|
+
this.beginTurn();
|
|
720
|
+
try {
|
|
721
|
+
for (let i = 0; i < subscriberActivationTasks.length; i++) {
|
|
722
|
+
this.scheduledCount--;
|
|
723
|
+
this.pendingTasks?.delete(
|
|
724
|
+
subscriberActivationTasks[i]
|
|
725
|
+
);
|
|
726
|
+
this.qEnqueue(subscriberActivationTasks[i]);
|
|
727
|
+
}
|
|
728
|
+
this.tryResolveCompleted();
|
|
729
|
+
} finally {
|
|
730
|
+
this.endTurn();
|
|
597
731
|
}
|
|
598
|
-
this.tryResolveCompleted();
|
|
599
732
|
}
|
|
600
733
|
);
|
|
601
734
|
return;
|
|
@@ -608,12 +741,21 @@ var CNSStimulation = class {
|
|
|
608
741
|
this.tryResolveCompleted();
|
|
609
742
|
}
|
|
610
743
|
responseToSignal(signalOrSignals) {
|
|
611
|
-
|
|
612
|
-
|
|
613
|
-
|
|
744
|
+
this.beginTurn();
|
|
745
|
+
try {
|
|
746
|
+
if (Array.isArray(signalOrSignals)) {
|
|
747
|
+
this.processResponseOrResponses(
|
|
748
|
+
void 0,
|
|
749
|
+
void 0,
|
|
750
|
+
signalOrSignals
|
|
751
|
+
);
|
|
752
|
+
return;
|
|
753
|
+
}
|
|
754
|
+
this.processResponse(void 0, void 0, signalOrSignals);
|
|
755
|
+
this.tryResolveCompleted();
|
|
756
|
+
} finally {
|
|
757
|
+
this.endTurn();
|
|
614
758
|
}
|
|
615
|
-
this.processResponse(void 0, void 0, signalOrSignals);
|
|
616
|
-
this.tryResolveCompleted();
|
|
617
759
|
}
|
|
618
760
|
};
|
|
619
761
|
|
|
@@ -960,6 +1102,10 @@ var CNS = class {
|
|
|
960
1102
|
* Global response listeners applied to every stimulation.
|
|
961
1103
|
*/
|
|
962
1104
|
this.globalResponseListeners = [];
|
|
1105
|
+
/**
|
|
1106
|
+
* Global batch-boundary listeners applied to every stimulation.
|
|
1107
|
+
*/
|
|
1108
|
+
this.globalDrainListeners = [];
|
|
963
1109
|
this.network = new CNSNetwork(this.neurons);
|
|
964
1110
|
this.global = global;
|
|
965
1111
|
}
|
|
@@ -973,6 +1119,50 @@ var CNS = class {
|
|
|
973
1119
|
if (idx >= 0) this.globalResponseListeners.splice(idx, 1);
|
|
974
1120
|
};
|
|
975
1121
|
}
|
|
1122
|
+
/**
|
|
1123
|
+
* Register a listener called once at the end of every synchronous turn of
|
|
1124
|
+
* every stimulation - see {@link TCNSStimulationDrain}. This is how an
|
|
1125
|
+
* integration (a state manager, an in-memory database) installs a single
|
|
1126
|
+
* commit point for the whole organism instead of passing `onDrain` per call.
|
|
1127
|
+
*
|
|
1128
|
+
* Returns an unsubscribe function.
|
|
1129
|
+
*/
|
|
1130
|
+
addDrainListener(listener) {
|
|
1131
|
+
this.globalDrainListeners.push(listener);
|
|
1132
|
+
let active = true;
|
|
1133
|
+
return () => {
|
|
1134
|
+
if (!active) return;
|
|
1135
|
+
active = false;
|
|
1136
|
+
const idx = this.globalDrainListeners.indexOf(listener);
|
|
1137
|
+
if (idx >= 0) this.globalDrainListeners.splice(idx, 1);
|
|
1138
|
+
};
|
|
1139
|
+
}
|
|
1140
|
+
/**
|
|
1141
|
+
* Fan a drain out to the local and global listeners, or return undefined when
|
|
1142
|
+
* there are none so the stimulation can skip the boundary check entirely.
|
|
1143
|
+
*
|
|
1144
|
+
* Listener errors are isolated: a drain is a notification, and one broken
|
|
1145
|
+
* flush must not stop the others or derail the stimulation that triggered it.
|
|
1146
|
+
*/
|
|
1147
|
+
wrapOnDrain(local) {
|
|
1148
|
+
if (this.globalDrainListeners.length === 0 && !local) return void 0;
|
|
1149
|
+
return (d) => {
|
|
1150
|
+
if (local) {
|
|
1151
|
+
try {
|
|
1152
|
+
local(d);
|
|
1153
|
+
} catch (error) {
|
|
1154
|
+
console.error("[CNS] onDrain listener threw", error);
|
|
1155
|
+
}
|
|
1156
|
+
}
|
|
1157
|
+
for (let i = 0; i < this.globalDrainListeners.length; i++) {
|
|
1158
|
+
try {
|
|
1159
|
+
this.globalDrainListeners[i](d);
|
|
1160
|
+
} catch (error) {
|
|
1161
|
+
console.error("[CNS] drain listener threw", error);
|
|
1162
|
+
}
|
|
1163
|
+
}
|
|
1164
|
+
};
|
|
1165
|
+
}
|
|
976
1166
|
wrapOnResponse(local) {
|
|
977
1167
|
if (this.globalResponseListeners.length === 0 && !local) {
|
|
978
1168
|
return void 0;
|
|
@@ -1020,7 +1210,8 @@ var CNS = class {
|
|
|
1020
1210
|
this,
|
|
1021
1211
|
this.instanceNeuronQueue,
|
|
1022
1212
|
options,
|
|
1023
|
-
wrapped
|
|
1213
|
+
wrapped,
|
|
1214
|
+
this.wrapOnDrain(options?.onDrain)
|
|
1024
1215
|
);
|
|
1025
1216
|
stimulation.responseToSignal(signalOrSignals);
|
|
1026
1217
|
return stimulation;
|
|
@@ -1034,79 +1225,14 @@ var CNS = class {
|
|
|
1034
1225
|
this,
|
|
1035
1226
|
this.instanceNeuronQueue,
|
|
1036
1227
|
options,
|
|
1037
|
-
wrapped
|
|
1228
|
+
wrapped,
|
|
1229
|
+
this.wrapOnDrain(options?.onDrain)
|
|
1038
1230
|
);
|
|
1039
1231
|
stimulation.enqueueTasks(tasks);
|
|
1040
1232
|
return stimulation;
|
|
1041
1233
|
}
|
|
1042
1234
|
};
|
|
1043
1235
|
|
|
1044
|
-
// src/CNSPersistOptionsRegistry.ts
|
|
1045
|
-
var CNSPersistOptionsRegistry = class {
|
|
1046
|
-
constructor() {
|
|
1047
|
-
this.neurons = /* @__PURE__ */ new Map();
|
|
1048
|
-
this.neuronNames = /* @__PURE__ */ new WeakMap();
|
|
1049
|
-
this.collaterals = /* @__PURE__ */ new Map();
|
|
1050
|
-
this.stimulations = /* @__PURE__ */ new Map();
|
|
1051
|
-
}
|
|
1052
|
-
addNeuron(neuron2, options) {
|
|
1053
|
-
this.neurons.set(options.name, neuron2);
|
|
1054
|
-
this.neuronNames.set(neuron2, options.name);
|
|
1055
|
-
}
|
|
1056
|
-
getNeuron(name) {
|
|
1057
|
-
return this.neurons.get(name);
|
|
1058
|
-
}
|
|
1059
|
-
getNeuronName(neuron2) {
|
|
1060
|
-
return this.neuronNames.get(neuron2);
|
|
1061
|
-
}
|
|
1062
|
-
getNamedNeurons() {
|
|
1063
|
-
return this.neurons;
|
|
1064
|
-
}
|
|
1065
|
-
getCollateralName(collateral2) {
|
|
1066
|
-
for (const [name, col] of this.collaterals) {
|
|
1067
|
-
if (col === collateral2) return name;
|
|
1068
|
-
}
|
|
1069
|
-
return void 0;
|
|
1070
|
-
}
|
|
1071
|
-
removeNeuron(name) {
|
|
1072
|
-
const neuron2 = this.neurons.get(name);
|
|
1073
|
-
if (neuron2) this.neuronNames.delete(neuron2);
|
|
1074
|
-
this.neurons.delete(name);
|
|
1075
|
-
}
|
|
1076
|
-
addCollateral(collateral2, options) {
|
|
1077
|
-
this.collaterals.set(options.name, collateral2);
|
|
1078
|
-
}
|
|
1079
|
-
getCollateral(name) {
|
|
1080
|
-
return this.collaterals.get(name);
|
|
1081
|
-
}
|
|
1082
|
-
removeCollateral(name) {
|
|
1083
|
-
this.collaterals.delete(name);
|
|
1084
|
-
}
|
|
1085
|
-
addStimulation(stimulation, options) {
|
|
1086
|
-
this.stimulations.set(options.stimulationId, stimulation);
|
|
1087
|
-
}
|
|
1088
|
-
getStimulation(stimulationId) {
|
|
1089
|
-
return this.stimulations.get(stimulationId);
|
|
1090
|
-
}
|
|
1091
|
-
removeStimulation(stimulationId) {
|
|
1092
|
-
this.stimulations.delete(stimulationId);
|
|
1093
|
-
}
|
|
1094
|
-
register(name, neuron2, collateralNames) {
|
|
1095
|
-
this.addNeuron(neuron2, { name, neuron: neuron2 });
|
|
1096
|
-
for (const [key, col] of Object.entries(neuron2.axon)) {
|
|
1097
|
-
this.addCollateral(col, {
|
|
1098
|
-
name: collateralNames?.[key] ?? key,
|
|
1099
|
-
collateral: col
|
|
1100
|
-
});
|
|
1101
|
-
}
|
|
1102
|
-
return this;
|
|
1103
|
-
}
|
|
1104
|
-
registerCollateral(name, collateral2) {
|
|
1105
|
-
this.addCollateral(collateral2, { name, collateral: collateral2 });
|
|
1106
|
-
return this;
|
|
1107
|
-
}
|
|
1108
|
-
};
|
|
1109
|
-
|
|
1110
1236
|
// src/CNSCollateral.ts
|
|
1111
1237
|
var CNSCollateral = class {
|
|
1112
1238
|
createSignal(payload) {
|
|
@@ -1309,31 +1435,7 @@ var modality = (afferentPaths) => {
|
|
|
1309
1435
|
afferentPaths
|
|
1310
1436
|
};
|
|
1311
1437
|
};
|
|
1312
|
-
var createPersistRegistry = (namedNeurons) => {
|
|
1313
|
-
const registry = new CNSPersistOptionsRegistry();
|
|
1314
|
-
for (const [name, entry] of Object.entries(namedNeurons)) {
|
|
1315
|
-
const isEntry = "neuron" in entry && !("axon" in entry);
|
|
1316
|
-
const neuron2 = isEntry ? entry.neuron : entry;
|
|
1317
|
-
const colNames = isEntry ? entry.collaterals ?? {} : {};
|
|
1318
|
-
registry.addNeuron(neuron2, { name, neuron: neuron2 });
|
|
1319
|
-
for (const [key, col] of Object.entries(neuron2.axon)) {
|
|
1320
|
-
registry.addCollateral(col, {
|
|
1321
|
-
name: colNames[key] ?? key,
|
|
1322
|
-
collateral: col
|
|
1323
|
-
});
|
|
1324
|
-
}
|
|
1325
|
-
}
|
|
1326
|
-
return registry;
|
|
1327
|
-
};
|
|
1328
|
-
var createCNS = (namedNeurons, options) => {
|
|
1329
|
-
const neurons = Object.values(namedNeurons).map(
|
|
1330
|
-
(entry) => entry && typeof entry === "object" && "neuron" in entry ? entry.neuron : entry
|
|
1331
|
-
);
|
|
1332
|
-
const cns = new CNS(neurons, options, options?.global);
|
|
1333
|
-
const registry = createPersistRegistry(namedNeurons);
|
|
1334
|
-
return { cns, registry };
|
|
1335
|
-
};
|
|
1336
1438
|
|
|
1337
|
-
export { CNS, CNSCollateral,
|
|
1439
|
+
export { CNS, CNSCollateral, CNSStimulationContextStore, CNSStimulationGate, afferentPath, collateral, modality, neuron, neuronFactory, withCtx, withGlobal };
|
|
1338
1440
|
//# sourceMappingURL=index.js.map
|
|
1339
1441
|
//# sourceMappingURL=index.js.map
|