@cnstra/core 2.2.0 → 2.3.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.map +1 -1
- package/dist/CNSNetwork.d.ts +8 -15
- package/dist/CNSNetwork.d.ts.map +1 -1
- package/dist/CNSStimulation.d.ts +41 -11
- 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.map +1 -1
- package/dist/index.cjs +380 -295
- package/dist/index.cjs.map +1 -1
- package/dist/index.js +380 -295
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
- package/dist/CNSNeuronActivationPump.d.ts +0 -27
- package/dist/CNSNeuronActivationPump.d.ts.map +0 -1
- package/dist/CNSTaskQueue.d.ts +0 -12
- package/dist/CNSTaskQueue.d.ts.map +0 -1
package/dist/index.cjs
CHANGED
|
@@ -2,80 +2,155 @@
|
|
|
2
2
|
|
|
3
3
|
// src/CNSStimulationContextStore.ts
|
|
4
4
|
var CNSStimulationContextStore = class {
|
|
5
|
-
constructor(ctx
|
|
5
|
+
constructor(ctx) {
|
|
6
6
|
this.ctx = ctx;
|
|
7
7
|
}
|
|
8
8
|
get(key) {
|
|
9
|
-
return this.ctx
|
|
9
|
+
return this.ctx?.get(key);
|
|
10
10
|
}
|
|
11
11
|
set(key, value) {
|
|
12
|
-
this.ctx.set(key, value);
|
|
12
|
+
(this.ctx ?? (this.ctx = /* @__PURE__ */ new Map())).set(key, value);
|
|
13
13
|
}
|
|
14
14
|
getAll() {
|
|
15
|
-
return new Map(this.ctx);
|
|
15
|
+
return this.ctx ? new Map(this.ctx) : /* @__PURE__ */ new Map();
|
|
16
16
|
}
|
|
17
17
|
setAll(values) {
|
|
18
|
-
this.ctx.
|
|
19
|
-
|
|
18
|
+
const ctx = this.ctx ?? (this.ctx = /* @__PURE__ */ new Map());
|
|
19
|
+
ctx.clear();
|
|
20
|
+
for (const [key, value] of values) ctx.set(key, value);
|
|
20
21
|
}
|
|
21
22
|
delete(key) {
|
|
22
|
-
this.ctx
|
|
23
|
+
this.ctx?.delete(key);
|
|
23
24
|
}
|
|
24
25
|
};
|
|
25
26
|
|
|
26
|
-
// src/
|
|
27
|
-
var
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
this.
|
|
27
|
+
// src/CNSStimulation.ts
|
|
28
|
+
var TASK_DENDRITE = /* @__PURE__ */ Symbol("cnstra.taskDendrite");
|
|
29
|
+
var CNSDendriteContext = class {
|
|
30
|
+
constructor(stimulation, neuron2, abortSignal, cns) {
|
|
31
|
+
this.stimulation = stimulation;
|
|
32
|
+
this.neuron = neuron2;
|
|
31
33
|
this.abortSignal = abortSignal;
|
|
32
|
-
this.
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
this.
|
|
36
|
-
|
|
34
|
+
this.cns = cns;
|
|
35
|
+
}
|
|
36
|
+
get() {
|
|
37
|
+
return this.stimulation.getContext().get(this.neuron);
|
|
38
|
+
}
|
|
39
|
+
set(value) {
|
|
40
|
+
this.stimulation.getContext().set(this.neuron, value);
|
|
41
|
+
}
|
|
42
|
+
delete() {
|
|
43
|
+
this.stimulation.getContext().delete(this.neuron);
|
|
44
|
+
}
|
|
45
|
+
};
|
|
46
|
+
var CNSStimulationResponseImpl = class {
|
|
47
|
+
constructor(stimulation, store, inputSignal, outputSignal, queueLength, hops, error) {
|
|
48
|
+
this.stimulation = stimulation;
|
|
49
|
+
this.store = store;
|
|
50
|
+
this.inputSignal = inputSignal;
|
|
51
|
+
this.outputSignal = outputSignal;
|
|
52
|
+
this.queueLength = queueLength;
|
|
53
|
+
this.hops = hops;
|
|
54
|
+
this.error = error;
|
|
55
|
+
}
|
|
56
|
+
get contextValue() {
|
|
57
|
+
return this.store ? this.store.getAll() : /* @__PURE__ */ new Map();
|
|
58
|
+
}
|
|
59
|
+
};
|
|
60
|
+
var CNSStimulation = class {
|
|
61
|
+
constructor(cns, instanceNeuronQueue, options, onResponse) {
|
|
62
|
+
this.cns = cns;
|
|
63
|
+
this.options = options;
|
|
64
|
+
this.qHead = 0;
|
|
65
|
+
this.qTail = 0;
|
|
66
|
+
this.qSize = 0;
|
|
67
|
+
this.qCapacity = 4;
|
|
37
68
|
this.activeOperations = 0;
|
|
38
|
-
|
|
39
|
-
// NEW: prevent re-entrant pump; defer extra runs
|
|
69
|
+
// Re-entrancy guard for the pump loop.
|
|
40
70
|
this.pumping = false;
|
|
41
71
|
this.needsPump = false;
|
|
42
|
-
|
|
43
|
-
|
|
72
|
+
this.scheduledCount = 0;
|
|
73
|
+
this.isCompleted = false;
|
|
74
|
+
this.completionRejected = false;
|
|
75
|
+
this.ctxStore = options?.ctx;
|
|
76
|
+
this.instanceNeuronQueue = instanceNeuronQueue;
|
|
77
|
+
this.onResponse = onResponse;
|
|
78
|
+
if (this.options?.maxNeuronHops) {
|
|
79
|
+
this.neuronVisitMap = /* @__PURE__ */ new Map();
|
|
80
|
+
}
|
|
81
|
+
if (this.autoCleanupContextsEnabled) {
|
|
82
|
+
this.activeSccCounts = /* @__PURE__ */ new Map();
|
|
44
83
|
}
|
|
45
|
-
this.items = new Array(this.capacity);
|
|
46
84
|
}
|
|
85
|
+
pushFailedTask(failure) {
|
|
86
|
+
(this.failedTasks ?? (this.failedTasks = [])).push(failure);
|
|
87
|
+
}
|
|
88
|
+
finalizeResolve() {
|
|
89
|
+
this.completionRejected = false;
|
|
90
|
+
this.resolveCompleted?.();
|
|
91
|
+
}
|
|
92
|
+
finalizeReject(error) {
|
|
93
|
+
this.completionRejected = true;
|
|
94
|
+
this.completionError = error;
|
|
95
|
+
this.rejectCompleted?.(error);
|
|
96
|
+
}
|
|
97
|
+
/** Lazily-created neuron context store (see {@link ctxStore}). */
|
|
98
|
+
get ctx() {
|
|
99
|
+
return this.ctxStore ?? (this.ctxStore = new CNSStimulationContextStore());
|
|
100
|
+
}
|
|
101
|
+
// ----- Inlined activation queue / pump -----
|
|
47
102
|
get canStartOperation() {
|
|
48
|
-
const limit = this.concurrency ?? Infinity;
|
|
49
|
-
return this.activeOperations < limit && !this.abortSignal?.aborted;
|
|
50
|
-
}
|
|
51
|
-
|
|
52
|
-
const oldCapacity = this.
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
103
|
+
const limit = this.options?.concurrency ?? Infinity;
|
|
104
|
+
return this.activeOperations < limit && !this.options?.abortSignal?.aborted;
|
|
105
|
+
}
|
|
106
|
+
qResize() {
|
|
107
|
+
const oldCapacity = this.qCapacity;
|
|
108
|
+
const oldItems = this.qItems;
|
|
109
|
+
this.qCapacity = oldCapacity * 2;
|
|
110
|
+
const newItems = new Array(this.qCapacity);
|
|
111
|
+
let oldIndex = this.qHead;
|
|
112
|
+
for (let i = 0; i < this.qSize; i++) {
|
|
113
|
+
newItems[i] = oldItems[oldIndex];
|
|
58
114
|
oldIndex = (oldIndex + 1) % oldCapacity;
|
|
59
115
|
}
|
|
60
|
-
this.
|
|
61
|
-
this.
|
|
62
|
-
this.
|
|
63
|
-
}
|
|
64
|
-
|
|
65
|
-
if (this.
|
|
66
|
-
const
|
|
67
|
-
|
|
68
|
-
this.
|
|
69
|
-
this.
|
|
70
|
-
|
|
116
|
+
this.qItems = newItems;
|
|
117
|
+
this.qHead = 0;
|
|
118
|
+
this.qTail = this.qSize;
|
|
119
|
+
}
|
|
120
|
+
qDequeue() {
|
|
121
|
+
if (this.qSize === 0) return void 0;
|
|
122
|
+
const items = this.qItems;
|
|
123
|
+
const task = items[this.qHead];
|
|
124
|
+
items[this.qHead] = void 0;
|
|
125
|
+
this.qHead = (this.qHead + 1) % this.qCapacity;
|
|
126
|
+
this.qSize--;
|
|
127
|
+
return task;
|
|
128
|
+
}
|
|
129
|
+
qEnqueueItem(task) {
|
|
130
|
+
if (!this.qItems) {
|
|
131
|
+
this.qItems = new Array(this.qCapacity);
|
|
132
|
+
} else if (this.qSize === this.qCapacity) {
|
|
133
|
+
this.qResize();
|
|
134
|
+
}
|
|
135
|
+
this.qItems[this.qTail] = task;
|
|
136
|
+
this.qTail = (this.qTail + 1) % this.qCapacity;
|
|
137
|
+
this.qSize++;
|
|
138
|
+
}
|
|
139
|
+
/** Enqueue a task and drive the pump unless one is already running. */
|
|
140
|
+
qEnqueue(task) {
|
|
141
|
+
this.qEnqueueItem(task);
|
|
142
|
+
if (!this.pumping) this.pump();
|
|
143
|
+
else this.needsPump = true;
|
|
71
144
|
}
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
145
|
+
qGetQueuedTasks() {
|
|
146
|
+
const result = [];
|
|
147
|
+
if (!this.qItems) return result;
|
|
148
|
+
let index = this.qHead;
|
|
149
|
+
for (let i = 0; i < this.qSize; i++) {
|
|
150
|
+
result.push(this.qItems[index]);
|
|
151
|
+
index = (index + 1) % this.qCapacity;
|
|
75
152
|
}
|
|
76
|
-
|
|
77
|
-
this.tail = (this.tail + 1) % this.capacity;
|
|
78
|
-
this.size++;
|
|
153
|
+
return result;
|
|
79
154
|
}
|
|
80
155
|
pump() {
|
|
81
156
|
if (this.pumping) {
|
|
@@ -83,26 +158,26 @@ var CNSNeuronActivationPump = class {
|
|
|
83
158
|
return;
|
|
84
159
|
}
|
|
85
160
|
this.pumping = true;
|
|
86
|
-
while (this.canStartOperation && this.
|
|
87
|
-
const
|
|
161
|
+
while (this.canStartOperation && this.qSize > 0) {
|
|
162
|
+
const task = this.qDequeue();
|
|
88
163
|
this.activeOperations++;
|
|
89
|
-
this.
|
|
90
|
-
const ret = this.processor(neuronActivationTask);
|
|
164
|
+
const ret = this.executeActivationTask(task);
|
|
91
165
|
if (ret && typeof ret.then === "function") {
|
|
166
|
+
(this.activeTasks ?? (this.activeTasks = /* @__PURE__ */ new Set())).add(task);
|
|
92
167
|
ret.then(
|
|
93
168
|
(cb) => {
|
|
94
169
|
this.activeOperations--;
|
|
95
|
-
this.activeTasks.delete(
|
|
170
|
+
this.activeTasks.delete(task);
|
|
96
171
|
if (typeof cb === "function") cb();
|
|
97
|
-
if (this.
|
|
172
|
+
if (this.qSize > 0 && this.canStartOperation) {
|
|
98
173
|
if (this.pumping) this.needsPump = true;
|
|
99
174
|
else this.pump();
|
|
100
175
|
}
|
|
101
176
|
},
|
|
102
177
|
(err) => {
|
|
103
178
|
this.activeOperations--;
|
|
104
|
-
this.activeTasks.delete(
|
|
105
|
-
if (this.
|
|
179
|
+
this.activeTasks.delete(task);
|
|
180
|
+
if (this.qSize > 0 && this.canStartOperation) {
|
|
106
181
|
if (this.pumping) this.needsPump = true;
|
|
107
182
|
else this.pump();
|
|
108
183
|
}
|
|
@@ -112,7 +187,6 @@ var CNSNeuronActivationPump = class {
|
|
|
112
187
|
continue;
|
|
113
188
|
}
|
|
114
189
|
this.activeOperations--;
|
|
115
|
-
this.activeTasks.delete(neuronActivationTask);
|
|
116
190
|
if (typeof ret === "function") ret();
|
|
117
191
|
}
|
|
118
192
|
this.pumping = false;
|
|
@@ -121,73 +195,20 @@ var CNSNeuronActivationPump = class {
|
|
|
121
195
|
this.pump();
|
|
122
196
|
}
|
|
123
197
|
}
|
|
124
|
-
enqueue(neuronActivationTask) {
|
|
125
|
-
this.enqueueItem(neuronActivationTask);
|
|
126
|
-
if (!this.pumping) this.pump();
|
|
127
|
-
else this.needsPump = true;
|
|
128
|
-
}
|
|
129
|
-
get length() {
|
|
130
|
-
return this.size;
|
|
131
|
-
}
|
|
132
|
-
getActiveOperationsCount() {
|
|
133
|
-
return this.activeOperations;
|
|
134
|
-
}
|
|
135
|
-
getQueuedTasks() {
|
|
136
|
-
const result = [];
|
|
137
|
-
let index = this.head;
|
|
138
|
-
for (let i = 0; i < this.size; i++) {
|
|
139
|
-
result.push(this.items[index]);
|
|
140
|
-
index = (index + 1) % this.capacity;
|
|
141
|
-
}
|
|
142
|
-
return result;
|
|
143
|
-
}
|
|
144
|
-
getActiveTasks() {
|
|
145
|
-
return Array.from(this.activeTasks);
|
|
146
|
-
}
|
|
147
|
-
};
|
|
148
|
-
|
|
149
|
-
// src/CNSStimulation.ts
|
|
150
|
-
var CNSStimulation = class {
|
|
151
|
-
constructor(cns, instanceNeuronQueue, options) {
|
|
152
|
-
this.cns = cns;
|
|
153
|
-
this.options = options;
|
|
154
|
-
this.scheduledCount = 0;
|
|
155
|
-
this.pendingTasks = /* @__PURE__ */ new Set();
|
|
156
|
-
this.failedTasks = [];
|
|
157
|
-
this.completed = new Promise((resolve, reject) => {
|
|
158
|
-
this.resolveCompleted = resolve;
|
|
159
|
-
this.rejectCompleted = reject;
|
|
160
|
-
});
|
|
161
|
-
this.isCompleted = false;
|
|
162
|
-
/**
|
|
163
|
-
* Track active SCCs: SCC index -> count of active neurons in that SCC
|
|
164
|
-
*/
|
|
165
|
-
this.activeSccCounts = /* @__PURE__ */ new Map();
|
|
166
|
-
this.ctx = options?.ctx ?? new CNSStimulationContextStore();
|
|
167
|
-
this.queue = new CNSNeuronActivationPump(
|
|
168
|
-
(neuronActivationTask) => this.executeActivationTask(neuronActivationTask),
|
|
169
|
-
options?.concurrency,
|
|
170
|
-
options?.abortSignal
|
|
171
|
-
);
|
|
172
|
-
this.instanceNeuronQueue = instanceNeuronQueue;
|
|
173
|
-
if (this.options?.maxNeuronHops) {
|
|
174
|
-
this.nueronVisitMap = /* @__PURE__ */ new Map();
|
|
175
|
-
}
|
|
176
|
-
}
|
|
177
198
|
tryResolveCompleted() {
|
|
178
199
|
if (this.isCompleted) return;
|
|
179
|
-
const noActive = this.
|
|
180
|
-
const noPending = this.
|
|
200
|
+
const noActive = this.activeOperations === 0;
|
|
201
|
+
const noPending = this.qSize + this.scheduledCount === 0;
|
|
181
202
|
const aborted = !!this.options?.abortSignal?.aborted;
|
|
182
203
|
if (noPending && noActive || aborted && noActive && !noPending) {
|
|
183
204
|
if (aborted) {
|
|
184
|
-
const queuedTasks = this.
|
|
205
|
+
const queuedTasks = this.qGetQueuedTasks();
|
|
185
206
|
for (const task of [...queuedTasks]) {
|
|
186
|
-
const alreadyTracked = this.failedTasks
|
|
207
|
+
const alreadyTracked = this.failedTasks?.some(
|
|
187
208
|
(ft) => ft.task === task
|
|
188
209
|
);
|
|
189
210
|
if (!alreadyTracked) {
|
|
190
|
-
this.
|
|
211
|
+
this.pushFailedTask({
|
|
191
212
|
task,
|
|
192
213
|
error: new Error(
|
|
193
214
|
"Task aborted - not started due to abort signal"
|
|
@@ -197,37 +218,47 @@ var CNSStimulation = class {
|
|
|
197
218
|
}
|
|
198
219
|
}
|
|
199
220
|
this.isCompleted = true;
|
|
200
|
-
this.
|
|
221
|
+
this.finalizeReject(new Error("Stimulation aborted"));
|
|
201
222
|
return;
|
|
202
223
|
}
|
|
203
224
|
this.isCompleted = true;
|
|
204
|
-
|
|
225
|
+
const failedCount = this.failedTasks?.length ?? 0;
|
|
226
|
+
if (failedCount > 0 || this.onResponseError) {
|
|
205
227
|
const error = this.onResponseError || new Error(
|
|
206
|
-
`Stimulation completed with ${
|
|
228
|
+
`Stimulation completed with ${failedCount} failed task(s)`
|
|
207
229
|
);
|
|
208
|
-
this.
|
|
230
|
+
this.finalizeReject(error);
|
|
209
231
|
} else {
|
|
210
|
-
this.
|
|
232
|
+
this.finalizeResolve();
|
|
211
233
|
}
|
|
212
234
|
}
|
|
213
235
|
}
|
|
214
236
|
waitUntilComplete() {
|
|
237
|
+
if (this.completed) return this.completed;
|
|
238
|
+
if (this.isCompleted) {
|
|
239
|
+
this.completed = this.completionRejected ? Promise.reject(this.completionError) : Promise.resolve();
|
|
240
|
+
return this.completed;
|
|
241
|
+
}
|
|
242
|
+
this.completed = new Promise((resolve, reject) => {
|
|
243
|
+
this.resolveCompleted = resolve;
|
|
244
|
+
this.rejectCompleted = reject;
|
|
245
|
+
});
|
|
215
246
|
return this.completed;
|
|
216
247
|
}
|
|
217
248
|
/**
|
|
218
249
|
* Returns all current activation tasks: queued, active, and pending (scheduled but not yet enqueued)
|
|
219
250
|
*/
|
|
220
251
|
getAllActivationTasks() {
|
|
221
|
-
const queuedTasks = this.
|
|
222
|
-
const activeTasks = this.
|
|
223
|
-
const pendingTasks = Array.from(this.pendingTasks);
|
|
252
|
+
const queuedTasks = this.qGetQueuedTasks();
|
|
253
|
+
const activeTasks = this.activeTasks ? Array.from(this.activeTasks) : [];
|
|
254
|
+
const pendingTasks = this.pendingTasks ? Array.from(this.pendingTasks) : [];
|
|
224
255
|
return [...queuedTasks, ...activeTasks, ...pendingTasks];
|
|
225
256
|
}
|
|
226
257
|
/**
|
|
227
258
|
* Returns all tasks that failed or were aborted
|
|
228
259
|
*/
|
|
229
260
|
getFailedTasks() {
|
|
230
|
-
return [...this.failedTasks];
|
|
261
|
+
return this.failedTasks ? [...this.failedTasks] : [];
|
|
231
262
|
}
|
|
232
263
|
/**
|
|
233
264
|
* Get the context store for this stimulation
|
|
@@ -240,7 +271,7 @@ var CNSStimulation = class {
|
|
|
240
271
|
*/
|
|
241
272
|
enqueueTasks(tasks) {
|
|
242
273
|
for (const task of tasks) {
|
|
243
|
-
this.
|
|
274
|
+
this.qEnqueue(task);
|
|
244
275
|
}
|
|
245
276
|
this.tryResolveCompleted();
|
|
246
277
|
}
|
|
@@ -268,20 +299,24 @@ var CNSStimulation = class {
|
|
|
268
299
|
* Increment the active count for the SCC containing this neuron
|
|
269
300
|
*/
|
|
270
301
|
incrementSccCount(neuron2) {
|
|
302
|
+
const counts = this.activeSccCounts;
|
|
303
|
+
if (!counts) return;
|
|
271
304
|
const sccIndex = this.cns.network.getSccIndexByNeuron(neuron2);
|
|
272
305
|
if (sccIndex === void 0) return;
|
|
273
|
-
const currentCount =
|
|
274
|
-
|
|
306
|
+
const currentCount = counts.get(sccIndex) || 0;
|
|
307
|
+
counts.set(sccIndex, currentCount + 1);
|
|
275
308
|
}
|
|
276
309
|
/**
|
|
277
310
|
* Decrement the active count for the SCC containing this neuron
|
|
278
311
|
*/
|
|
279
312
|
decrementSccCount(neuron2) {
|
|
313
|
+
const counts = this.activeSccCounts;
|
|
314
|
+
if (!counts) return;
|
|
280
315
|
const sccIndex = this.cns.network.getSccIndexByNeuron(neuron2);
|
|
281
316
|
if (sccIndex === void 0) return;
|
|
282
|
-
const currentCount =
|
|
317
|
+
const currentCount = counts.get(sccIndex) || 0;
|
|
283
318
|
const nextCount = Math.max(0, currentCount - 1);
|
|
284
|
-
|
|
319
|
+
counts.set(sccIndex, nextCount);
|
|
285
320
|
if (currentCount === 0) {
|
|
286
321
|
console.warn(
|
|
287
322
|
`[CNSStimulation] Attempting to decrement SCC count below 0 for neuron`
|
|
@@ -292,7 +327,8 @@ var CNSStimulation = class {
|
|
|
292
327
|
* Check if a neuron can be guaranteed not to be visited again
|
|
293
328
|
*/
|
|
294
329
|
canNeuronBeGuaranteedDone(neuron2) {
|
|
295
|
-
if (!this.autoCleanupContextsEnabled
|
|
330
|
+
if (!this.autoCleanupContextsEnabled || !this.activeSccCounts)
|
|
331
|
+
return false;
|
|
296
332
|
return this.cns.network.canNeuronBeGuaranteedDone(
|
|
297
333
|
neuron2,
|
|
298
334
|
this.activeSccCounts
|
|
@@ -300,19 +336,19 @@ var CNSStimulation = class {
|
|
|
300
336
|
}
|
|
301
337
|
cleanupCtxIfNeeded(neuron2) {
|
|
302
338
|
if (this.autoCleanupContextsEnabled && this.canNeuronBeGuaranteedDone(neuron2)) {
|
|
303
|
-
this.
|
|
339
|
+
this.ctxStore?.delete(neuron2);
|
|
304
340
|
}
|
|
305
341
|
}
|
|
306
342
|
createSubscriberQueueItem(subscriber, inputSignal) {
|
|
307
343
|
if (this.options?.maxNeuronHops) {
|
|
308
|
-
if ((this.
|
|
344
|
+
if ((this.neuronVisitMap?.get(subscriber.neuron) ?? 0) >= this.options?.maxNeuronHops) {
|
|
309
345
|
throw new Error(
|
|
310
346
|
`Max neuron hops reached when trying to enqueue subscriber`
|
|
311
347
|
);
|
|
312
348
|
} else {
|
|
313
|
-
this.
|
|
349
|
+
this.neuronVisitMap?.set(
|
|
314
350
|
subscriber.neuron,
|
|
315
|
-
(this.
|
|
351
|
+
(this.neuronVisitMap?.get(subscriber.neuron) ?? 0) + 1
|
|
316
352
|
);
|
|
317
353
|
}
|
|
318
354
|
}
|
|
@@ -321,17 +357,24 @@ var CNSStimulation = class {
|
|
|
321
357
|
dendriteCollateral: subscriber.dendrite.collateral,
|
|
322
358
|
input: inputSignal
|
|
323
359
|
};
|
|
360
|
+
neuronActivationTask[TASK_DENDRITE] = subscriber;
|
|
324
361
|
return neuronActivationTask;
|
|
325
362
|
}
|
|
326
363
|
executeActivationTask(neuronActivationTask) {
|
|
327
|
-
|
|
328
|
-
neuronActivationTask.dendriteCollateral
|
|
329
|
-
);
|
|
330
|
-
const subscriber = subscribers.find(
|
|
331
|
-
(s) => s.neuron === neuronActivationTask.neuron
|
|
332
|
-
);
|
|
364
|
+
let subscriber = neuronActivationTask[TASK_DENDRITE];
|
|
333
365
|
if (!subscriber) {
|
|
334
|
-
this.
|
|
366
|
+
const subscribers = this.cns.network.getSubscribers(
|
|
367
|
+
neuronActivationTask.dendriteCollateral
|
|
368
|
+
);
|
|
369
|
+
for (let i = 0; i < subscribers.length; i++) {
|
|
370
|
+
if (subscribers[i].neuron === neuronActivationTask.neuron) {
|
|
371
|
+
subscriber = subscribers[i];
|
|
372
|
+
break;
|
|
373
|
+
}
|
|
374
|
+
}
|
|
375
|
+
}
|
|
376
|
+
if (!subscriber) {
|
|
377
|
+
this.pushFailedTask({
|
|
335
378
|
task: neuronActivationTask,
|
|
336
379
|
error: new Error(
|
|
337
380
|
`Subscriber not found for activation task`
|
|
@@ -344,40 +387,58 @@ var CNSStimulation = class {
|
|
|
344
387
|
const neuron2 = subscriber.neuron;
|
|
345
388
|
const dendrite = subscriber.dendrite;
|
|
346
389
|
const inputSignal = neuronActivationTask.input;
|
|
347
|
-
const
|
|
348
|
-
|
|
349
|
-
|
|
350
|
-
|
|
351
|
-
|
|
352
|
-
|
|
353
|
-
|
|
354
|
-
|
|
355
|
-
|
|
356
|
-
|
|
357
|
-
|
|
358
|
-
|
|
359
|
-
|
|
360
|
-
|
|
361
|
-
|
|
362
|
-
|
|
363
|
-
|
|
364
|
-
|
|
365
|
-
|
|
366
|
-
|
|
367
|
-
|
|
368
|
-
|
|
369
|
-
|
|
370
|
-
|
|
371
|
-
|
|
390
|
+
const concurrency = neuron2.concurrency;
|
|
391
|
+
if (concurrency === void 0 || concurrency <= 0) {
|
|
392
|
+
return this.runStarter(
|
|
393
|
+
neuron2,
|
|
394
|
+
dendrite,
|
|
395
|
+
inputSignal,
|
|
396
|
+
neuronActivationTask
|
|
397
|
+
);
|
|
398
|
+
}
|
|
399
|
+
return this.instanceNeuronQueue.run(
|
|
400
|
+
neuron2,
|
|
401
|
+
() => this.runStarter(
|
|
402
|
+
neuron2,
|
|
403
|
+
dendrite,
|
|
404
|
+
inputSignal,
|
|
405
|
+
neuronActivationTask
|
|
406
|
+
)
|
|
407
|
+
);
|
|
408
|
+
}
|
|
409
|
+
runStarter(neuron2, dendrite, inputSignal, neuronActivationTask) {
|
|
410
|
+
this.markNeuronActive(neuron2);
|
|
411
|
+
let response;
|
|
412
|
+
try {
|
|
413
|
+
response = dendrite.response(
|
|
414
|
+
inputSignal?.payload,
|
|
415
|
+
neuron2.axon,
|
|
416
|
+
new CNSDendriteContext(
|
|
417
|
+
this,
|
|
372
418
|
neuron2,
|
|
373
|
-
|
|
374
|
-
|
|
375
|
-
|
|
376
|
-
|
|
377
|
-
|
|
378
|
-
|
|
379
|
-
|
|
380
|
-
|
|
419
|
+
this.options?.abortSignal,
|
|
420
|
+
this.cns
|
|
421
|
+
)
|
|
422
|
+
);
|
|
423
|
+
} catch (error) {
|
|
424
|
+
this.markNeuronInactive(neuron2);
|
|
425
|
+
const isAborted = this.options?.abortSignal?.aborted ?? false;
|
|
426
|
+
this.pushFailedTask({
|
|
427
|
+
task: neuronActivationTask,
|
|
428
|
+
error: error instanceof Error ? error : new Error(String(error)),
|
|
429
|
+
aborted: isAborted
|
|
430
|
+
});
|
|
431
|
+
this.processResponseOrResponses(
|
|
432
|
+
neuron2,
|
|
433
|
+
inputSignal,
|
|
434
|
+
void 0,
|
|
435
|
+
error
|
|
436
|
+
);
|
|
437
|
+
return () => {
|
|
438
|
+
};
|
|
439
|
+
}
|
|
440
|
+
const maxDuration = neuron2.maxDuration;
|
|
441
|
+
if (response instanceof Promise || maxDuration) {
|
|
381
442
|
const asPromise = response instanceof Promise ? response : Promise.resolve(response);
|
|
382
443
|
const timedPromise = maxDuration && maxDuration > 0 ? new Promise((resolve, reject) => {
|
|
383
444
|
const t = setTimeout(() => {
|
|
@@ -397,48 +458,45 @@ var CNSStimulation = class {
|
|
|
397
458
|
}
|
|
398
459
|
);
|
|
399
460
|
}) : asPromise;
|
|
400
|
-
|
|
401
|
-
|
|
402
|
-
(
|
|
403
|
-
|
|
404
|
-
|
|
405
|
-
|
|
406
|
-
|
|
407
|
-
|
|
408
|
-
|
|
409
|
-
|
|
410
|
-
|
|
411
|
-
|
|
412
|
-
(
|
|
413
|
-
|
|
414
|
-
|
|
415
|
-
|
|
416
|
-
|
|
417
|
-
|
|
418
|
-
|
|
419
|
-
|
|
420
|
-
|
|
421
|
-
|
|
422
|
-
|
|
423
|
-
|
|
424
|
-
|
|
425
|
-
|
|
426
|
-
|
|
427
|
-
|
|
428
|
-
|
|
461
|
+
return timedPromise.then(
|
|
462
|
+
(signal) => {
|
|
463
|
+
return () => {
|
|
464
|
+
this.markNeuronInactive(neuron2);
|
|
465
|
+
return this.processResponseOrResponses(
|
|
466
|
+
neuron2,
|
|
467
|
+
inputSignal,
|
|
468
|
+
signal
|
|
469
|
+
);
|
|
470
|
+
};
|
|
471
|
+
},
|
|
472
|
+
(error) => {
|
|
473
|
+
return () => {
|
|
474
|
+
this.markNeuronInactive(neuron2);
|
|
475
|
+
const isAborted = this.options?.abortSignal?.aborted ?? false;
|
|
476
|
+
this.pushFailedTask({
|
|
477
|
+
task: neuronActivationTask,
|
|
478
|
+
error: error instanceof Error ? error : new Error(String(error)),
|
|
479
|
+
aborted: isAborted
|
|
480
|
+
});
|
|
481
|
+
return this.processResponseOrResponses(
|
|
482
|
+
neuron2,
|
|
483
|
+
inputSignal,
|
|
484
|
+
void 0,
|
|
485
|
+
error
|
|
486
|
+
);
|
|
487
|
+
};
|
|
488
|
+
}
|
|
489
|
+
);
|
|
490
|
+
} else {
|
|
491
|
+
return () => {
|
|
492
|
+
this.markNeuronInactive(neuron2);
|
|
493
|
+
return this.processResponseOrResponses(
|
|
494
|
+
neuron2,
|
|
495
|
+
inputSignal,
|
|
496
|
+
response
|
|
429
497
|
);
|
|
430
|
-
}
|
|
431
|
-
|
|
432
|
-
this.markNeuronInactive(neuron2);
|
|
433
|
-
return this.processResponseOrResponses(
|
|
434
|
-
neuron2,
|
|
435
|
-
inputSignal,
|
|
436
|
-
response
|
|
437
|
-
);
|
|
438
|
-
};
|
|
439
|
-
}
|
|
440
|
-
};
|
|
441
|
-
return this.instanceNeuronQueue.run(neuron2, starter);
|
|
498
|
+
};
|
|
499
|
+
}
|
|
442
500
|
}
|
|
443
501
|
processResponseOrResponses(emitter, inputSignal, outputSignalOrSignals, error) {
|
|
444
502
|
if (Array.isArray(outputSignalOrSignals)) {
|
|
@@ -456,36 +514,62 @@ var CNSStimulation = class {
|
|
|
456
514
|
processResponse(emitter, inputSignal, outputSignal, error) {
|
|
457
515
|
const collateral2 = outputSignal?.collateral;
|
|
458
516
|
const subscribers = collateral2 ? this.cns.network.getSubscribers(collateral2) : [];
|
|
517
|
+
const onResponse = this.onResponse;
|
|
518
|
+
if (!onResponse) {
|
|
519
|
+
if (collateral2 && !error) {
|
|
520
|
+
if (emitter) this.cleanupCtxIfNeeded(emitter);
|
|
521
|
+
const n = subscribers.length;
|
|
522
|
+
if (n > 0) {
|
|
523
|
+
const tasks = new Array(n);
|
|
524
|
+
for (let i = 0; i < n; i++) {
|
|
525
|
+
tasks[i] = this.createSubscriberQueueItem(
|
|
526
|
+
subscribers[i],
|
|
527
|
+
outputSignal
|
|
528
|
+
);
|
|
529
|
+
}
|
|
530
|
+
this.scheduledCount += n;
|
|
531
|
+
for (let i = 0; i < n; i++) {
|
|
532
|
+
this.scheduledCount--;
|
|
533
|
+
this.qEnqueue(tasks[i]);
|
|
534
|
+
}
|
|
535
|
+
}
|
|
536
|
+
}
|
|
537
|
+
this.tryResolveCompleted();
|
|
538
|
+
return;
|
|
539
|
+
}
|
|
459
540
|
const subscriberActivationTasks = [];
|
|
460
541
|
if (collateral2 && !error) {
|
|
461
542
|
if (emitter) this.cleanupCtxIfNeeded(emitter);
|
|
543
|
+
const pending = this.pendingTasks ?? (this.pendingTasks = /* @__PURE__ */ new Set());
|
|
462
544
|
for (let i = 0; i < subscribers.length; i++) {
|
|
463
545
|
const task = this.createSubscriberQueueItem(
|
|
464
546
|
subscribers[i],
|
|
465
547
|
outputSignal
|
|
466
548
|
);
|
|
467
549
|
subscriberActivationTasks.push(task);
|
|
468
|
-
|
|
550
|
+
pending.add(task);
|
|
469
551
|
}
|
|
470
552
|
}
|
|
471
553
|
this.scheduledCount += subscriberActivationTasks.length;
|
|
472
554
|
let maybePromise;
|
|
473
555
|
try {
|
|
474
|
-
maybePromise =
|
|
475
|
-
|
|
476
|
-
|
|
477
|
-
|
|
478
|
-
|
|
479
|
-
|
|
480
|
-
|
|
481
|
-
|
|
482
|
-
|
|
556
|
+
maybePromise = onResponse(
|
|
557
|
+
new CNSStimulationResponseImpl(
|
|
558
|
+
this,
|
|
559
|
+
this.ctxStore,
|
|
560
|
+
inputSignal,
|
|
561
|
+
outputSignal,
|
|
562
|
+
this.qSize + this.scheduledCount,
|
|
563
|
+
this.options?.maxNeuronHops && emitter ? this.neuronVisitMap?.get(emitter) ?? 0 : void 0,
|
|
564
|
+
error
|
|
565
|
+
)
|
|
566
|
+
);
|
|
483
567
|
} catch (e) {
|
|
484
568
|
this.onResponseError = e instanceof Error ? e : new Error(String(e));
|
|
485
569
|
for (let i = 0; i < subscriberActivationTasks.length; i++) {
|
|
486
570
|
this.scheduledCount--;
|
|
487
|
-
this.pendingTasks
|
|
488
|
-
this.
|
|
571
|
+
this.pendingTasks?.delete(subscriberActivationTasks[i]);
|
|
572
|
+
this.qEnqueue(subscriberActivationTasks[i]);
|
|
489
573
|
}
|
|
490
574
|
this.tryResolveCompleted();
|
|
491
575
|
return;
|
|
@@ -495,8 +579,8 @@ var CNSStimulation = class {
|
|
|
495
579
|
() => {
|
|
496
580
|
for (let i = 0; i < subscriberActivationTasks.length; i++) {
|
|
497
581
|
this.scheduledCount--;
|
|
498
|
-
this.pendingTasks
|
|
499
|
-
this.
|
|
582
|
+
this.pendingTasks?.delete(subscriberActivationTasks[i]);
|
|
583
|
+
this.qEnqueue(subscriberActivationTasks[i]);
|
|
500
584
|
}
|
|
501
585
|
this.tryResolveCompleted();
|
|
502
586
|
},
|
|
@@ -504,8 +588,8 @@ var CNSStimulation = class {
|
|
|
504
588
|
this.onResponseError = error2 instanceof Error ? error2 : new Error(String(error2));
|
|
505
589
|
for (let i = 0; i < subscriberActivationTasks.length; i++) {
|
|
506
590
|
this.scheduledCount--;
|
|
507
|
-
this.pendingTasks
|
|
508
|
-
this.
|
|
591
|
+
this.pendingTasks?.delete(subscriberActivationTasks[i]);
|
|
592
|
+
this.qEnqueue(subscriberActivationTasks[i]);
|
|
509
593
|
}
|
|
510
594
|
this.tryResolveCompleted();
|
|
511
595
|
}
|
|
@@ -514,8 +598,8 @@ var CNSStimulation = class {
|
|
|
514
598
|
}
|
|
515
599
|
for (let i = 0; i < subscriberActivationTasks.length; i++) {
|
|
516
600
|
this.scheduledCount--;
|
|
517
|
-
this.pendingTasks
|
|
518
|
-
this.
|
|
601
|
+
this.pendingTasks?.delete(subscriberActivationTasks[i]);
|
|
602
|
+
this.qEnqueue(subscriberActivationTasks[i]);
|
|
519
603
|
}
|
|
520
604
|
this.tryResolveCompleted();
|
|
521
605
|
}
|
|
@@ -591,8 +675,12 @@ var CNSNetwork = class {
|
|
|
591
675
|
/**
|
|
592
676
|
* Strongly Connected Components of the neuron graph.
|
|
593
677
|
* Each component is a set of neuron objects that can reach each other.
|
|
678
|
+
*
|
|
679
|
+
* Computed lazily on first access: the SCC machinery is only needed for
|
|
680
|
+
* `autoCleanupContexts` (off by default), so most networks never pay for it.
|
|
594
681
|
*/
|
|
595
|
-
this.
|
|
682
|
+
this._stronglyConnectedComponents = [];
|
|
683
|
+
this.sccBuilt = false;
|
|
596
684
|
/**
|
|
597
685
|
* Quick lookup: neuron -> SCC index for fast reachability checks.
|
|
598
686
|
*/
|
|
@@ -610,21 +698,18 @@ var CNSNetwork = class {
|
|
|
610
698
|
* Built once at construction time.
|
|
611
699
|
*/
|
|
612
700
|
this.subIndex = /* @__PURE__ */ new Map();
|
|
613
|
-
this.dendriteIndex = /* @__PURE__ */ new Map();
|
|
614
|
-
this.collateralIndex = /* @__PURE__ */ new Set();
|
|
615
701
|
this.parentNeuronByCollateral = /* @__PURE__ */ new Map();
|
|
616
|
-
this.validateUniqueIdentifiers();
|
|
617
702
|
this.buildIndexes();
|
|
618
|
-
this.buildSCC();
|
|
619
703
|
}
|
|
620
|
-
|
|
621
|
-
|
|
622
|
-
|
|
623
|
-
|
|
624
|
-
|
|
625
|
-
|
|
626
|
-
|
|
627
|
-
|
|
704
|
+
get stronglyConnectedComponents() {
|
|
705
|
+
this.ensureSCC();
|
|
706
|
+
return this._stronglyConnectedComponents;
|
|
707
|
+
}
|
|
708
|
+
/** Build the SCC analysis the first time anything needs it. */
|
|
709
|
+
ensureSCC() {
|
|
710
|
+
if (this.sccBuilt) return;
|
|
711
|
+
this.sccBuilt = true;
|
|
712
|
+
this.buildSCC();
|
|
628
713
|
}
|
|
629
714
|
/**
|
|
630
715
|
* Build the neuron graph where neurons are connected if one can stimulate the other.
|
|
@@ -699,7 +784,7 @@ var CNSNetwork = class {
|
|
|
699
784
|
strongConnect(neuron2);
|
|
700
785
|
}
|
|
701
786
|
}
|
|
702
|
-
this.
|
|
787
|
+
this._stronglyConnectedComponents = components;
|
|
703
788
|
for (let i = 0; i < components.length; i++) {
|
|
704
789
|
for (const neuronId of Array.from(components[i])) {
|
|
705
790
|
this.neuronToSCC.set(neuronId, i);
|
|
@@ -713,11 +798,11 @@ var CNSNetwork = class {
|
|
|
713
798
|
*/
|
|
714
799
|
buildSCCDAG(neuronGraph) {
|
|
715
800
|
this.sccDag.clear();
|
|
716
|
-
for (let i = 0; i < this.
|
|
801
|
+
for (let i = 0; i < this._stronglyConnectedComponents.length; i++) {
|
|
717
802
|
this.sccDag.set(i, /* @__PURE__ */ new Set());
|
|
718
803
|
}
|
|
719
|
-
for (let i = 0; i < this.
|
|
720
|
-
const scc = this.
|
|
804
|
+
for (let i = 0; i < this._stronglyConnectedComponents.length; i++) {
|
|
805
|
+
const scc = this._stronglyConnectedComponents[i];
|
|
721
806
|
for (const neuron2 of Array.from(scc)) {
|
|
722
807
|
const neighbors = neuronGraph.get(neuron2) || /* @__PURE__ */ new Set();
|
|
723
808
|
for (const neighbor of Array.from(neighbors)) {
|
|
@@ -735,25 +820,27 @@ var CNSNetwork = class {
|
|
|
735
820
|
*/
|
|
736
821
|
buildSCCAncestors() {
|
|
737
822
|
this.sccAncestors.clear();
|
|
738
|
-
for (let i = 0; i < this.
|
|
823
|
+
for (let i = 0; i < this._stronglyConnectedComponents.length; i++) {
|
|
739
824
|
this.sccAncestors.set(i, /* @__PURE__ */ new Set());
|
|
740
825
|
}
|
|
826
|
+
const n = this._stronglyConnectedComponents.length;
|
|
827
|
+
const forward = Array.from({ length: n }, () => []);
|
|
741
828
|
const inDegree = /* @__PURE__ */ new Map();
|
|
742
829
|
const queue = [];
|
|
743
|
-
for (let
|
|
744
|
-
const
|
|
745
|
-
inDegree.set(
|
|
746
|
-
if (
|
|
747
|
-
|
|
830
|
+
for (let target = 0; target < n; target++) {
|
|
831
|
+
const sources = this.sccDag.get(target) || /* @__PURE__ */ new Set();
|
|
832
|
+
inDegree.set(target, sources.size);
|
|
833
|
+
if (sources.size === 0) queue.push(target);
|
|
834
|
+
for (const source of Array.from(sources)) {
|
|
835
|
+
forward[source].push(target);
|
|
748
836
|
}
|
|
749
837
|
}
|
|
750
838
|
while (queue.length > 0) {
|
|
751
839
|
const current = queue.shift();
|
|
752
|
-
const
|
|
753
|
-
for (const neighbor of
|
|
840
|
+
const currentAncestors = this.sccAncestors.get(current);
|
|
841
|
+
for (const neighbor of forward[current]) {
|
|
754
842
|
const neighborAncestors = this.sccAncestors.get(neighbor);
|
|
755
843
|
neighborAncestors.add(current);
|
|
756
|
-
const currentAncestors = this.sccAncestors.get(current);
|
|
757
844
|
for (const ancestor of Array.from(currentAncestors)) {
|
|
758
845
|
neighborAncestors.add(ancestor);
|
|
759
846
|
}
|
|
@@ -765,32 +852,22 @@ var CNSNetwork = class {
|
|
|
765
852
|
}
|
|
766
853
|
}
|
|
767
854
|
}
|
|
768
|
-
/**
|
|
769
|
-
* Get outgoing edges for a given SCC index
|
|
770
|
-
*/
|
|
771
|
-
getOutgoingEdges(sccIndex) {
|
|
772
|
-
const outgoing = /* @__PURE__ */ new Set();
|
|
773
|
-
for (const [targetScc, incomingEdges] of Array.from(this.sccDag)) {
|
|
774
|
-
if (incomingEdges.has(sccIndex)) {
|
|
775
|
-
outgoing.add(targetScc);
|
|
776
|
-
}
|
|
777
|
-
}
|
|
778
|
-
return outgoing;
|
|
779
|
-
}
|
|
780
855
|
/**
|
|
781
856
|
* Check if a neuron can be reached again (including self-calling).
|
|
782
857
|
* Returns true if the neuron is in a strongly connected component with more than one member,
|
|
783
858
|
* or if it's in a single-member SCC that can reach itself.
|
|
784
859
|
*/
|
|
785
860
|
getSCCSetByNeuron(neuron2) {
|
|
861
|
+
this.ensureSCC();
|
|
786
862
|
const sccIndex = this.neuronToSCC.get(neuron2);
|
|
787
863
|
if (sccIndex === void 0) return;
|
|
788
|
-
return this.
|
|
864
|
+
return this._stronglyConnectedComponents[sccIndex];
|
|
789
865
|
}
|
|
790
866
|
/**
|
|
791
867
|
* Get the SCC index for a given neuron
|
|
792
868
|
*/
|
|
793
869
|
getSccIndexByNeuron(neuron2) {
|
|
870
|
+
this.ensureSCC();
|
|
794
871
|
return this.neuronToSCC.get(neuron2);
|
|
795
872
|
}
|
|
796
873
|
/**
|
|
@@ -798,6 +875,7 @@ var CNSNetwork = class {
|
|
|
798
875
|
* This is the core logic for safe context cleanup.
|
|
799
876
|
*/
|
|
800
877
|
canNeuronBeGuaranteedDone(neuron2, activeSccCounts) {
|
|
878
|
+
this.ensureSCC();
|
|
801
879
|
const sccIndex = this.neuronToSCC.get(neuron2);
|
|
802
880
|
if (sccIndex === void 0) return true;
|
|
803
881
|
if (activeSccCounts.get(sccIndex) && activeSccCounts.get(sccIndex) > 0) {
|
|
@@ -815,8 +893,6 @@ var CNSNetwork = class {
|
|
|
815
893
|
buildIndexes() {
|
|
816
894
|
this.subIndex.clear();
|
|
817
895
|
this.parentNeuronByCollateral.clear();
|
|
818
|
-
this.dendriteIndex.clear();
|
|
819
|
-
this.collateralIndex.clear();
|
|
820
896
|
for (const neuron2 of this.neurons) {
|
|
821
897
|
for (const dendrite of neuron2.dendrites) {
|
|
822
898
|
const key = dendrite.collateral;
|
|
@@ -826,25 +902,40 @@ var CNSNetwork = class {
|
|
|
826
902
|
key,
|
|
827
903
|
arr
|
|
828
904
|
);
|
|
829
|
-
this.dendriteIndex.set(key, dendrite);
|
|
830
905
|
}
|
|
831
906
|
Object.values(neuron2.axon).forEach((collateral2) => {
|
|
832
907
|
this.parentNeuronByCollateral.set(
|
|
833
908
|
collateral2,
|
|
834
909
|
neuron2
|
|
835
910
|
);
|
|
836
|
-
this.collateralIndex.add(collateral2);
|
|
837
911
|
});
|
|
838
912
|
}
|
|
839
913
|
}
|
|
840
914
|
getParentNeuronByCollateral(collateral2) {
|
|
841
915
|
return this.parentNeuronByCollateral.get(collateral2);
|
|
842
916
|
}
|
|
917
|
+
// Computed on demand (rarely used): one dendrite per collateral, last wins —
|
|
918
|
+
// preserving the previous index semantics without building it every construct.
|
|
843
919
|
getDendrites() {
|
|
844
|
-
|
|
920
|
+
const byCollateral = /* @__PURE__ */ new Map();
|
|
921
|
+
for (const neuron2 of this.neurons) {
|
|
922
|
+
for (const dendrite of neuron2.dendrites) {
|
|
923
|
+
byCollateral.set(
|
|
924
|
+
dendrite.collateral,
|
|
925
|
+
dendrite
|
|
926
|
+
);
|
|
927
|
+
}
|
|
928
|
+
}
|
|
929
|
+
return Array.from(byCollateral.values());
|
|
845
930
|
}
|
|
846
931
|
getCollaterals() {
|
|
847
|
-
|
|
932
|
+
const collaterals = /* @__PURE__ */ new Set();
|
|
933
|
+
for (const neuron2 of this.neurons) {
|
|
934
|
+
for (const collateral2 of Object.values(neuron2.axon)) {
|
|
935
|
+
collaterals.add(collateral2);
|
|
936
|
+
}
|
|
937
|
+
}
|
|
938
|
+
return Array.from(collaterals);
|
|
848
939
|
}
|
|
849
940
|
getSubscribers(collateral2) {
|
|
850
941
|
return this.subIndex.get(collateral2) ?? [];
|
|
@@ -879,8 +970,7 @@ var CNS = class {
|
|
|
879
970
|
}
|
|
880
971
|
wrapOnResponse(local) {
|
|
881
972
|
if (this.globalResponseListeners.length === 0 && !local) {
|
|
882
|
-
return
|
|
883
|
-
};
|
|
973
|
+
return void 0;
|
|
884
974
|
}
|
|
885
975
|
return (r) => {
|
|
886
976
|
let anyPromise = false;
|
|
@@ -924,10 +1014,8 @@ var CNS = class {
|
|
|
924
1014
|
const stimulation = new CNSStimulation(
|
|
925
1015
|
this,
|
|
926
1016
|
this.instanceNeuronQueue,
|
|
927
|
-
|
|
928
|
-
|
|
929
|
-
onResponse: wrapped
|
|
930
|
-
}
|
|
1017
|
+
options,
|
|
1018
|
+
wrapped
|
|
931
1019
|
);
|
|
932
1020
|
stimulation.responseToSignal(signalOrSignals);
|
|
933
1021
|
return stimulation;
|
|
@@ -940,10 +1028,8 @@ var CNS = class {
|
|
|
940
1028
|
const stimulation = new CNSStimulation(
|
|
941
1029
|
this,
|
|
942
1030
|
this.instanceNeuronQueue,
|
|
943
|
-
|
|
944
|
-
|
|
945
|
-
onResponse: wrapped
|
|
946
|
-
}
|
|
1031
|
+
options,
|
|
1032
|
+
wrapped
|
|
947
1033
|
);
|
|
948
1034
|
stimulation.enqueueTasks(tasks);
|
|
949
1035
|
return stimulation;
|
|
@@ -1123,27 +1209,26 @@ var neuron = (axon) => {
|
|
|
1123
1209
|
modality: singleModality,
|
|
1124
1210
|
modalities: multipleModalities,
|
|
1125
1211
|
afferentPaths: singleAfferentPaths,
|
|
1126
|
-
default:
|
|
1127
|
-
default: globalDefaultHandler,
|
|
1212
|
+
default: defaultHandler,
|
|
1128
1213
|
output
|
|
1129
1214
|
} = s;
|
|
1130
1215
|
const modalityConfigs = multipleModalities ? multipleModalities : singleModality ? [
|
|
1131
1216
|
{
|
|
1132
1217
|
modality: singleModality,
|
|
1133
1218
|
afferentPaths: singleAfferentPaths,
|
|
1134
|
-
default:
|
|
1219
|
+
default: defaultHandler
|
|
1135
1220
|
}
|
|
1136
1221
|
] : [];
|
|
1137
1222
|
const response = (payload, axon2, ctx) => {
|
|
1138
1223
|
const stimulation = ctx.stimulation;
|
|
1139
1224
|
const stimOptions = stimulation?.options;
|
|
1140
1225
|
const runGlobalDefault = () => {
|
|
1141
|
-
if (!
|
|
1226
|
+
if (!defaultHandler) {
|
|
1142
1227
|
throw new Error(
|
|
1143
1228
|
`modalityDendrite: No handler found for modality and no default handler provided`
|
|
1144
1229
|
);
|
|
1145
1230
|
}
|
|
1146
|
-
const res =
|
|
1231
|
+
const res = defaultHandler(payload, axon2, ctx);
|
|
1147
1232
|
if (res && typeof res.then === "function") {
|
|
1148
1233
|
return res.then(
|
|
1149
1234
|
(result) => output(result, axon2, ctx)
|
|
@@ -1162,7 +1247,7 @@ var neuron = (axon) => {
|
|
|
1162
1247
|
}
|
|
1163
1248
|
const stimAfferentPath = stimOptions.afferentPath;
|
|
1164
1249
|
const handler = stimAfferentPath && matchingConfig.afferentPaths ? matchingConfig.afferentPaths.get(stimAfferentPath) : void 0;
|
|
1165
|
-
const effectiveHandler = handler ?? matchingConfig.default ??
|
|
1250
|
+
const effectiveHandler = handler ?? matchingConfig.default ?? defaultHandler;
|
|
1166
1251
|
if (!effectiveHandler) {
|
|
1167
1252
|
throw new Error(
|
|
1168
1253
|
`modalityDendrite: No handler found for afferent path in modality and no default handler provided`
|