@unlaxer/tramli 3.4.0 → 3.5.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.
@@ -53,6 +53,10 @@ export declare class FlowEngine {
53
53
  setStateLogger(logger: ((entry: StateLogEntry) => void) | null): void;
54
54
  setErrorLogger(logger: ((entry: ErrorLogEntry) => void) | null): void;
55
55
  setGuardLogger(logger: ((entry: GuardLogEntry) => void) | null): void;
56
+ getTransitionLogger(): ((entry: TransitionLogEntry) => void) | undefined;
57
+ getStateLogger(): ((entry: StateLogEntry) => void) | undefined;
58
+ getErrorLogger(): ((entry: ErrorLogEntry) => void) | undefined;
59
+ getGuardLogger(): ((entry: GuardLogEntry) => void) | undefined;
56
60
  removeAllLoggers(): void;
57
61
  startFlow<S extends string>(definition: FlowDefinition<S>, sessionId: string, initialData: Map<string, unknown>): Promise<FlowInstance<S>>;
58
62
  resumeAndExecute<S extends string>(flowId: string, definition: FlowDefinition<S>, externalData?: Map<string, unknown>): Promise<FlowInstance<S>>;
@@ -31,6 +31,10 @@ class FlowEngine {
31
31
  setGuardLogger(logger) {
32
32
  this.guardLogger = logger ?? undefined;
33
33
  }
34
+ getTransitionLogger() { return this.transitionLogger; }
35
+ getStateLogger() { return this.stateLogger; }
36
+ getErrorLogger() { return this.errorLogger; }
37
+ getGuardLogger() { return this.guardLogger; }
34
38
  removeAllLoggers() {
35
39
  this.transitionLogger = undefined;
36
40
  this.stateLogger = undefined;
@@ -97,13 +101,13 @@ class FlowEngine {
97
101
  }
98
102
  const guard = transition.guard;
99
103
  if (guard) {
100
- const guardStart = this.guardLogger ? performance.now() : 0;
104
+ const guardStart = performance.now();
101
105
  const output = await guard.validate(flow.context);
102
- const guardDurationMicros = this.guardLogger ? Math.round((performance.now() - guardStart) * 1000) : 0;
106
+ const guardDurationMicros = Math.round((performance.now() - guardStart) * 1000);
103
107
  switch (output.type) {
104
108
  case 'accepted': {
105
109
  this.logGuard(flow, currentState, guard.name, 'accepted', guardDurationMicros);
106
- const transStart = this.transitionLogger ? performance.now() : 0;
110
+ const transStart = performance.now();
107
111
  const backup = flow.context.snapshot();
108
112
  if (output.data) {
109
113
  for (const [key, value] of output.data)
@@ -145,7 +149,7 @@ class FlowEngine {
145
149
  }
146
150
  }
147
151
  else {
148
- const transStart = this.transitionLogger ? performance.now() : 0;
152
+ const transStart = performance.now();
149
153
  const from = flow.currentState;
150
154
  this.fireExit(flow, from);
151
155
  flow.transitionTo(transition.to);
@@ -179,7 +183,7 @@ class FlowEngine {
179
183
  if (!autoOrBranch)
180
184
  break;
181
185
  const backup = flow.context.snapshot();
182
- const stepStart = this.transitionLogger ? performance.now() : 0;
186
+ const stepStart = performance.now();
183
187
  try {
184
188
  if (autoOrBranch.type === 'auto') {
185
189
  if (autoOrBranch.processor) {
@@ -234,7 +238,7 @@ class FlowEngine {
234
238
  parentFlow.setActiveSubFlow(null);
235
239
  const target = exitMappings.get(subFlow.exitState);
236
240
  if (target) {
237
- const sfStart = this.transitionLogger ? performance.now() : 0;
241
+ const sfStart = performance.now();
238
242
  const from = parentFlow.currentState;
239
243
  this.fireExit(parentFlow, from);
240
244
  parentFlow.transitionTo(target);
@@ -259,15 +263,15 @@ class FlowEngine {
259
263
  }
260
264
  const guard = transition.guard;
261
265
  if (guard) {
262
- const guardStart = this.guardLogger ? performance.now() : 0;
266
+ const guardStart = performance.now();
263
267
  const output = await guard.validate(parentFlow.context);
264
- const guardDur = this.guardLogger ? Math.round((performance.now() - guardStart) * 1000) : 0;
268
+ const guardDur = Math.round((performance.now() - guardStart) * 1000);
265
269
  if (output.type === 'accepted') {
266
270
  if (output.data) {
267
271
  for (const [key, value] of output.data)
268
272
  parentFlow.context.put(key, value);
269
273
  }
270
- const sfStart = this.transitionLogger ? performance.now() : 0;
274
+ const sfStart = performance.now();
271
275
  const sfFrom = subFlow.currentState;
272
276
  subFlow.transitionTo(transition.to);
273
277
  this.store.recordTransition(parentFlow.id, sfFrom, transition.to, guard.name, parentFlow.context);
@@ -299,7 +303,7 @@ class FlowEngine {
299
303
  if (subFlowT?.exitMappings) {
300
304
  const target = subFlowT.exitMappings.get(subFlow.exitState);
301
305
  if (target) {
302
- const exitStart = this.transitionLogger ? performance.now() : 0;
306
+ const exitStart = performance.now();
303
307
  const from = parentFlow.currentState;
304
308
  this.fireExit(parentFlow, from);
305
309
  parentFlow.transitionTo(target);
@@ -349,7 +353,7 @@ class FlowEngine {
349
353
  this.guardLogger?.({ flowId: flow.id, flowName: flow.definition.name, state, guardName, result, reason, durationMicros });
350
354
  }
351
355
  handleError(flow, fromState, cause) {
352
- const errorStart = (this.transitionLogger || this.errorLogger) ? performance.now() : 0;
356
+ const errorStart = performance.now();
353
357
  if (cause) {
354
358
  flow.setLastError(`${cause.constructor.name}: ${cause.message}`);
355
359
  if (cause instanceof flow_error_js_1.FlowError) {
@@ -8,6 +8,7 @@ export { FlowError } from './flow-error.js';
8
8
  export { InMemoryFlowStore } from './in-memory-flow-store.js';
9
9
  export type { TransitionRecord } from './in-memory-flow-store.js';
10
10
  export { MermaidGenerator } from './mermaid-generator.js';
11
+ export type { MermaidOptions } from './mermaid-generator.js';
11
12
  export { SkeletonGenerator } from './skeleton-generator.js';
12
13
  export type { TargetLanguage } from './skeleton-generator.js';
13
14
  export { DataFlowGraph } from './data-flow-graph.js';
@@ -1,6 +1,9 @@
1
1
  import type { FlowDefinition } from './flow-definition.js';
2
+ export interface MermaidOptions {
3
+ excludeErrorTransitions?: boolean;
4
+ }
2
5
  export declare class MermaidGenerator {
3
- static generate<S extends string>(def: FlowDefinition<S>): string;
6
+ static generate<S extends string>(def: FlowDefinition<S>, options?: MermaidOptions): string;
4
7
  /** Generate Mermaid diagram highlighting external transitions and their data contracts. */
5
8
  static generateExternalContract<S extends string>(def: FlowDefinition<S>): string;
6
9
  /** Generate Mermaid data-flow diagram from requires/produces declarations. */
@@ -2,7 +2,7 @@
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.MermaidGenerator = void 0;
4
4
  class MermaidGenerator {
5
- static generate(def) {
5
+ static generate(def, options) {
6
6
  const lines = ['stateDiagram-v2'];
7
7
  if (def.initialState)
8
8
  lines.push(` [*] --> ${def.initialState}`);
@@ -34,11 +34,13 @@ class MermaidGenerator {
34
34
  const label = this.transitionLabel(t);
35
35
  lines.push(label ? ` ${t.from} --> ${t.to}: ${label}` : ` ${t.from} --> ${t.to}`);
36
36
  }
37
- for (const [from, to] of def.errorTransitions) {
38
- const key = `${from}->${to}`;
39
- if (!seen.has(key)) {
40
- seen.add(key);
41
- lines.push(` ${from} --> ${to}: error`);
37
+ if (!options?.excludeErrorTransitions) {
38
+ for (const [from, to] of def.errorTransitions) {
39
+ const key = `${from}->${to}`;
40
+ if (!seen.has(key)) {
41
+ seen.add(key);
42
+ lines.push(` ${from} --> ${to}: error`);
43
+ }
42
44
  }
43
45
  }
44
46
  for (const s of def.terminalStates) {
@@ -92,7 +92,7 @@ class Pipeline {
92
92
  const completed = [];
93
93
  let prev = 'initial';
94
94
  for (const step of this.steps) {
95
- const stepStart = (this.transitionLogger || this.errorLogger) ? performance.now() : 0;
95
+ const stepStart = performance.now();
96
96
  this.transitionLogger?.({ flowId, flowName: this.name, from: prev, to: step.name, trigger: step.name, durationMicros: 0 });
97
97
  const keysBefore = this.stateLogger ? new Set(ctx.snapshot().keys()) : null;
98
98
  try {
@@ -53,6 +53,10 @@ export declare class FlowEngine {
53
53
  setStateLogger(logger: ((entry: StateLogEntry) => void) | null): void;
54
54
  setErrorLogger(logger: ((entry: ErrorLogEntry) => void) | null): void;
55
55
  setGuardLogger(logger: ((entry: GuardLogEntry) => void) | null): void;
56
+ getTransitionLogger(): ((entry: TransitionLogEntry) => void) | undefined;
57
+ getStateLogger(): ((entry: StateLogEntry) => void) | undefined;
58
+ getErrorLogger(): ((entry: ErrorLogEntry) => void) | undefined;
59
+ getGuardLogger(): ((entry: GuardLogEntry) => void) | undefined;
56
60
  removeAllLoggers(): void;
57
61
  startFlow<S extends string>(definition: FlowDefinition<S>, sessionId: string, initialData: Map<string, unknown>): Promise<FlowInstance<S>>;
58
62
  resumeAndExecute<S extends string>(flowId: string, definition: FlowDefinition<S>, externalData?: Map<string, unknown>): Promise<FlowInstance<S>>;
@@ -28,6 +28,10 @@ export class FlowEngine {
28
28
  setGuardLogger(logger) {
29
29
  this.guardLogger = logger ?? undefined;
30
30
  }
31
+ getTransitionLogger() { return this.transitionLogger; }
32
+ getStateLogger() { return this.stateLogger; }
33
+ getErrorLogger() { return this.errorLogger; }
34
+ getGuardLogger() { return this.guardLogger; }
31
35
  removeAllLoggers() {
32
36
  this.transitionLogger = undefined;
33
37
  this.stateLogger = undefined;
@@ -94,13 +98,13 @@ export class FlowEngine {
94
98
  }
95
99
  const guard = transition.guard;
96
100
  if (guard) {
97
- const guardStart = this.guardLogger ? performance.now() : 0;
101
+ const guardStart = performance.now();
98
102
  const output = await guard.validate(flow.context);
99
- const guardDurationMicros = this.guardLogger ? Math.round((performance.now() - guardStart) * 1000) : 0;
103
+ const guardDurationMicros = Math.round((performance.now() - guardStart) * 1000);
100
104
  switch (output.type) {
101
105
  case 'accepted': {
102
106
  this.logGuard(flow, currentState, guard.name, 'accepted', guardDurationMicros);
103
- const transStart = this.transitionLogger ? performance.now() : 0;
107
+ const transStart = performance.now();
104
108
  const backup = flow.context.snapshot();
105
109
  if (output.data) {
106
110
  for (const [key, value] of output.data)
@@ -142,7 +146,7 @@ export class FlowEngine {
142
146
  }
143
147
  }
144
148
  else {
145
- const transStart = this.transitionLogger ? performance.now() : 0;
149
+ const transStart = performance.now();
146
150
  const from = flow.currentState;
147
151
  this.fireExit(flow, from);
148
152
  flow.transitionTo(transition.to);
@@ -176,7 +180,7 @@ export class FlowEngine {
176
180
  if (!autoOrBranch)
177
181
  break;
178
182
  const backup = flow.context.snapshot();
179
- const stepStart = this.transitionLogger ? performance.now() : 0;
183
+ const stepStart = performance.now();
180
184
  try {
181
185
  if (autoOrBranch.type === 'auto') {
182
186
  if (autoOrBranch.processor) {
@@ -231,7 +235,7 @@ export class FlowEngine {
231
235
  parentFlow.setActiveSubFlow(null);
232
236
  const target = exitMappings.get(subFlow.exitState);
233
237
  if (target) {
234
- const sfStart = this.transitionLogger ? performance.now() : 0;
238
+ const sfStart = performance.now();
235
239
  const from = parentFlow.currentState;
236
240
  this.fireExit(parentFlow, from);
237
241
  parentFlow.transitionTo(target);
@@ -256,15 +260,15 @@ export class FlowEngine {
256
260
  }
257
261
  const guard = transition.guard;
258
262
  if (guard) {
259
- const guardStart = this.guardLogger ? performance.now() : 0;
263
+ const guardStart = performance.now();
260
264
  const output = await guard.validate(parentFlow.context);
261
- const guardDur = this.guardLogger ? Math.round((performance.now() - guardStart) * 1000) : 0;
265
+ const guardDur = Math.round((performance.now() - guardStart) * 1000);
262
266
  if (output.type === 'accepted') {
263
267
  if (output.data) {
264
268
  for (const [key, value] of output.data)
265
269
  parentFlow.context.put(key, value);
266
270
  }
267
- const sfStart = this.transitionLogger ? performance.now() : 0;
271
+ const sfStart = performance.now();
268
272
  const sfFrom = subFlow.currentState;
269
273
  subFlow.transitionTo(transition.to);
270
274
  this.store.recordTransition(parentFlow.id, sfFrom, transition.to, guard.name, parentFlow.context);
@@ -296,7 +300,7 @@ export class FlowEngine {
296
300
  if (subFlowT?.exitMappings) {
297
301
  const target = subFlowT.exitMappings.get(subFlow.exitState);
298
302
  if (target) {
299
- const exitStart = this.transitionLogger ? performance.now() : 0;
303
+ const exitStart = performance.now();
300
304
  const from = parentFlow.currentState;
301
305
  this.fireExit(parentFlow, from);
302
306
  parentFlow.transitionTo(target);
@@ -346,7 +350,7 @@ export class FlowEngine {
346
350
  this.guardLogger?.({ flowId: flow.id, flowName: flow.definition.name, state, guardName, result, reason, durationMicros });
347
351
  }
348
352
  handleError(flow, fromState, cause) {
349
- const errorStart = (this.transitionLogger || this.errorLogger) ? performance.now() : 0;
353
+ const errorStart = performance.now();
350
354
  if (cause) {
351
355
  flow.setLastError(`${cause.constructor.name}: ${cause.message}`);
352
356
  if (cause instanceof FlowError) {
@@ -8,6 +8,7 @@ export { FlowError } from './flow-error.js';
8
8
  export { InMemoryFlowStore } from './in-memory-flow-store.js';
9
9
  export type { TransitionRecord } from './in-memory-flow-store.js';
10
10
  export { MermaidGenerator } from './mermaid-generator.js';
11
+ export type { MermaidOptions } from './mermaid-generator.js';
11
12
  export { SkeletonGenerator } from './skeleton-generator.js';
12
13
  export type { TargetLanguage } from './skeleton-generator.js';
13
14
  export { DataFlowGraph } from './data-flow-graph.js';
@@ -1,6 +1,9 @@
1
1
  import type { FlowDefinition } from './flow-definition.js';
2
+ export interface MermaidOptions {
3
+ excludeErrorTransitions?: boolean;
4
+ }
2
5
  export declare class MermaidGenerator {
3
- static generate<S extends string>(def: FlowDefinition<S>): string;
6
+ static generate<S extends string>(def: FlowDefinition<S>, options?: MermaidOptions): string;
4
7
  /** Generate Mermaid diagram highlighting external transitions and their data contracts. */
5
8
  static generateExternalContract<S extends string>(def: FlowDefinition<S>): string;
6
9
  /** Generate Mermaid data-flow diagram from requires/produces declarations. */
@@ -1,5 +1,5 @@
1
1
  export class MermaidGenerator {
2
- static generate(def) {
2
+ static generate(def, options) {
3
3
  const lines = ['stateDiagram-v2'];
4
4
  if (def.initialState)
5
5
  lines.push(` [*] --> ${def.initialState}`);
@@ -31,11 +31,13 @@ export class MermaidGenerator {
31
31
  const label = this.transitionLabel(t);
32
32
  lines.push(label ? ` ${t.from} --> ${t.to}: ${label}` : ` ${t.from} --> ${t.to}`);
33
33
  }
34
- for (const [from, to] of def.errorTransitions) {
35
- const key = `${from}->${to}`;
36
- if (!seen.has(key)) {
37
- seen.add(key);
38
- lines.push(` ${from} --> ${to}: error`);
34
+ if (!options?.excludeErrorTransitions) {
35
+ for (const [from, to] of def.errorTransitions) {
36
+ const key = `${from}->${to}`;
37
+ if (!seen.has(key)) {
38
+ seen.add(key);
39
+ lines.push(` ${from} --> ${to}: error`);
40
+ }
39
41
  }
40
42
  }
41
43
  for (const s of def.terminalStates) {
@@ -87,7 +87,7 @@ export class Pipeline {
87
87
  const completed = [];
88
88
  let prev = 'initial';
89
89
  for (const step of this.steps) {
90
- const stepStart = (this.transitionLogger || this.errorLogger) ? performance.now() : 0;
90
+ const stepStart = performance.now();
91
91
  this.transitionLogger?.({ flowId, flowName: this.name, from: prev, to: step.name, trigger: step.name, durationMicros: 0 });
92
92
  const keysBefore = this.stateLogger ? new Set(ctx.snapshot().keys()) : null;
93
93
  try {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@unlaxer/tramli",
3
- "version": "3.4.0",
3
+ "version": "3.5.1",
4
4
  "description": "Constrained flow engine — state machines that prevent invalid transitions at build time",
5
5
  "type": "module",
6
6
  "exports": {