@sema-agent/core
Version:
Stateless, task-oriented AI agent core
31 lines (30 loc) • 1.42 kB
JavaScript
import { settleTeardownLeg } from "./teardown-bounded.js";
export function createRollbackStack(report) {
const cleanups = [];
let state = "armed";
return {
push(cleanup) {
if (state !== "armed") {
throw new Error(`RollbackStack.push after ${state}: a cleanup registered once prepare has ${state === "committed" ? "succeeded" : "started unwinding"} would ${state === "committed" ? "never be owned by the failure path" : "never run"} — acquire resources only while the stack is armed.`);
}
cleanups.push(cleanup);
},
commit() {
if (state !== "armed")
throw new Error(`RollbackStack.commit after ${state}: commit is the success path's one disarm and cannot follow an unwind or a second commit.`);
state = "committed";
cleanups.length = 0;
},
async unwindAll() {
if (state !== "armed")
return;
state = "unwinding";
const total = cleanups.length;
let leg = total;
for (let cleanup = cleanups.pop(); cleanup !== undefined; cleanup = cleanups.pop(), leg--) {
await settleTeardownLeg(cleanup, `${cleanup.name !== "" ? cleanup.name : "anonymous cleanup"} (rollback leg ${leg} of ${total}, prepare-throw)`, report);
}
state = "unwound";
},
};
}