first commit

This commit is contained in:
2026-05-29 08:20:56 +01:00
commit 949299f58d
6368 changed files with 527176 additions and 0 deletions

View File

@@ -0,0 +1,111 @@
# undo-error
<!-- begin:auto-docs -->
_(no submodules)_
<!-- end:auto-docs -->
## Purpose
Provides the structured error class `UndoError` and its stable code registry `UNDO_CODES` for `@suaveplan/undo`. All errors thrown by this package are instances of `UndoError`, enabling callers to discriminate failures precisely via `error.code` without relying on string-matching error messages.
The codes are registered via `defineCodes` from `@suaveplan/error`, which guarantees namespace-scoped uniqueness, prevents accidental collisions with other packages, and produces stable string identifiers (e.g., `"UNDO.EMPTY_STACK"`) that survive minification and serialization.
## Features
- Six error codes covering every failure scenario in the package
- Typed `UndoErrorContext` carrying optional `commandId`, `branchId`, and `conflictIds`
- `instanceof UndoError` discrimination across module boundaries
- `error.code` discrimination without `instanceof` (safe for cross-realm use)
- Extends `SuaveplanError` for full cause-chain traversal and OTel span-event adapter support
## Usage: Basic Example
```ts
import { UndoError, UNDO_CODES } from "@suaveplan/undo/errors/undo-error";
import { UndoStack } from "@suaveplan/undo/stack/stack";
const stack = new UndoStack(0);
try {
stack.undo(); // nothing to undo
} catch (err) {
if (err instanceof UndoError && err.code === UNDO_CODES.EMPTY_STACK) {
console.warn("Nothing to undo");
}
}
```
## Usage: Advanced Example
```ts
import { UndoError, UNDO_CODES } from "@suaveplan/undo/errors/undo-error";
import { SelectiveUndoStack } from "@suaveplan/undo/selective/selective-undo";
const stack = new SelectiveUndoStack({ x: 0 }, { throwOnConflict: true });
// Simulate two dependent commands
const cmd1 = { id: "c1", label: "Set x", /* ... */ };
const cmd2 = { id: "c2", label: "Double x", metadata: { dependsOn: "c1" } /* ... */ };
try {
stack.undoById("c1");
} catch (err) {
if (err instanceof UndoError && err.code === UNDO_CODES.DEPENDENCY_CONFLICT) {
const ctx = err.context as { conflictIds?: string[] };
console.error("Conflict with:", ctx.conflictIds?.join(", "));
}
}
// Transaction guard
try {
stack.beginTransaction();
stack.beginTransaction(); // second call throws
} catch (err) {
if (err instanceof UndoError && err.code === UNDO_CODES.TRANSACTION_ACTIVE) {
console.error("Transaction already in progress");
}
}
```
## API Reference
### `UNDO_CODES`
| Code | Value | Thrown By |
|---|---|---|
| `UNDO_CODES.EMPTY_STACK` | `"UNDO.EMPTY_STACK"` | `undo()` / `redo()` when nothing available |
| `UNDO_CODES.AT_BRANCH_ROOT` | `"UNDO.AT_BRANCH_ROOT"` | `BranchingHistory.switchBranch` for unknown branch |
| `UNDO_CODES.DEPENDENCY_CONFLICT` | `"UNDO.DEPENDENCY_CONFLICT"` | `SelectiveUndoStack.undoById` when `throwOnConflict` is set |
| `UNDO_CODES.COMMAND_FAILED` | `"UNDO.COMMAND_FAILED"` | `AsyncUndoStack` when async command rejects |
| `UNDO_CODES.TRANSACTION_ACTIVE` | `"UNDO.TRANSACTION_ACTIVE"` | `beginTransaction()` when one is already open |
| `UNDO_CODES.TRANSACTION_INACTIVE` | `"UNDO.TRANSACTION_INACTIVE"` | `handle.add/commit/rollback` after close |
### `UndoError`
```ts
new UndoError(code: UndoCode, message: string, options?: {
cause?: Error;
context?: UndoErrorContext;
})
```
| Property | Type | Description |
|---|---|---|
| `code` | `UndoCode` | Stable string code |
| `message` | `string` | Human-readable description |
| `context` | `UndoErrorContext \| undefined` | Structured context data |
| `cause` | `Error \| undefined` | Original error (for wrapping) |
| `name` | `"UndoError"` | Always set |
### `UndoErrorContext`
```ts
interface UndoErrorContext {
commandId?: string;
branchId?: string;
conflictIds?: string[];
}
```
## Implementation Notes
`defineCodes` ensures each code string is globally unique per prefix within the process lifetime. The `UNDO_CODES` object is frozen and the union type `UndoCode` is derived via `typeof UNDO_CODES[keyof typeof UNDO_CODES]`, making exhaustive switch-case type-safe. Context fields are typed as `UndoErrorContext` but passed to the base class as `Record<string, unknown>` to satisfy the generic base signature without a breaking cast.