@cnstra/core 1.7.0 → 1.8.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 +47 -24
- package/dist/CNS.d.ts +12 -83
- package/dist/CNS.d.ts.map +1 -1
- package/dist/CNSNetwork.d.ts +87 -0
- package/dist/CNSNetwork.d.ts.map +1 -0
- package/dist/CNSNeuronActivationPump.d.ts +27 -0
- package/dist/CNSNeuronActivationPump.d.ts.map +1 -0
- package/dist/CNSStimulation.d.ts +27 -6
- package/dist/CNSStimulation.d.ts.map +1 -1
- package/dist/index.cjs +324 -304
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.ts +2 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +324 -304
- package/dist/index.js.map +1 -1
- package/dist/interfaces/ICNS.d.ts +12 -24
- package/dist/interfaces/ICNS.d.ts.map +1 -1
- package/dist/interfaces/ICNSStimulationContextStore.d.ts +3 -2
- package/dist/interfaces/ICNSStimulationContextStore.d.ts.map +1 -1
- package/dist/types/TCNSDendrite.d.ts +2 -2
- package/dist/types/TCNSDendrite.d.ts.map +1 -1
- package/dist/types/TCNSNeuronActivationTask.d.ts +8 -0
- package/dist/types/TCNSNeuronActivationTask.d.ts.map +1 -0
- package/dist/types/TCNSNeuronActivationTaskFailure.d.ts +7 -0
- package/dist/types/TCNSNeuronActivationTaskFailure.d.ts.map +1 -0
- package/dist/types/TCNSStimulationOptions.d.ts +6 -5
- package/dist/types/TCNSStimulationOptions.d.ts.map +1 -1
- package/dist/types/TCNSStimulationResponse.d.ts +11 -4
- package/dist/types/TCNSStimulationResponse.d.ts.map +1 -1
- package/dist/types/TCNSStimulationSerializedContextValue.d.ts +4 -0
- package/dist/types/TCNSStimulationSerializedContextValue.d.ts.map +1 -0
- package/package.json +1 -1
- package/dist/CNSFunctionalQueue.d.ts +0 -26
- package/dist/CNSFunctionalQueue.d.ts.map +0 -1
- package/dist/types/TCNSSerializedSignal.d.ts +0 -7
- package/dist/types/TCNSSerializedSignal.d.ts.map +0 -1
package/dist/index.js
CHANGED
|
@@ -22,8 +22,8 @@ var CNSStimulationContextStore = class {
|
|
|
22
22
|
}
|
|
23
23
|
};
|
|
24
24
|
|
|
25
|
-
// src/
|
|
26
|
-
var
|
|
25
|
+
// src/CNSNeuronActivationPump.ts
|
|
26
|
+
var CNSNeuronActivationPump = class {
|
|
27
27
|
constructor(processor, concurrency, abortSignal, initialCapacity) {
|
|
28
28
|
this.processor = processor;
|
|
29
29
|
this.concurrency = concurrency;
|
|
@@ -34,6 +34,7 @@ var CNSFunctionalQueue = class {
|
|
|
34
34
|
this.size = 0;
|
|
35
35
|
this.capacity = 16;
|
|
36
36
|
this.activeOperations = 0;
|
|
37
|
+
this.activeTasks = /* @__PURE__ */ new Set();
|
|
37
38
|
// NEW: prevent re-entrant pump; defer extra runs
|
|
38
39
|
this.pumping = false;
|
|
39
40
|
this.needsPump = false;
|
|
@@ -61,17 +62,17 @@ var CNSFunctionalQueue = class {
|
|
|
61
62
|
}
|
|
62
63
|
dequeue() {
|
|
63
64
|
if (this.size === 0) return void 0;
|
|
64
|
-
const
|
|
65
|
+
const neuronActivationTask = this.items[this.head];
|
|
65
66
|
this.items[this.head] = void 0;
|
|
66
67
|
this.head = (this.head + 1) % this.capacity;
|
|
67
68
|
this.size--;
|
|
68
|
-
return
|
|
69
|
+
return neuronActivationTask;
|
|
69
70
|
}
|
|
70
|
-
enqueueItem(
|
|
71
|
+
enqueueItem(neuronActivationTask) {
|
|
71
72
|
if (this.size === this.capacity) {
|
|
72
73
|
this.resize();
|
|
73
74
|
}
|
|
74
|
-
this.items[this.tail] =
|
|
75
|
+
this.items[this.tail] = neuronActivationTask;
|
|
75
76
|
this.tail = (this.tail + 1) % this.capacity;
|
|
76
77
|
this.size++;
|
|
77
78
|
}
|
|
@@ -82,13 +83,15 @@ var CNSFunctionalQueue = class {
|
|
|
82
83
|
}
|
|
83
84
|
this.pumping = true;
|
|
84
85
|
while (this.canStartOperation && this.size > 0) {
|
|
85
|
-
const
|
|
86
|
+
const neuronActivationTask = this.dequeue();
|
|
86
87
|
this.activeOperations++;
|
|
87
|
-
|
|
88
|
+
this.activeTasks.add(neuronActivationTask);
|
|
89
|
+
const ret = this.processor(neuronActivationTask);
|
|
88
90
|
if (ret && typeof ret.then === "function") {
|
|
89
91
|
ret.then(
|
|
90
92
|
(cb) => {
|
|
91
93
|
this.activeOperations--;
|
|
94
|
+
this.activeTasks.delete(neuronActivationTask);
|
|
92
95
|
if (typeof cb === "function") cb();
|
|
93
96
|
if (this.size > 0 && this.canStartOperation) {
|
|
94
97
|
if (this.pumping) this.needsPump = true;
|
|
@@ -97,6 +100,7 @@ var CNSFunctionalQueue = class {
|
|
|
97
100
|
},
|
|
98
101
|
(err) => {
|
|
99
102
|
this.activeOperations--;
|
|
103
|
+
this.activeTasks.delete(neuronActivationTask);
|
|
100
104
|
if (this.size > 0 && this.canStartOperation) {
|
|
101
105
|
if (this.pumping) this.needsPump = true;
|
|
102
106
|
else this.pump();
|
|
@@ -107,6 +111,7 @@ var CNSFunctionalQueue = class {
|
|
|
107
111
|
continue;
|
|
108
112
|
}
|
|
109
113
|
this.activeOperations--;
|
|
114
|
+
this.activeTasks.delete(neuronActivationTask);
|
|
110
115
|
if (typeof ret === "function") ret();
|
|
111
116
|
}
|
|
112
117
|
this.pumping = false;
|
|
@@ -115,8 +120,8 @@ var CNSFunctionalQueue = class {
|
|
|
115
120
|
this.pump();
|
|
116
121
|
}
|
|
117
122
|
}
|
|
118
|
-
enqueue(
|
|
119
|
-
this.enqueueItem(
|
|
123
|
+
enqueue(neuronActivationTask) {
|
|
124
|
+
this.enqueueItem(neuronActivationTask);
|
|
120
125
|
if (!this.pumping) this.pump();
|
|
121
126
|
else this.needsPump = true;
|
|
122
127
|
}
|
|
@@ -126,6 +131,18 @@ var CNSFunctionalQueue = class {
|
|
|
126
131
|
getActiveOperationsCount() {
|
|
127
132
|
return this.activeOperations;
|
|
128
133
|
}
|
|
134
|
+
getQueuedTasks() {
|
|
135
|
+
const result = [];
|
|
136
|
+
let index = this.head;
|
|
137
|
+
for (let i = 0; i < this.size; i++) {
|
|
138
|
+
result.push(this.items[index]);
|
|
139
|
+
index = (index + 1) % this.capacity;
|
|
140
|
+
}
|
|
141
|
+
return result;
|
|
142
|
+
}
|
|
143
|
+
getActiveTasks() {
|
|
144
|
+
return Array.from(this.activeTasks);
|
|
145
|
+
}
|
|
129
146
|
};
|
|
130
147
|
|
|
131
148
|
// src/CNSStimulation.ts
|
|
@@ -134,6 +151,8 @@ var CNSStimulation = class {
|
|
|
134
151
|
this.cns = cns;
|
|
135
152
|
this.options = options;
|
|
136
153
|
this.scheduledCount = 0;
|
|
154
|
+
this.pendingTasks = /* @__PURE__ */ new Set();
|
|
155
|
+
this.failedTasks = [];
|
|
137
156
|
this.completed = new Promise((resolve, reject) => {
|
|
138
157
|
this.resolveCompleted = resolve;
|
|
139
158
|
this.rejectCompleted = reject;
|
|
@@ -143,10 +162,12 @@ var CNSStimulation = class {
|
|
|
143
162
|
* Track active SCCs: SCC index -> count of active neurons in that SCC
|
|
144
163
|
*/
|
|
145
164
|
this.activeSccCounts = /* @__PURE__ */ new Map();
|
|
146
|
-
this.ctx =
|
|
165
|
+
this.ctx = new CNSStimulationContextStore(
|
|
166
|
+
new Map(Object.entries(options?.contextValues ?? {}))
|
|
167
|
+
);
|
|
147
168
|
this.id = options?.stimulationId || Math.random().toString(36).slice(2);
|
|
148
|
-
this.queue = new
|
|
149
|
-
(
|
|
169
|
+
this.queue = new CNSNeuronActivationPump(
|
|
170
|
+
(neuronActivationTask) => this.executeActivationTask(neuronActivationTask),
|
|
150
171
|
options?.concurrency,
|
|
151
172
|
options?.abortSignal
|
|
152
173
|
);
|
|
@@ -154,25 +175,81 @@ var CNSStimulation = class {
|
|
|
154
175
|
if (this.options?.maxNeuronHops) {
|
|
155
176
|
this.nueronVisitMap = /* @__PURE__ */ new Map();
|
|
156
177
|
}
|
|
157
|
-
if (this.options?.abortSignal) {
|
|
158
|
-
this.options.abortSignal.addEventListener("abort", () => {
|
|
159
|
-
this.tryResolveCompleted();
|
|
160
|
-
});
|
|
161
|
-
}
|
|
162
178
|
}
|
|
163
179
|
tryResolveCompleted() {
|
|
164
180
|
if (this.isCompleted) return;
|
|
165
181
|
const noActive = this.queue.getActiveOperationsCount() === 0;
|
|
166
182
|
const noPending = this.queue.length + this.scheduledCount === 0;
|
|
167
183
|
const aborted = !!this.options?.abortSignal?.aborted;
|
|
168
|
-
if (noPending && noActive || aborted && noActive) {
|
|
184
|
+
if (noPending && noActive || aborted && noActive && !noPending) {
|
|
185
|
+
if (aborted) {
|
|
186
|
+
const queuedTasks = this.queue.getQueuedTasks();
|
|
187
|
+
for (const task of [...queuedTasks]) {
|
|
188
|
+
const alreadyTracked = this.failedTasks.some(
|
|
189
|
+
(ft) => ft.task.neuronId === task.neuronId && ft.task.dendriteCollateralName === task.dendriteCollateralName && ft.task.stimulationId === task.stimulationId
|
|
190
|
+
);
|
|
191
|
+
if (!alreadyTracked) {
|
|
192
|
+
this.failedTasks.push({
|
|
193
|
+
task,
|
|
194
|
+
error: new Error(
|
|
195
|
+
"Task aborted - not started due to abort signal"
|
|
196
|
+
),
|
|
197
|
+
aborted: true
|
|
198
|
+
});
|
|
199
|
+
}
|
|
200
|
+
}
|
|
201
|
+
this.isCompleted = true;
|
|
202
|
+
this.rejectCompleted(new Error("Stimulation aborted"));
|
|
203
|
+
return;
|
|
204
|
+
}
|
|
169
205
|
this.isCompleted = true;
|
|
170
|
-
this.
|
|
206
|
+
if (this.failedTasks.length > 0 || this.onResponseError) {
|
|
207
|
+
const error = this.onResponseError || new Error(
|
|
208
|
+
`Stimulation completed with ${this.failedTasks.length} failed task(s)`
|
|
209
|
+
);
|
|
210
|
+
this.rejectCompleted(error);
|
|
211
|
+
} else {
|
|
212
|
+
this.resolveCompleted();
|
|
213
|
+
}
|
|
171
214
|
}
|
|
172
215
|
}
|
|
173
216
|
waitUntilComplete() {
|
|
174
217
|
return this.completed;
|
|
175
218
|
}
|
|
219
|
+
/**
|
|
220
|
+
* Returns all current activation tasks: queued, active, and pending (scheduled but not yet enqueued)
|
|
221
|
+
*/
|
|
222
|
+
getAllActivationTasks() {
|
|
223
|
+
const queuedTasks = this.queue.getQueuedTasks();
|
|
224
|
+
const activeTasks = this.queue.getActiveTasks();
|
|
225
|
+
const pendingTasks = Array.from(this.pendingTasks);
|
|
226
|
+
return [...queuedTasks, ...activeTasks, ...pendingTasks];
|
|
227
|
+
}
|
|
228
|
+
/**
|
|
229
|
+
* Returns all tasks that failed or were aborted
|
|
230
|
+
*/
|
|
231
|
+
getFailedTasks() {
|
|
232
|
+
return [...this.failedTasks];
|
|
233
|
+
}
|
|
234
|
+
/**
|
|
235
|
+
* Get the context store for this stimulation
|
|
236
|
+
*/
|
|
237
|
+
getContext() {
|
|
238
|
+
return this.ctx;
|
|
239
|
+
}
|
|
240
|
+
/**
|
|
241
|
+
* Enqueue activation tasks directly into the stimulation queue
|
|
242
|
+
*/
|
|
243
|
+
enqueueTasks(tasks) {
|
|
244
|
+
for (const task of tasks) {
|
|
245
|
+
const taskWithId = {
|
|
246
|
+
...task,
|
|
247
|
+
stimulationId: this.id
|
|
248
|
+
};
|
|
249
|
+
this.queue.enqueue(taskWithId);
|
|
250
|
+
}
|
|
251
|
+
this.tryResolveCompleted();
|
|
252
|
+
}
|
|
176
253
|
get concurrencyEnabled() {
|
|
177
254
|
return this.options?.concurrency !== void 0 && this.options?.concurrency > 0;
|
|
178
255
|
}
|
|
@@ -197,7 +274,7 @@ var CNSStimulation = class {
|
|
|
197
274
|
* Increment the active count for the SCC containing this neuron
|
|
198
275
|
*/
|
|
199
276
|
incrementSccCount(neuronId) {
|
|
200
|
-
const sccIndex = this.cns.getSccIndexByNeuronName(neuronId);
|
|
277
|
+
const sccIndex = this.cns.network.getSccIndexByNeuronName(neuronId);
|
|
201
278
|
if (sccIndex === void 0) return;
|
|
202
279
|
const currentCount = this.activeSccCounts.get(sccIndex) || 0;
|
|
203
280
|
this.activeSccCounts.set(sccIndex, currentCount + 1);
|
|
@@ -206,7 +283,7 @@ var CNSStimulation = class {
|
|
|
206
283
|
* Decrement the active count for the SCC containing this neuron
|
|
207
284
|
*/
|
|
208
285
|
decrementSccCount(neuronId) {
|
|
209
|
-
const sccIndex = this.cns.getSccIndexByNeuronName(neuronId);
|
|
286
|
+
const sccIndex = this.cns.network.getSccIndexByNeuronName(neuronId);
|
|
210
287
|
if (sccIndex === void 0) return;
|
|
211
288
|
const currentCount = this.activeSccCounts.get(sccIndex) || 0;
|
|
212
289
|
const nextCount = Math.max(0, currentCount - 1);
|
|
@@ -222,7 +299,7 @@ var CNSStimulation = class {
|
|
|
222
299
|
*/
|
|
223
300
|
canNeuronBeGuaranteedDone(neuronId) {
|
|
224
301
|
if (!this.autoCleanupContextsEnabled) return false;
|
|
225
|
-
return this.cns.canNeuronBeGuaranteedDone(
|
|
302
|
+
return this.cns.network.canNeuronBeGuaranteedDone(
|
|
226
303
|
neuronId,
|
|
227
304
|
this.activeSccCounts
|
|
228
305
|
);
|
|
@@ -245,45 +322,70 @@ var CNSStimulation = class {
|
|
|
245
322
|
);
|
|
246
323
|
}
|
|
247
324
|
}
|
|
248
|
-
const
|
|
325
|
+
const neuronActivationTask = {
|
|
326
|
+
stimulationId: this.id,
|
|
249
327
|
neuronId: subscriber.neuron.name,
|
|
250
328
|
dendriteCollateralName: subscriber.dendrite.collateral.name,
|
|
251
|
-
input: inputSignal
|
|
252
|
-
collateralName: inputSignal.collateralName,
|
|
253
|
-
payload: inputSignal.payload
|
|
254
|
-
} : void 0
|
|
329
|
+
input: inputSignal
|
|
255
330
|
};
|
|
256
|
-
return
|
|
331
|
+
return neuronActivationTask;
|
|
257
332
|
}
|
|
258
|
-
|
|
259
|
-
const subscribers = this.cns.getSubscribers(
|
|
260
|
-
|
|
333
|
+
executeActivationTask(neuronActivationTask) {
|
|
334
|
+
const subscribers = this.cns.network.getSubscribers(
|
|
335
|
+
neuronActivationTask.dendriteCollateralName
|
|
261
336
|
);
|
|
262
337
|
const subscriber = subscribers.find(
|
|
263
|
-
(s) => s.neuron.name ===
|
|
338
|
+
(s) => s.neuron.name === neuronActivationTask.neuronId
|
|
264
339
|
);
|
|
265
|
-
if (!subscriber)
|
|
266
|
-
|
|
340
|
+
if (!subscriber) {
|
|
341
|
+
this.failedTasks.push({
|
|
342
|
+
task: neuronActivationTask,
|
|
343
|
+
error: new Error(
|
|
344
|
+
`Subscriber not found for neuron "${neuronActivationTask.neuronId}" and collateral "${neuronActivationTask.dendriteCollateralName}"`
|
|
345
|
+
),
|
|
346
|
+
aborted: false
|
|
347
|
+
});
|
|
348
|
+
return () => {
|
|
349
|
+
};
|
|
350
|
+
}
|
|
267
351
|
const neuron2 = subscriber.neuron;
|
|
268
352
|
const dendrite = subscriber.dendrite;
|
|
269
|
-
const inputSignal =
|
|
270
|
-
collateralName:
|
|
271
|
-
payload:
|
|
353
|
+
const inputSignal = neuronActivationTask.input ? {
|
|
354
|
+
collateralName: neuronActivationTask.input.collateralName,
|
|
355
|
+
payload: neuronActivationTask.input.payload
|
|
272
356
|
} : void 0;
|
|
273
357
|
const starter = () => {
|
|
274
358
|
this.markNeuronActive(neuron2.name);
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
|
|
359
|
+
let response;
|
|
360
|
+
try {
|
|
361
|
+
response = dendrite.response(
|
|
362
|
+
inputSignal?.payload,
|
|
363
|
+
neuron2.axon,
|
|
364
|
+
{
|
|
365
|
+
get: () => this.ctx.get(neuron2.name),
|
|
366
|
+
set: (value) => this.ctx.set(neuron2.name, value),
|
|
367
|
+
delete: () => this.ctx.delete(neuron2.name),
|
|
368
|
+
abortSignal: this.options?.abortSignal,
|
|
369
|
+
cns: this.cns,
|
|
370
|
+
stimulationId: this.id
|
|
371
|
+
}
|
|
372
|
+
);
|
|
373
|
+
} catch (error) {
|
|
374
|
+
this.markNeuronInactive(neuron2.name);
|
|
375
|
+
const isAborted = this.options?.abortSignal?.aborted ?? false;
|
|
376
|
+
this.failedTasks.push({
|
|
377
|
+
task: neuronActivationTask,
|
|
378
|
+
error: error instanceof Error ? error : new Error(String(error)),
|
|
379
|
+
aborted: isAborted
|
|
380
|
+
});
|
|
381
|
+
this.processResponseOrResponses(
|
|
382
|
+
inputSignal,
|
|
383
|
+
void 0,
|
|
384
|
+
error
|
|
385
|
+
);
|
|
386
|
+
return () => {
|
|
387
|
+
};
|
|
388
|
+
}
|
|
287
389
|
const maxDuration = neuron2.maxDuration;
|
|
288
390
|
const asPromise = response instanceof Promise ? response : Promise.resolve(response);
|
|
289
391
|
const timedPromise = maxDuration && maxDuration > 0 ? new Promise((resolve, reject) => {
|
|
@@ -320,6 +422,12 @@ var CNSStimulation = class {
|
|
|
320
422
|
(error) => {
|
|
321
423
|
return () => {
|
|
322
424
|
this.markNeuronInactive(neuron2.name);
|
|
425
|
+
const isAborted = this.options?.abortSignal?.aborted ?? false;
|
|
426
|
+
this.failedTasks.push({
|
|
427
|
+
task: neuronActivationTask,
|
|
428
|
+
error: error instanceof Error ? error : new Error(String(error)),
|
|
429
|
+
aborted: isAborted
|
|
430
|
+
});
|
|
323
431
|
return this.processResponseOrResponses(
|
|
324
432
|
inputSignal,
|
|
325
433
|
void 0,
|
|
@@ -355,60 +463,78 @@ var CNSStimulation = class {
|
|
|
355
463
|
}
|
|
356
464
|
processResponse(inputSignal, outputSignal, error) {
|
|
357
465
|
const collateralName = outputSignal?.collateralName;
|
|
358
|
-
const ownerNeuron = collateralName ? this.cns.getParentNeuronByCollateralName(collateralName) : void 0;
|
|
359
|
-
const subscribers = collateralName ? this.cns.getSubscribers(collateralName) : [];
|
|
360
|
-
const
|
|
466
|
+
const ownerNeuron = collateralName ? this.cns.network.getParentNeuronByCollateralName(collateralName) : void 0;
|
|
467
|
+
const subscribers = collateralName ? this.cns.network.getSubscribers(collateralName) : [];
|
|
468
|
+
const subscriberActivationTasks = [];
|
|
361
469
|
if (collateralName && !error) {
|
|
362
470
|
if (ownerNeuron) {
|
|
363
471
|
this.cleanupCtxIfNeeded(ownerNeuron);
|
|
364
472
|
}
|
|
365
473
|
for (let i = 0; i < subscribers.length; i++) {
|
|
366
|
-
|
|
367
|
-
|
|
474
|
+
const task = this.createSubscriberQueueItem(
|
|
475
|
+
subscribers[i],
|
|
476
|
+
outputSignal
|
|
368
477
|
);
|
|
478
|
+
subscriberActivationTasks.push(task);
|
|
479
|
+
this.pendingTasks.add(task);
|
|
369
480
|
}
|
|
370
481
|
}
|
|
371
|
-
this.scheduledCount +=
|
|
482
|
+
this.scheduledCount += subscriberActivationTasks.length;
|
|
372
483
|
let maybePromise;
|
|
373
484
|
try {
|
|
374
485
|
maybePromise = this.options?.onResponse?.({
|
|
375
486
|
inputSignal,
|
|
376
487
|
outputSignal,
|
|
377
|
-
|
|
488
|
+
contextValue: this.ctx.getAll(),
|
|
378
489
|
queueLength: this.queue.length + this.scheduledCount,
|
|
490
|
+
stimulation: this,
|
|
379
491
|
stimulationId: this.id,
|
|
380
492
|
hops: this.options?.maxNeuronHops && ownerNeuron ? this.nueronVisitMap?.get(ownerNeuron.name) ?? 0 : void 0,
|
|
381
493
|
error
|
|
382
494
|
});
|
|
383
495
|
} catch (e) {
|
|
384
|
-
this.
|
|
496
|
+
this.onResponseError = e instanceof Error ? e : new Error(String(e));
|
|
497
|
+
for (let i = 0; i < subscriberActivationTasks.length; i++) {
|
|
498
|
+
this.scheduledCount--;
|
|
499
|
+
this.pendingTasks.delete(subscriberActivationTasks[i]);
|
|
500
|
+
this.queue.enqueue(subscriberActivationTasks[i]);
|
|
501
|
+
}
|
|
502
|
+
this.tryResolveCompleted();
|
|
385
503
|
return;
|
|
386
504
|
}
|
|
387
505
|
if (maybePromise && typeof maybePromise.then === "function") {
|
|
388
506
|
maybePromise.then(
|
|
389
507
|
() => {
|
|
390
|
-
for (let i = 0; i <
|
|
508
|
+
for (let i = 0; i < subscriberActivationTasks.length; i++) {
|
|
391
509
|
this.scheduledCount--;
|
|
392
|
-
this.
|
|
510
|
+
this.pendingTasks.delete(subscriberActivationTasks[i]);
|
|
511
|
+
this.queue.enqueue(subscriberActivationTasks[i]);
|
|
393
512
|
}
|
|
394
513
|
this.tryResolveCompleted();
|
|
395
514
|
},
|
|
396
515
|
(error2) => {
|
|
397
|
-
this.
|
|
516
|
+
this.onResponseError = error2 instanceof Error ? error2 : new Error(String(error2));
|
|
517
|
+
for (let i = 0; i < subscriberActivationTasks.length; i++) {
|
|
518
|
+
this.scheduledCount--;
|
|
519
|
+
this.pendingTasks.delete(subscriberActivationTasks[i]);
|
|
520
|
+
this.queue.enqueue(subscriberActivationTasks[i]);
|
|
521
|
+
}
|
|
522
|
+
this.tryResolveCompleted();
|
|
398
523
|
}
|
|
399
524
|
);
|
|
400
525
|
return;
|
|
401
526
|
}
|
|
402
|
-
for (let i = 0; i <
|
|
527
|
+
for (let i = 0; i < subscriberActivationTasks.length; i++) {
|
|
403
528
|
this.scheduledCount--;
|
|
404
|
-
this.
|
|
529
|
+
this.pendingTasks.delete(subscriberActivationTasks[i]);
|
|
530
|
+
this.queue.enqueue(subscriberActivationTasks[i]);
|
|
405
531
|
}
|
|
406
532
|
this.tryResolveCompleted();
|
|
407
533
|
}
|
|
408
534
|
responseToSignal(signalOrSignals) {
|
|
409
535
|
if (Array.isArray(signalOrSignals)) {
|
|
410
536
|
for (const signal of signalOrSignals) {
|
|
411
|
-
const ownerNeuron2 = this.cns.getParentNeuronByCollateralName(
|
|
537
|
+
const ownerNeuron2 = this.cns.network.getParentNeuronByCollateralName(
|
|
412
538
|
signal.collateralName
|
|
413
539
|
);
|
|
414
540
|
if (ownerNeuron2) {
|
|
@@ -418,7 +544,7 @@ var CNSStimulation = class {
|
|
|
418
544
|
this.processResponseOrResponses(void 0, signalOrSignals);
|
|
419
545
|
return;
|
|
420
546
|
}
|
|
421
|
-
const ownerNeuron = this.cns.getParentNeuronByCollateralName(
|
|
547
|
+
const ownerNeuron = this.cns.network.getParentNeuronByCollateralName(
|
|
422
548
|
signalOrSignals.collateralName
|
|
423
549
|
);
|
|
424
550
|
if (ownerNeuron) {
|
|
@@ -429,88 +555,6 @@ var CNSStimulation = class {
|
|
|
429
555
|
}
|
|
430
556
|
};
|
|
431
557
|
|
|
432
|
-
// src/CNSTaskQueue.ts
|
|
433
|
-
var CNSTaskQueue = class {
|
|
434
|
-
constructor(concurrency) {
|
|
435
|
-
this.concurrency = concurrency;
|
|
436
|
-
this.pumping = false;
|
|
437
|
-
this.needsPump = false;
|
|
438
|
-
this.activeOperations = 0;
|
|
439
|
-
this.items = [];
|
|
440
|
-
}
|
|
441
|
-
get canStartOperation() {
|
|
442
|
-
const limit = this.concurrency ?? Infinity;
|
|
443
|
-
return this.activeOperations < limit;
|
|
444
|
-
}
|
|
445
|
-
enqueue(task) {
|
|
446
|
-
return new Promise((resolve, reject) => {
|
|
447
|
-
this.items.push({ task, resolve, reject });
|
|
448
|
-
if (!this.pumping) this.pump();
|
|
449
|
-
else this.needsPump = true;
|
|
450
|
-
});
|
|
451
|
-
}
|
|
452
|
-
pump() {
|
|
453
|
-
if (this.pumping) {
|
|
454
|
-
this.needsPump = true;
|
|
455
|
-
return;
|
|
456
|
-
}
|
|
457
|
-
this.pumping = true;
|
|
458
|
-
while (this.canStartOperation && this.items.length > 0) {
|
|
459
|
-
const { task, resolve, reject } = this.items.shift();
|
|
460
|
-
this.activeOperations++;
|
|
461
|
-
try {
|
|
462
|
-
const ret = task();
|
|
463
|
-
if (ret && typeof ret.then === "function") {
|
|
464
|
-
ret.then(
|
|
465
|
-
(cb) => {
|
|
466
|
-
try {
|
|
467
|
-
if (typeof cb === "function") cb();
|
|
468
|
-
resolve();
|
|
469
|
-
} finally {
|
|
470
|
-
this.activeOperations--;
|
|
471
|
-
if (this.items.length > 0 && this.canStartOperation) {
|
|
472
|
-
if (this.pumping) this.needsPump = true;
|
|
473
|
-
else this.pump();
|
|
474
|
-
}
|
|
475
|
-
}
|
|
476
|
-
},
|
|
477
|
-
(err) => {
|
|
478
|
-
try {
|
|
479
|
-
reject(err);
|
|
480
|
-
} finally {
|
|
481
|
-
this.activeOperations--;
|
|
482
|
-
if (this.items.length > 0 && this.canStartOperation) {
|
|
483
|
-
if (this.pumping) this.needsPump = true;
|
|
484
|
-
else this.pump();
|
|
485
|
-
}
|
|
486
|
-
}
|
|
487
|
-
}
|
|
488
|
-
);
|
|
489
|
-
break;
|
|
490
|
-
} else {
|
|
491
|
-
try {
|
|
492
|
-
if (typeof ret === "function") ret();
|
|
493
|
-
resolve();
|
|
494
|
-
} finally {
|
|
495
|
-
this.activeOperations--;
|
|
496
|
-
}
|
|
497
|
-
}
|
|
498
|
-
} catch (e) {
|
|
499
|
-
try {
|
|
500
|
-
reject(e);
|
|
501
|
-
} finally {
|
|
502
|
-
this.activeOperations--;
|
|
503
|
-
}
|
|
504
|
-
}
|
|
505
|
-
}
|
|
506
|
-
this.pumping = false;
|
|
507
|
-
if (this.needsPump) {
|
|
508
|
-
this.needsPump = false;
|
|
509
|
-
this.pump();
|
|
510
|
-
}
|
|
511
|
-
}
|
|
512
|
-
};
|
|
513
|
-
|
|
514
558
|
// src/CNSInstanceNeuronQueue.ts
|
|
515
559
|
var CNSInstanceNeuronQueue = class {
|
|
516
560
|
constructor() {
|
|
@@ -566,20 +610,10 @@ var CNSInstanceNeuronQueue = class {
|
|
|
566
610
|
}
|
|
567
611
|
};
|
|
568
612
|
|
|
569
|
-
// src/
|
|
570
|
-
var
|
|
571
|
-
constructor(neurons
|
|
613
|
+
// src/CNSNetwork.ts
|
|
614
|
+
var CNSNetwork = class {
|
|
615
|
+
constructor(neurons) {
|
|
572
616
|
this.neurons = neurons;
|
|
573
|
-
this.options = options;
|
|
574
|
-
/**
|
|
575
|
-
* Fast lookup: collateralName -> list of (neuron, dendrite) subscribers.
|
|
576
|
-
* Built once at construction time.
|
|
577
|
-
*/
|
|
578
|
-
this.subIndex = /* @__PURE__ */ new Map();
|
|
579
|
-
this.neuronIndex = /* @__PURE__ */ new Map();
|
|
580
|
-
this.dendriteIndex = /* @__PURE__ */ new Map();
|
|
581
|
-
this.collateralIndex = /* @__PURE__ */ new Map();
|
|
582
|
-
this.parentNeuronByCollateralName = /* @__PURE__ */ new Map();
|
|
583
617
|
/**
|
|
584
618
|
* Strongly Connected Components of the neuron graph.
|
|
585
619
|
* Each component is a set of neuron IDs that can reach each other.
|
|
@@ -598,24 +632,17 @@ var CNS = class {
|
|
|
598
632
|
*/
|
|
599
633
|
this.sccAncestors = /* @__PURE__ */ new Map();
|
|
600
634
|
/**
|
|
601
|
-
*
|
|
602
|
-
|
|
603
|
-
this.neuronGates = /* @__PURE__ */ new Map();
|
|
604
|
-
/**
|
|
605
|
-
* Global task queue used by stimulation to schedule per-neuron gated work.
|
|
606
|
-
* Does not replace per-stimulation concurrency; only coordinates global per-neuron limits.
|
|
607
|
-
*/
|
|
608
|
-
this.globalTaskQueue = new CNSTaskQueue();
|
|
609
|
-
this.instanceNeuronQueue = new CNSInstanceNeuronQueue();
|
|
610
|
-
/**
|
|
611
|
-
* Global response listeners applied to every stimulation.
|
|
635
|
+
* Fast lookup: collateralName -> list of (neuron, dendrite) subscribers.
|
|
636
|
+
* Built once at construction time.
|
|
612
637
|
*/
|
|
613
|
-
this.
|
|
638
|
+
this.subIndex = /* @__PURE__ */ new Map();
|
|
639
|
+
this.neuronIndex = /* @__PURE__ */ new Map();
|
|
640
|
+
this.dendriteIndex = /* @__PURE__ */ new Map();
|
|
641
|
+
this.collateralIndex = /* @__PURE__ */ new Map();
|
|
642
|
+
this.parentNeuronByCollateralName = /* @__PURE__ */ new Map();
|
|
614
643
|
this.validateUniqueIdentifiers();
|
|
615
644
|
this.buildIndexes();
|
|
616
|
-
|
|
617
|
-
this.buildSCC();
|
|
618
|
-
}
|
|
645
|
+
this.buildSCC();
|
|
619
646
|
}
|
|
620
647
|
/**
|
|
621
648
|
* Validate uniqueness constraints:
|
|
@@ -645,126 +672,6 @@ var CNS = class {
|
|
|
645
672
|
);
|
|
646
673
|
}
|
|
647
674
|
}
|
|
648
|
-
addResponseListener(listener) {
|
|
649
|
-
this.globalResponseListeners.push(listener);
|
|
650
|
-
let active = true;
|
|
651
|
-
return () => {
|
|
652
|
-
if (!active) return;
|
|
653
|
-
active = false;
|
|
654
|
-
const idx = this.globalResponseListeners.indexOf(listener);
|
|
655
|
-
if (idx >= 0) this.globalResponseListeners.splice(idx, 1);
|
|
656
|
-
};
|
|
657
|
-
}
|
|
658
|
-
wrapOnResponse(local) {
|
|
659
|
-
if (this.globalResponseListeners.length === 0 && !local) {
|
|
660
|
-
return () => {
|
|
661
|
-
};
|
|
662
|
-
}
|
|
663
|
-
return (r) => {
|
|
664
|
-
let anyPromise = false;
|
|
665
|
-
const promises = [];
|
|
666
|
-
if (local) {
|
|
667
|
-
const res = local(r);
|
|
668
|
-
if (res && typeof res.then === "function") {
|
|
669
|
-
anyPromise = true;
|
|
670
|
-
promises.push(res);
|
|
671
|
-
}
|
|
672
|
-
}
|
|
673
|
-
for (let i = 0; i < this.globalResponseListeners.length; i++) {
|
|
674
|
-
const res = this.globalResponseListeners[i](r);
|
|
675
|
-
if (res && typeof res.then === "function") {
|
|
676
|
-
anyPromise = true;
|
|
677
|
-
promises.push(res);
|
|
678
|
-
}
|
|
679
|
-
}
|
|
680
|
-
if (anyPromise) {
|
|
681
|
-
return Promise.allSettled(promises).then((results) => {
|
|
682
|
-
const rejected = results.find(
|
|
683
|
-
(r2) => r2.status === "rejected"
|
|
684
|
-
);
|
|
685
|
-
if (rejected) throw rejected.reason;
|
|
686
|
-
});
|
|
687
|
-
}
|
|
688
|
-
};
|
|
689
|
-
}
|
|
690
|
-
runWithNeuronConcurrency(neuron2, fn) {
|
|
691
|
-
const limit = neuron2.concurrency;
|
|
692
|
-
if (limit === void 0 || limit <= 0) {
|
|
693
|
-
return this.globalTaskQueue.enqueue(fn);
|
|
694
|
-
}
|
|
695
|
-
let gate = this.neuronGates.get(neuron2.name);
|
|
696
|
-
if (!gate) {
|
|
697
|
-
gate = { limit, active: 0, waiters: [] };
|
|
698
|
-
this.neuronGates.set(neuron2.name, gate);
|
|
699
|
-
} else {
|
|
700
|
-
gate.limit = limit;
|
|
701
|
-
}
|
|
702
|
-
const wrap = (cb) => {
|
|
703
|
-
return () => {
|
|
704
|
-
try {
|
|
705
|
-
cb();
|
|
706
|
-
} finally {
|
|
707
|
-
gate.active = Math.max(0, gate.active - 1);
|
|
708
|
-
if (gate.waiters.length > 0) {
|
|
709
|
-
const next = gate.waiters.shift();
|
|
710
|
-
next();
|
|
711
|
-
}
|
|
712
|
-
}
|
|
713
|
-
};
|
|
714
|
-
};
|
|
715
|
-
if (gate.active < gate.limit) {
|
|
716
|
-
gate.active++;
|
|
717
|
-
return this.globalTaskQueue.enqueue(() => {
|
|
718
|
-
const ret = fn();
|
|
719
|
-
if (ret && typeof ret.then === "function") {
|
|
720
|
-
return ret.then((cb) => wrap(cb));
|
|
721
|
-
}
|
|
722
|
-
return wrap(ret);
|
|
723
|
-
});
|
|
724
|
-
}
|
|
725
|
-
return new Promise((resolve) => {
|
|
726
|
-
const starter = () => {
|
|
727
|
-
gate.active++;
|
|
728
|
-
this.globalTaskQueue.enqueue(() => {
|
|
729
|
-
const ret = fn();
|
|
730
|
-
if (ret && typeof ret.then === "function") {
|
|
731
|
-
return ret.then(
|
|
732
|
-
(cb) => wrap(cb)
|
|
733
|
-
);
|
|
734
|
-
}
|
|
735
|
-
return wrap(ret);
|
|
736
|
-
}).then(resolve);
|
|
737
|
-
};
|
|
738
|
-
gate.waiters.push(starter);
|
|
739
|
-
});
|
|
740
|
-
}
|
|
741
|
-
buildIndexes() {
|
|
742
|
-
this.subIndex.clear();
|
|
743
|
-
this.parentNeuronByCollateralName.clear();
|
|
744
|
-
for (const neuron2 of this.neurons) {
|
|
745
|
-
this.neuronIndex.set(neuron2.name, neuron2);
|
|
746
|
-
for (const dendrite of neuron2.dendrites) {
|
|
747
|
-
const key = dendrite.collateral.name;
|
|
748
|
-
const arr = this.subIndex.get(key) ?? [];
|
|
749
|
-
arr.push({ neuron: neuron2, dendrite });
|
|
750
|
-
this.subIndex.set(
|
|
751
|
-
key,
|
|
752
|
-
arr
|
|
753
|
-
);
|
|
754
|
-
this.dendriteIndex.set(key, dendrite);
|
|
755
|
-
}
|
|
756
|
-
Object.values(neuron2.axon).forEach((collateral2) => {
|
|
757
|
-
this.parentNeuronByCollateralName.set(
|
|
758
|
-
collateral2.name,
|
|
759
|
-
neuron2
|
|
760
|
-
);
|
|
761
|
-
this.collateralIndex.set(
|
|
762
|
-
collateral2.name,
|
|
763
|
-
collateral2
|
|
764
|
-
);
|
|
765
|
-
});
|
|
766
|
-
}
|
|
767
|
-
}
|
|
768
675
|
/**
|
|
769
676
|
* Build the neuron graph where neurons are connected if one can stimulate the other.
|
|
770
677
|
*/
|
|
@@ -809,7 +716,7 @@ var CNS = class {
|
|
|
809
716
|
stack.push(neuronId);
|
|
810
717
|
onStack.add(neuronId);
|
|
811
718
|
const neighbors = graph.get(neuronId) || /* @__PURE__ */ new Set();
|
|
812
|
-
for (const neighbor of neighbors) {
|
|
719
|
+
for (const neighbor of Array.from(neighbors)) {
|
|
813
720
|
if (!index.has(neighbor)) {
|
|
814
721
|
strongConnect(neighbor);
|
|
815
722
|
lowlink.set(
|
|
@@ -841,7 +748,7 @@ var CNS = class {
|
|
|
841
748
|
}
|
|
842
749
|
this.stronglyConnectedComponents = components;
|
|
843
750
|
for (let i = 0; i < components.length; i++) {
|
|
844
|
-
for (const neuronId of components[i]) {
|
|
751
|
+
for (const neuronId of Array.from(components[i])) {
|
|
845
752
|
this.neuronToSCC.set(neuronId, i);
|
|
846
753
|
}
|
|
847
754
|
}
|
|
@@ -858,9 +765,9 @@ var CNS = class {
|
|
|
858
765
|
}
|
|
859
766
|
for (let i = 0; i < this.stronglyConnectedComponents.length; i++) {
|
|
860
767
|
const scc = this.stronglyConnectedComponents[i];
|
|
861
|
-
for (const neuronId of scc) {
|
|
768
|
+
for (const neuronId of Array.from(scc)) {
|
|
862
769
|
const neighbors = neuronGraph.get(neuronId) || /* @__PURE__ */ new Set();
|
|
863
|
-
for (const neighborId of neighbors) {
|
|
770
|
+
for (const neighborId of Array.from(neighbors)) {
|
|
864
771
|
const neighborSccIndex = this.neuronToSCC.get(neighborId);
|
|
865
772
|
if (neighborSccIndex !== void 0 && neighborSccIndex !== i) {
|
|
866
773
|
this.sccDag.get(neighborSccIndex).add(i);
|
|
@@ -890,11 +797,11 @@ var CNS = class {
|
|
|
890
797
|
while (queue.length > 0) {
|
|
891
798
|
const current = queue.shift();
|
|
892
799
|
const outgoingEdges = this.getOutgoingEdges(current);
|
|
893
|
-
for (const neighbor of outgoingEdges) {
|
|
800
|
+
for (const neighbor of Array.from(outgoingEdges)) {
|
|
894
801
|
const neighborAncestors = this.sccAncestors.get(neighbor);
|
|
895
802
|
neighborAncestors.add(current);
|
|
896
803
|
const currentAncestors = this.sccAncestors.get(current);
|
|
897
|
-
for (const ancestor of currentAncestors) {
|
|
804
|
+
for (const ancestor of Array.from(currentAncestors)) {
|
|
898
805
|
neighborAncestors.add(ancestor);
|
|
899
806
|
}
|
|
900
807
|
const newInDegree = (inDegree.get(neighbor) || 0) - 1;
|
|
@@ -910,7 +817,7 @@ var CNS = class {
|
|
|
910
817
|
*/
|
|
911
818
|
getOutgoingEdges(sccIndex) {
|
|
912
819
|
const outgoing = /* @__PURE__ */ new Set();
|
|
913
|
-
for (const [targetScc, incomingEdges] of this.sccDag) {
|
|
820
|
+
for (const [targetScc, incomingEdges] of Array.from(this.sccDag)) {
|
|
914
821
|
if (incomingEdges.has(sccIndex)) {
|
|
915
822
|
outgoing.add(targetScc);
|
|
916
823
|
}
|
|
@@ -945,13 +852,40 @@ var CNS = class {
|
|
|
945
852
|
}
|
|
946
853
|
const ancestors = this.sccAncestors.get(sccIndex);
|
|
947
854
|
if (!ancestors) return true;
|
|
948
|
-
for (const ancestorSccIndex of ancestors) {
|
|
855
|
+
for (const ancestorSccIndex of Array.from(ancestors)) {
|
|
949
856
|
if (activeSccCounts.get(ancestorSccIndex) && activeSccCounts.get(ancestorSccIndex) > 0) {
|
|
950
857
|
return false;
|
|
951
858
|
}
|
|
952
859
|
}
|
|
953
860
|
return true;
|
|
954
861
|
}
|
|
862
|
+
buildIndexes() {
|
|
863
|
+
this.subIndex.clear();
|
|
864
|
+
this.parentNeuronByCollateralName.clear();
|
|
865
|
+
for (const neuron2 of this.neurons) {
|
|
866
|
+
this.neuronIndex.set(neuron2.name, neuron2);
|
|
867
|
+
for (const dendrite of neuron2.dendrites) {
|
|
868
|
+
const key = dendrite.collateral.name;
|
|
869
|
+
const arr = this.subIndex.get(key) ?? [];
|
|
870
|
+
arr.push({ neuron: neuron2, dendrite });
|
|
871
|
+
this.subIndex.set(
|
|
872
|
+
key,
|
|
873
|
+
arr
|
|
874
|
+
);
|
|
875
|
+
this.dendriteIndex.set(key, dendrite);
|
|
876
|
+
}
|
|
877
|
+
Object.values(neuron2.axon).forEach((collateral2) => {
|
|
878
|
+
this.parentNeuronByCollateralName.set(
|
|
879
|
+
collateral2.name,
|
|
880
|
+
neuron2
|
|
881
|
+
);
|
|
882
|
+
this.collateralIndex.set(
|
|
883
|
+
collateral2.name,
|
|
884
|
+
collateral2
|
|
885
|
+
);
|
|
886
|
+
});
|
|
887
|
+
}
|
|
888
|
+
}
|
|
955
889
|
getParentNeuronByCollateralName(collateralName) {
|
|
956
890
|
return this.parentNeuronByCollateralName.get(collateralName);
|
|
957
891
|
}
|
|
@@ -975,6 +909,80 @@ var CNS = class {
|
|
|
975
909
|
getSubscribers(collateralName) {
|
|
976
910
|
return this.subIndex.get(collateralName) ?? [];
|
|
977
911
|
}
|
|
912
|
+
};
|
|
913
|
+
|
|
914
|
+
// src/CNS.ts
|
|
915
|
+
var CNS = class {
|
|
916
|
+
constructor(neurons, options) {
|
|
917
|
+
this.neurons = neurons;
|
|
918
|
+
this.options = options;
|
|
919
|
+
/**
|
|
920
|
+
* Global per-neuron concurrency gates shared across all stimulations.
|
|
921
|
+
*/
|
|
922
|
+
this.neuronGates = /* @__PURE__ */ new Map();
|
|
923
|
+
/**
|
|
924
|
+
* Global task queue used by stimulation to schedule per-neuron gated work.
|
|
925
|
+
* Does not replace per-stimulation concurrency; only coordinates global per-neuron limits.
|
|
926
|
+
*/
|
|
927
|
+
this.instanceNeuronQueue = new CNSInstanceNeuronQueue();
|
|
928
|
+
/**
|
|
929
|
+
* Global response listeners applied to every stimulation.
|
|
930
|
+
*/
|
|
931
|
+
this.globalResponseListeners = [];
|
|
932
|
+
this.network = new CNSNetwork(this.neurons);
|
|
933
|
+
}
|
|
934
|
+
addResponseListener(listener) {
|
|
935
|
+
this.globalResponseListeners.push(listener);
|
|
936
|
+
let active = true;
|
|
937
|
+
return () => {
|
|
938
|
+
if (!active) return;
|
|
939
|
+
active = false;
|
|
940
|
+
const idx = this.globalResponseListeners.indexOf(listener);
|
|
941
|
+
if (idx >= 0) this.globalResponseListeners.splice(idx, 1);
|
|
942
|
+
};
|
|
943
|
+
}
|
|
944
|
+
wrapOnResponse(local) {
|
|
945
|
+
if (this.globalResponseListeners.length === 0 && !local) {
|
|
946
|
+
return () => {
|
|
947
|
+
};
|
|
948
|
+
}
|
|
949
|
+
return (r) => {
|
|
950
|
+
let anyPromise = false;
|
|
951
|
+
const promises = [];
|
|
952
|
+
if (local) {
|
|
953
|
+
try {
|
|
954
|
+
const res = local(r);
|
|
955
|
+
if (res && typeof res.then === "function") {
|
|
956
|
+
anyPromise = true;
|
|
957
|
+
promises.push(res);
|
|
958
|
+
}
|
|
959
|
+
} catch (error) {
|
|
960
|
+
anyPromise = true;
|
|
961
|
+
promises.push(Promise.reject(error));
|
|
962
|
+
}
|
|
963
|
+
}
|
|
964
|
+
for (let i = 0; i < this.globalResponseListeners.length; i++) {
|
|
965
|
+
try {
|
|
966
|
+
const res = this.globalResponseListeners[i](r);
|
|
967
|
+
if (res && typeof res.then === "function") {
|
|
968
|
+
anyPromise = true;
|
|
969
|
+
promises.push(res);
|
|
970
|
+
}
|
|
971
|
+
} catch (error) {
|
|
972
|
+
anyPromise = true;
|
|
973
|
+
promises.push(Promise.reject(error));
|
|
974
|
+
}
|
|
975
|
+
}
|
|
976
|
+
if (anyPromise) {
|
|
977
|
+
return Promise.allSettled(promises).then((results) => {
|
|
978
|
+
const rejected = results.find(
|
|
979
|
+
(r2) => r2.status === "rejected"
|
|
980
|
+
);
|
|
981
|
+
if (rejected) throw rejected.reason;
|
|
982
|
+
});
|
|
983
|
+
}
|
|
984
|
+
};
|
|
985
|
+
}
|
|
978
986
|
stimulate(signalOrSignals, options) {
|
|
979
987
|
const wrapped = this.wrapOnResponse(options?.onResponse);
|
|
980
988
|
const stimulation = new CNSStimulation(this, this.instanceNeuronQueue, {
|
|
@@ -982,7 +990,19 @@ var CNS = class {
|
|
|
982
990
|
onResponse: wrapped
|
|
983
991
|
});
|
|
984
992
|
stimulation.responseToSignal(signalOrSignals);
|
|
985
|
-
return stimulation
|
|
993
|
+
return stimulation;
|
|
994
|
+
}
|
|
995
|
+
/**
|
|
996
|
+
* Start a stimulation with activation tasks directly
|
|
997
|
+
*/
|
|
998
|
+
activate(tasks, options) {
|
|
999
|
+
const wrapped = this.wrapOnResponse(options?.onResponse);
|
|
1000
|
+
const stimulation = new CNSStimulation(this, this.instanceNeuronQueue, {
|
|
1001
|
+
...options,
|
|
1002
|
+
onResponse: wrapped
|
|
1003
|
+
});
|
|
1004
|
+
stimulation.enqueueTasks(tasks);
|
|
1005
|
+
return stimulation;
|
|
986
1006
|
}
|
|
987
1007
|
};
|
|
988
1008
|
|