libpetri 0.3.2

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/index.js ADDED
@@ -0,0 +1,1972 @@
1
+ import {
2
+ MAX_DURATION_MS,
3
+ deadline,
4
+ delayed,
5
+ earliest,
6
+ exact,
7
+ hasDeadline,
8
+ immediate,
9
+ latest,
10
+ window
11
+ } from "./chunk-FN773SSE.js";
12
+ import {
13
+ allPlaces,
14
+ and,
15
+ andPlaces,
16
+ enumerateBranches,
17
+ forwardInput,
18
+ outPlace,
19
+ timeout,
20
+ timeoutPlace,
21
+ xor,
22
+ xorPlaces
23
+ } from "./chunk-VQ4XMJTD.js";
24
+
25
+ // src/core/token.ts
26
+ var UNIT_TOKEN = Object.freeze({
27
+ value: null,
28
+ createdAt: 0
29
+ });
30
+ function tokenOf(value) {
31
+ return { value, createdAt: Date.now() };
32
+ }
33
+ function unitToken() {
34
+ return UNIT_TOKEN;
35
+ }
36
+ function tokenAt(value, createdAt) {
37
+ return { value, createdAt };
38
+ }
39
+ function isUnit(token) {
40
+ return token === UNIT_TOKEN;
41
+ }
42
+
43
+ // src/core/place.ts
44
+ function place(name) {
45
+ return { name };
46
+ }
47
+ function environmentPlace(name) {
48
+ return { place: place(name) };
49
+ }
50
+
51
+ // src/core/arc.ts
52
+ function inputArc(place2, guard) {
53
+ return guard !== void 0 ? { type: "input", place: place2, guard } : { type: "input", place: place2 };
54
+ }
55
+ function outputArc(place2) {
56
+ return { type: "output", place: place2 };
57
+ }
58
+ function inhibitorArc(place2) {
59
+ return { type: "inhibitor", place: place2 };
60
+ }
61
+ function readArc(place2) {
62
+ return { type: "read", place: place2 };
63
+ }
64
+ function resetArc(place2) {
65
+ return { type: "reset", place: place2 };
66
+ }
67
+ function arcPlace(arc) {
68
+ return arc.place;
69
+ }
70
+ function hasGuard(arc) {
71
+ return arc.guard !== void 0;
72
+ }
73
+ function matchesGuard(arc, value) {
74
+ if (arc.guard === void 0) return true;
75
+ return arc.guard(value);
76
+ }
77
+
78
+ // src/core/in.ts
79
+ function one(place2, guard) {
80
+ return guard !== void 0 ? { type: "one", place: place2, guard } : { type: "one", place: place2 };
81
+ }
82
+ function exactly(count, place2, guard) {
83
+ if (count < 1) {
84
+ throw new Error(`count must be >= 1, got: ${count}`);
85
+ }
86
+ return guard !== void 0 ? { type: "exactly", place: place2, count, guard } : { type: "exactly", place: place2, count };
87
+ }
88
+ function all(place2, guard) {
89
+ return guard !== void 0 ? { type: "all", place: place2, guard } : { type: "all", place: place2 };
90
+ }
91
+ function atLeast(minimum, place2, guard) {
92
+ if (minimum < 1) {
93
+ throw new Error(`minimum must be >= 1, got: ${minimum}`);
94
+ }
95
+ return guard !== void 0 ? { type: "at-least", place: place2, minimum, guard } : { type: "at-least", place: place2, minimum };
96
+ }
97
+ function requiredCount(spec) {
98
+ switch (spec.type) {
99
+ case "one":
100
+ return 1;
101
+ case "exactly":
102
+ return spec.count;
103
+ case "all":
104
+ return 1;
105
+ case "at-least":
106
+ return spec.minimum;
107
+ }
108
+ }
109
+ function consumptionCount(spec, available) {
110
+ if (available < requiredCount(spec)) {
111
+ throw new Error(
112
+ `Cannot consume from '${spec.place.name}': available=${available}, required=${requiredCount(spec)}`
113
+ );
114
+ }
115
+ switch (spec.type) {
116
+ case "one":
117
+ return 1;
118
+ case "exactly":
119
+ return spec.count;
120
+ case "all":
121
+ return available;
122
+ case "at-least":
123
+ return available;
124
+ }
125
+ }
126
+
127
+ // src/core/transition-action.ts
128
+ function passthrough() {
129
+ return async () => {
130
+ };
131
+ }
132
+ function transform(fn) {
133
+ return async (ctx) => {
134
+ const result = fn(ctx);
135
+ for (const outputPlace of ctx.outputPlaces()) {
136
+ ctx.output(outputPlace, result);
137
+ }
138
+ };
139
+ }
140
+ function fork() {
141
+ return transform((ctx) => {
142
+ const inputPlaces = ctx.inputPlaces();
143
+ if (inputPlaces.size !== 1) {
144
+ throw new Error(`Fork requires exactly 1 input place, found ${inputPlaces.size}`);
145
+ }
146
+ const inputPlace = inputPlaces.values().next().value;
147
+ return ctx.input(inputPlace);
148
+ });
149
+ }
150
+ function transformFrom(inputPlace, fn) {
151
+ return transform((ctx) => fn(ctx.input(inputPlace)));
152
+ }
153
+ function transformAsync(fn) {
154
+ return async (ctx) => {
155
+ const result = await fn(ctx);
156
+ for (const outputPlace of ctx.outputPlaces()) {
157
+ ctx.output(outputPlace, result);
158
+ }
159
+ };
160
+ }
161
+ function produce(place2, value) {
162
+ return async (ctx) => {
163
+ ctx.output(place2, value);
164
+ };
165
+ }
166
+ function withTimeout(action, timeoutMs, timeoutPlace2, timeoutValue) {
167
+ return (ctx) => {
168
+ return new Promise((resolve, reject) => {
169
+ let completed = false;
170
+ const timer = setTimeout(() => {
171
+ if (!completed) {
172
+ completed = true;
173
+ ctx.output(timeoutPlace2, timeoutValue);
174
+ resolve();
175
+ }
176
+ }, timeoutMs);
177
+ action(ctx).then(
178
+ () => {
179
+ if (!completed) {
180
+ completed = true;
181
+ clearTimeout(timer);
182
+ resolve();
183
+ }
184
+ },
185
+ (err) => {
186
+ if (!completed) {
187
+ completed = true;
188
+ clearTimeout(timer);
189
+ reject(err);
190
+ }
191
+ }
192
+ );
193
+ });
194
+ };
195
+ }
196
+
197
+ // src/core/transition-context.ts
198
+ var TransitionContext = class {
199
+ rawInput;
200
+ _rawOutput;
201
+ allowedInputs;
202
+ allowedReads;
203
+ allowedOutputs;
204
+ _inputPlaces;
205
+ _readPlaces;
206
+ _outputPlaces;
207
+ _transitionName;
208
+ executionCtx;
209
+ _logFn;
210
+ constructor(transitionName, rawInput, rawOutput, inputPlaces, readPlaces, outputPlaces, executionContext, logFn) {
211
+ this._transitionName = transitionName;
212
+ this.rawInput = rawInput;
213
+ this._rawOutput = rawOutput;
214
+ this._inputPlaces = inputPlaces;
215
+ this._readPlaces = readPlaces;
216
+ this._outputPlaces = outputPlaces;
217
+ const ai = /* @__PURE__ */ new Set();
218
+ for (const p of inputPlaces) ai.add(p.name);
219
+ this.allowedInputs = ai;
220
+ const ar = /* @__PURE__ */ new Set();
221
+ for (const p of readPlaces) ar.add(p.name);
222
+ this.allowedReads = ar;
223
+ const ao = /* @__PURE__ */ new Set();
224
+ for (const p of outputPlaces) ao.add(p.name);
225
+ this.allowedOutputs = ao;
226
+ this.executionCtx = executionContext ?? /* @__PURE__ */ new Map();
227
+ this._logFn = logFn;
228
+ }
229
+ // ==================== Input Access (consumed) ====================
230
+ /** Get single consumed input value. Throws if place not declared or multiple tokens. */
231
+ input(place2) {
232
+ this.requireInput(place2);
233
+ const values = this.rawInput.values(place2);
234
+ if (values.length !== 1) {
235
+ throw new Error(
236
+ `Place '${place2.name}' consumed ${values.length} tokens, use inputs() for batched access`
237
+ );
238
+ }
239
+ return values[0];
240
+ }
241
+ /** Get all consumed input values for a place. */
242
+ inputs(place2) {
243
+ this.requireInput(place2);
244
+ return this.rawInput.values(place2);
245
+ }
246
+ /** Get consumed input token with metadata. */
247
+ inputToken(place2) {
248
+ this.requireInput(place2);
249
+ return this.rawInput.get(place2);
250
+ }
251
+ /** Returns declared input places (consumed). */
252
+ inputPlaces() {
253
+ return this._inputPlaces;
254
+ }
255
+ requireInput(place2) {
256
+ if (!this.allowedInputs.has(place2.name)) {
257
+ throw new Error(
258
+ `Place '${place2.name}' not in declared inputs: [${[...this.allowedInputs].join(", ")}]`
259
+ );
260
+ }
261
+ }
262
+ // ==================== Read Access (not consumed) ====================
263
+ /** Get read-only context value. Throws if place not declared as read. */
264
+ read(place2) {
265
+ this.requireRead(place2);
266
+ return this.rawInput.value(place2);
267
+ }
268
+ /** Get all read-only context values for a place. */
269
+ reads(place2) {
270
+ this.requireRead(place2);
271
+ return this.rawInput.values(place2);
272
+ }
273
+ /** Returns declared read places (context, not consumed). */
274
+ readPlaces() {
275
+ return this._readPlaces;
276
+ }
277
+ requireRead(place2) {
278
+ if (!this.allowedReads.has(place2.name)) {
279
+ throw new Error(
280
+ `Place '${place2.name}' not in declared reads: [${[...this.allowedReads].join(", ")}]`
281
+ );
282
+ }
283
+ }
284
+ // ==================== Output Access ====================
285
+ /** Add output value. Throws if place not declared as output. */
286
+ output(place2, value) {
287
+ this.requireOutput(place2);
288
+ this._rawOutput.add(place2, value);
289
+ return this;
290
+ }
291
+ /** Add output token with metadata. */
292
+ outputToken(place2, token) {
293
+ this.requireOutput(place2);
294
+ this._rawOutput.addToken(place2, token);
295
+ return this;
296
+ }
297
+ /** Returns declared output places. */
298
+ outputPlaces() {
299
+ return this._outputPlaces;
300
+ }
301
+ requireOutput(place2) {
302
+ if (!this.allowedOutputs.has(place2.name)) {
303
+ throw new Error(
304
+ `Place '${place2.name}' not in declared outputs: [${[...this.allowedOutputs].join(", ")}]`
305
+ );
306
+ }
307
+ }
308
+ // ==================== Structure Info ====================
309
+ /** Returns the transition name. */
310
+ transitionName() {
311
+ return this._transitionName;
312
+ }
313
+ // ==================== Execution Context ====================
314
+ /** Retrieves an execution context object by key. */
315
+ executionContext(key) {
316
+ return this.executionCtx.get(key);
317
+ }
318
+ /** Checks if an execution context object of the given key is present. */
319
+ hasExecutionContext(key) {
320
+ return this.executionCtx.has(key);
321
+ }
322
+ // ==================== Logging ====================
323
+ /** Emits a structured log message into the event store. */
324
+ log(level, message, error) {
325
+ this._logFn?.(level, message, error);
326
+ }
327
+ // ==================== Internal ====================
328
+ /** @internal Used by BitmapNetExecutor to collect outputs after action completion. */
329
+ rawOutput() {
330
+ return this._rawOutput;
331
+ }
332
+ };
333
+
334
+ // src/core/token-input.ts
335
+ var TokenInput = class {
336
+ tokens = /* @__PURE__ */ new Map();
337
+ /** Add a token (used by executor when firing transition). */
338
+ add(place2, token) {
339
+ const existing = this.tokens.get(place2.name);
340
+ if (existing) {
341
+ existing.push(token);
342
+ } else {
343
+ this.tokens.set(place2.name, [token]);
344
+ }
345
+ return this;
346
+ }
347
+ /** Get all tokens for a place. */
348
+ getAll(place2) {
349
+ return this.tokens.get(place2.name) ?? [];
350
+ }
351
+ /** Get the first token for a place. Throws if no tokens. */
352
+ get(place2) {
353
+ const list = this.tokens.get(place2.name);
354
+ if (!list || list.length === 0) {
355
+ throw new Error(`No token for place: ${place2.name}`);
356
+ }
357
+ return list[0];
358
+ }
359
+ /** Get the first token's value for a place. Throws if no tokens. */
360
+ value(place2) {
361
+ return this.get(place2).value;
362
+ }
363
+ /** Get all token values for a place. */
364
+ values(place2) {
365
+ return this.getAll(place2).map((t) => t.value);
366
+ }
367
+ /** Get token count for a place. */
368
+ count(place2) {
369
+ return this.getAll(place2).length;
370
+ }
371
+ /** Check if any tokens exist for a place. */
372
+ has(place2) {
373
+ return this.count(place2) > 0;
374
+ }
375
+ };
376
+
377
+ // src/core/token-output.ts
378
+ var TokenOutput = class {
379
+ _entries = [];
380
+ /** Add a value to an output place (creates token with current timestamp). */
381
+ add(place2, value) {
382
+ this._entries.push({ place: place2, token: tokenOf(value) });
383
+ return this;
384
+ }
385
+ /** Add a pre-existing token to an output place. */
386
+ addToken(place2, token) {
387
+ this._entries.push({ place: place2, token });
388
+ return this;
389
+ }
390
+ /** Returns all collected outputs. */
391
+ entries() {
392
+ return this._entries;
393
+ }
394
+ /** Check if any outputs were produced. */
395
+ isEmpty() {
396
+ return this._entries.length === 0;
397
+ }
398
+ /** Returns the set of place names that received tokens. */
399
+ placesWithTokens() {
400
+ const result = /* @__PURE__ */ new Set();
401
+ for (const entry of this._entries) {
402
+ result.add(entry.place.name);
403
+ }
404
+ return result;
405
+ }
406
+ };
407
+
408
+ // src/core/transition.ts
409
+ var TRANSITION_KEY = /* @__PURE__ */ Symbol("Transition.internal");
410
+ var Transition = class {
411
+ name;
412
+ inputSpecs;
413
+ outputSpec;
414
+ inhibitors;
415
+ reads;
416
+ resets;
417
+ timing;
418
+ actionTimeout;
419
+ action;
420
+ priority;
421
+ _inputPlaces;
422
+ _readPlaces;
423
+ _outputPlaces;
424
+ /** @internal Use {@link Transition.builder} to create instances. */
425
+ constructor(key, name, inputSpecs, outputSpec, inhibitors, reads, resets, timing, action, priority) {
426
+ if (key !== TRANSITION_KEY) throw new Error("Use Transition.builder() to create instances");
427
+ this.name = name;
428
+ this.inputSpecs = inputSpecs;
429
+ this.outputSpec = outputSpec;
430
+ this.inhibitors = inhibitors;
431
+ this.reads = reads;
432
+ this.resets = resets;
433
+ this.timing = timing;
434
+ this.actionTimeout = findTimeout(outputSpec);
435
+ this.action = action;
436
+ this.priority = priority;
437
+ const inputPlaces = /* @__PURE__ */ new Set();
438
+ for (const spec of inputSpecs) {
439
+ inputPlaces.add(spec.place);
440
+ }
441
+ this._inputPlaces = inputPlaces;
442
+ const readPlaces = /* @__PURE__ */ new Set();
443
+ for (const r of reads) {
444
+ readPlaces.add(r.place);
445
+ }
446
+ this._readPlaces = readPlaces;
447
+ const outputPlaces = /* @__PURE__ */ new Set();
448
+ if (outputSpec !== null) {
449
+ for (const p of allPlaces(outputSpec)) {
450
+ outputPlaces.add(p);
451
+ }
452
+ }
453
+ this._outputPlaces = outputPlaces;
454
+ }
455
+ /** Returns set of input places — consumed tokens. */
456
+ inputPlaces() {
457
+ return this._inputPlaces;
458
+ }
459
+ /** Returns set of read places — context tokens, not consumed. */
460
+ readPlaces() {
461
+ return this._readPlaces;
462
+ }
463
+ /** Returns set of output places — where tokens are produced. */
464
+ outputPlaces() {
465
+ return this._outputPlaces;
466
+ }
467
+ /** Returns true if this transition has an action timeout. */
468
+ hasActionTimeout() {
469
+ return this.actionTimeout !== null;
470
+ }
471
+ toString() {
472
+ return `Transition[${this.name}]`;
473
+ }
474
+ static builder(name) {
475
+ return new TransitionBuilder(name);
476
+ }
477
+ };
478
+ var TransitionBuilder = class {
479
+ _name;
480
+ _inputSpecs = [];
481
+ _outputSpec = null;
482
+ _inhibitors = [];
483
+ _reads = [];
484
+ _resets = [];
485
+ _timing = immediate();
486
+ _action = passthrough();
487
+ _priority = 0;
488
+ constructor(name) {
489
+ this._name = name;
490
+ }
491
+ /** Add input specifications with cardinality. */
492
+ inputs(...specs) {
493
+ this._inputSpecs.push(...specs);
494
+ return this;
495
+ }
496
+ /** Set the output specification (composite AND/XOR structure). */
497
+ outputs(spec) {
498
+ this._outputSpec = spec;
499
+ return this;
500
+ }
501
+ /** Add inhibitor arc. */
502
+ inhibitor(place2) {
503
+ this._inhibitors.push({ type: "inhibitor", place: place2 });
504
+ return this;
505
+ }
506
+ /** Add inhibitor arcs. */
507
+ inhibitors(...places) {
508
+ for (const p of places) {
509
+ this._inhibitors.push({ type: "inhibitor", place: p });
510
+ }
511
+ return this;
512
+ }
513
+ /** Add read arc. */
514
+ read(place2) {
515
+ this._reads.push({ type: "read", place: place2 });
516
+ return this;
517
+ }
518
+ /** Add read arcs. */
519
+ reads(...places) {
520
+ for (const p of places) {
521
+ this._reads.push({ type: "read", place: p });
522
+ }
523
+ return this;
524
+ }
525
+ /** Add reset arc. */
526
+ reset(place2) {
527
+ this._resets.push({ type: "reset", place: place2 });
528
+ return this;
529
+ }
530
+ /** Add reset arcs. */
531
+ resets(...places) {
532
+ for (const p of places) {
533
+ this._resets.push({ type: "reset", place: p });
534
+ }
535
+ return this;
536
+ }
537
+ /** Set timing specification. */
538
+ timing(timing) {
539
+ this._timing = timing;
540
+ return this;
541
+ }
542
+ /** Set the transition action. */
543
+ action(action) {
544
+ this._action = action;
545
+ return this;
546
+ }
547
+ /** Set the priority (higher fires first). */
548
+ priority(priority) {
549
+ this._priority = priority;
550
+ return this;
551
+ }
552
+ build() {
553
+ if (this._outputSpec !== null) {
554
+ const inputPlaceNames = new Set(this._inputSpecs.map((s) => s.place.name));
555
+ for (const fi of findForwardInputs(this._outputSpec)) {
556
+ if (!inputPlaceNames.has(fi.from.name)) {
557
+ throw new Error(
558
+ `Transition '${this._name}': ForwardInput references non-input place '${fi.from.name}'`
559
+ );
560
+ }
561
+ }
562
+ }
563
+ return new Transition(
564
+ TRANSITION_KEY,
565
+ this._name,
566
+ [...this._inputSpecs],
567
+ this._outputSpec,
568
+ [...this._inhibitors],
569
+ [...this._reads],
570
+ [...this._resets],
571
+ this._timing,
572
+ this._action,
573
+ this._priority
574
+ );
575
+ }
576
+ };
577
+ function findTimeout(out) {
578
+ if (out === null) return null;
579
+ switch (out.type) {
580
+ case "timeout":
581
+ return out;
582
+ case "and":
583
+ case "xor":
584
+ for (const child of out.children) {
585
+ const found = findTimeout(child);
586
+ if (found !== null) return found;
587
+ }
588
+ return null;
589
+ case "place":
590
+ case "forward-input":
591
+ return null;
592
+ }
593
+ }
594
+ function findForwardInputs(out) {
595
+ switch (out.type) {
596
+ case "forward-input":
597
+ return [{ from: out.from, to: out.to }];
598
+ case "and":
599
+ case "xor":
600
+ return out.children.flatMap(findForwardInputs);
601
+ case "timeout":
602
+ return findForwardInputs(out.child);
603
+ case "place":
604
+ return [];
605
+ }
606
+ }
607
+
608
+ // src/core/petri-net.ts
609
+ var PETRI_NET_KEY = /* @__PURE__ */ Symbol("PetriNet.internal");
610
+ var PetriNet = class _PetriNet {
611
+ name;
612
+ places;
613
+ transitions;
614
+ /** @internal Use {@link PetriNet.builder} to create instances. */
615
+ constructor(key, name, places, transitions) {
616
+ if (key !== PETRI_NET_KEY) throw new Error("Use PetriNet.builder() to create instances");
617
+ this.name = name;
618
+ this.places = places;
619
+ this.transitions = transitions;
620
+ }
621
+ /**
622
+ * Creates a new PetriNet with actions bound to transitions by name.
623
+ * Unbound transitions keep passthrough action.
624
+ */
625
+ bindActions(actionBindings) {
626
+ const bindings = actionBindings instanceof Map ? actionBindings : new Map(Object.entries(actionBindings));
627
+ return this.bindActionsWithResolver(
628
+ (name) => bindings.get(name) ?? passthrough()
629
+ );
630
+ }
631
+ /**
632
+ * Creates a new PetriNet with actions bound via a resolver function.
633
+ */
634
+ bindActionsWithResolver(actionResolver) {
635
+ const boundTransitions = /* @__PURE__ */ new Set();
636
+ for (const t of this.transitions) {
637
+ const action = actionResolver(t.name);
638
+ if (action !== null && action !== t.action) {
639
+ boundTransitions.add(rebuildWithAction(t, action));
640
+ } else {
641
+ boundTransitions.add(t);
642
+ }
643
+ }
644
+ return new _PetriNet(PETRI_NET_KEY, this.name, this.places, boundTransitions);
645
+ }
646
+ static builder(name) {
647
+ return new PetriNetBuilder(name);
648
+ }
649
+ };
650
+ var PetriNetBuilder = class {
651
+ _name;
652
+ _places = /* @__PURE__ */ new Set();
653
+ _transitions = /* @__PURE__ */ new Set();
654
+ constructor(name) {
655
+ this._name = name;
656
+ }
657
+ /** Add an explicit place. */
658
+ place(place2) {
659
+ this._places.add(place2);
660
+ return this;
661
+ }
662
+ /** Add explicit places. */
663
+ places(...places) {
664
+ for (const p of places) this._places.add(p);
665
+ return this;
666
+ }
667
+ /** Add a transition (auto-collects places from arcs). */
668
+ transition(transition) {
669
+ this._transitions.add(transition);
670
+ for (const spec of transition.inputSpecs) {
671
+ this._places.add(spec.place);
672
+ }
673
+ for (const p of transition.outputPlaces()) {
674
+ this._places.add(p);
675
+ }
676
+ for (const inh of transition.inhibitors) {
677
+ this._places.add(inh.place);
678
+ }
679
+ for (const r of transition.reads) {
680
+ this._places.add(r.place);
681
+ }
682
+ for (const r of transition.resets) {
683
+ this._places.add(r.place);
684
+ }
685
+ return this;
686
+ }
687
+ /** Add transitions (auto-collects places from arcs). */
688
+ transitions(...transitions) {
689
+ for (const t of transitions) this.transition(t);
690
+ return this;
691
+ }
692
+ build() {
693
+ return new PetriNet(PETRI_NET_KEY, this._name, this._places, this._transitions);
694
+ }
695
+ };
696
+ function rebuildWithAction(t, action) {
697
+ const builder = Transition.builder(t.name).timing(t.timing).priority(t.priority).action(action);
698
+ if (t.inputSpecs.length > 0) {
699
+ builder.inputs(...t.inputSpecs);
700
+ }
701
+ if (t.outputSpec !== null) {
702
+ builder.outputs(t.outputSpec);
703
+ }
704
+ for (const inh of t.inhibitors) {
705
+ builder.inhibitor(inh.place);
706
+ }
707
+ for (const r of t.reads) {
708
+ builder.read(r.place);
709
+ }
710
+ for (const r of t.resets) {
711
+ builder.reset(r.place);
712
+ }
713
+ return builder.build();
714
+ }
715
+
716
+ // src/runtime/marking.ts
717
+ var EMPTY_TOKENS = Object.freeze([]);
718
+ var Marking = class _Marking {
719
+ /** Place name -> FIFO queue of tokens. */
720
+ tokens = /* @__PURE__ */ new Map();
721
+ /** Place name -> Place reference (for inspection). */
722
+ placeRefs = /* @__PURE__ */ new Map();
723
+ static empty() {
724
+ return new _Marking();
725
+ }
726
+ static from(initial) {
727
+ const m = new _Marking();
728
+ for (const [place2, tokens] of initial) {
729
+ m.placeRefs.set(place2.name, place2);
730
+ m.tokens.set(place2.name, [...tokens]);
731
+ }
732
+ return m;
733
+ }
734
+ // ======================== Token Addition ========================
735
+ addToken(place2, token) {
736
+ this.placeRefs.set(place2.name, place2);
737
+ const queue = this.tokens.get(place2.name);
738
+ if (queue) {
739
+ queue.push(token);
740
+ } else {
741
+ this.tokens.set(place2.name, [token]);
742
+ }
743
+ }
744
+ // ======================== Token Removal ========================
745
+ /** Removes and returns the oldest token. Returns null if empty. */
746
+ removeFirst(place2) {
747
+ const queue = this.tokens.get(place2.name);
748
+ if (!queue || queue.length === 0) return null;
749
+ return queue.shift();
750
+ }
751
+ /** Removes and returns all tokens from a place. */
752
+ removeAll(place2) {
753
+ const queue = this.tokens.get(place2.name);
754
+ if (!queue || queue.length === 0) return [];
755
+ const result = [...queue];
756
+ queue.length = 0;
757
+ return result;
758
+ }
759
+ /**
760
+ * Removes and returns the first token whose value satisfies the guard predicate.
761
+ *
762
+ * Performs a linear scan of the place's FIFO queue. If no guard is provided,
763
+ * behaves like `removeFirst()`. If a guard is provided, skips non-matching
764
+ * tokens and splices the first match out of the queue (O(n) worst case).
765
+ */
766
+ removeFirstMatching(spec) {
767
+ const queue = this.tokens.get(spec.place.name);
768
+ if (!queue || queue.length === 0) return null;
769
+ if (!spec.guard) {
770
+ return queue.shift();
771
+ }
772
+ for (let i = 0; i < queue.length; i++) {
773
+ const token = queue[i];
774
+ if (spec.guard(token.value)) {
775
+ queue.splice(i, 1);
776
+ return token;
777
+ }
778
+ }
779
+ return null;
780
+ }
781
+ // ======================== Token Inspection ========================
782
+ /** Check if any token matches a guard predicate. */
783
+ hasMatchingToken(spec) {
784
+ const queue = this.tokens.get(spec.place.name);
785
+ if (!queue || queue.length === 0) return false;
786
+ if (!spec.guard) return true;
787
+ return queue.some((t) => spec.guard(t.value));
788
+ }
789
+ /**
790
+ * Counts tokens in a place whose values satisfy the guard predicate.
791
+ *
792
+ * If no guard is provided, returns the total token count (O(1)).
793
+ * With a guard, performs a linear scan over all tokens (O(n)).
794
+ * Used by the executor for enablement checks on guarded `all`/`at-least` inputs.
795
+ */
796
+ countMatching(spec) {
797
+ const queue = this.tokens.get(spec.place.name);
798
+ if (!queue || queue.length === 0) return 0;
799
+ if (!spec.guard) return queue.length;
800
+ let count = 0;
801
+ for (const t of queue) {
802
+ if (spec.guard(t.value)) count++;
803
+ }
804
+ return count;
805
+ }
806
+ /**
807
+ * Returns tokens in a place. **Returns a live reference** to the internal
808
+ * array — callers must not mutate it. Copy with `[...peekTokens(p)]` if
809
+ * mutation or snapshot semantics are needed.
810
+ */
811
+ peekTokens(place2) {
812
+ return this.tokens.get(place2.name) ?? EMPTY_TOKENS;
813
+ }
814
+ /** Returns the oldest token without removing it. */
815
+ peekFirst(place2) {
816
+ const queue = this.tokens.get(place2.name);
817
+ return queue && queue.length > 0 ? queue[0] : null;
818
+ }
819
+ /** Checks if a place has any tokens. */
820
+ hasTokens(place2) {
821
+ const queue = this.tokens.get(place2.name);
822
+ return queue !== void 0 && queue.length > 0;
823
+ }
824
+ /** Returns the number of tokens in a place. */
825
+ tokenCount(place2) {
826
+ const queue = this.tokens.get(place2.name);
827
+ return queue ? queue.length : 0;
828
+ }
829
+ // ======================== Debugging ========================
830
+ toString() {
831
+ const parts = [];
832
+ for (const [name, queue] of this.tokens) {
833
+ if (queue.length > 0) {
834
+ parts.push(`${name}: ${queue.length}`);
835
+ }
836
+ }
837
+ return `Marking{${parts.join(", ")}}`;
838
+ }
839
+ };
840
+
841
+ // src/runtime/compiled-net.ts
842
+ var WORD_SHIFT = 5;
843
+ var BIT_MASK = 31;
844
+ var CompiledNet = class _CompiledNet {
845
+ net;
846
+ placeCount;
847
+ transitionCount;
848
+ wordCount;
849
+ // ID mappings
850
+ _placesById;
851
+ _transitionsById;
852
+ _placeIndex;
853
+ _transitionIndex;
854
+ // Precomputed masks per transition
855
+ _needsMask;
856
+ _inhibitorMask;
857
+ // Reverse index: place -> affected transition IDs
858
+ _placeToTransitions;
859
+ // Consumption place IDs per transition (input + reset places)
860
+ _consumptionPlaceIds;
861
+ // Cardinality and guard flags
862
+ _cardinalityChecks;
863
+ _hasGuards;
864
+ constructor(net) {
865
+ this.net = net;
866
+ const allPlacesSet = /* @__PURE__ */ new Map();
867
+ for (const t of net.transitions) {
868
+ for (const spec of t.inputSpecs) allPlacesSet.set(spec.place.name, spec.place);
869
+ for (const r of t.reads) allPlacesSet.set(r.place.name, r.place);
870
+ for (const inh of t.inhibitors) allPlacesSet.set(inh.place.name, inh.place);
871
+ for (const rst of t.resets) allPlacesSet.set(rst.place.name, rst.place);
872
+ if (t.outputSpec !== null) {
873
+ for (const p of allPlaces(t.outputSpec)) allPlacesSet.set(p.name, p);
874
+ }
875
+ }
876
+ for (const p of net.places) allPlacesSet.set(p.name, p);
877
+ this.placeCount = allPlacesSet.size;
878
+ this.wordCount = this.placeCount + BIT_MASK >>> WORD_SHIFT;
879
+ this._placesById = [...allPlacesSet.values()];
880
+ this._placeIndex = /* @__PURE__ */ new Map();
881
+ for (let i = 0; i < this._placesById.length; i++) {
882
+ this._placeIndex.set(this._placesById[i].name, i);
883
+ }
884
+ this._transitionsById = [...net.transitions];
885
+ this.transitionCount = this._transitionsById.length;
886
+ this._transitionIndex = /* @__PURE__ */ new Map();
887
+ for (let i = 0; i < this._transitionsById.length; i++) {
888
+ this._transitionIndex.set(this._transitionsById[i], i);
889
+ }
890
+ this._needsMask = new Array(this.transitionCount);
891
+ this._inhibitorMask = new Array(this.transitionCount);
892
+ this._consumptionPlaceIds = new Array(this.transitionCount);
893
+ this._cardinalityChecks = new Array(this.transitionCount).fill(null);
894
+ this._hasGuards = new Array(this.transitionCount).fill(false);
895
+ const placeToTransitionsList = new Array(this.placeCount);
896
+ for (let i = 0; i < this.placeCount; i++) {
897
+ placeToTransitionsList[i] = [];
898
+ }
899
+ for (let tid = 0; tid < this.transitionCount; tid++) {
900
+ const t = this._transitionsById[tid];
901
+ const needs = new Uint32Array(this.wordCount);
902
+ const inhibitors = new Uint32Array(this.wordCount);
903
+ let needsCardinality = false;
904
+ for (const inSpec of t.inputSpecs) {
905
+ const pid = this._placeIndex.get(inSpec.place.name);
906
+ setBit(needs, pid);
907
+ placeToTransitionsList[pid].push(tid);
908
+ if (inSpec.type !== "one") {
909
+ needsCardinality = true;
910
+ }
911
+ if (inSpec.guard) {
912
+ this._hasGuards[tid] = true;
913
+ }
914
+ }
915
+ if (needsCardinality) {
916
+ const pids = [];
917
+ const reqs = [];
918
+ for (const inSpec of t.inputSpecs) {
919
+ pids.push(this._placeIndex.get(inSpec.place.name));
920
+ reqs.push(requiredCount(inSpec));
921
+ }
922
+ this._cardinalityChecks[tid] = { placeIds: pids, requiredCounts: reqs };
923
+ }
924
+ for (const arc of t.reads) {
925
+ const pid = this._placeIndex.get(arc.place.name);
926
+ setBit(needs, pid);
927
+ placeToTransitionsList[pid].push(tid);
928
+ }
929
+ for (const arc of t.inhibitors) {
930
+ const pid = this._placeIndex.get(arc.place.name);
931
+ setBit(inhibitors, pid);
932
+ placeToTransitionsList[pid].push(tid);
933
+ }
934
+ for (const arc of t.resets) {
935
+ const pid = this._placeIndex.get(arc.place.name);
936
+ placeToTransitionsList[pid].push(tid);
937
+ }
938
+ const consumptionSet = /* @__PURE__ */ new Set();
939
+ for (const spec of t.inputSpecs) consumptionSet.add(this._placeIndex.get(spec.place.name));
940
+ for (const arc of t.resets) consumptionSet.add(this._placeIndex.get(arc.place.name));
941
+ this._consumptionPlaceIds[tid] = [...consumptionSet];
942
+ this._needsMask[tid] = needs;
943
+ this._inhibitorMask[tid] = inhibitors;
944
+ }
945
+ this._placeToTransitions = new Array(this.placeCount);
946
+ for (let pid = 0; pid < this.placeCount; pid++) {
947
+ this._placeToTransitions[pid] = [...new Set(placeToTransitionsList[pid])];
948
+ }
949
+ }
950
+ static compile(net) {
951
+ return new _CompiledNet(net);
952
+ }
953
+ // ==================== Accessors ====================
954
+ place(pid) {
955
+ return this._placesById[pid];
956
+ }
957
+ transition(tid) {
958
+ return this._transitionsById[tid];
959
+ }
960
+ placeId(place2) {
961
+ const id = this._placeIndex.get(place2.name);
962
+ if (id === void 0) throw new Error(`Unknown place: ${place2.name}`);
963
+ return id;
964
+ }
965
+ transitionId(t) {
966
+ const id = this._transitionIndex.get(t);
967
+ if (id === void 0) throw new Error(`Unknown transition: ${t.name}`);
968
+ return id;
969
+ }
970
+ affectedTransitions(pid) {
971
+ return this._placeToTransitions[pid];
972
+ }
973
+ consumptionPlaceIds(tid) {
974
+ return this._consumptionPlaceIds[tid];
975
+ }
976
+ cardinalityCheck(tid) {
977
+ return this._cardinalityChecks[tid];
978
+ }
979
+ hasGuards(tid) {
980
+ return this._hasGuards[tid];
981
+ }
982
+ // ==================== Enablement Check ====================
983
+ /**
984
+ * Two-phase bitmap enablement check for a transition:
985
+ * 1. **Presence check**: verifies all required places (inputs + reads) have tokens
986
+ * via `containsAll(snapshot, needsMask)`.
987
+ * 2. **Inhibitor check**: verifies no inhibitor places have tokens
988
+ * via `!intersects(snapshot, inhibitorMask)`.
989
+ *
990
+ * This is a necessary but not sufficient condition — cardinality and guard checks
991
+ * are performed separately by the executor for transitions that pass this fast path.
992
+ */
993
+ canEnableBitmap(tid, markingSnapshot) {
994
+ if (!containsAll(markingSnapshot, this._needsMask[tid])) return false;
995
+ if (intersects(markingSnapshot, this._inhibitorMask[tid])) return false;
996
+ return true;
997
+ }
998
+ };
999
+ function setBit(arr, bit) {
1000
+ arr[bit >>> WORD_SHIFT] |= 1 << (bit & BIT_MASK);
1001
+ }
1002
+ function clearBit(arr, bit) {
1003
+ arr[bit >>> WORD_SHIFT] &= ~(1 << (bit & BIT_MASK));
1004
+ }
1005
+ function testBit(arr, bit) {
1006
+ return (arr[bit >>> WORD_SHIFT] & 1 << (bit & BIT_MASK)) !== 0;
1007
+ }
1008
+ function containsAll(snapshot, mask) {
1009
+ for (let i = 0; i < mask.length; i++) {
1010
+ const m = mask[i];
1011
+ if (m === 0) continue;
1012
+ const s = i < snapshot.length ? snapshot[i] : 0;
1013
+ if ((s & m) !== m) return false;
1014
+ }
1015
+ return true;
1016
+ }
1017
+ function intersects(snapshot, mask) {
1018
+ for (let i = 0; i < mask.length; i++) {
1019
+ const m = mask[i];
1020
+ if (m === 0) continue;
1021
+ if (i < snapshot.length && (snapshot[i] & m) !== 0) return true;
1022
+ }
1023
+ return false;
1024
+ }
1025
+
1026
+ // src/event/net-event.ts
1027
+ function eventTransitionName(event) {
1028
+ switch (event.type) {
1029
+ case "transition-enabled":
1030
+ case "transition-clock-restarted":
1031
+ case "transition-started":
1032
+ case "transition-completed":
1033
+ case "transition-failed":
1034
+ case "transition-timed-out":
1035
+ case "action-timed-out":
1036
+ case "log-message":
1037
+ return event.transitionName;
1038
+ default:
1039
+ return null;
1040
+ }
1041
+ }
1042
+ function isFailureEvent(event) {
1043
+ return event.type === "transition-failed" || event.type === "transition-timed-out" || event.type === "action-timed-out";
1044
+ }
1045
+
1046
+ // src/event/event-store.ts
1047
+ function filterEvents(store, predicate) {
1048
+ return store.events().filter(predicate);
1049
+ }
1050
+ function eventsOfType(store, type) {
1051
+ return store.events().filter((e) => e.type === type);
1052
+ }
1053
+ function transitionEvents(store, transitionName) {
1054
+ return store.events().filter((e) => eventTransitionName(e) === transitionName);
1055
+ }
1056
+ function failures(store) {
1057
+ return store.events().filter(isFailureEvent);
1058
+ }
1059
+ var InMemoryEventStore = class {
1060
+ _events = [];
1061
+ append(event) {
1062
+ this._events.push(event);
1063
+ }
1064
+ events() {
1065
+ return this._events;
1066
+ }
1067
+ isEnabled() {
1068
+ return true;
1069
+ }
1070
+ size() {
1071
+ return this._events.length;
1072
+ }
1073
+ isEmpty() {
1074
+ return this._events.length === 0;
1075
+ }
1076
+ /** Clears all stored events. */
1077
+ clear() {
1078
+ this._events.length = 0;
1079
+ }
1080
+ };
1081
+ var EMPTY = Object.freeze([]);
1082
+ var NoopEventStoreImpl = class {
1083
+ append(_event) {
1084
+ }
1085
+ events() {
1086
+ return EMPTY;
1087
+ }
1088
+ isEnabled() {
1089
+ return false;
1090
+ }
1091
+ size() {
1092
+ return 0;
1093
+ }
1094
+ isEmpty() {
1095
+ return true;
1096
+ }
1097
+ };
1098
+ var NOOP_INSTANCE = new NoopEventStoreImpl();
1099
+ function noopEventStore() {
1100
+ return NOOP_INSTANCE;
1101
+ }
1102
+ function inMemoryEventStore() {
1103
+ return new InMemoryEventStore();
1104
+ }
1105
+
1106
+ // src/runtime/out-violation-error.ts
1107
+ var OutViolationError = class extends Error {
1108
+ constructor(message) {
1109
+ super(message);
1110
+ this.name = "OutViolationError";
1111
+ }
1112
+ };
1113
+
1114
+ // src/runtime/executor-support.ts
1115
+ function validateOutSpec(tName, spec, producedPlaceNames) {
1116
+ switch (spec.type) {
1117
+ case "place":
1118
+ return producedPlaceNames.has(spec.place.name) ? /* @__PURE__ */ new Set([spec.place.name]) : null;
1119
+ case "forward-input":
1120
+ return producedPlaceNames.has(spec.to.name) ? /* @__PURE__ */ new Set([spec.to.name]) : null;
1121
+ case "and": {
1122
+ const claimed = /* @__PURE__ */ new Set();
1123
+ for (const child of spec.children) {
1124
+ const result = validateOutSpec(tName, child, producedPlaceNames);
1125
+ if (result === null) return null;
1126
+ for (const p of result) claimed.add(p);
1127
+ }
1128
+ return claimed;
1129
+ }
1130
+ case "xor": {
1131
+ const satisfied = [];
1132
+ for (const child of spec.children) {
1133
+ const result = validateOutSpec(tName, child, producedPlaceNames);
1134
+ if (result !== null) satisfied.push(result);
1135
+ }
1136
+ if (satisfied.length === 0) {
1137
+ throw new OutViolationError(
1138
+ `'${tName}': XOR violation - no branch produced (exactly 1 required)`
1139
+ );
1140
+ }
1141
+ if (satisfied.length > 1) {
1142
+ throw new OutViolationError(
1143
+ `'${tName}': XOR violation - multiple branches produced`
1144
+ );
1145
+ }
1146
+ return satisfied[0];
1147
+ }
1148
+ case "timeout":
1149
+ return validateOutSpec(tName, spec.child, producedPlaceNames);
1150
+ }
1151
+ }
1152
+ function produceTimeoutOutput(context, timeoutChild) {
1153
+ switch (timeoutChild.type) {
1154
+ case "place":
1155
+ context.output(timeoutChild.place, null);
1156
+ break;
1157
+ case "forward-input": {
1158
+ const value = context.input(timeoutChild.from);
1159
+ context.output(timeoutChild.to, value);
1160
+ break;
1161
+ }
1162
+ case "and":
1163
+ for (const child of timeoutChild.children) {
1164
+ produceTimeoutOutput(context, child);
1165
+ }
1166
+ break;
1167
+ case "xor":
1168
+ throw new Error("XOR not allowed in timeout child");
1169
+ case "timeout":
1170
+ throw new Error("Nested Timeout not allowed");
1171
+ }
1172
+ }
1173
+
1174
+ // src/runtime/bitmap-net-executor.ts
1175
+ var DEADLINE_TOLERANCE_MS = 1;
1176
+ var BitmapNetExecutor = class {
1177
+ compiled;
1178
+ marking;
1179
+ eventStore;
1180
+ environmentPlaces;
1181
+ longRunning;
1182
+ executionContextProvider;
1183
+ startMs;
1184
+ hasAnyDeadlines;
1185
+ allImmediate;
1186
+ allSamePriority;
1187
+ eventStoreEnabled;
1188
+ // Bitmaps (Uint32Array, direct writes)
1189
+ markedPlaces;
1190
+ dirtySet;
1191
+ markingSnapBuffer;
1192
+ dirtySnapBuffer;
1193
+ firingSnapBuffer;
1194
+ // Orchestrator state
1195
+ enabledAtMs;
1196
+ inFlightFlags;
1197
+ enabledFlags;
1198
+ /** Precomputed: 1 if transition has a finite deadline, 0 otherwise. */
1199
+ hasDeadlineFlags;
1200
+ enabledTransitionCount = 0;
1201
+ // In-flight tracking
1202
+ inFlight = /* @__PURE__ */ new Map();
1203
+ inFlightPromises = [];
1204
+ awaitPromises = [];
1205
+ // Queues
1206
+ completionQueue = [];
1207
+ externalQueue = [];
1208
+ // Wake-up mechanism
1209
+ wakeUpResolve = null;
1210
+ // Pre-allocated buffer for fireReadyTransitions() to avoid per-cycle allocation
1211
+ readyBuffer = [];
1212
+ // Pending reset places for clock-restart detection
1213
+ pendingResetPlaces = /* @__PURE__ */ new Set();
1214
+ transitionInputPlaceNames;
1215
+ running = false;
1216
+ closed = false;
1217
+ constructor(net, initialTokens, options = {}) {
1218
+ this.compiled = CompiledNet.compile(net);
1219
+ this.marking = Marking.from(initialTokens);
1220
+ this.eventStore = options.eventStore ?? noopEventStore();
1221
+ this.environmentPlaces = new Set(
1222
+ [...options.environmentPlaces ?? []].map((ep) => ep.place.name)
1223
+ );
1224
+ this.longRunning = options.longRunning ?? false;
1225
+ this.executionContextProvider = options.executionContextProvider;
1226
+ this.startMs = performance.now();
1227
+ const wordCount = this.compiled.wordCount;
1228
+ this.markedPlaces = new Uint32Array(wordCount);
1229
+ this.markingSnapBuffer = new Uint32Array(wordCount);
1230
+ this.firingSnapBuffer = new Uint32Array(wordCount);
1231
+ const dirtyWords = this.compiled.transitionCount + BIT_MASK >>> WORD_SHIFT;
1232
+ this.dirtySet = new Uint32Array(dirtyWords);
1233
+ this.dirtySnapBuffer = new Uint32Array(dirtyWords);
1234
+ this.enabledAtMs = new Float64Array(this.compiled.transitionCount);
1235
+ this.enabledAtMs.fill(-Infinity);
1236
+ this.inFlightFlags = new Uint8Array(this.compiled.transitionCount);
1237
+ this.enabledFlags = new Uint8Array(this.compiled.transitionCount);
1238
+ this.hasDeadlineFlags = new Uint8Array(this.compiled.transitionCount);
1239
+ let anyDeadlines = false;
1240
+ let allImm = true;
1241
+ let samePrio = true;
1242
+ const firstPriority = this.compiled.transitionCount > 0 ? this.compiled.transition(0).priority : 0;
1243
+ for (let tid = 0; tid < this.compiled.transitionCount; tid++) {
1244
+ const t = this.compiled.transition(tid);
1245
+ if (hasDeadline(t.timing)) {
1246
+ this.hasDeadlineFlags[tid] = 1;
1247
+ anyDeadlines = true;
1248
+ }
1249
+ if (t.timing.type !== "immediate") allImm = false;
1250
+ if (t.priority !== firstPriority) samePrio = false;
1251
+ }
1252
+ this.hasAnyDeadlines = anyDeadlines;
1253
+ this.allImmediate = allImm;
1254
+ this.allSamePriority = samePrio;
1255
+ this.eventStoreEnabled = this.eventStore.isEnabled();
1256
+ this.transitionInputPlaceNames = /* @__PURE__ */ new Map();
1257
+ for (const t of net.transitions) {
1258
+ const names = /* @__PURE__ */ new Set();
1259
+ for (const spec of t.inputSpecs) names.add(spec.place.name);
1260
+ this.transitionInputPlaceNames.set(t, names);
1261
+ }
1262
+ }
1263
+ // ======================== Execution ========================
1264
+ async run(timeoutMs) {
1265
+ if (timeoutMs !== void 0) {
1266
+ let timer;
1267
+ const timeoutPromise = new Promise((_, reject) => {
1268
+ timer = setTimeout(() => reject(new Error("Execution timed out")), timeoutMs);
1269
+ });
1270
+ try {
1271
+ return await Promise.race([this.executeLoop(), timeoutPromise]);
1272
+ } finally {
1273
+ if (timer !== void 0) clearTimeout(timer);
1274
+ }
1275
+ }
1276
+ return this.executeLoop();
1277
+ }
1278
+ async executeLoop() {
1279
+ this.running = true;
1280
+ this.emitEvent({
1281
+ type: "execution-started",
1282
+ timestamp: Date.now(),
1283
+ netName: this.compiled.net.name,
1284
+ executionId: this.executionId()
1285
+ });
1286
+ this.initializeMarkedBitmap();
1287
+ this.markAllDirty();
1288
+ this.emitEvent({
1289
+ type: "marking-snapshot",
1290
+ timestamp: Date.now(),
1291
+ marking: this.snapshotMarking()
1292
+ });
1293
+ while (this.running && !this.closed) {
1294
+ this.processCompletedTransitions();
1295
+ this.processExternalEvents();
1296
+ this.updateDirtyTransitions();
1297
+ if (this.hasAnyDeadlines) this.enforceDeadlines(performance.now());
1298
+ if (this.shouldTerminate()) break;
1299
+ this.fireReadyTransitions();
1300
+ if (this.hasDirtyBits()) continue;
1301
+ await this.awaitWork();
1302
+ }
1303
+ this.running = false;
1304
+ this.drainPendingExternalEvents();
1305
+ this.emitEvent({
1306
+ type: "marking-snapshot",
1307
+ timestamp: Date.now(),
1308
+ marking: this.snapshotMarking()
1309
+ });
1310
+ this.emitEvent({
1311
+ type: "execution-completed",
1312
+ timestamp: Date.now(),
1313
+ netName: this.compiled.net.name,
1314
+ executionId: this.executionId(),
1315
+ totalDurationMs: performance.now() - this.startMs
1316
+ });
1317
+ return this.marking;
1318
+ }
1319
+ // ======================== Environment Place API ========================
1320
+ async inject(envPlace, token) {
1321
+ if (!this.environmentPlaces.has(envPlace.place.name)) {
1322
+ throw new Error(`Place ${envPlace.place.name} is not registered as an environment place`);
1323
+ }
1324
+ if (this.closed) return false;
1325
+ return new Promise((resolve, reject) => {
1326
+ this.externalQueue.push({
1327
+ place: envPlace.place,
1328
+ token,
1329
+ resolve,
1330
+ reject
1331
+ });
1332
+ this.wakeUp();
1333
+ });
1334
+ }
1335
+ /** Convenience: inject a raw value (creates token with current timestamp). */
1336
+ async injectValue(envPlace, value) {
1337
+ return this.inject(envPlace, tokenOf(value));
1338
+ }
1339
+ // ======================== Initialize ========================
1340
+ initializeMarkedBitmap() {
1341
+ for (let pid = 0; pid < this.compiled.placeCount; pid++) {
1342
+ const place2 = this.compiled.place(pid);
1343
+ if (this.marking.hasTokens(place2)) {
1344
+ setBit(this.markedPlaces, pid);
1345
+ }
1346
+ }
1347
+ }
1348
+ markAllDirty() {
1349
+ const tc = this.compiled.transitionCount;
1350
+ const dirtyWords = this.dirtySet.length;
1351
+ for (let w = 0; w < dirtyWords - 1; w++) {
1352
+ this.dirtySet[w] = 4294967295;
1353
+ }
1354
+ if (dirtyWords > 0) {
1355
+ const lastWordBits = tc & BIT_MASK;
1356
+ this.dirtySet[dirtyWords - 1] = lastWordBits === 0 ? 4294967295 : (1 << lastWordBits) - 1;
1357
+ }
1358
+ }
1359
+ shouldTerminate() {
1360
+ if (this.longRunning) return this.closed;
1361
+ return this.enabledTransitionCount === 0 && this.inFlight.size === 0 && this.completionQueue.length === 0;
1362
+ }
1363
+ // ======================== Dirty Set Transitions ========================
1364
+ updateDirtyTransitions() {
1365
+ const nowMs = performance.now();
1366
+ const markingSnap = this.markingSnapBuffer;
1367
+ markingSnap.set(this.markedPlaces);
1368
+ const dirtyWords = this.dirtySet.length;
1369
+ const dirtySnap = this.dirtySnapBuffer;
1370
+ for (let w = 0; w < dirtyWords; w++) {
1371
+ dirtySnap[w] = this.dirtySet[w];
1372
+ this.dirtySet[w] = 0;
1373
+ }
1374
+ for (let w = 0; w < dirtyWords; w++) {
1375
+ let word = dirtySnap[w];
1376
+ while (word !== 0) {
1377
+ const bit = Math.clz32(word & -word) ^ 31;
1378
+ const tid = w << WORD_SHIFT | bit;
1379
+ word &= word - 1;
1380
+ if (tid >= this.compiled.transitionCount) break;
1381
+ if (this.inFlightFlags[tid]) continue;
1382
+ const wasEnabled = this.enabledFlags[tid] !== 0;
1383
+ const canNow = this.canEnable(tid, markingSnap);
1384
+ if (canNow && !wasEnabled) {
1385
+ this.enabledFlags[tid] = 1;
1386
+ this.enabledTransitionCount++;
1387
+ this.enabledAtMs[tid] = nowMs;
1388
+ this.emitEvent({
1389
+ type: "transition-enabled",
1390
+ timestamp: Date.now(),
1391
+ transitionName: this.compiled.transition(tid).name
1392
+ });
1393
+ } else if (!canNow && wasEnabled) {
1394
+ this.enabledFlags[tid] = 0;
1395
+ this.enabledTransitionCount--;
1396
+ this.enabledAtMs[tid] = -Infinity;
1397
+ } else if (canNow && wasEnabled && this.hasInputFromResetPlace(this.compiled.transition(tid))) {
1398
+ this.enabledAtMs[tid] = nowMs;
1399
+ this.emitEvent({
1400
+ type: "transition-clock-restarted",
1401
+ timestamp: Date.now(),
1402
+ transitionName: this.compiled.transition(tid).name
1403
+ });
1404
+ }
1405
+ }
1406
+ }
1407
+ this.pendingResetPlaces.clear();
1408
+ }
1409
+ /**
1410
+ * Checks all enabled transitions with finite deadlines. If a transition has been
1411
+ * enabled longer than `latest(timing)`, it is forcibly disabled and a
1412
+ * `TransitionTimedOut` event is emitted. Classical TPN semantics require transitions
1413
+ * to either fire within their window or become disabled.
1414
+ *
1415
+ * A 1ms tolerance is applied to account for timer jitter and microtask scheduling
1416
+ * delays. Without this, exact-timed transitions (where earliest == latest) would
1417
+ * almost always be disabled before they can fire.
1418
+ */
1419
+ enforceDeadlines(nowMs) {
1420
+ for (let tid = 0; tid < this.compiled.transitionCount; tid++) {
1421
+ if (!this.hasDeadlineFlags[tid]) continue;
1422
+ if (!this.enabledFlags[tid] || this.inFlightFlags[tid]) continue;
1423
+ const t = this.compiled.transition(tid);
1424
+ const elapsed = nowMs - this.enabledAtMs[tid];
1425
+ const latestMs = latest(t.timing);
1426
+ if (elapsed > latestMs + DEADLINE_TOLERANCE_MS) {
1427
+ this.enabledFlags[tid] = 0;
1428
+ this.enabledTransitionCount--;
1429
+ this.emitEvent({
1430
+ type: "transition-timed-out",
1431
+ timestamp: Date.now(),
1432
+ transitionName: t.name,
1433
+ deadlineMs: latestMs,
1434
+ actualDurationMs: elapsed
1435
+ });
1436
+ this.enabledAtMs[tid] = -Infinity;
1437
+ }
1438
+ }
1439
+ }
1440
+ canEnable(tid, markingSnap) {
1441
+ if (!this.compiled.canEnableBitmap(tid, markingSnap)) return false;
1442
+ const cardCheck = this.compiled.cardinalityCheck(tid);
1443
+ if (cardCheck !== null) {
1444
+ for (let i = 0; i < cardCheck.placeIds.length; i++) {
1445
+ const pid = cardCheck.placeIds[i];
1446
+ const required = cardCheck.requiredCounts[i];
1447
+ const place2 = this.compiled.place(pid);
1448
+ if (this.marking.tokenCount(place2) < required) return false;
1449
+ }
1450
+ }
1451
+ if (this.compiled.hasGuards(tid)) {
1452
+ const t = this.compiled.transition(tid);
1453
+ for (const spec of t.inputSpecs) {
1454
+ if (!spec.guard) continue;
1455
+ const requiredCount2 = spec.type === "one" ? 1 : spec.type === "exactly" ? spec.count : spec.type === "at-least" ? spec.minimum : 1;
1456
+ if (this.marking.countMatching(spec) < requiredCount2) return false;
1457
+ }
1458
+ }
1459
+ return true;
1460
+ }
1461
+ hasInputFromResetPlace(t) {
1462
+ if (this.pendingResetPlaces.size === 0) return false;
1463
+ const inputNames = this.transitionInputPlaceNames.get(t);
1464
+ if (!inputNames) return false;
1465
+ for (const name of this.pendingResetPlaces) {
1466
+ if (inputNames.has(name)) return true;
1467
+ }
1468
+ return false;
1469
+ }
1470
+ // ======================== Firing ========================
1471
+ fireReadyTransitions() {
1472
+ if (this.allImmediate && this.allSamePriority) {
1473
+ this.fireReadyImmediate();
1474
+ return;
1475
+ }
1476
+ this.fireReadyGeneral();
1477
+ }
1478
+ /**
1479
+ * Fast path for nets where all transitions are immediate and same priority.
1480
+ * Skips timing checks, sorting, and snapshot buffer — just scan and fire.
1481
+ *
1482
+ * Uses live `markedPlaces` instead of a snapshot. Safe because
1483
+ * `updateBitmapAfterConsumption()` synchronously updates the bitmap before the next
1484
+ * iteration. For equal-priority immediate transitions, tid scan order satisfies
1485
+ * FIFO-by-enablement-time (all enabled in the same cycle).
1486
+ */
1487
+ fireReadyImmediate() {
1488
+ for (let tid = 0; tid < this.compiled.transitionCount; tid++) {
1489
+ if (!this.enabledFlags[tid] || this.inFlightFlags[tid]) continue;
1490
+ if (this.canEnable(tid, this.markedPlaces)) {
1491
+ this.fireTransition(tid);
1492
+ } else {
1493
+ this.enabledFlags[tid] = 0;
1494
+ this.enabledTransitionCount--;
1495
+ this.enabledAtMs[tid] = -Infinity;
1496
+ }
1497
+ }
1498
+ }
1499
+ fireReadyGeneral() {
1500
+ const nowMs = performance.now();
1501
+ const ready = this.readyBuffer;
1502
+ ready.length = 0;
1503
+ for (let tid = 0; tid < this.compiled.transitionCount; tid++) {
1504
+ if (!this.enabledFlags[tid] || this.inFlightFlags[tid]) continue;
1505
+ const t = this.compiled.transition(tid);
1506
+ const enabledMs = this.enabledAtMs[tid];
1507
+ const elapsedMs = nowMs - enabledMs;
1508
+ const earliestMs = earliest(t.timing);
1509
+ if (earliestMs <= elapsedMs) {
1510
+ ready.push({ tid, priority: t.priority, enabledAtMs: enabledMs });
1511
+ }
1512
+ }
1513
+ if (ready.length === 0) return;
1514
+ ready.sort((a, b) => {
1515
+ const prioCmp = b.priority - a.priority;
1516
+ if (prioCmp !== 0) return prioCmp;
1517
+ return a.enabledAtMs - b.enabledAtMs;
1518
+ });
1519
+ const freshSnap = this.firingSnapBuffer;
1520
+ freshSnap.set(this.markedPlaces);
1521
+ for (const entry of ready) {
1522
+ const { tid } = entry;
1523
+ if (this.enabledFlags[tid] && this.canEnable(tid, freshSnap)) {
1524
+ this.fireTransition(tid);
1525
+ freshSnap.set(this.markedPlaces);
1526
+ } else {
1527
+ this.enabledFlags[tid] = 0;
1528
+ this.enabledTransitionCount--;
1529
+ this.enabledAtMs[tid] = -Infinity;
1530
+ }
1531
+ }
1532
+ }
1533
+ fireTransition(tid) {
1534
+ const t = this.compiled.transition(tid);
1535
+ const inputs = new TokenInput();
1536
+ const consumed = [];
1537
+ for (const inSpec of t.inputSpecs) {
1538
+ let toConsume;
1539
+ switch (inSpec.type) {
1540
+ case "one":
1541
+ toConsume = 1;
1542
+ break;
1543
+ case "exactly":
1544
+ toConsume = inSpec.count;
1545
+ break;
1546
+ case "all":
1547
+ toConsume = inSpec.guard ? this.marking.countMatching(inSpec) : this.marking.tokenCount(inSpec.place);
1548
+ break;
1549
+ case "at-least":
1550
+ toConsume = inSpec.guard ? this.marking.countMatching(inSpec) : this.marking.tokenCount(inSpec.place);
1551
+ break;
1552
+ }
1553
+ for (let i = 0; i < toConsume; i++) {
1554
+ const token = inSpec.guard ? this.marking.removeFirstMatching(inSpec) : this.marking.removeFirst(inSpec.place);
1555
+ if (token === null) break;
1556
+ consumed.push(token);
1557
+ inputs.add(inSpec.place, token);
1558
+ this.emitEvent({
1559
+ type: "token-removed",
1560
+ timestamp: Date.now(),
1561
+ placeName: inSpec.place.name,
1562
+ token
1563
+ });
1564
+ }
1565
+ }
1566
+ for (const arc of t.reads) {
1567
+ const token = this.marking.peekFirst(arc.place);
1568
+ if (token !== null) {
1569
+ inputs.add(arc.place, token);
1570
+ }
1571
+ }
1572
+ for (const arc of t.resets) {
1573
+ const removed = this.marking.removeAll(arc.place);
1574
+ this.pendingResetPlaces.add(arc.place.name);
1575
+ for (const token of removed) {
1576
+ consumed.push(token);
1577
+ this.emitEvent({
1578
+ type: "token-removed",
1579
+ timestamp: Date.now(),
1580
+ placeName: arc.place.name,
1581
+ token
1582
+ });
1583
+ }
1584
+ }
1585
+ this.updateBitmapAfterConsumption(tid);
1586
+ this.emitEvent({
1587
+ type: "transition-started",
1588
+ timestamp: Date.now(),
1589
+ transitionName: t.name,
1590
+ consumedTokens: consumed
1591
+ });
1592
+ const execCtx = this.executionContextProvider?.(t.name, consumed);
1593
+ const logFn = (level, message, error) => {
1594
+ this.emitEvent({
1595
+ type: "log-message",
1596
+ timestamp: Date.now(),
1597
+ transitionName: t.name,
1598
+ logger: t.name,
1599
+ level,
1600
+ message,
1601
+ error: error?.name ?? null,
1602
+ errorMessage: error?.message ?? null
1603
+ });
1604
+ };
1605
+ const context = new TransitionContext(
1606
+ t.name,
1607
+ inputs,
1608
+ new TokenOutput(),
1609
+ t.inputPlaces(),
1610
+ t.readPlaces(),
1611
+ t.outputPlaces(),
1612
+ execCtx,
1613
+ logFn
1614
+ );
1615
+ let actionPromise = t.action(context);
1616
+ if (t.hasActionTimeout()) {
1617
+ const timeoutSpec = t.actionTimeout;
1618
+ if (timeoutSpec === null) throw new Error(`Expected actionTimeout on ${t.name}`);
1619
+ const timeoutMs = timeoutSpec.afterMs;
1620
+ actionPromise = Promise.race([
1621
+ actionPromise,
1622
+ new Promise(
1623
+ (_, reject) => setTimeout(() => reject(new TimeoutSentinel()), timeoutMs)
1624
+ )
1625
+ ]).catch((err) => {
1626
+ if (err instanceof TimeoutSentinel) {
1627
+ produceTimeoutOutput(context, timeoutSpec.child);
1628
+ this.emitEvent({
1629
+ type: "action-timed-out",
1630
+ timestamp: Date.now(),
1631
+ transitionName: t.name,
1632
+ timeoutMs
1633
+ });
1634
+ return;
1635
+ }
1636
+ throw err;
1637
+ });
1638
+ }
1639
+ let resolveInFlight;
1640
+ const completionPromise = new Promise((r) => {
1641
+ resolveInFlight = r;
1642
+ });
1643
+ const flight = {
1644
+ promise: completionPromise,
1645
+ context,
1646
+ consumed,
1647
+ startMs: performance.now(),
1648
+ resolve: resolveInFlight
1649
+ };
1650
+ actionPromise.then(
1651
+ () => {
1652
+ this.completionQueue.push(t);
1653
+ this.wakeUp();
1654
+ resolveInFlight();
1655
+ },
1656
+ (err) => {
1657
+ flight.error = err;
1658
+ this.completionQueue.push(t);
1659
+ this.wakeUp();
1660
+ resolveInFlight();
1661
+ }
1662
+ );
1663
+ this.inFlight.set(t, flight);
1664
+ this.inFlightFlags[tid] = 1;
1665
+ this.enabledFlags[tid] = 0;
1666
+ this.enabledTransitionCount--;
1667
+ this.enabledAtMs[tid] = -Infinity;
1668
+ }
1669
+ updateBitmapAfterConsumption(tid) {
1670
+ const pids = this.compiled.consumptionPlaceIds(tid);
1671
+ for (const pid of pids) {
1672
+ const place2 = this.compiled.place(pid);
1673
+ if (!this.marking.hasTokens(place2)) {
1674
+ clearBit(this.markedPlaces, pid);
1675
+ }
1676
+ this.markDirty(pid);
1677
+ }
1678
+ }
1679
+ // ======================== Completion Processing ========================
1680
+ processCompletedTransitions() {
1681
+ if (this.completionQueue.length === 0) return;
1682
+ const len = this.completionQueue.length;
1683
+ for (let i = 0; i < len; i++) {
1684
+ const t = this.completionQueue[i];
1685
+ const flight = this.inFlight.get(t);
1686
+ if (!flight) continue;
1687
+ this.inFlight.delete(t);
1688
+ const tid = this.compiled.transitionId(t);
1689
+ this.inFlightFlags[tid] = 0;
1690
+ if (flight.error) {
1691
+ const err = flight.error instanceof Error ? flight.error : new Error(String(flight.error));
1692
+ this.emitEvent({
1693
+ type: "transition-failed",
1694
+ timestamp: Date.now(),
1695
+ transitionName: t.name,
1696
+ errorMessage: err.message,
1697
+ exceptionType: err.name,
1698
+ stack: err.stack
1699
+ });
1700
+ this.markTransitionDirty(tid);
1701
+ continue;
1702
+ }
1703
+ try {
1704
+ const outputs = flight.context.rawOutput();
1705
+ if (t.outputSpec !== null) {
1706
+ const produced2 = outputs.placesWithTokens();
1707
+ const result = validateOutSpec(t.name, t.outputSpec, produced2);
1708
+ if (result === null) {
1709
+ throw new OutViolationError(
1710
+ `'${t.name}': output does not satisfy declared spec`
1711
+ );
1712
+ }
1713
+ }
1714
+ const produced = [];
1715
+ for (const entry of outputs.entries()) {
1716
+ this.marking.addToken(entry.place, entry.token);
1717
+ produced.push(entry.token);
1718
+ const pid = this.compiled.placeId(entry.place);
1719
+ setBit(this.markedPlaces, pid);
1720
+ this.markDirty(pid);
1721
+ this.emitEvent({
1722
+ type: "token-added",
1723
+ timestamp: Date.now(),
1724
+ placeName: entry.place.name,
1725
+ token: entry.token
1726
+ });
1727
+ }
1728
+ this.markTransitionDirty(tid);
1729
+ this.emitEvent({
1730
+ type: "transition-completed",
1731
+ timestamp: Date.now(),
1732
+ transitionName: t.name,
1733
+ producedTokens: produced,
1734
+ durationMs: performance.now() - flight.startMs
1735
+ });
1736
+ } catch (e) {
1737
+ const err = e instanceof Error ? e : new Error(String(e));
1738
+ this.emitEvent({
1739
+ type: "transition-failed",
1740
+ timestamp: Date.now(),
1741
+ transitionName: t.name,
1742
+ errorMessage: err.message,
1743
+ exceptionType: err.name,
1744
+ stack: err.stack
1745
+ });
1746
+ this.markTransitionDirty(tid);
1747
+ }
1748
+ }
1749
+ this.completionQueue.length = 0;
1750
+ }
1751
+ // ======================== External Events ========================
1752
+ processExternalEvents() {
1753
+ if (this.externalQueue.length === 0) return;
1754
+ const len = this.externalQueue.length;
1755
+ for (let i = 0; i < len; i++) {
1756
+ const event = this.externalQueue[i];
1757
+ try {
1758
+ this.marking.addToken(event.place, event.token);
1759
+ const pid = this.compiled.placeId(event.place);
1760
+ setBit(this.markedPlaces, pid);
1761
+ this.markDirty(pid);
1762
+ this.emitEvent({
1763
+ type: "token-added",
1764
+ timestamp: Date.now(),
1765
+ placeName: event.place.name,
1766
+ token: event.token
1767
+ });
1768
+ event.resolve(true);
1769
+ } catch (e) {
1770
+ event.reject(e instanceof Error ? e : new Error(String(e)));
1771
+ }
1772
+ }
1773
+ this.externalQueue.length = 0;
1774
+ }
1775
+ drainPendingExternalEvents() {
1776
+ while (this.externalQueue.length > 0) {
1777
+ this.externalQueue.shift().resolve(false);
1778
+ }
1779
+ }
1780
+ // ======================== Await Work ========================
1781
+ /**
1782
+ * Suspends the executor until work is available. Composes up to 3 promise sources
1783
+ * into a single Promise.race: (1) any in-flight action completing, (2) external
1784
+ * event injection via wakeUp(), (3) timer for the next delayed transition's earliest
1785
+ * firing time. This avoids busy-waiting while remaining responsive to all event types.
1786
+ *
1787
+ * **Microtask flush**: Before building Promise.race, yields via `await Promise.resolve()`
1788
+ * to drain the microtask queue. Sync actions complete via `.then()` microtask; this
1789
+ * yield lets those fire, avoiding ~5 allocations when work is already available.
1790
+ * After the yield, re-checks queues and `this.closed` for close-during-yield safety.
1791
+ */
1792
+ async awaitWork() {
1793
+ if (this.completionQueue.length > 0 || this.externalQueue.length > 0) return;
1794
+ await Promise.resolve();
1795
+ if (this.completionQueue.length > 0 || this.externalQueue.length > 0 || this.closed) return;
1796
+ const promises = this.awaitPromises;
1797
+ promises.length = 0;
1798
+ if (this.inFlight.size > 0) {
1799
+ const arr = this.inFlightPromises;
1800
+ arr.length = 0;
1801
+ for (const f of this.inFlight.values()) arr.push(f.promise);
1802
+ promises.push(Promise.race(arr));
1803
+ }
1804
+ promises.push(new Promise((resolve) => {
1805
+ this.wakeUpResolve = resolve;
1806
+ }));
1807
+ const timerMs = this.millisUntilNextTimedTransition();
1808
+ if (timerMs > 0 && timerMs < Infinity) {
1809
+ promises.push(new Promise((r) => setTimeout(r, timerMs)));
1810
+ }
1811
+ if (promises.length > 0) {
1812
+ await Promise.race(promises);
1813
+ }
1814
+ this.wakeUpResolve = null;
1815
+ }
1816
+ millisUntilNextTimedTransition() {
1817
+ const nowMs = performance.now();
1818
+ let minWaitMs = Infinity;
1819
+ for (let tid = 0; tid < this.compiled.transitionCount; tid++) {
1820
+ if (!this.enabledFlags[tid]) continue;
1821
+ const t = this.compiled.transition(tid);
1822
+ const enabledMs = this.enabledAtMs[tid];
1823
+ const elapsedMs = nowMs - enabledMs;
1824
+ const earliestMs = earliest(t.timing);
1825
+ const remainingEarliest = earliestMs - elapsedMs;
1826
+ if (remainingEarliest <= 0) return 0;
1827
+ minWaitMs = Math.min(minWaitMs, remainingEarliest);
1828
+ if (hasDeadline(t.timing)) {
1829
+ const latestMs = latest(t.timing);
1830
+ const remainingDeadline = latestMs - elapsedMs;
1831
+ if (remainingDeadline <= 0) return 0;
1832
+ minWaitMs = Math.min(minWaitMs, remainingDeadline);
1833
+ }
1834
+ }
1835
+ return minWaitMs;
1836
+ }
1837
+ wakeUp() {
1838
+ this.wakeUpResolve?.();
1839
+ }
1840
+ // ======================== Dirty Set Helpers ========================
1841
+ /** Returns true if any transition needs re-evaluation. O(W) where W = ceil(transitions/32). */
1842
+ hasDirtyBits() {
1843
+ for (let w = 0; w < this.dirtySet.length; w++) {
1844
+ if (this.dirtySet[w] !== 0) return true;
1845
+ }
1846
+ return false;
1847
+ }
1848
+ markDirty(pid) {
1849
+ const tids = this.compiled.affectedTransitions(pid);
1850
+ for (const tid of tids) {
1851
+ this.markTransitionDirty(tid);
1852
+ }
1853
+ }
1854
+ markTransitionDirty(tid) {
1855
+ this.dirtySet[tid >>> WORD_SHIFT] |= 1 << (tid & BIT_MASK);
1856
+ }
1857
+ // ======================== State Inspection ========================
1858
+ getMarking() {
1859
+ return this.marking;
1860
+ }
1861
+ /** Builds a snapshot of the current marking for event emission. */
1862
+ snapshotMarking() {
1863
+ const snap = /* @__PURE__ */ new Map();
1864
+ for (let pid = 0; pid < this.compiled.placeCount; pid++) {
1865
+ const p = this.compiled.place(pid);
1866
+ const tokens = this.marking.peekTokens(p);
1867
+ if (tokens.length > 0) {
1868
+ snap.set(p.name, [...tokens]);
1869
+ }
1870
+ }
1871
+ return snap;
1872
+ }
1873
+ isQuiescent() {
1874
+ return this.enabledTransitionCount === 0 && this.inFlight.size === 0;
1875
+ }
1876
+ executionId() {
1877
+ return this.startMs.toString(16);
1878
+ }
1879
+ close() {
1880
+ this.running = false;
1881
+ this.closed = true;
1882
+ this.wakeUp();
1883
+ }
1884
+ // ======================== Event Emission ========================
1885
+ emitEvent(event) {
1886
+ if (this.eventStoreEnabled) {
1887
+ this.eventStore.append(event);
1888
+ }
1889
+ }
1890
+ };
1891
+ var TimeoutSentinel = class extends Error {
1892
+ constructor() {
1893
+ super("action timeout");
1894
+ this.name = "TimeoutSentinel";
1895
+ }
1896
+ };
1897
+ export {
1898
+ BitmapNetExecutor,
1899
+ CompiledNet,
1900
+ InMemoryEventStore,
1901
+ MAX_DURATION_MS,
1902
+ Marking,
1903
+ OutViolationError,
1904
+ PetriNet,
1905
+ PetriNetBuilder,
1906
+ TokenInput,
1907
+ TokenOutput,
1908
+ Transition,
1909
+ TransitionBuilder,
1910
+ TransitionContext,
1911
+ all,
1912
+ allPlaces,
1913
+ and,
1914
+ andPlaces,
1915
+ arcPlace,
1916
+ atLeast,
1917
+ clearBit,
1918
+ consumptionCount,
1919
+ containsAll,
1920
+ deadline,
1921
+ delayed,
1922
+ earliest,
1923
+ enumerateBranches,
1924
+ environmentPlace,
1925
+ eventTransitionName,
1926
+ eventsOfType,
1927
+ exact,
1928
+ exactly,
1929
+ failures,
1930
+ filterEvents,
1931
+ fork,
1932
+ forwardInput,
1933
+ hasDeadline,
1934
+ hasGuard,
1935
+ immediate,
1936
+ inMemoryEventStore,
1937
+ inhibitorArc,
1938
+ inputArc,
1939
+ intersects,
1940
+ isFailureEvent,
1941
+ isUnit,
1942
+ latest,
1943
+ matchesGuard,
1944
+ noopEventStore,
1945
+ one,
1946
+ outPlace,
1947
+ outputArc,
1948
+ passthrough,
1949
+ place,
1950
+ produce,
1951
+ produceTimeoutOutput,
1952
+ readArc,
1953
+ requiredCount,
1954
+ resetArc,
1955
+ setBit,
1956
+ testBit,
1957
+ timeout,
1958
+ timeoutPlace,
1959
+ tokenAt,
1960
+ tokenOf,
1961
+ transform,
1962
+ transformAsync,
1963
+ transformFrom,
1964
+ transitionEvents,
1965
+ unitToken,
1966
+ validateOutSpec,
1967
+ window,
1968
+ withTimeout,
1969
+ xor,
1970
+ xorPlaces
1971
+ };
1972
+ //# sourceMappingURL=index.js.map