libpetri 2.11.0 → 2.12.1
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/{chunk-YKJQ7IKZ.js → chunk-V3WTQRHC.js} +425 -59
- package/dist/chunk-V3WTQRHC.js.map +1 -0
- package/dist/debug/index.d.ts +2 -2
- package/dist/doclet/index.d.ts +1 -1
- package/dist/{event-store-CAkN_ayv.d.ts → event-store--nMbAO1v.d.ts} +1 -1
- package/dist/export/index.d.ts +1 -1
- package/dist/index.d.ts +51 -4
- package/dist/index.js +233 -44
- package/dist/index.js.map +1 -1
- package/dist/{petri-net-B4wQwsUj.d.ts → petri-net-Byc3gSgJ.d.ts} +47 -1
- package/dist/verification/index.d.ts +84 -4
- package/dist/verification/index.js +3 -1
- package/dist/verification/index.js.map +1 -1
- package/package.json +1 -1
- package/dist/chunk-YKJQ7IKZ.js.map +0 -1
package/dist/debug/index.d.ts
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { Writable } from 'node:stream';
|
|
2
|
-
import { P as PetriNet, b as Transition, T as Token } from '../petri-net-
|
|
3
|
-
import { E as EventStore, N as NetEvent } from '../event-store
|
|
2
|
+
import { P as PetriNet, b as Transition, T as Token } from '../petri-net-Byc3gSgJ.js';
|
|
3
|
+
import { E as EventStore, N as NetEvent } from '../event-store--nMbAO1v.js';
|
|
4
4
|
|
|
5
5
|
/**
|
|
6
6
|
* Commands sent from debug UI client to server via WebSocket.
|
package/dist/doclet/index.d.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { Application } from 'typedoc';
|
|
2
|
-
import { P as PetriNet, S as SubnetDef, o as Instance } from '../petri-net-
|
|
2
|
+
import { P as PetriNet, S as SubnetDef, o as Instance } from '../petri-net-Byc3gSgJ.js';
|
|
3
3
|
|
|
4
4
|
/**
|
|
5
5
|
* TypeDoc plugin for `@petrinet` and `@subnet` tags — auto-generates
|
package/dist/export/index.d.ts
CHANGED
package/dist/index.d.ts
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
|
-
import { P as PetriNet, S as SubnetDef, a as Place, T as Token, b as Transition, E as EnvironmentPlace, c as TransitionContext, O as Out } from './petri-net-
|
|
2
|
-
export { A as Arc, d as ArcInhibitor, e as ArcInput, f as ArcOutput, g as ArcRead, h as ArcReset, C as Channel, i as ComposeBindings, F as FusionSet, j as FusionSetBuilder, I as In, k as InAll, l as InAtLeast, m as InExactly, n as InOne, o as Instance, p as Interface, q as InterfaceBuilder, K as KeyFn, L as LogFn, M as MAX_DURATION_MS, r as MatchKey, s as MatchSpec, N as NameId, t as OutAnd, u as OutForwardInput, v as OutPlace, w as OutTimeout, x as OutXor, y as OutputEntry, z as PetriNetBuilder, B as Port, D as PortDirection, G as SubnetDefBuilder, H as SubnetInstance, J as Timing, Q as TimingDeadline, R as TimingDelayed, U as TimingExact, V as TimingImmediate, W as TimingWindow, X as TokenInput, Y as TokenOutput, Z as TransitionAction, _ as TransitionBuilder, $ as VerificationHarness, a0 as VerificationResult, a1 as all, a2 as allPlaces, a3 as and, a4 as andPlaces, a5 as arcPlace, a6 as atLeast, a7 as consumptionCount, a8 as deadline, a9 as delayed, aa as earliest, ab as enumerateBranches, ac as environmentPlace, ad as exact, ae as exactly, af as fork, ag as forwardInput, ah as hasDeadline, ai as hasGuard, aj as immediate, ak as inhibitorArc, al as inputArc, am as isUnit, an as keyForPlace, ao as latest, ap as matchCorrelates, aq as matchKey, ar as matchSpec, as as matchesGuard, at as nameId, au as one, av as outPlace, aw as outputArc, ax as passthrough, ay as place, az as produce, aA as readArc, aB as requiredCount, aC as resetArc, aD as timeout, aE as timeoutPlace, aF as tokenAt, aG as tokenOf, aH as transform, aI as transformAsync, aJ as transformFrom, aK as unitToken, aL as window, aM as withTimeout, aN as xor, aO as xorPlaces } from './petri-net-
|
|
3
|
-
import { E as EventStore } from './event-store
|
|
4
|
-
export { A as ActionTimedOut, a as ExecutionCompleted, b as ExecutionStarted, I as InMemoryEventStore, L as LogMessage, M as MarkingSnapshot, N as NetEvent, T as TokenAdded, c as TokenRemoved, d as TransitionClockRestarted, e as TransitionCompleted, f as TransitionEnabled, g as TransitionFailed, h as TransitionStarted, i as TransitionTimedOut, j as eventTransitionName, k as eventsOfType, l as failures, m as filterEvents, n as inMemoryEventStore, o as isFailureEvent, p as noopEventStore, t as transitionEvents } from './event-store
|
|
1
|
+
import { P as PetriNet, S as SubnetDef, a as Place, T as Token, b as Transition, E as EnvironmentPlace, c as TransitionContext, O as Out } from './petri-net-Byc3gSgJ.js';
|
|
2
|
+
export { A as Arc, d as ArcInhibitor, e as ArcInput, f as ArcOutput, g as ArcRead, h as ArcReset, C as Channel, i as ComposeBindings, F as FusionSet, j as FusionSetBuilder, I as In, k as InAll, l as InAtLeast, m as InExactly, n as InOne, o as Instance, p as Interface, q as InterfaceBuilder, K as KeyFn, L as LogFn, M as MAX_DURATION_MS, r as MatchKey, s as MatchSpec, N as NameId, t as OutAnd, u as OutForwardInput, v as OutPlace, w as OutTimeout, x as OutXor, y as OutputEntry, z as PetriNetBuilder, B as Port, D as PortDirection, G as SubnetDefBuilder, H as SubnetInstance, J as Timing, Q as TimingDeadline, R as TimingDelayed, U as TimingExact, V as TimingImmediate, W as TimingWindow, X as TokenInput, Y as TokenOutput, Z as TransitionAction, _ as TransitionBuilder, $ as VerificationHarness, a0 as VerificationResult, a1 as all, a2 as allPlaces, a3 as and, a4 as andPlaces, a5 as arcPlace, a6 as atLeast, a7 as consumptionCount, a8 as deadline, a9 as delayed, aa as earliest, ab as enumerateBranches, ac as environmentPlace, ad as exact, ae as exactly, af as fork, ag as forwardInput, ah as hasDeadline, ai as hasGuard, aj as immediate, ak as inhibitorArc, al as inputArc, am as isUnit, an as keyForPlace, ao as latest, ap as matchCorrelates, aq as matchKey, ar as matchSpec, as as matchesGuard, at as nameId, au as one, av as outPlace, aw as outputArc, ax as passthrough, ay as place, az as produce, aA as readArc, aB as requiredCount, aC as resetArc, aD as timeout, aE as timeoutPlace, aF as tokenAt, aG as tokenOf, aH as transform, aI as transformAsync, aJ as transformFrom, aK as unitToken, aL as window, aM as withTimeout, aN as xor, aO as xorPlaces } from './petri-net-Byc3gSgJ.js';
|
|
3
|
+
import { E as EventStore } from './event-store--nMbAO1v.js';
|
|
4
|
+
export { A as ActionTimedOut, a as ExecutionCompleted, b as ExecutionStarted, I as InMemoryEventStore, L as LogMessage, M as MarkingSnapshot, N as NetEvent, T as TokenAdded, c as TokenRemoved, d as TransitionClockRestarted, e as TransitionCompleted, f as TransitionEnabled, g as TransitionFailed, h as TransitionStarted, i as TransitionTimedOut, j as eventTransitionName, k as eventsOfType, l as failures, m as filterEvents, n as inMemoryEventStore, o as isFailureEvent, p as noopEventStore, t as transitionEvents } from './event-store--nMbAO1v.js';
|
|
5
5
|
|
|
6
6
|
/**
|
|
7
7
|
* Discriminated sum-type abstraction over Petri nets, distinguishing **closed**
|
|
@@ -344,6 +344,27 @@ declare class BitmapNetExecutor implements PetriNetExecutor {
|
|
|
344
344
|
*/
|
|
345
345
|
private fireReadyImmediate;
|
|
346
346
|
private fireReadyGeneral;
|
|
347
|
+
/**
|
|
348
|
+
* Fires a transition, containing any synchronous throw to that one firing so it fails
|
|
349
|
+
* only that transition, not the whole run.
|
|
350
|
+
*
|
|
351
|
+
* Without this boundary an unchecked throw raised while a transition fires — a hostile
|
|
352
|
+
* EventStore.append on a token-removed or transition-started emit, or an error thrown while
|
|
353
|
+
* consuming the matched tokens — unwinds out of the orchestrator loop and kills the executor.
|
|
354
|
+
* The transition is instead failed and marked dirty for re-evaluation, the same treatment an
|
|
355
|
+
* asynchronously-reported failure gets. Enablement-phase throws (a guard or key function that
|
|
356
|
+
* throws inside canEnable, before the firing) run outside this boundary and are not contained
|
|
357
|
+
* here.
|
|
358
|
+
*
|
|
359
|
+
* fireTransition removes tokens from the marking before it reconciles the presence
|
|
360
|
+
* bitmap, so a throw inside that window would leave bits asserting tokens that are gone;
|
|
361
|
+
* the recovery re-runs updateBitmapAfterConsumption against the real marking.
|
|
362
|
+
*
|
|
363
|
+
* Unlike the Java runtime there is no VirtualMachineError/LinkageError analogue on the JS
|
|
364
|
+
* side, so every throw is contained here — there is deliberately no fatal-rethrow escape
|
|
365
|
+
* hatch.
|
|
366
|
+
*/
|
|
367
|
+
private fireTransitionContained;
|
|
347
368
|
private fireTransition;
|
|
348
369
|
private updateBitmapAfterConsumption;
|
|
349
370
|
private processCompletedTransitions;
|
|
@@ -609,6 +630,28 @@ declare class PrecompiledNetExecutor implements PetriNetExecutor {
|
|
|
609
630
|
*/
|
|
610
631
|
private fireReadyImmediate;
|
|
611
632
|
private fireReadyGeneral;
|
|
633
|
+
/**
|
|
634
|
+
* Fires a transition, containing any synchronous throw to that one firing so it fails
|
|
635
|
+
* only that transition, not the whole run.
|
|
636
|
+
*
|
|
637
|
+
* Without this boundary an unchecked throw raised while a transition fires — a hostile
|
|
638
|
+
* EventStore.append on a token-removed or transition-started emit, or an error thrown while
|
|
639
|
+
* consuming the matched tokens — unwinds out of the orchestrator loop and kills the executor.
|
|
640
|
+
* The transition is instead failed and marked dirty for re-evaluation, the same treatment an
|
|
641
|
+
* asynchronously-reported failure gets. Enablement-phase throws (a guard or key function that
|
|
642
|
+
* throws inside canEnable, before the firing) run outside this boundary and are not contained
|
|
643
|
+
* here.
|
|
644
|
+
*
|
|
645
|
+
* fireTransition drains tokens from the queues before it reconciles the presence bitmap,
|
|
646
|
+
* so a throw inside that window would leave bits asserting tokens that are gone; the
|
|
647
|
+
* recovery re-runs updateBitmapAfterConsumption against the true queue lengths.
|
|
648
|
+
*
|
|
649
|
+
* Named to avoid colliding with the pre-existing {@link fireTransitionGuarded}
|
|
650
|
+
* guard-consume helper. Unlike the Java runtime there is no VirtualMachineError/
|
|
651
|
+
* LinkageError analogue on the JS side, so every throw is contained here — there is
|
|
652
|
+
* deliberately no fatal-rethrow escape hatch.
|
|
653
|
+
*/
|
|
654
|
+
private fireTransitionContained;
|
|
612
655
|
private fireTransition;
|
|
613
656
|
/**
|
|
614
657
|
* Consumes the name-matched tokens for a ν-net join (NU-020): correlated
|
|
@@ -677,6 +720,10 @@ declare function validateOutSpec(tName: string, spec: Out, producedPlaceNames: S
|
|
|
677
720
|
* - **AND**: recurses into all children (all branches get tokens).
|
|
678
721
|
* - **XOR**: disallowed — timeout cannot choose a branch non-deterministically.
|
|
679
722
|
* - **Timeout**: disallowed — nested timeouts would create ambiguous recovery paths.
|
|
723
|
+
*
|
|
724
|
+
* Writes through {@link TransitionContext.outputToHarvest} rather than `output(...)`:
|
|
725
|
+
* by this point the context has been detached, so the ordinary write target is closed
|
|
726
|
+
* and only the harvest collector still reaches the marking.
|
|
680
727
|
*/
|
|
681
728
|
declare function produceTimeoutOutput(context: TransitionContext, timeoutChild: Out): void;
|
|
682
729
|
|
package/dist/index.js
CHANGED
|
@@ -12,7 +12,7 @@ import {
|
|
|
12
12
|
timeoutPlace,
|
|
13
13
|
xor,
|
|
14
14
|
xorPlaces
|
|
15
|
-
} from "./chunk-
|
|
15
|
+
} from "./chunk-V3WTQRHC.js";
|
|
16
16
|
import {
|
|
17
17
|
eventTransitionName,
|
|
18
18
|
isFailureEvent
|
|
@@ -213,12 +213,69 @@ function withTimeout(action, timeoutMs, timeoutPlace2, timeoutValue) {
|
|
|
213
213
|
};
|
|
214
214
|
}
|
|
215
215
|
|
|
216
|
+
// src/core/token-output.ts
|
|
217
|
+
var TokenOutput = class {
|
|
218
|
+
_entries = [];
|
|
219
|
+
/**
|
|
220
|
+
* Once true, further writes are dropped instead of appended. Set by the executor
|
|
221
|
+
* (via {@link import('./transition-context.js').TransitionContext.detachForTimeout})
|
|
222
|
+
* when a firing times out, so the action it has stopped waiting for can no longer
|
|
223
|
+
* reach the marking. Irreversible.
|
|
224
|
+
*/
|
|
225
|
+
detached = false;
|
|
226
|
+
/** Add a value to an output place (creates token with current timestamp). */
|
|
227
|
+
add(place2, value) {
|
|
228
|
+
if (this.detached) return this;
|
|
229
|
+
this._entries.push({ place: place2, token: tokenOf(value) });
|
|
230
|
+
return this;
|
|
231
|
+
}
|
|
232
|
+
/** Add a pre-existing token to an output place. */
|
|
233
|
+
addToken(place2, token) {
|
|
234
|
+
if (this.detached) return this;
|
|
235
|
+
this._entries.push({ place: place2, token });
|
|
236
|
+
return this;
|
|
237
|
+
}
|
|
238
|
+
/**
|
|
239
|
+
* @internal Severs this collector: subsequent {@link add}/{@link addToken} calls are
|
|
240
|
+
* dropped. Executor machinery invoked when a firing times out — never call from an action.
|
|
241
|
+
*/
|
|
242
|
+
detach() {
|
|
243
|
+
this.detached = true;
|
|
244
|
+
}
|
|
245
|
+
/** Returns all collected outputs. */
|
|
246
|
+
entries() {
|
|
247
|
+
return this._entries;
|
|
248
|
+
}
|
|
249
|
+
/** Check if any outputs were produced. */
|
|
250
|
+
isEmpty() {
|
|
251
|
+
return this._entries.length === 0;
|
|
252
|
+
}
|
|
253
|
+
/** Returns the set of place names that received tokens. */
|
|
254
|
+
placesWithTokens() {
|
|
255
|
+
const result = /* @__PURE__ */ new Set();
|
|
256
|
+
for (const entry of this._entries) {
|
|
257
|
+
result.add(entry.place.name);
|
|
258
|
+
}
|
|
259
|
+
return result;
|
|
260
|
+
}
|
|
261
|
+
};
|
|
262
|
+
|
|
216
263
|
// src/core/transition-context.ts
|
|
217
264
|
var EMPTY_ALIAS = /* @__PURE__ */ new Map();
|
|
218
265
|
var GLOBAL_FRESH_NAME_COUNTER = 0;
|
|
219
266
|
var TransitionContext = class {
|
|
220
267
|
rawInput;
|
|
268
|
+
/**
|
|
269
|
+
* What the executor harvests. Identical to {@link writeTarget} until
|
|
270
|
+
* {@link detachForTimeout} replaces it with a fresh collector the action cannot reach.
|
|
271
|
+
*/
|
|
221
272
|
_rawOutput;
|
|
273
|
+
/**
|
|
274
|
+
* What the action writes to. Never reassigned, so an action already inside
|
|
275
|
+
* `output(...)` cannot be redirected mid-write; severance happens by detaching this
|
|
276
|
+
* collector, not by swapping it.
|
|
277
|
+
*/
|
|
278
|
+
writeTarget;
|
|
222
279
|
allowedInputs;
|
|
223
280
|
allowedReads;
|
|
224
281
|
allowedOutputs;
|
|
@@ -234,6 +291,7 @@ var TransitionContext = class {
|
|
|
234
291
|
this._transitionName = transitionName;
|
|
235
292
|
this.rawInput = rawInput;
|
|
236
293
|
this._rawOutput = rawOutput;
|
|
294
|
+
this.writeTarget = rawOutput;
|
|
237
295
|
this._inputPlaces = inputPlaces;
|
|
238
296
|
this._readPlaces = readPlaces;
|
|
239
297
|
this._outputPlaces = outputPlaces;
|
|
@@ -340,7 +398,7 @@ var TransitionContext = class {
|
|
|
340
398
|
const actual = this.resolve(place2);
|
|
341
399
|
this.requireOutput(actual);
|
|
342
400
|
for (const value of values) {
|
|
343
|
-
this.
|
|
401
|
+
this.writeTarget.add(actual, value);
|
|
344
402
|
}
|
|
345
403
|
return this;
|
|
346
404
|
}
|
|
@@ -356,7 +414,7 @@ var TransitionContext = class {
|
|
|
356
414
|
const actual = this.resolve(place2);
|
|
357
415
|
this.requireOutput(actual);
|
|
358
416
|
for (const token of tokens) {
|
|
359
|
-
this.
|
|
417
|
+
this.writeTarget.addToken(actual, token);
|
|
360
418
|
}
|
|
361
419
|
return this;
|
|
362
420
|
}
|
|
@@ -371,6 +429,38 @@ var TransitionContext = class {
|
|
|
371
429
|
);
|
|
372
430
|
}
|
|
373
431
|
}
|
|
432
|
+
/**
|
|
433
|
+
* Severs the action's output from the marking, for use when a firing times out.
|
|
434
|
+
*
|
|
435
|
+
* After this call the action's `output(...)` writes are dropped, and the executor
|
|
436
|
+
* harvests a fresh collector the action holds no reference to. Anything the action
|
|
437
|
+
* wrote *before* the timeout is discarded with it: a partial result merged with the
|
|
438
|
+
* timeout branch would violate the transition's own output spec.
|
|
439
|
+
*
|
|
440
|
+
* This is the only isolation available — libpetri does not own the promise the action
|
|
441
|
+
* runs on, so it cannot stop the work, only stop the result from landing.
|
|
442
|
+
*
|
|
443
|
+
* @internal Executor machinery — must be called by the executor, never by an action.
|
|
444
|
+
*/
|
|
445
|
+
detachForTimeout() {
|
|
446
|
+
this.writeTarget.detach();
|
|
447
|
+
this._rawOutput = new TokenOutput();
|
|
448
|
+
}
|
|
449
|
+
/**
|
|
450
|
+
* Produces into the executor's harvest collector rather than the action's write target.
|
|
451
|
+
*
|
|
452
|
+
* Identical to {@link output} before {@link detachForTimeout}; after it, this is the
|
|
453
|
+
* only route that still reaches the marking. Used by the executor to deposit the
|
|
454
|
+
* timeout branch.
|
|
455
|
+
*
|
|
456
|
+
* @internal Executor machinery — must be called by the executor, never by an action.
|
|
457
|
+
*/
|
|
458
|
+
outputToHarvest(place2, value) {
|
|
459
|
+
const actual = this.resolve(place2);
|
|
460
|
+
this.requireOutput(actual);
|
|
461
|
+
this._rawOutput.add(actual, value);
|
|
462
|
+
return this;
|
|
463
|
+
}
|
|
374
464
|
// ==================== ν-name minting (NU-010) ====================
|
|
375
465
|
/**
|
|
376
466
|
* @internal Installs the ν-name minter. Wired by the executor at firing time
|
|
@@ -462,37 +552,6 @@ var TokenInput = class {
|
|
|
462
552
|
}
|
|
463
553
|
};
|
|
464
554
|
|
|
465
|
-
// src/core/token-output.ts
|
|
466
|
-
var TokenOutput = class {
|
|
467
|
-
_entries = [];
|
|
468
|
-
/** Add a value to an output place (creates token with current timestamp). */
|
|
469
|
-
add(place2, value) {
|
|
470
|
-
this._entries.push({ place: place2, token: tokenOf(value) });
|
|
471
|
-
return this;
|
|
472
|
-
}
|
|
473
|
-
/** Add a pre-existing token to an output place. */
|
|
474
|
-
addToken(place2, token) {
|
|
475
|
-
this._entries.push({ place: place2, token });
|
|
476
|
-
return this;
|
|
477
|
-
}
|
|
478
|
-
/** Returns all collected outputs. */
|
|
479
|
-
entries() {
|
|
480
|
-
return this._entries;
|
|
481
|
-
}
|
|
482
|
-
/** Check if any outputs were produced. */
|
|
483
|
-
isEmpty() {
|
|
484
|
-
return this._entries.length === 0;
|
|
485
|
-
}
|
|
486
|
-
/** Returns the set of place names that received tokens. */
|
|
487
|
-
placesWithTokens() {
|
|
488
|
-
const result = /* @__PURE__ */ new Set();
|
|
489
|
-
for (const entry of this._entries) {
|
|
490
|
-
result.add(entry.place.name);
|
|
491
|
-
}
|
|
492
|
-
return result;
|
|
493
|
-
}
|
|
494
|
-
};
|
|
495
|
-
|
|
496
555
|
// src/core/transition.ts
|
|
497
556
|
var TRANSITION_KEY = /* @__PURE__ */ Symbol("Transition.internal");
|
|
498
557
|
var EMPTY_PLACE_ALIAS = /* @__PURE__ */ new Map();
|
|
@@ -3006,6 +3065,25 @@ var OutViolationError = class extends Error {
|
|
|
3006
3065
|
};
|
|
3007
3066
|
|
|
3008
3067
|
// src/runtime/executor-support.ts
|
|
3068
|
+
function executeAction(t, context) {
|
|
3069
|
+
try {
|
|
3070
|
+
const stage = t.action(context);
|
|
3071
|
+
if (stage == null || typeof stage.then !== "function") {
|
|
3072
|
+
return Promise.reject(new Error(
|
|
3073
|
+
`'${t.name}': action returned null/non-thenable instead of a Promise`
|
|
3074
|
+
));
|
|
3075
|
+
}
|
|
3076
|
+
return Promise.resolve(stage);
|
|
3077
|
+
} catch (err) {
|
|
3078
|
+
return Promise.reject(err);
|
|
3079
|
+
}
|
|
3080
|
+
}
|
|
3081
|
+
function swallowEventStoreFailure(when, err) {
|
|
3082
|
+
console.warn(
|
|
3083
|
+
`libpetri: EventStore.append threw while emitting ${when}; the event is dropped`,
|
|
3084
|
+
err
|
|
3085
|
+
);
|
|
3086
|
+
}
|
|
3009
3087
|
var DEADLINE_TOLERANCE_MS = 5;
|
|
3010
3088
|
function validateOutSpec(tName, spec, producedPlaceNames) {
|
|
3011
3089
|
switch (spec.type) {
|
|
@@ -3047,11 +3125,11 @@ function validateOutSpec(tName, spec, producedPlaceNames) {
|
|
|
3047
3125
|
function produceTimeoutOutput(context, timeoutChild) {
|
|
3048
3126
|
switch (timeoutChild.type) {
|
|
3049
3127
|
case "place":
|
|
3050
|
-
context.
|
|
3128
|
+
context.outputToHarvest(timeoutChild.place, null);
|
|
3051
3129
|
break;
|
|
3052
3130
|
case "forward-input": {
|
|
3053
3131
|
const value = context.input(timeoutChild.from);
|
|
3054
|
-
context.
|
|
3132
|
+
context.outputToHarvest(timeoutChild.to, value);
|
|
3055
3133
|
break;
|
|
3056
3134
|
}
|
|
3057
3135
|
case "and":
|
|
@@ -3506,7 +3584,7 @@ var BitmapNetExecutor = class {
|
|
|
3506
3584
|
for (let tid = 0; tid < this.compiled.transitionCount; tid++) {
|
|
3507
3585
|
if (!this.enabledFlags[tid] || this.inFlightFlags[tid]) continue;
|
|
3508
3586
|
if (this.canEnable(tid, this.markedPlaces)) {
|
|
3509
|
-
this.
|
|
3587
|
+
this.fireTransitionContained(tid);
|
|
3510
3588
|
} else {
|
|
3511
3589
|
this.enabledFlags[tid] = 0;
|
|
3512
3590
|
this.enabledTransitionCount--;
|
|
@@ -3538,7 +3616,7 @@ var BitmapNetExecutor = class {
|
|
|
3538
3616
|
for (const entry of ready) {
|
|
3539
3617
|
const { tid } = entry;
|
|
3540
3618
|
if (this.enabledFlags[tid] && this.canEnable(tid, freshSnap)) {
|
|
3541
|
-
this.
|
|
3619
|
+
this.fireTransitionContained(tid);
|
|
3542
3620
|
freshSnap.set(this.markedPlaces);
|
|
3543
3621
|
} else {
|
|
3544
3622
|
this.enabledFlags[tid] = 0;
|
|
@@ -3547,6 +3625,53 @@ var BitmapNetExecutor = class {
|
|
|
3547
3625
|
}
|
|
3548
3626
|
}
|
|
3549
3627
|
}
|
|
3628
|
+
/**
|
|
3629
|
+
* Fires a transition, containing any synchronous throw to that one firing so it fails
|
|
3630
|
+
* only that transition, not the whole run.
|
|
3631
|
+
*
|
|
3632
|
+
* Without this boundary an unchecked throw raised while a transition fires — a hostile
|
|
3633
|
+
* EventStore.append on a token-removed or transition-started emit, or an error thrown while
|
|
3634
|
+
* consuming the matched tokens — unwinds out of the orchestrator loop and kills the executor.
|
|
3635
|
+
* The transition is instead failed and marked dirty for re-evaluation, the same treatment an
|
|
3636
|
+
* asynchronously-reported failure gets. Enablement-phase throws (a guard or key function that
|
|
3637
|
+
* throws inside canEnable, before the firing) run outside this boundary and are not contained
|
|
3638
|
+
* here.
|
|
3639
|
+
*
|
|
3640
|
+
* fireTransition removes tokens from the marking before it reconciles the presence
|
|
3641
|
+
* bitmap, so a throw inside that window would leave bits asserting tokens that are gone;
|
|
3642
|
+
* the recovery re-runs updateBitmapAfterConsumption against the real marking.
|
|
3643
|
+
*
|
|
3644
|
+
* Unlike the Java runtime there is no VirtualMachineError/LinkageError analogue on the JS
|
|
3645
|
+
* side, so every throw is contained here — there is deliberately no fatal-rethrow escape
|
|
3646
|
+
* hatch.
|
|
3647
|
+
*/
|
|
3648
|
+
fireTransitionContained(tid) {
|
|
3649
|
+
try {
|
|
3650
|
+
this.fireTransition(tid);
|
|
3651
|
+
} catch (e) {
|
|
3652
|
+
const t = this.compiled.transition(tid);
|
|
3653
|
+
if (this.enabledFlags[tid]) {
|
|
3654
|
+
this.enabledFlags[tid] = 0;
|
|
3655
|
+
this.enabledTransitionCount--;
|
|
3656
|
+
this.enabledAtMs[tid] = -Infinity;
|
|
3657
|
+
}
|
|
3658
|
+
if (this.inFlight.delete(t)) {
|
|
3659
|
+
this.inFlightFlags[tid] = 0;
|
|
3660
|
+
}
|
|
3661
|
+
this.updateBitmapAfterConsumption(tid);
|
|
3662
|
+
this.matchCaches[tid] = null;
|
|
3663
|
+
const err = e instanceof Error ? e : new Error(String(e));
|
|
3664
|
+
this.emitEvent({
|
|
3665
|
+
type: "transition-failed",
|
|
3666
|
+
timestamp: Date.now(),
|
|
3667
|
+
transitionName: t.name,
|
|
3668
|
+
errorMessage: err.message,
|
|
3669
|
+
exceptionType: err.name,
|
|
3670
|
+
stack: err.stack
|
|
3671
|
+
});
|
|
3672
|
+
this.markTransitionDirty(tid);
|
|
3673
|
+
}
|
|
3674
|
+
}
|
|
3550
3675
|
fireTransition(tid) {
|
|
3551
3676
|
const t = this.compiled.transition(tid);
|
|
3552
3677
|
const inputs = new TokenInput();
|
|
@@ -3645,7 +3770,7 @@ var BitmapNetExecutor = class {
|
|
|
3645
3770
|
);
|
|
3646
3771
|
const freshNameBase = t.name;
|
|
3647
3772
|
context.setFreshNameSupplier(() => nameId(`${freshNameBase}#${this.freshNameCounter++}`));
|
|
3648
|
-
let actionPromise = t
|
|
3773
|
+
let actionPromise = executeAction(t, context);
|
|
3649
3774
|
if (t.hasActionTimeout()) {
|
|
3650
3775
|
const timeoutSpec = t.actionTimeout;
|
|
3651
3776
|
if (timeoutSpec === null) throw new Error(`Expected actionTimeout on ${t.name}`);
|
|
@@ -3657,6 +3782,7 @@ var BitmapNetExecutor = class {
|
|
|
3657
3782
|
)
|
|
3658
3783
|
]).catch((err) => {
|
|
3659
3784
|
if (err instanceof TimeoutSentinel) {
|
|
3785
|
+
context.detachForTimeout();
|
|
3660
3786
|
produceTimeoutOutput(context, timeoutSpec.child);
|
|
3661
3787
|
this.emitEvent({
|
|
3662
3788
|
type: "action-timed-out",
|
|
@@ -3927,7 +4053,11 @@ var BitmapNetExecutor = class {
|
|
|
3927
4053
|
// ======================== Event Emission ========================
|
|
3928
4054
|
emitEvent(event) {
|
|
3929
4055
|
if (this.eventStoreEnabled) {
|
|
3930
|
-
|
|
4056
|
+
try {
|
|
4057
|
+
this.eventStore.append(event);
|
|
4058
|
+
} catch (err) {
|
|
4059
|
+
swallowEventStoreFailure(event.type, err);
|
|
4060
|
+
}
|
|
3931
4061
|
}
|
|
3932
4062
|
}
|
|
3933
4063
|
};
|
|
@@ -4764,7 +4894,7 @@ var PrecompiledNetExecutor = class {
|
|
|
4764
4894
|
for (let tid = 0; tid < tc; tid++) {
|
|
4765
4895
|
if (!this.enabledFlags[tid] || this.inFlightFlags[tid]) continue;
|
|
4766
4896
|
if (this.canEnable(tid, this.markingBitmap)) {
|
|
4767
|
-
this.
|
|
4897
|
+
this.fireTransitionContained(tid);
|
|
4768
4898
|
} else {
|
|
4769
4899
|
this.enabledFlags[tid] = 0;
|
|
4770
4900
|
this.enabledTransitionCount--;
|
|
@@ -4795,7 +4925,7 @@ var PrecompiledNetExecutor = class {
|
|
|
4795
4925
|
for (const entry of ready) {
|
|
4796
4926
|
const { tid } = entry;
|
|
4797
4927
|
if (this.enabledFlags[tid] && this.canEnable(tid, freshSnap)) {
|
|
4798
|
-
this.
|
|
4928
|
+
this.fireTransitionContained(tid);
|
|
4799
4929
|
freshSnap.set(this.markingBitmap);
|
|
4800
4930
|
} else {
|
|
4801
4931
|
this.enabledFlags[tid] = 0;
|
|
@@ -4804,6 +4934,60 @@ var PrecompiledNetExecutor = class {
|
|
|
4804
4934
|
}
|
|
4805
4935
|
}
|
|
4806
4936
|
}
|
|
4937
|
+
/**
|
|
4938
|
+
* Fires a transition, containing any synchronous throw to that one firing so it fails
|
|
4939
|
+
* only that transition, not the whole run.
|
|
4940
|
+
*
|
|
4941
|
+
* Without this boundary an unchecked throw raised while a transition fires — a hostile
|
|
4942
|
+
* EventStore.append on a token-removed or transition-started emit, or an error thrown while
|
|
4943
|
+
* consuming the matched tokens — unwinds out of the orchestrator loop and kills the executor.
|
|
4944
|
+
* The transition is instead failed and marked dirty for re-evaluation, the same treatment an
|
|
4945
|
+
* asynchronously-reported failure gets. Enablement-phase throws (a guard or key function that
|
|
4946
|
+
* throws inside canEnable, before the firing) run outside this boundary and are not contained
|
|
4947
|
+
* here.
|
|
4948
|
+
*
|
|
4949
|
+
* fireTransition drains tokens from the queues before it reconciles the presence bitmap,
|
|
4950
|
+
* so a throw inside that window would leave bits asserting tokens that are gone; the
|
|
4951
|
+
* recovery re-runs updateBitmapAfterConsumption against the true queue lengths.
|
|
4952
|
+
*
|
|
4953
|
+
* Named to avoid colliding with the pre-existing {@link fireTransitionGuarded}
|
|
4954
|
+
* guard-consume helper. Unlike the Java runtime there is no VirtualMachineError/
|
|
4955
|
+
* LinkageError analogue on the JS side, so every throw is contained here — there is
|
|
4956
|
+
* deliberately no fatal-rethrow escape hatch.
|
|
4957
|
+
*/
|
|
4958
|
+
fireTransitionContained(tid) {
|
|
4959
|
+
try {
|
|
4960
|
+
this.fireTransition(tid);
|
|
4961
|
+
} catch (e) {
|
|
4962
|
+
const t = this.program.compiled.transition(tid);
|
|
4963
|
+
if (this.enabledFlags[tid]) {
|
|
4964
|
+
this.enabledFlags[tid] = 0;
|
|
4965
|
+
this.enabledTransitionCount--;
|
|
4966
|
+
this.enabledAtMs[tid] = -Infinity;
|
|
4967
|
+
}
|
|
4968
|
+
if (this.inFlightFlags[tid]) {
|
|
4969
|
+
this.inFlightPromises[tid] = null;
|
|
4970
|
+
this.inFlightContexts[tid] = null;
|
|
4971
|
+
this.inFlightConsumed[tid] = null;
|
|
4972
|
+
this.inFlightResolves[tid] = null;
|
|
4973
|
+
this.inFlightErrors[tid] = null;
|
|
4974
|
+
this.inFlightFlags[tid] = 0;
|
|
4975
|
+
this.inFlightCount--;
|
|
4976
|
+
}
|
|
4977
|
+
this.updateBitmapAfterConsumption(tid);
|
|
4978
|
+
this.matchCaches[tid] = null;
|
|
4979
|
+
const err = e instanceof Error ? e : new Error(String(e));
|
|
4980
|
+
this.emitEvent({
|
|
4981
|
+
type: "transition-failed",
|
|
4982
|
+
timestamp: Date.now(),
|
|
4983
|
+
transitionName: t.name,
|
|
4984
|
+
errorMessage: err.message,
|
|
4985
|
+
exceptionType: err.name,
|
|
4986
|
+
stack: err.stack
|
|
4987
|
+
});
|
|
4988
|
+
this.markTransitionDirty(tid);
|
|
4989
|
+
}
|
|
4990
|
+
}
|
|
4807
4991
|
fireTransition(tid) {
|
|
4808
4992
|
const prog = this.program;
|
|
4809
4993
|
const t = prog.compiled.transition(tid);
|
|
@@ -4952,7 +5136,7 @@ var PrecompiledNetExecutor = class {
|
|
|
4952
5136
|
this.freshNameSuppliers[tid] = freshNameSupplier;
|
|
4953
5137
|
}
|
|
4954
5138
|
context.setFreshNameSupplier(freshNameSupplier);
|
|
4955
|
-
let actionPromise = t
|
|
5139
|
+
let actionPromise = executeAction(t, context);
|
|
4956
5140
|
if (t.hasActionTimeout()) {
|
|
4957
5141
|
const timeoutSpec = t.actionTimeout;
|
|
4958
5142
|
if (timeoutSpec === null) throw new Error(`Expected actionTimeout on ${t.name}`);
|
|
@@ -4964,6 +5148,7 @@ var PrecompiledNetExecutor = class {
|
|
|
4964
5148
|
)
|
|
4965
5149
|
]).catch((err) => {
|
|
4966
5150
|
if (err instanceof TimeoutSentinel2) {
|
|
5151
|
+
context.detachForTimeout();
|
|
4967
5152
|
produceTimeoutOutput(context, timeoutSpec.child);
|
|
4968
5153
|
this.emitEvent({
|
|
4969
5154
|
type: "action-timed-out",
|
|
@@ -5358,7 +5543,11 @@ var PrecompiledNetExecutor = class {
|
|
|
5358
5543
|
// ======================== Event Emission ========================
|
|
5359
5544
|
emitEvent(event) {
|
|
5360
5545
|
if (this.eventStoreEnabled) {
|
|
5361
|
-
|
|
5546
|
+
try {
|
|
5547
|
+
this.eventStore.append(event);
|
|
5548
|
+
} catch (err) {
|
|
5549
|
+
swallowEventStoreFailure(event.type, err);
|
|
5550
|
+
}
|
|
5362
5551
|
}
|
|
5363
5552
|
}
|
|
5364
5553
|
};
|