Merge branch 'feat/error-hierarchy'

This commit is contained in:
2026-05-21 20:52:00 +00:00
3 changed files with 381 additions and 6 deletions

View File

@@ -1 +1,125 @@
export {};
type CallStatus = "pending" | "running" | "completed" | "failed" | "aborted";
class FlowgraphError extends Error {
constructor(message: string) {
super(message);
this.name = "FlowgraphError";
}
}
class ConstructionError extends FlowgraphError {
constructor(message: string) {
super(message);
this.name = "ConstructionError";
}
}
class DuplicateNodeError extends ConstructionError {
readonly key: string;
constructor(key: string) {
super(`Node with key "${key}" already exists`);
this.name = "DuplicateNodeError";
this.key = key;
}
}
class DuplicateEdgeError extends ConstructionError {
readonly source: string;
readonly target: string;
constructor(source: string, target: string) {
super(`Edge "${source} -> ${target}" already exists`);
this.name = "DuplicateEdgeError";
this.source = source;
this.target = target;
}
}
class NodeNotFoundError extends ConstructionError {
readonly key: string;
constructor(key: string) {
super(`Node "${key}" not found in graph`);
this.name = "NodeNotFoundError";
this.key = key;
}
}
class CycleError extends ConstructionError {
readonly cycles: string[][];
constructor(cycles: string[][]) {
super(`Adding this edge would create a cycle: ${JSON.stringify(cycles)}`);
this.name = "CycleError";
this.cycles = cycles;
}
}
class InvalidInputError extends ConstructionError {
readonly errors: ValidationError[];
constructor(errors: ValidationError[]) {
super(`Invalid input: ${errors.length} validation error(s)`);
this.name = "InvalidInputError";
this.errors = errors;
}
}
class InvalidTransitionError extends FlowgraphError {
readonly requestId: string;
readonly from: CallStatus;
readonly to: CallStatus;
constructor(requestId: string, from: CallStatus, to: CallStatus) {
super(`Invalid status transition for call ${requestId}: ${from}${to}`);
this.name = "InvalidTransitionError";
this.requestId = requestId;
this.from = from;
this.to = to;
}
}
interface ValidationError {
type: "schema";
nodeKey: string;
field: string;
message: string;
value?: unknown;
}
interface GraphValidationError {
type: "graph";
category: "cycle" | "dangling-reference" | "orphan-node" | "status-inconsistency";
details: unknown;
}
interface TypeMismatch {
path: string;
expected: string;
actual: string;
}
interface TypeIncompatError {
type: "type-compat";
sourceKey: string;
targetKey: string;
compatible: false;
mismatches: TypeMismatch[];
}
type AnyValidationError = ValidationError | GraphValidationError | TypeIncompatError;
export {
FlowgraphError,
ConstructionError,
DuplicateNodeError,
DuplicateEdgeError,
NodeNotFoundError,
CycleError,
InvalidInputError,
InvalidTransitionError,
};
export type {
CallStatus,
ValidationError,
GraphValidationError,
TypeMismatch,
TypeIncompatError,
AnyValidationError,
};

View File

@@ -1 +1 @@
export {};
export * from "./error/index.js";