@cnstra/core 2.3.0 → 2.5.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/README.md +28 -6
- package/dist/CNS.d.ts +29 -1
- package/dist/CNS.d.ts.map +1 -1
- package/dist/CNSStimulation.d.ts +33 -1
- package/dist/CNSStimulation.d.ts.map +1 -1
- package/dist/factory/index.d.ts +94 -67
- package/dist/factory/index.d.ts.map +1 -1
- package/dist/index.cjs +241 -48
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.ts +5 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +239 -49
- package/dist/index.js.map +1 -1
- package/dist/interfaces/ICNS.d.ts +7 -0
- package/dist/interfaces/ICNS.d.ts.map +1 -1
- package/dist/types/TCNSDendrite.d.ts +3 -8
- package/dist/types/TCNSDendrite.d.ts.map +1 -1
- package/dist/types/TCNSHandlerContext.d.ts +24 -0
- package/dist/types/TCNSHandlerContext.d.ts.map +1 -0
- package/dist/types/TCNSNeuron.d.ts +1 -1
- package/dist/types/TCNSNeuron.d.ts.map +1 -1
- package/dist/types/TCNSStimulationDrain.d.ts +37 -0
- package/dist/types/TCNSStimulationDrain.d.ts.map +1 -0
- package/dist/types/TCNSStimulationOptions.d.ts +18 -0
- package/dist/types/TCNSStimulationOptions.d.ts.map +1 -1
- package/dist/types/TCNSStimulationResponse.d.ts +40 -0
- package/dist/types/TCNSStimulationResponse.d.ts.map +1 -1
- package/package.json +1 -1
package/dist/index.d.ts
CHANGED
|
@@ -7,13 +7,17 @@ export type { ICNS } from './interfaces/ICNS';
|
|
|
7
7
|
export type { TCNSNeuron } from './types/TCNSNeuron';
|
|
8
8
|
export type { TCNSAxon } from './types/TCNSAxon';
|
|
9
9
|
export type { TCNSDendrite } from './types/TCNSDendrite';
|
|
10
|
+
export type { TCNSHandlerContext } from './types/TCNSHandlerContext';
|
|
10
11
|
export type { TCNSSignal } from './types/TCNSSignal';
|
|
11
12
|
export type { TCNSNeuronActivationTask } from './types/TCNSNeuronActivationTask';
|
|
12
13
|
export type { TCNSStimulationOptions } from './types/TCNSStimulationOptions';
|
|
14
|
+
export type { TCNSStimulationResponse } from './types/TCNSStimulationResponse';
|
|
15
|
+
export type { TCNSStimulationDrain } from './types/TCNSStimulationDrain';
|
|
13
16
|
export type { TCNSModality } from './types/TCNSModality';
|
|
14
17
|
export type { TCNSAfferentPath } from './types/TCNSAfferentPath';
|
|
15
18
|
export type { TCNSNeuronActivationTaskFailure } from './types/TCNSNeuronActivationTaskFailure';
|
|
16
19
|
export type { TCNSNeuronPersistOptions, TCNSCollateralPersistOptions, TCNSStimulationPersistOptions } from './types/TCNSPersist';
|
|
17
20
|
export type { TCNSStimulationGateOptions, TCNSStimulationGateSignal } from './utils/CNSStimulationGate';
|
|
18
|
-
export { collateral, neuron, withCtx, afferentPath, modality, createPersistRegistry, } from './factory/index';
|
|
21
|
+
export { collateral, neuron, neuronFactory, withCtx, withGlobal, afferentPath, modality, createPersistRegistry, createCNS, } from './factory/index';
|
|
22
|
+
export type { TNeuronFactory } from './factory/index';
|
|
19
23
|
//# 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;AAC5B,OAAO,EAAE,yBAAyB,EAAE,MAAM,6BAA6B,CAAC;AACxE,OAAO,EAAE,aAAa,EAAE,MAAM,iBAAiB,CAAC;AAChD,OAAO,EAAE,0BAA0B,EAAE,MAAM,8BAA8B,CAAC;AAC1E,OAAO,EAAE,kBAAkB,EAAE,MAAM,4BAA4B,CAAC;AAEhE,YAAY,EAAE,IAAI,EAAE,MAAM,mBAAmB,CAAC;AAE9C,YAAY,EAAE,UAAU,EAAE,MAAM,oBAAoB,CAAC;AACrD,YAAY,EAAE,QAAQ,EAAE,MAAM,kBAAkB,CAAC;AACjD,YAAY,EAAE,YAAY,EAAE,MAAM,sBAAsB,CAAC;AACzD,YAAY,EAAE,UAAU,EAAE,MAAM,oBAAoB,CAAC;AACrD,YAAY,EAAE,wBAAwB,EAAE,MAAM,kCAAkC,CAAC;AACjF,YAAY,EAAE,sBAAsB,EAAE,MAAM,gCAAgC,CAAC;AAC7E,YAAY,EAAE,YAAY,EAAE,MAAM,sBAAsB,CAAC;AACzD,YAAY,EAAE,gBAAgB,EAAE,MAAM,0BAA0B,CAAC;AACjE,YAAY,EAAE,+BAA+B,EAAE,MAAM,yCAAyC,CAAC;AAC/F,YAAY,EAAE,wBAAwB,EAAE,4BAA4B,EAAE,6BAA6B,EAAE,MAAM,qBAAqB,CAAC;AACjI,YAAY,EAAE,0BAA0B,EAAE,yBAAyB,EAAE,MAAM,4BAA4B,CAAC;AAGxG,OAAO,EACH,UAAU,EACV,MAAM,EACN,OAAO,EACP,YAAY,EACZ,QAAQ,EACR,qBAAqB,
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,GAAG,EAAE,MAAM,OAAO,CAAC;AAC5B,OAAO,EAAE,yBAAyB,EAAE,MAAM,6BAA6B,CAAC;AACxE,OAAO,EAAE,aAAa,EAAE,MAAM,iBAAiB,CAAC;AAChD,OAAO,EAAE,0BAA0B,EAAE,MAAM,8BAA8B,CAAC;AAC1E,OAAO,EAAE,kBAAkB,EAAE,MAAM,4BAA4B,CAAC;AAEhE,YAAY,EAAE,IAAI,EAAE,MAAM,mBAAmB,CAAC;AAE9C,YAAY,EAAE,UAAU,EAAE,MAAM,oBAAoB,CAAC;AACrD,YAAY,EAAE,QAAQ,EAAE,MAAM,kBAAkB,CAAC;AACjD,YAAY,EAAE,YAAY,EAAE,MAAM,sBAAsB,CAAC;AACzD,YAAY,EAAE,kBAAkB,EAAE,MAAM,4BAA4B,CAAC;AACrE,YAAY,EAAE,UAAU,EAAE,MAAM,oBAAoB,CAAC;AACrD,YAAY,EAAE,wBAAwB,EAAE,MAAM,kCAAkC,CAAC;AACjF,YAAY,EAAE,sBAAsB,EAAE,MAAM,gCAAgC,CAAC;AAC7E,YAAY,EAAE,uBAAuB,EAAE,MAAM,iCAAiC,CAAC;AAC/E,YAAY,EAAE,oBAAoB,EAAE,MAAM,8BAA8B,CAAC;AACzE,YAAY,EAAE,YAAY,EAAE,MAAM,sBAAsB,CAAC;AACzD,YAAY,EAAE,gBAAgB,EAAE,MAAM,0BAA0B,CAAC;AACjE,YAAY,EAAE,+BAA+B,EAAE,MAAM,yCAAyC,CAAC;AAC/F,YAAY,EAAE,wBAAwB,EAAE,4BAA4B,EAAE,6BAA6B,EAAE,MAAM,qBAAqB,CAAC;AACjI,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,EACR,qBAAqB,EACrB,SAAS,GACZ,MAAM,iBAAiB,CAAC;AACzB,YAAY,EAAE,cAAc,EAAE,MAAM,iBAAiB,CAAC"}
|
package/dist/index.js
CHANGED
|
@@ -31,6 +31,12 @@ var CNSDendriteContext = class {
|
|
|
31
31
|
this.abortSignal = abortSignal;
|
|
32
32
|
this.cns = cns;
|
|
33
33
|
}
|
|
34
|
+
// Prototype getter, not a constructor field: the per-activation allocation is
|
|
35
|
+
// unchanged (still 4 fields) and you only pay a single `cns.global` read on the
|
|
36
|
+
// dendrites that actually reach for it. Value getter, so `{ global }` destructuring is safe.
|
|
37
|
+
get global() {
|
|
38
|
+
return this.cns.global;
|
|
39
|
+
}
|
|
34
40
|
get() {
|
|
35
41
|
return this.stimulation.getContext().get(this.neuron);
|
|
36
42
|
}
|
|
@@ -42,12 +48,14 @@ var CNSDendriteContext = class {
|
|
|
42
48
|
}
|
|
43
49
|
};
|
|
44
50
|
var CNSStimulationResponseImpl = class {
|
|
45
|
-
constructor(stimulation, store, inputSignal, outputSignal, queueLength, hops, error) {
|
|
51
|
+
constructor(stimulation, store, inputSignal, outputSignal, queueLength, pendingActivations, activeActivations, hops, error) {
|
|
46
52
|
this.stimulation = stimulation;
|
|
47
53
|
this.store = store;
|
|
48
54
|
this.inputSignal = inputSignal;
|
|
49
55
|
this.outputSignal = outputSignal;
|
|
50
56
|
this.queueLength = queueLength;
|
|
57
|
+
this.pendingActivations = pendingActivations;
|
|
58
|
+
this.activeActivations = activeActivations;
|
|
51
59
|
this.hops = hops;
|
|
52
60
|
this.error = error;
|
|
53
61
|
}
|
|
@@ -56,7 +64,7 @@ var CNSStimulationResponseImpl = class {
|
|
|
56
64
|
}
|
|
57
65
|
};
|
|
58
66
|
var CNSStimulation = class {
|
|
59
|
-
constructor(cns, instanceNeuronQueue, options, onResponse) {
|
|
67
|
+
constructor(cns, instanceNeuronQueue, options, onResponse, onDrain) {
|
|
60
68
|
this.cns = cns;
|
|
61
69
|
this.options = options;
|
|
62
70
|
this.qHead = 0;
|
|
@@ -67,9 +75,20 @@ var CNSStimulation = class {
|
|
|
67
75
|
// Re-entrancy guard for the pump loop.
|
|
68
76
|
this.pumping = false;
|
|
69
77
|
this.needsPump = false;
|
|
78
|
+
// Nesting depth of the current synchronous turn. Only the outermost close
|
|
79
|
+
// announces a drain - see beginTurn/endTurn.
|
|
80
|
+
this.turnDepth = 0;
|
|
70
81
|
this.scheduledCount = 0;
|
|
82
|
+
// Activations belonging to signals of an in-progress array fan-out that have
|
|
83
|
+
// not been handed to processResponse yet, so the task objects do not exist.
|
|
84
|
+
// processResponse enqueues synchronously, so the first signal's whole subtree
|
|
85
|
+
// drains before the second signal is even looked at; without this counter
|
|
86
|
+
// that subtree's leaf sees an empty queue and reads as "all work done".
|
|
87
|
+
// Counted in activations, not signals, so every public counter shares a unit.
|
|
88
|
+
this.reservedActivations = 0;
|
|
71
89
|
this.isCompleted = false;
|
|
72
90
|
this.completionRejected = false;
|
|
91
|
+
this.onDrain = onDrain;
|
|
73
92
|
this.ctxStore = options?.ctx;
|
|
74
93
|
this.instanceNeuronQueue = instanceNeuronQueue;
|
|
75
94
|
this.onResponse = onResponse;
|
|
@@ -166,18 +185,28 @@ var CNSStimulation = class {
|
|
|
166
185
|
(cb) => {
|
|
167
186
|
this.activeOperations--;
|
|
168
187
|
this.activeTasks.delete(task);
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
if (
|
|
172
|
-
|
|
188
|
+
this.beginTurn();
|
|
189
|
+
try {
|
|
190
|
+
if (typeof cb === "function") cb();
|
|
191
|
+
if (this.qSize > 0 && this.canStartOperation) {
|
|
192
|
+
if (this.pumping) this.needsPump = true;
|
|
193
|
+
else this.pump();
|
|
194
|
+
}
|
|
195
|
+
} finally {
|
|
196
|
+
this.endTurn();
|
|
173
197
|
}
|
|
174
198
|
},
|
|
175
199
|
(err) => {
|
|
176
200
|
this.activeOperations--;
|
|
177
201
|
this.activeTasks.delete(task);
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
202
|
+
this.beginTurn();
|
|
203
|
+
try {
|
|
204
|
+
if (this.qSize > 0 && this.canStartOperation) {
|
|
205
|
+
if (this.pumping) this.needsPump = true;
|
|
206
|
+
else this.pump();
|
|
207
|
+
}
|
|
208
|
+
} finally {
|
|
209
|
+
this.endTurn();
|
|
181
210
|
}
|
|
182
211
|
throw err;
|
|
183
212
|
}
|
|
@@ -193,10 +222,54 @@ var CNSStimulation = class {
|
|
|
193
222
|
this.pump();
|
|
194
223
|
}
|
|
195
224
|
}
|
|
225
|
+
/**
|
|
226
|
+
* Open a synchronous turn. Turns nest: a drain is announced only when the
|
|
227
|
+
* outermost one closes, so an enqueue that happens while the pump is already
|
|
228
|
+
* running does not produce its own boundary.
|
|
229
|
+
*/
|
|
230
|
+
beginTurn() {
|
|
231
|
+
this.turnDepth++;
|
|
232
|
+
}
|
|
233
|
+
/**
|
|
234
|
+
* Close a synchronous turn and, if it was the outermost and nothing more can
|
|
235
|
+
* run without yielding to the event loop, announce the drain.
|
|
236
|
+
*
|
|
237
|
+
* This is the only place the synchronous frontier is observable. A response
|
|
238
|
+
* cannot serve the purpose: responses are emitted when an activation
|
|
239
|
+
* *finishes*, but a turn just as often ends when one *starts* and returns a
|
|
240
|
+
* promise - at which point there is nothing left to emit a response from.
|
|
241
|
+
*/
|
|
242
|
+
endTurn() {
|
|
243
|
+
if (--this.turnDepth > 0) return;
|
|
244
|
+
const onDrain = this.onDrain;
|
|
245
|
+
if (!onDrain) return;
|
|
246
|
+
if (this.pumping) return;
|
|
247
|
+
if (this.qSize > 0 && this.canStartOperation) return;
|
|
248
|
+
this.turnDepth++;
|
|
249
|
+
try {
|
|
250
|
+
onDrain({
|
|
251
|
+
stimulation: this,
|
|
252
|
+
queueLength: this.pendingActivations + this.activeOperations,
|
|
253
|
+
pendingActivations: this.pendingActivations,
|
|
254
|
+
activeActivations: this.activeOperations
|
|
255
|
+
});
|
|
256
|
+
} finally {
|
|
257
|
+
this.turnDepth--;
|
|
258
|
+
}
|
|
259
|
+
}
|
|
260
|
+
/**
|
|
261
|
+
* Activations that exist (or are reserved) but whose dendrite body has not
|
|
262
|
+
* been invoked yet: sitting in the ring buffer, created and held in
|
|
263
|
+
* pendingTasks, or reserved by an array fan-out mid-dispatch. Subscribers
|
|
264
|
+
* parked behind an async onResponse land here too - their body has not run.
|
|
265
|
+
*/
|
|
266
|
+
get pendingActivations() {
|
|
267
|
+
return this.qSize + this.scheduledCount + this.reservedActivations;
|
|
268
|
+
}
|
|
196
269
|
tryResolveCompleted() {
|
|
197
270
|
if (this.isCompleted) return;
|
|
198
271
|
const noActive = this.activeOperations === 0;
|
|
199
|
-
const noPending = this.
|
|
272
|
+
const noPending = this.pendingActivations === 0;
|
|
200
273
|
const aborted = !!this.options?.abortSignal?.aborted;
|
|
201
274
|
if (noPending && noActive || aborted && noActive && !noPending) {
|
|
202
275
|
if (aborted) {
|
|
@@ -268,10 +341,15 @@ var CNSStimulation = class {
|
|
|
268
341
|
* Enqueue activation tasks directly into the stimulation queue
|
|
269
342
|
*/
|
|
270
343
|
enqueueTasks(tasks) {
|
|
271
|
-
|
|
272
|
-
|
|
344
|
+
this.beginTurn();
|
|
345
|
+
try {
|
|
346
|
+
for (const task of tasks) {
|
|
347
|
+
this.qEnqueue(task);
|
|
348
|
+
}
|
|
349
|
+
this.tryResolveCompleted();
|
|
350
|
+
} finally {
|
|
351
|
+
this.endTurn();
|
|
273
352
|
}
|
|
274
|
-
this.tryResolveCompleted();
|
|
275
353
|
}
|
|
276
354
|
get concurrencyEnabled() {
|
|
277
355
|
return this.options?.concurrency !== void 0 && this.options?.concurrency > 0;
|
|
@@ -372,14 +450,19 @@ var CNSStimulation = class {
|
|
|
372
450
|
}
|
|
373
451
|
}
|
|
374
452
|
if (!subscriber) {
|
|
453
|
+
const error = new Error(`Subscriber not found for activation task`);
|
|
375
454
|
this.pushFailedTask({
|
|
376
455
|
task: neuronActivationTask,
|
|
377
|
-
error
|
|
378
|
-
`Subscriber not found for activation task`
|
|
379
|
-
),
|
|
456
|
+
error,
|
|
380
457
|
aborted: false
|
|
381
458
|
});
|
|
382
459
|
return () => {
|
|
460
|
+
this.processResponseOrResponses(
|
|
461
|
+
void 0,
|
|
462
|
+
neuronActivationTask.input,
|
|
463
|
+
void 0,
|
|
464
|
+
error
|
|
465
|
+
);
|
|
383
466
|
};
|
|
384
467
|
}
|
|
385
468
|
const neuron2 = subscriber.neuron;
|
|
@@ -426,13 +509,13 @@ var CNSStimulation = class {
|
|
|
426
509
|
error: error instanceof Error ? error : new Error(String(error)),
|
|
427
510
|
aborted: isAborted
|
|
428
511
|
});
|
|
429
|
-
this.processResponseOrResponses(
|
|
430
|
-
neuron2,
|
|
431
|
-
inputSignal,
|
|
432
|
-
void 0,
|
|
433
|
-
error
|
|
434
|
-
);
|
|
435
512
|
return () => {
|
|
513
|
+
this.processResponseOrResponses(
|
|
514
|
+
neuron2,
|
|
515
|
+
inputSignal,
|
|
516
|
+
void 0,
|
|
517
|
+
error
|
|
518
|
+
);
|
|
436
519
|
};
|
|
437
520
|
}
|
|
438
521
|
const maxDuration = neuron2.maxDuration;
|
|
@@ -502,8 +585,26 @@ var CNSStimulation = class {
|
|
|
502
585
|
this.processResponse(emitter, inputSignal, void 0, error);
|
|
503
586
|
return;
|
|
504
587
|
}
|
|
505
|
-
|
|
506
|
-
|
|
588
|
+
let perSignal;
|
|
589
|
+
if (!error) {
|
|
590
|
+
perSignal = new Array(outputSignalOrSignals.length);
|
|
591
|
+
let reserved = 0;
|
|
592
|
+
for (let i = 0; i < outputSignalOrSignals.length; i++) {
|
|
593
|
+
const c = outputSignalOrSignals[i]?.collateral;
|
|
594
|
+
const n = c ? this.cns.network.getSubscribers(c).length : 0;
|
|
595
|
+
perSignal[i] = n;
|
|
596
|
+
reserved += n;
|
|
597
|
+
}
|
|
598
|
+
this.reservedActivations += reserved;
|
|
599
|
+
}
|
|
600
|
+
for (let i = 0; i < outputSignalOrSignals.length; i++) {
|
|
601
|
+
if (perSignal) this.reservedActivations -= perSignal[i];
|
|
602
|
+
this.processResponse(
|
|
603
|
+
emitter,
|
|
604
|
+
inputSignal,
|
|
605
|
+
outputSignalOrSignals[i],
|
|
606
|
+
error
|
|
607
|
+
);
|
|
507
608
|
}
|
|
508
609
|
return;
|
|
509
610
|
}
|
|
@@ -557,7 +658,9 @@ var CNSStimulation = class {
|
|
|
557
658
|
this.ctxStore,
|
|
558
659
|
inputSignal,
|
|
559
660
|
outputSignal,
|
|
560
|
-
this.
|
|
661
|
+
this.pendingActivations + this.activeOperations,
|
|
662
|
+
this.pendingActivations,
|
|
663
|
+
this.activeOperations,
|
|
561
664
|
this.options?.maxNeuronHops && emitter ? this.neuronVisitMap?.get(emitter) ?? 0 : void 0,
|
|
562
665
|
error
|
|
563
666
|
)
|
|
@@ -575,21 +678,35 @@ var CNSStimulation = class {
|
|
|
575
678
|
if (maybePromise && typeof maybePromise.then === "function") {
|
|
576
679
|
maybePromise.then(
|
|
577
680
|
() => {
|
|
578
|
-
|
|
579
|
-
|
|
580
|
-
|
|
581
|
-
|
|
681
|
+
this.beginTurn();
|
|
682
|
+
try {
|
|
683
|
+
for (let i = 0; i < subscriberActivationTasks.length; i++) {
|
|
684
|
+
this.scheduledCount--;
|
|
685
|
+
this.pendingTasks?.delete(
|
|
686
|
+
subscriberActivationTasks[i]
|
|
687
|
+
);
|
|
688
|
+
this.qEnqueue(subscriberActivationTasks[i]);
|
|
689
|
+
}
|
|
690
|
+
this.tryResolveCompleted();
|
|
691
|
+
} finally {
|
|
692
|
+
this.endTurn();
|
|
582
693
|
}
|
|
583
|
-
this.tryResolveCompleted();
|
|
584
694
|
},
|
|
585
695
|
(error2) => {
|
|
586
696
|
this.onResponseError = error2 instanceof Error ? error2 : new Error(String(error2));
|
|
587
|
-
|
|
588
|
-
|
|
589
|
-
|
|
590
|
-
|
|
697
|
+
this.beginTurn();
|
|
698
|
+
try {
|
|
699
|
+
for (let i = 0; i < subscriberActivationTasks.length; i++) {
|
|
700
|
+
this.scheduledCount--;
|
|
701
|
+
this.pendingTasks?.delete(
|
|
702
|
+
subscriberActivationTasks[i]
|
|
703
|
+
);
|
|
704
|
+
this.qEnqueue(subscriberActivationTasks[i]);
|
|
705
|
+
}
|
|
706
|
+
this.tryResolveCompleted();
|
|
707
|
+
} finally {
|
|
708
|
+
this.endTurn();
|
|
591
709
|
}
|
|
592
|
-
this.tryResolveCompleted();
|
|
593
710
|
}
|
|
594
711
|
);
|
|
595
712
|
return;
|
|
@@ -602,12 +719,21 @@ var CNSStimulation = class {
|
|
|
602
719
|
this.tryResolveCompleted();
|
|
603
720
|
}
|
|
604
721
|
responseToSignal(signalOrSignals) {
|
|
605
|
-
|
|
606
|
-
|
|
607
|
-
|
|
722
|
+
this.beginTurn();
|
|
723
|
+
try {
|
|
724
|
+
if (Array.isArray(signalOrSignals)) {
|
|
725
|
+
this.processResponseOrResponses(
|
|
726
|
+
void 0,
|
|
727
|
+
void 0,
|
|
728
|
+
signalOrSignals
|
|
729
|
+
);
|
|
730
|
+
return;
|
|
731
|
+
}
|
|
732
|
+
this.processResponse(void 0, void 0, signalOrSignals);
|
|
733
|
+
this.tryResolveCompleted();
|
|
734
|
+
} finally {
|
|
735
|
+
this.endTurn();
|
|
608
736
|
}
|
|
609
|
-
this.processResponse(void 0, void 0, signalOrSignals);
|
|
610
|
-
this.tryResolveCompleted();
|
|
611
737
|
}
|
|
612
738
|
};
|
|
613
739
|
|
|
@@ -942,7 +1068,7 @@ var CNSNetwork = class {
|
|
|
942
1068
|
|
|
943
1069
|
// src/CNS.ts
|
|
944
1070
|
var CNS = class {
|
|
945
|
-
constructor(neurons, options) {
|
|
1071
|
+
constructor(neurons, options, global) {
|
|
946
1072
|
this.neurons = neurons;
|
|
947
1073
|
this.options = options;
|
|
948
1074
|
/**
|
|
@@ -954,7 +1080,12 @@ var CNS = class {
|
|
|
954
1080
|
* Global response listeners applied to every stimulation.
|
|
955
1081
|
*/
|
|
956
1082
|
this.globalResponseListeners = [];
|
|
1083
|
+
/**
|
|
1084
|
+
* Global batch-boundary listeners applied to every stimulation.
|
|
1085
|
+
*/
|
|
1086
|
+
this.globalDrainListeners = [];
|
|
957
1087
|
this.network = new CNSNetwork(this.neurons);
|
|
1088
|
+
this.global = global;
|
|
958
1089
|
}
|
|
959
1090
|
addResponseListener(listener) {
|
|
960
1091
|
this.globalResponseListeners.push(listener);
|
|
@@ -966,6 +1097,50 @@ var CNS = class {
|
|
|
966
1097
|
if (idx >= 0) this.globalResponseListeners.splice(idx, 1);
|
|
967
1098
|
};
|
|
968
1099
|
}
|
|
1100
|
+
/**
|
|
1101
|
+
* Register a listener called once at the end of every synchronous turn of
|
|
1102
|
+
* every stimulation - see {@link TCNSStimulationDrain}. This is how an
|
|
1103
|
+
* integration (a state manager, an in-memory database) installs a single
|
|
1104
|
+
* commit point for the whole organism instead of passing `onDrain` per call.
|
|
1105
|
+
*
|
|
1106
|
+
* Returns an unsubscribe function.
|
|
1107
|
+
*/
|
|
1108
|
+
addDrainListener(listener) {
|
|
1109
|
+
this.globalDrainListeners.push(listener);
|
|
1110
|
+
let active = true;
|
|
1111
|
+
return () => {
|
|
1112
|
+
if (!active) return;
|
|
1113
|
+
active = false;
|
|
1114
|
+
const idx = this.globalDrainListeners.indexOf(listener);
|
|
1115
|
+
if (idx >= 0) this.globalDrainListeners.splice(idx, 1);
|
|
1116
|
+
};
|
|
1117
|
+
}
|
|
1118
|
+
/**
|
|
1119
|
+
* Fan a drain out to the local and global listeners, or return undefined when
|
|
1120
|
+
* there are none so the stimulation can skip the boundary check entirely.
|
|
1121
|
+
*
|
|
1122
|
+
* Listener errors are isolated: a drain is a notification, and one broken
|
|
1123
|
+
* flush must not stop the others or derail the stimulation that triggered it.
|
|
1124
|
+
*/
|
|
1125
|
+
wrapOnDrain(local) {
|
|
1126
|
+
if (this.globalDrainListeners.length === 0 && !local) return void 0;
|
|
1127
|
+
return (d) => {
|
|
1128
|
+
if (local) {
|
|
1129
|
+
try {
|
|
1130
|
+
local(d);
|
|
1131
|
+
} catch (error) {
|
|
1132
|
+
console.error("[CNS] onDrain listener threw", error);
|
|
1133
|
+
}
|
|
1134
|
+
}
|
|
1135
|
+
for (let i = 0; i < this.globalDrainListeners.length; i++) {
|
|
1136
|
+
try {
|
|
1137
|
+
this.globalDrainListeners[i](d);
|
|
1138
|
+
} catch (error) {
|
|
1139
|
+
console.error("[CNS] drain listener threw", error);
|
|
1140
|
+
}
|
|
1141
|
+
}
|
|
1142
|
+
};
|
|
1143
|
+
}
|
|
969
1144
|
wrapOnResponse(local) {
|
|
970
1145
|
if (this.globalResponseListeners.length === 0 && !local) {
|
|
971
1146
|
return void 0;
|
|
@@ -1013,7 +1188,8 @@ var CNS = class {
|
|
|
1013
1188
|
this,
|
|
1014
1189
|
this.instanceNeuronQueue,
|
|
1015
1190
|
options,
|
|
1016
|
-
wrapped
|
|
1191
|
+
wrapped,
|
|
1192
|
+
this.wrapOnDrain(options?.onDrain)
|
|
1017
1193
|
);
|
|
1018
1194
|
stimulation.responseToSignal(signalOrSignals);
|
|
1019
1195
|
return stimulation;
|
|
@@ -1027,7 +1203,8 @@ var CNS = class {
|
|
|
1027
1203
|
this,
|
|
1028
1204
|
this.instanceNeuronQueue,
|
|
1029
1205
|
options,
|
|
1030
|
-
wrapped
|
|
1206
|
+
wrapped,
|
|
1207
|
+
this.wrapOnDrain(options?.onDrain)
|
|
1031
1208
|
);
|
|
1032
1209
|
stimulation.enqueueTasks(tasks);
|
|
1033
1210
|
return stimulation;
|
|
@@ -1280,11 +1457,16 @@ var neuron = (axon) => {
|
|
|
1280
1457
|
};
|
|
1281
1458
|
return api;
|
|
1282
1459
|
};
|
|
1283
|
-
var
|
|
1284
|
-
|
|
1285
|
-
|
|
1286
|
-
|
|
1287
|
-
|
|
1460
|
+
var neuronFactory = () => {
|
|
1461
|
+
const factory = {
|
|
1462
|
+
withCtx: () => factory,
|
|
1463
|
+
withGlobal: () => factory,
|
|
1464
|
+
neuron: (axon) => neuron(axon)
|
|
1465
|
+
};
|
|
1466
|
+
return factory;
|
|
1467
|
+
};
|
|
1468
|
+
var withCtx = () => neuronFactory();
|
|
1469
|
+
var withGlobal = () => neuronFactory();
|
|
1288
1470
|
var afferentPath = (parentAfferentPath) => {
|
|
1289
1471
|
return {
|
|
1290
1472
|
...parentAfferentPath !== void 0 && {
|
|
@@ -1313,7 +1495,15 @@ var createPersistRegistry = (namedNeurons) => {
|
|
|
1313
1495
|
}
|
|
1314
1496
|
return registry;
|
|
1315
1497
|
};
|
|
1498
|
+
var createCNS = (namedNeurons, options) => {
|
|
1499
|
+
const neurons = Object.values(namedNeurons).map(
|
|
1500
|
+
(entry) => entry && typeof entry === "object" && "neuron" in entry ? entry.neuron : entry
|
|
1501
|
+
);
|
|
1502
|
+
const cns = new CNS(neurons, options, options?.global);
|
|
1503
|
+
const registry = createPersistRegistry(namedNeurons);
|
|
1504
|
+
return { cns, registry };
|
|
1505
|
+
};
|
|
1316
1506
|
|
|
1317
|
-
export { CNS, CNSCollateral, CNSPersistOptionsRegistry, CNSStimulationContextStore, CNSStimulationGate, afferentPath, collateral, createPersistRegistry, modality, neuron, withCtx };
|
|
1507
|
+
export { CNS, CNSCollateral, CNSPersistOptionsRegistry, CNSStimulationContextStore, CNSStimulationGate, afferentPath, collateral, createCNS, createPersistRegistry, modality, neuron, neuronFactory, withCtx, withGlobal };
|
|
1318
1508
|
//# sourceMappingURL=index.js.map
|
|
1319
1509
|
//# sourceMappingURL=index.js.map
|