libpetri 1.3.2 → 1.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/dist/debug/index.d.ts +3 -0
- package/dist/debug/index.js +23 -8
- package/dist/debug/index.js.map +1 -1
- package/dist/index.d.ts +9 -5
- package/dist/index.js +56 -28
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
package/dist/index.d.ts
CHANGED
|
@@ -150,7 +150,9 @@ interface PetriNetExecutor {
|
|
|
150
150
|
run(timeoutMs?: number): Promise<Marking>;
|
|
151
151
|
/** Inject an external token. Returns true if accepted. */
|
|
152
152
|
inject<T>(place: EnvironmentPlace<T>, token: Token<T>): Promise<boolean>;
|
|
153
|
-
/**
|
|
153
|
+
/** Graceful shutdown: reject new inject() calls, process queued events, terminate at quiescence. */
|
|
154
|
+
drain(): void;
|
|
155
|
+
/** Immediate shutdown: discard queued events, wait for in-flight, terminate. */
|
|
154
156
|
close(): void;
|
|
155
157
|
}
|
|
156
158
|
|
|
@@ -181,7 +183,6 @@ interface PetriNetExecutor {
|
|
|
181
183
|
interface BitmapNetExecutorOptions {
|
|
182
184
|
eventStore?: EventStore;
|
|
183
185
|
environmentPlaces?: Set<EnvironmentPlace<any>>;
|
|
184
|
-
longRunning?: boolean;
|
|
185
186
|
/** Provides execution context data for each transition firing. */
|
|
186
187
|
executionContextProvider?: (transitionName: string, consumed: Token<any>[]) => Map<string, unknown>;
|
|
187
188
|
}
|
|
@@ -208,7 +209,7 @@ declare class BitmapNetExecutor implements PetriNetExecutor {
|
|
|
208
209
|
private readonly marking;
|
|
209
210
|
private readonly eventStore;
|
|
210
211
|
private readonly environmentPlaces;
|
|
211
|
-
private readonly
|
|
212
|
+
private readonly hasEnvironmentPlaces;
|
|
212
213
|
private readonly executionContextProvider?;
|
|
213
214
|
private readonly startMs;
|
|
214
215
|
private readonly hasAnyDeadlines;
|
|
@@ -236,6 +237,7 @@ declare class BitmapNetExecutor implements PetriNetExecutor {
|
|
|
236
237
|
private readonly pendingResetPlaces;
|
|
237
238
|
private readonly transitionInputPlaceNames;
|
|
238
239
|
private running;
|
|
240
|
+
private draining;
|
|
239
241
|
private closed;
|
|
240
242
|
constructor(net: PetriNet, initialTokens: Map<Place<any>, Token<any>[]>, options?: BitmapNetExecutorOptions);
|
|
241
243
|
run(timeoutMs?: number): Promise<Marking>;
|
|
@@ -300,6 +302,7 @@ declare class BitmapNetExecutor implements PetriNetExecutor {
|
|
|
300
302
|
private snapshotMarking;
|
|
301
303
|
isQuiescent(): boolean;
|
|
302
304
|
executionId(): string;
|
|
305
|
+
drain(): void;
|
|
303
306
|
close(): void;
|
|
304
307
|
private emitEvent;
|
|
305
308
|
}
|
|
@@ -412,7 +415,6 @@ declare class PrecompiledNet {
|
|
|
412
415
|
interface PrecompiledNetExecutorOptions {
|
|
413
416
|
eventStore?: EventStore;
|
|
414
417
|
environmentPlaces?: Set<EnvironmentPlace<any>>;
|
|
415
|
-
longRunning?: boolean;
|
|
416
418
|
executionContextProvider?: (transitionName: string, consumed: Token<any>[]) => Map<string, unknown>;
|
|
417
419
|
/** Skip output spec validation for trusted actions (CONC-026). */
|
|
418
420
|
skipOutputValidation?: boolean;
|
|
@@ -429,7 +431,7 @@ declare class PrecompiledNetExecutor implements PetriNetExecutor {
|
|
|
429
431
|
private readonly program;
|
|
430
432
|
private readonly eventStore;
|
|
431
433
|
private readonly environmentPlaces;
|
|
432
|
-
private readonly
|
|
434
|
+
private readonly hasEnvironmentPlaces;
|
|
433
435
|
private readonly executionContextProvider?;
|
|
434
436
|
private readonly skipOutputValidation;
|
|
435
437
|
private readonly startMs;
|
|
@@ -462,6 +464,7 @@ declare class PrecompiledNetExecutor implements PetriNetExecutor {
|
|
|
462
464
|
private readonly racePromises;
|
|
463
465
|
private readonly readyBuffer;
|
|
464
466
|
private running;
|
|
467
|
+
private draining;
|
|
465
468
|
private closed;
|
|
466
469
|
private marking;
|
|
467
470
|
constructor(net: PetriNet, initialTokens: Map<Place<any>, Token<any>[]>, options?: PrecompiledNetExecutorOptions);
|
|
@@ -504,6 +507,7 @@ declare class PrecompiledNetExecutor implements PetriNetExecutor {
|
|
|
504
507
|
private snapshotMarking;
|
|
505
508
|
isQuiescent(): boolean;
|
|
506
509
|
executionId(): string;
|
|
510
|
+
drain(): void;
|
|
507
511
|
close(): void;
|
|
508
512
|
private emitEvent;
|
|
509
513
|
}
|
package/dist/index.js
CHANGED
|
@@ -1178,7 +1178,7 @@ var BitmapNetExecutor = class {
|
|
|
1178
1178
|
marking;
|
|
1179
1179
|
eventStore;
|
|
1180
1180
|
environmentPlaces;
|
|
1181
|
-
|
|
1181
|
+
hasEnvironmentPlaces;
|
|
1182
1182
|
executionContextProvider;
|
|
1183
1183
|
startMs;
|
|
1184
1184
|
hasAnyDeadlines;
|
|
@@ -1213,6 +1213,7 @@ var BitmapNetExecutor = class {
|
|
|
1213
1213
|
pendingResetPlaces = /* @__PURE__ */ new Set();
|
|
1214
1214
|
transitionInputPlaceNames;
|
|
1215
1215
|
running = false;
|
|
1216
|
+
draining = false;
|
|
1216
1217
|
closed = false;
|
|
1217
1218
|
constructor(net, initialTokens, options = {}) {
|
|
1218
1219
|
this.compiled = CompiledNet.compile(net);
|
|
@@ -1221,7 +1222,7 @@ var BitmapNetExecutor = class {
|
|
|
1221
1222
|
this.environmentPlaces = new Set(
|
|
1222
1223
|
[...options.environmentPlaces ?? []].map((ep) => ep.place.name)
|
|
1223
1224
|
);
|
|
1224
|
-
this.
|
|
1225
|
+
this.hasEnvironmentPlaces = this.environmentPlaces.size > 0;
|
|
1225
1226
|
this.executionContextProvider = options.executionContextProvider;
|
|
1226
1227
|
this.startMs = performance.now();
|
|
1227
1228
|
const wordCount = this.compiled.wordCount;
|
|
@@ -1290,7 +1291,7 @@ var BitmapNetExecutor = class {
|
|
|
1290
1291
|
timestamp: Date.now(),
|
|
1291
1292
|
marking: this.snapshotMarking()
|
|
1292
1293
|
});
|
|
1293
|
-
while (this.running
|
|
1294
|
+
while (this.running) {
|
|
1294
1295
|
this.processCompletedTransitions();
|
|
1295
1296
|
this.processExternalEvents();
|
|
1296
1297
|
this.updateDirtyTransitions();
|
|
@@ -1322,7 +1323,7 @@ var BitmapNetExecutor = class {
|
|
|
1322
1323
|
if (!this.environmentPlaces.has(envPlace.place.name)) {
|
|
1323
1324
|
throw new Error(`Place ${envPlace.place.name} is not registered as an environment place`);
|
|
1324
1325
|
}
|
|
1325
|
-
if (this.closed) return false;
|
|
1326
|
+
if (this.closed || this.draining) return false;
|
|
1326
1327
|
return new Promise((resolve, reject) => {
|
|
1327
1328
|
this.externalQueue.push({
|
|
1328
1329
|
place: envPlace.place,
|
|
@@ -1358,7 +1359,12 @@ var BitmapNetExecutor = class {
|
|
|
1358
1359
|
}
|
|
1359
1360
|
}
|
|
1360
1361
|
shouldTerminate() {
|
|
1361
|
-
if (this.
|
|
1362
|
+
if (this.closed) {
|
|
1363
|
+
return this.inFlight.size === 0 && this.completionQueue.length === 0;
|
|
1364
|
+
}
|
|
1365
|
+
if (this.hasEnvironmentPlaces) {
|
|
1366
|
+
return this.draining && this.enabledTransitionCount === 0 && this.inFlight.size === 0 && this.completionQueue.length === 0;
|
|
1367
|
+
}
|
|
1362
1368
|
return this.enabledTransitionCount === 0 && this.inFlight.size === 0 && this.completionQueue.length === 0;
|
|
1363
1369
|
}
|
|
1364
1370
|
// ======================== Dirty Set Transitions ========================
|
|
@@ -1751,6 +1757,7 @@ var BitmapNetExecutor = class {
|
|
|
1751
1757
|
// ======================== External Events ========================
|
|
1752
1758
|
processExternalEvents() {
|
|
1753
1759
|
if (this.externalQueue.length === 0) return;
|
|
1760
|
+
if (this.closed) return;
|
|
1754
1761
|
const len = this.externalQueue.length;
|
|
1755
1762
|
for (let i = 0; i < len; i++) {
|
|
1756
1763
|
const event = this.externalQueue[i];
|
|
@@ -1790,9 +1797,10 @@ var BitmapNetExecutor = class {
|
|
|
1790
1797
|
* After the yield, re-checks queues and `this.closed` for close-during-yield safety.
|
|
1791
1798
|
*/
|
|
1792
1799
|
async awaitWork() {
|
|
1793
|
-
if (this.completionQueue.length > 0 || this.externalQueue.length > 0) return;
|
|
1800
|
+
if (this.completionQueue.length > 0 || !this.closed && this.externalQueue.length > 0) return;
|
|
1794
1801
|
await Promise.resolve();
|
|
1795
|
-
if (this.completionQueue.length > 0 || this.externalQueue.length > 0
|
|
1802
|
+
if (this.completionQueue.length > 0 || !this.closed && this.externalQueue.length > 0) return;
|
|
1803
|
+
if (this.closed && this.inFlight.size === 0) return;
|
|
1796
1804
|
const promises = this.awaitPromises;
|
|
1797
1805
|
promises.length = 0;
|
|
1798
1806
|
if (this.inFlight.size > 0) {
|
|
@@ -1801,12 +1809,14 @@ var BitmapNetExecutor = class {
|
|
|
1801
1809
|
for (const f of this.inFlight.values()) arr.push(f.promise);
|
|
1802
1810
|
promises.push(Promise.race(arr));
|
|
1803
1811
|
}
|
|
1804
|
-
|
|
1805
|
-
|
|
1806
|
-
|
|
1807
|
-
|
|
1808
|
-
|
|
1809
|
-
|
|
1812
|
+
if (!this.closed) {
|
|
1813
|
+
promises.push(new Promise((resolve) => {
|
|
1814
|
+
this.wakeUpResolve = resolve;
|
|
1815
|
+
}));
|
|
1816
|
+
const timerMs = this.millisUntilNextTimedTransition();
|
|
1817
|
+
if (timerMs > 0 && timerMs < Infinity) {
|
|
1818
|
+
promises.push(new Promise((r) => setTimeout(r, timerMs)));
|
|
1819
|
+
}
|
|
1810
1820
|
}
|
|
1811
1821
|
if (promises.length > 0) {
|
|
1812
1822
|
await Promise.race(promises);
|
|
@@ -1876,8 +1886,12 @@ var BitmapNetExecutor = class {
|
|
|
1876
1886
|
executionId() {
|
|
1877
1887
|
return this.startMs.toString(16);
|
|
1878
1888
|
}
|
|
1889
|
+
drain() {
|
|
1890
|
+
this.draining = true;
|
|
1891
|
+
this.wakeUp();
|
|
1892
|
+
}
|
|
1879
1893
|
close() {
|
|
1880
|
-
this.
|
|
1894
|
+
this.draining = true;
|
|
1881
1895
|
this.closed = true;
|
|
1882
1896
|
this.wakeUp();
|
|
1883
1897
|
}
|
|
@@ -2235,7 +2249,7 @@ var PrecompiledNetExecutor = class {
|
|
|
2235
2249
|
program;
|
|
2236
2250
|
eventStore;
|
|
2237
2251
|
environmentPlaces;
|
|
2238
|
-
|
|
2252
|
+
hasEnvironmentPlaces;
|
|
2239
2253
|
executionContextProvider;
|
|
2240
2254
|
skipOutputValidation;
|
|
2241
2255
|
startMs;
|
|
@@ -2278,6 +2292,7 @@ var PrecompiledNetExecutor = class {
|
|
|
2278
2292
|
readyBuffer = [];
|
|
2279
2293
|
// ==================== Lifecycle ====================
|
|
2280
2294
|
running = false;
|
|
2295
|
+
draining = false;
|
|
2281
2296
|
closed = false;
|
|
2282
2297
|
// ==================== Lazy Marking ====================
|
|
2283
2298
|
marking = null;
|
|
@@ -2287,7 +2302,7 @@ var PrecompiledNetExecutor = class {
|
|
|
2287
2302
|
this.environmentPlaces = new Set(
|
|
2288
2303
|
[...options.environmentPlaces ?? []].map((ep) => ep.place.name)
|
|
2289
2304
|
);
|
|
2290
|
-
this.
|
|
2305
|
+
this.hasEnvironmentPlaces = this.environmentPlaces.size > 0;
|
|
2291
2306
|
this.executionContextProvider = options.executionContextProvider;
|
|
2292
2307
|
this.skipOutputValidation = options.skipOutputValidation ?? false;
|
|
2293
2308
|
this.startMs = performance.now();
|
|
@@ -2372,7 +2387,7 @@ var PrecompiledNetExecutor = class {
|
|
|
2372
2387
|
timestamp: Date.now(),
|
|
2373
2388
|
marking: this.snapshotMarking()
|
|
2374
2389
|
});
|
|
2375
|
-
while (this.running
|
|
2390
|
+
while (this.running) {
|
|
2376
2391
|
this.processCompletedTransitions();
|
|
2377
2392
|
this.processExternalEvents();
|
|
2378
2393
|
this.updateDirtyTransitions();
|
|
@@ -2404,7 +2419,7 @@ var PrecompiledNetExecutor = class {
|
|
|
2404
2419
|
if (!this.environmentPlaces.has(envPlace.place.name)) {
|
|
2405
2420
|
throw new Error(`Place ${envPlace.place.name} is not registered as an environment place`);
|
|
2406
2421
|
}
|
|
2407
|
-
if (this.closed) return false;
|
|
2422
|
+
if (this.closed || this.draining) return false;
|
|
2408
2423
|
return new Promise((resolve, reject) => {
|
|
2409
2424
|
this.externalQueue.push({
|
|
2410
2425
|
place: envPlace.place,
|
|
@@ -2438,7 +2453,12 @@ var PrecompiledNetExecutor = class {
|
|
|
2438
2453
|
}
|
|
2439
2454
|
}
|
|
2440
2455
|
shouldTerminate() {
|
|
2441
|
-
if (this.
|
|
2456
|
+
if (this.closed) {
|
|
2457
|
+
return this.inFlightCount === 0 && this.completionQueue.length === 0;
|
|
2458
|
+
}
|
|
2459
|
+
if (this.hasEnvironmentPlaces) {
|
|
2460
|
+
return this.draining && this.enabledTransitionCount === 0 && this.inFlightCount === 0 && this.completionQueue.length === 0;
|
|
2461
|
+
}
|
|
2442
2462
|
return this.enabledTransitionCount === 0 && this.inFlightCount === 0 && this.completionQueue.length === 0;
|
|
2443
2463
|
}
|
|
2444
2464
|
// ======================== Dirty Set Processing ========================
|
|
@@ -2960,6 +2980,7 @@ var PrecompiledNetExecutor = class {
|
|
|
2960
2980
|
// ======================== External Events ========================
|
|
2961
2981
|
processExternalEvents() {
|
|
2962
2982
|
if (this.externalQueue.length === 0) return;
|
|
2983
|
+
if (this.closed) return;
|
|
2963
2984
|
const prog = this.program;
|
|
2964
2985
|
const len = this.externalQueue.length;
|
|
2965
2986
|
for (let i = 0; i < len; i++) {
|
|
@@ -2989,9 +3010,10 @@ var PrecompiledNetExecutor = class {
|
|
|
2989
3010
|
}
|
|
2990
3011
|
// ======================== Await Work ========================
|
|
2991
3012
|
async awaitWork() {
|
|
2992
|
-
if (this.completionQueue.length > 0 || this.externalQueue.length > 0) return;
|
|
3013
|
+
if (this.completionQueue.length > 0 || !this.closed && this.externalQueue.length > 0) return;
|
|
2993
3014
|
await Promise.resolve();
|
|
2994
|
-
if (this.completionQueue.length > 0 || this.externalQueue.length > 0
|
|
3015
|
+
if (this.completionQueue.length > 0 || !this.closed && this.externalQueue.length > 0) return;
|
|
3016
|
+
if (this.closed && this.inFlightCount === 0) return;
|
|
2995
3017
|
const promises = this.awaitPromises;
|
|
2996
3018
|
promises.length = 0;
|
|
2997
3019
|
if (this.inFlightCount > 0) {
|
|
@@ -3006,12 +3028,14 @@ var PrecompiledNetExecutor = class {
|
|
|
3006
3028
|
promises.push(Promise.race(arr));
|
|
3007
3029
|
}
|
|
3008
3030
|
}
|
|
3009
|
-
|
|
3010
|
-
|
|
3011
|
-
|
|
3012
|
-
|
|
3013
|
-
|
|
3014
|
-
|
|
3031
|
+
if (!this.closed) {
|
|
3032
|
+
promises.push(new Promise((resolve) => {
|
|
3033
|
+
this.wakeUpResolve = resolve;
|
|
3034
|
+
}));
|
|
3035
|
+
const timerMs = this.millisUntilNextTimedTransition();
|
|
3036
|
+
if (timerMs > 0 && timerMs < Infinity) {
|
|
3037
|
+
promises.push(new Promise((r) => setTimeout(r, timerMs)));
|
|
3038
|
+
}
|
|
3015
3039
|
}
|
|
3016
3040
|
if (promises.length > 0) {
|
|
3017
3041
|
await Promise.race(promises);
|
|
@@ -3085,8 +3109,12 @@ var PrecompiledNetExecutor = class {
|
|
|
3085
3109
|
executionId() {
|
|
3086
3110
|
return this.startMs.toString(16);
|
|
3087
3111
|
}
|
|
3112
|
+
drain() {
|
|
3113
|
+
this.draining = true;
|
|
3114
|
+
this.wakeUp();
|
|
3115
|
+
}
|
|
3088
3116
|
close() {
|
|
3089
|
-
this.
|
|
3117
|
+
this.draining = true;
|
|
3090
3118
|
this.closed = true;
|
|
3091
3119
|
this.wakeUp();
|
|
3092
3120
|
}
|