import { defineCodes, SuaveplanError } from "@suaveplan/error"; /** * Stable error-code registry for `@suaveplan/undo`. * * Each code is scoped under the `UNDO` namespace via `defineCodes`, producing * fully-qualified strings such as `"UNDO.EMPTY_STACK"` that are safe for * `error.code`-based discrimination across module boundaries. */ export const UNDO_CODES = defineCodes("UNDO", [ "EMPTY_STACK", "AT_BRANCH_ROOT", "DEPENDENCY_CONFLICT", "COMMAND_FAILED", "TRANSACTION_ACTIVE", "TRANSACTION_INACTIVE", ] as const); export type UndoCode = (typeof UNDO_CODES)[keyof typeof UNDO_CODES]; /** * Context fields carried by an `UndoError`. */ export interface UndoErrorContext { /** ID of the command involved (if applicable). */ commandId?: string; /** ID of the branch involved (if applicable). */ branchId?: string; /** IDs of commands that conflict with a selective undo request. */ conflictIds?: string[]; } /** * Typed error for all `@suaveplan/undo` failures. * * Extends `SuaveplanError` so callers can discriminate via * `error instanceof UndoError` or the stable `error.code` property. * * @example * ```ts * import { UndoError, UNDO_CODES } from "@suaveplan/undo/errors/undo-error"; * * try { * stack.undo(); * } catch (err) { * if (err instanceof UndoError && err.code === UNDO_CODES.EMPTY_STACK) { * console.warn("Nothing to undo"); * } * } * ``` */ export class UndoError extends SuaveplanError { public constructor( code: UndoCode, message: string, options?: { cause?: Error; context?: UndoErrorContext } ) { super( code, message, options as { cause?: Error; context?: Record } ); this.name = "UndoError"; } }