@unlaxer/tramli 1.8.0 → 1.9.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1,12 +1,39 @@
1
1
  import type { FlowDefinition } from './flow-definition.js';
2
2
  import { FlowInstance } from './flow-instance.js';
3
3
  import type { InMemoryFlowStore } from './in-memory-flow-store.js';
4
+ /** Log entry types for tramli's pluggable logger API. */
5
+ export interface TransitionLogEntry {
6
+ flowId: string;
7
+ from: string | null;
8
+ to: string;
9
+ trigger: string;
10
+ }
11
+ export interface StateLogEntry {
12
+ flowId: string;
13
+ state: string;
14
+ key: string;
15
+ value: unknown;
16
+ }
17
+ export interface ErrorLogEntry {
18
+ flowId: string;
19
+ from: string | null;
20
+ to: string | null;
21
+ trigger: string;
22
+ cause: Error | null;
23
+ }
4
24
  export declare class FlowEngine {
5
25
  private readonly store;
6
26
  private readonly strictMode;
27
+ private transitionLogger?;
28
+ private stateLogger?;
29
+ private errorLogger?;
7
30
  constructor(store: InMemoryFlowStore, options?: {
8
31
  strictMode?: boolean;
9
32
  });
33
+ setTransitionLogger(logger: ((entry: TransitionLogEntry) => void) | null): void;
34
+ setStateLogger(logger: ((entry: StateLogEntry) => void) | null): void;
35
+ setErrorLogger(logger: ((entry: ErrorLogEntry) => void) | null): void;
36
+ removeAllLoggers(): void;
10
37
  startFlow<S extends string>(definition: FlowDefinition<S>, sessionId: string, initialData: Map<string, unknown>): Promise<FlowInstance<S>>;
11
38
  resumeAndExecute<S extends string>(flowId: string, definition: FlowDefinition<S>, externalData?: Map<string, unknown>): Promise<FlowInstance<S>>;
12
39
  private executeAutoChain;
@@ -8,10 +8,27 @@ const MAX_CHAIN_DEPTH = 10;
8
8
  class FlowEngine {
9
9
  store;
10
10
  strictMode;
11
+ transitionLogger;
12
+ stateLogger;
13
+ errorLogger;
11
14
  constructor(store, options) {
12
15
  this.store = store;
13
16
  this.strictMode = options?.strictMode ?? false;
14
17
  }
18
+ setTransitionLogger(logger) {
19
+ this.transitionLogger = logger ?? undefined;
20
+ }
21
+ setStateLogger(logger) {
22
+ this.stateLogger = logger ?? undefined;
23
+ }
24
+ setErrorLogger(logger) {
25
+ this.errorLogger = logger ?? undefined;
26
+ }
27
+ removeAllLoggers() {
28
+ this.transitionLogger = undefined;
29
+ this.stateLogger = undefined;
30
+ this.errorLogger = undefined;
31
+ }
15
32
  async startFlow(definition, sessionId, initialData) {
16
33
  const flowId = crypto.randomUUID();
17
34
  const ctx = new flow_context_js_1.FlowContext(flowId);
@@ -239,8 +256,16 @@ class FlowEngine {
239
256
  }
240
257
  }
241
258
  handleError(flow, fromState, cause) {
242
- if (cause)
259
+ if (cause) {
243
260
  flow.setLastError(`${cause.constructor.name}: ${cause.message}`);
261
+ if (cause instanceof flow_error_js_1.FlowError) {
262
+ const available = new Set();
263
+ for (const [k] of flow.context.snapshot())
264
+ available.add(k);
265
+ cause.withContextSnapshot(available, new Set());
266
+ }
267
+ }
268
+ this.errorLogger?.({ flowId: flow.id, from: fromState, to: null, trigger: 'error', cause: cause ?? null });
244
269
  const errorTarget = flow.definition.errorTransitions.get(fromState);
245
270
  if (errorTarget) {
246
271
  const from = flow.currentState;
@@ -1,5 +1,6 @@
1
1
  export { Tramli } from './tramli.js';
2
2
  export { FlowEngine } from './flow-engine.js';
3
+ export type { TransitionLogEntry, StateLogEntry, ErrorLogEntry } from './flow-engine.js';
3
4
  export { FlowContext } from './flow-context.js';
4
5
  export { FlowInstance } from './flow-instance.js';
5
6
  export { FlowDefinition, Builder, FromBuilder, BranchBuilder, SubFlowBuilder } from './flow-definition.js';
@@ -1,12 +1,39 @@
1
1
  import type { FlowDefinition } from './flow-definition.js';
2
2
  import { FlowInstance } from './flow-instance.js';
3
3
  import type { InMemoryFlowStore } from './in-memory-flow-store.js';
4
+ /** Log entry types for tramli's pluggable logger API. */
5
+ export interface TransitionLogEntry {
6
+ flowId: string;
7
+ from: string | null;
8
+ to: string;
9
+ trigger: string;
10
+ }
11
+ export interface StateLogEntry {
12
+ flowId: string;
13
+ state: string;
14
+ key: string;
15
+ value: unknown;
16
+ }
17
+ export interface ErrorLogEntry {
18
+ flowId: string;
19
+ from: string | null;
20
+ to: string | null;
21
+ trigger: string;
22
+ cause: Error | null;
23
+ }
4
24
  export declare class FlowEngine {
5
25
  private readonly store;
6
26
  private readonly strictMode;
27
+ private transitionLogger?;
28
+ private stateLogger?;
29
+ private errorLogger?;
7
30
  constructor(store: InMemoryFlowStore, options?: {
8
31
  strictMode?: boolean;
9
32
  });
33
+ setTransitionLogger(logger: ((entry: TransitionLogEntry) => void) | null): void;
34
+ setStateLogger(logger: ((entry: StateLogEntry) => void) | null): void;
35
+ setErrorLogger(logger: ((entry: ErrorLogEntry) => void) | null): void;
36
+ removeAllLoggers(): void;
10
37
  startFlow<S extends string>(definition: FlowDefinition<S>, sessionId: string, initialData: Map<string, unknown>): Promise<FlowInstance<S>>;
11
38
  resumeAndExecute<S extends string>(flowId: string, definition: FlowDefinition<S>, externalData?: Map<string, unknown>): Promise<FlowInstance<S>>;
12
39
  private executeAutoChain;
@@ -5,10 +5,27 @@ const MAX_CHAIN_DEPTH = 10;
5
5
  export class FlowEngine {
6
6
  store;
7
7
  strictMode;
8
+ transitionLogger;
9
+ stateLogger;
10
+ errorLogger;
8
11
  constructor(store, options) {
9
12
  this.store = store;
10
13
  this.strictMode = options?.strictMode ?? false;
11
14
  }
15
+ setTransitionLogger(logger) {
16
+ this.transitionLogger = logger ?? undefined;
17
+ }
18
+ setStateLogger(logger) {
19
+ this.stateLogger = logger ?? undefined;
20
+ }
21
+ setErrorLogger(logger) {
22
+ this.errorLogger = logger ?? undefined;
23
+ }
24
+ removeAllLoggers() {
25
+ this.transitionLogger = undefined;
26
+ this.stateLogger = undefined;
27
+ this.errorLogger = undefined;
28
+ }
12
29
  async startFlow(definition, sessionId, initialData) {
13
30
  const flowId = crypto.randomUUID();
14
31
  const ctx = new FlowContext(flowId);
@@ -236,8 +253,16 @@ export class FlowEngine {
236
253
  }
237
254
  }
238
255
  handleError(flow, fromState, cause) {
239
- if (cause)
256
+ if (cause) {
240
257
  flow.setLastError(`${cause.constructor.name}: ${cause.message}`);
258
+ if (cause instanceof FlowError) {
259
+ const available = new Set();
260
+ for (const [k] of flow.context.snapshot())
261
+ available.add(k);
262
+ cause.withContextSnapshot(available, new Set());
263
+ }
264
+ }
265
+ this.errorLogger?.({ flowId: flow.id, from: fromState, to: null, trigger: 'error', cause: cause ?? null });
241
266
  const errorTarget = flow.definition.errorTransitions.get(fromState);
242
267
  if (errorTarget) {
243
268
  const from = flow.currentState;
@@ -1,5 +1,6 @@
1
1
  export { Tramli } from './tramli.js';
2
2
  export { FlowEngine } from './flow-engine.js';
3
+ export type { TransitionLogEntry, StateLogEntry, ErrorLogEntry } from './flow-engine.js';
3
4
  export { FlowContext } from './flow-context.js';
4
5
  export { FlowInstance } from './flow-instance.js';
5
6
  export { FlowDefinition, Builder, FromBuilder, BranchBuilder, SubFlowBuilder } from './flow-definition.js';
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@unlaxer/tramli",
3
- "version": "1.8.0",
3
+ "version": "1.9.0",
4
4
  "description": "Constrained flow engine — state machines that prevent invalid transitions at build time",
5
5
  "type": "module",
6
6
  "exports": {