@michaelrwalker/stagehand 0.1.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.
package/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 Michael Walker
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
package/README.md ADDED
@@ -0,0 +1,277 @@
1
+ # stagehand
2
+
3
+ A fully typesafe, saga-style script framework for TypeScript, with a live terminal UI.
4
+
5
+ - **Scripts** are a collection of **phases**.
6
+ - **Phases** are a collection of **steps**.
7
+ - **Steps** have a `handler` and an optional `rollback` that fires when a *later* step fails.
8
+ - Whatever a handler returns is merged into a **typed context** that every later step can read.
9
+ - Zero runtime dependencies. Live rendering on a TTY, plain line output in CI.
10
+
11
+ ```ts
12
+ const result = await new Script<{ service: string }>({ name: "deploy" })
13
+ .addPhase("Validation")
14
+ .addStep({
15
+ name: "resolve commit",
16
+ handler: async ({ input, status }) => {
17
+ status("querying git");
18
+ return { sha: await git.head(input.service) };
19
+ },
20
+ })
21
+ .addPhase("Release")
22
+ .addStep({
23
+ name: "upload artifact",
24
+ handler: async ({ ctx, progress }) => {
25
+ const bar = progress({ total: 100, label: "uploading" });
26
+ // ^ ctx.sha is typed here
27
+ return { uploadId: await upload(ctx.sha, bar) };
28
+ },
29
+ rollback: async ({ output }) => cdn.delete(output.uploadId),
30
+ // ^ typed as { uploadId: string }
31
+ })
32
+ .run({ service: "api" });
33
+
34
+ if (result.ok) result.ctx.uploadId; // string
35
+ ```
36
+
37
+ ## The terminal
38
+
39
+ ```
40
+ ▌ deploy
41
+ ▌ Build, upload and release a service
42
+
43
+ ✔ Validation 739ms
44
+ ✔ resolve commit 222ms
45
+ ✔ check permissions 517ms
46
+
47
+ ⠸ Build 17.7s
48
+ ✔ install dependencies 14.4s
49
+ ⠸ compile bundle › transform 3.3s
50
+ ▕██████████████░░░░░░░░░░▏ 58% 412/710 src/router.ts
51
+ ✔ typecheck
52
+ ⠸ transform
53
+ ○ minify
54
+ ○ write manifest
55
+
56
+ ○ Release
57
+ ○ upload artifact
58
+ ○ shift traffic
59
+ ```
60
+
61
+ On failure:
62
+
63
+ ```
64
+ ─────────────────────────────────────────────────────────────────────────────
65
+ ✖ Failed at Release › shift traffic after 21.4s
66
+ health check failed: 3/5 pods unhealthy
67
+ ↺ Rolled back 2 steps
68
+ ```
69
+
70
+ Run `npm run example` and `npm run example:fail` to see both live.
71
+
72
+ ## Type flow
73
+
74
+ The context type parameter is inferred and never written by hand. Each `addStep`
75
+ whose handler returns an object widens it:
76
+
77
+ ```ts
78
+ new Script<{ id: string }>() // Ctx = {}
79
+ .addStep({ handler: () => ({ token: "x" }) }) // Ctx = { token: string }
80
+ .addStep({ handler: ({ ctx }) => ({ n: ctx.token.length }) })
81
+ // Ctx = { token: string; n: number }
82
+ ```
83
+
84
+ Reaching for a key a previous step did not produce is a compile error, as is
85
+ reading the wrong shape in a `rollback`. A handler that returns nothing leaves
86
+ the context unchanged.
87
+
88
+ ## Rollback semantics
89
+
90
+ When a step fails, every step that already **succeeded** is compensated in
91
+ reverse order. The step that failed is not compensated — it never completed.
92
+
93
+ | `rollback` option | behaviour |
94
+ | --- | --- |
95
+ | `"all"` (default) | unwind every completed step in the script |
96
+ | `"phase"` | unwind only the phase that failed |
97
+ | `"none"` | leave state as-is |
98
+
99
+ A rollback that throws is recorded in `result.rollbacks` and surfaced in the
100
+ summary; it never masks the original error, and the remaining rollbacks still
101
+ run.
102
+
103
+ ## The handler surface
104
+
105
+ Every handler receives one object:
106
+
107
+ | | |
108
+ | --- | --- |
109
+ | `input` | the value passed to `run()` |
110
+ | `ctx` | everything earlier steps produced, fully typed |
111
+ | `signal` | aborts on timeout, Ctrl-C, or an external signal |
112
+ | `attempt` | 1-based, useful with `retry` |
113
+ | `log` / `info` / `warn` / `error` / `success` | permanent lines above the live frame |
114
+ | `status(text)` | transient one-liner beside the step |
115
+ | `progress({ total, label })` | a progress bar → `update` / `increment` / `setTotal` / `done` |
116
+ | `task(label)` | one nested checklist item → `succeed` / `fail` / `skip` |
117
+ | `tasks([...] as const)` | a whole checklist, keyed for typed lookup |
118
+
119
+ `rollback` receives the same, plus `output` (that step's own return value) and
120
+ `error` (what triggered the unwind).
121
+
122
+ ## Step options
123
+
124
+ ```ts
125
+ .addStep({
126
+ name: "publish",
127
+ description: "push the tag",
128
+ when: ({ input, ctx }) => input.env === "production",
129
+ retry: { attempts: 3, delayMs: (attempt) => attempt * 250, retryIf: isTransient },
130
+ timeoutMs: 30_000,
131
+ handler,
132
+ rollback,
133
+ })
134
+ ```
135
+
136
+ `when` returning false marks the step **skipped** — its rollback never runs.
137
+ Phases accept `when` too, which skips all their steps.
138
+
139
+ ## Script options
140
+
141
+ ```ts
142
+ new Script<Input>({
143
+ name: "deploy",
144
+ description: "Build, upload and release a service",
145
+ rollback: "all", // "all" | "phase" | "none"
146
+ throwOnError: false, // true to throw instead of returning ok: false
147
+ plain: undefined, // force the CI renderer; default auto-detects a TTY
148
+ silent: false,
149
+ handleSignals: true, // Ctrl-C aborts and compensates; a second one gives up
150
+ })
151
+ ```
152
+
153
+ ## Result
154
+
155
+ ```ts
156
+ type RunResult<Ctx> =
157
+ | { ok: true; status: "success"; ctx: Ctx; durationMs: number; steps: StepReport[] }
158
+ | { ok: false; status: "failed" | "aborted"; error: unknown;
159
+ failedAt: { phase: string; step: string } | null;
160
+ ctx: Partial<Ctx>; // what did get produced
161
+ durationMs: number; steps: StepReport[]; rollbacks: RollbackReport[] }
162
+ ```
163
+
164
+ ## Splitting steps across files
165
+
166
+ `stepFor` binds the input and context a step expects while keeping inference:
167
+
168
+ ```ts
169
+ export const verifyId = stepFor<Input, { user: User }>()({
170
+ name: "verify id",
171
+ handler: async ({ ctx }) => ({ verified: ctx.user.id }),
172
+ });
173
+ ```
174
+
175
+ ## Scripts
176
+
177
+ ```
178
+ npm run build # emit dist/
179
+ npm test # node:test suite
180
+ npm run typecheck # library + examples + tests + scripts
181
+ npm run example # the happy path, live
182
+ npm run example:fail
183
+ npm run release # dry run of the publish pipeline
184
+ ```
185
+
186
+ ## TypeScript layout
187
+
188
+ One config per directory, because editors resolve a file's config by finding
189
+ the nearest `tsconfig.json` — a non-standard filename like `tsconfig.foo.json`
190
+ is invisible to them, so the IDE and the CLI disagree.
191
+
192
+ | Config | Covers | Why it differs |
193
+ | --- | --- | --- |
194
+ | `tsconfig.json` | `src` | The library. `noEmit`, strict. |
195
+ | `tsconfig.build.json` | `src` | The only config that emits `dist/`. |
196
+ | `examples/tsconfig.json` | `examples` | Imports the built `dist/`. |
197
+ | `test/tsconfig.json` | `test` | Same. |
198
+ | `scripts/tsconfig.json` | `scripts` | Adds `allowImportingTsExtensions`. |
199
+
200
+ Only `scripts/` needs that last flag. Node's type stripping does not rewrite
201
+ import extensions, so a script importing a sibling script must write
202
+ `./exec.ts` rather than `./exec.js`. The flag cannot go in the root config:
203
+ `tsconfig.build.json` extends it and sets `noEmit: false`, and TypeScript
204
+ rejects `allowImportingTsExtensions` unless `noEmit` or `emitDeclarationOnly`
205
+ is set (TS5096).
206
+
207
+ ## The release pipeline
208
+
209
+ `scripts/release.ts` builds and publishes this package, and is itself written
210
+ with this framework — the pipeline is the integration test.
211
+
212
+ ```
213
+ npm run release # dry run; mutates nothing
214
+ npm run release -- --simulate-failure # rehearse the rollback path
215
+ npm run release -- --publish # for real
216
+ npm run release -- --publish --bump minor
217
+ npm run release -- --publish --version 1.0.0 --tag next
218
+ ```
219
+
220
+ | Phase | Steps |
221
+ | --- | --- |
222
+ | Preflight | read manifest · authenticate npm · inspect git · resolve version · check registry |
223
+ | Verify | typecheck · run tests |
224
+ | Package | write version · clean dist · build · verify artifacts · audit tarball |
225
+ | Publish | tag release · push tag · publish to npm |
226
+
227
+ Three steps compensate, and the ordering is deliberate — `publish to npm` is
228
+ last, so a failure anywhere *before* it unwinds everything and nothing reaches
229
+ the registry:
230
+
231
+ | Step | Rollback |
232
+ | --- | --- |
233
+ | `write version` | restore the previous version in package.json |
234
+ | `clean dist` | rebuild from source |
235
+ | `tag release` | delete the local tag |
236
+ | `push tag` | delete the remote tag |
237
+ | `publish to npm` | `npm deprecate` — a published version cannot be recalled |
238
+
239
+ `--simulate-failure` performs the local mutations and then fails at the publish
240
+ step. Nothing leaves the machine, and you get to watch the unwind:
241
+
242
+ ```
243
+ ✖ publish to npm 0ms simulated publish failure (--simulate-failure)
244
+ ▲ deleted local tag v0.2.0
245
+ ▲ dist rebuilt from source
246
+ ▲ package.json version restored to 0.1.0
247
+
248
+ ✖ Failed at Publish › publish to npm after 8.1s
249
+ ↺ Rolled back 3 steps
250
+ ```
251
+
252
+ Other things it checks: a scoped package without `publishConfig.access`
253
+ (`"public"`) would be published as restricted, so preflight refuses; the tarball
254
+ is audited path-by-path against an allowlist so `src/` can never leak; and the
255
+ version is checked against the registry before any work is done.
256
+
257
+ ## Rendering notes
258
+
259
+ The live renderer repaints an in-place region and writes logs permanently above
260
+ it. It falls back to line-per-event output when stdout is not a TTY, when
261
+ `NO_COLOR` is set, or when `TERM=dumb` — so CI logs stay greppable.
262
+
263
+ **The frame is always made to fit the viewport**, and this is load-bearing
264
+ rather than cosmetic. Repainting works by moving the cursor up N lines, so a
265
+ frame taller than the terminal scrolls its own anchor off screen and each
266
+ repaint appends a copy instead of overwriting. `renderBody` applies four
267
+ progressively stronger reductions until the frame fits:
268
+
269
+ 1. everything, in full;
270
+ 2. finished phases collapse to a one-line summary;
271
+ 3. only the running phase keeps its steps, and drops detail lines;
272
+ 4. the running phase's steps are windowed around the one executing.
273
+
274
+ The executing step is never windowed out, and long lines are truncated rather
275
+ than wrapped. A terminal resize invalidates the recorded geometry, so the
276
+ renderer abandons the old region and redraws below it. The closing frame is
277
+ exempt — nothing repaints after it, so it keeps every step.
@@ -0,0 +1,11 @@
1
+ import type { StepState } from "./state.js";
2
+ import type { Renderer } from "./ui/renderer.js";
3
+ import type { RollbackContext, StepContext } from "./types.js";
4
+ export interface ContextDeps {
5
+ renderer: Renderer;
6
+ step: StepState;
7
+ phaseName: string;
8
+ }
9
+ export declare function createStepContext<In, Ctx>(deps: ContextDeps, input: In, ctx: Ctx, signal: AbortSignal, attempt: number): StepContext<In, Ctx>;
10
+ export declare function createRollbackContext<In, Ctx, Out>(deps: ContextDeps, input: In, ctx: Ctx, output: Out, error: unknown, signal: AbortSignal): RollbackContext<In, Ctx, Out>;
11
+ //# sourceMappingURL=context.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"context.d.ts","sourceRoot":"","sources":["../src/context.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAiB,SAAS,EAAa,MAAM,YAAY,CAAC;AACtE,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,kBAAkB,CAAC;AAEjD,OAAO,KAAK,EAEV,eAAe,EACf,WAAW,EAGZ,MAAM,YAAY,CAAC;AA6FpB,MAAM,WAAW,WAAW;IAC1B,QAAQ,EAAE,QAAQ,CAAC;IACnB,IAAI,EAAE,SAAS,CAAC;IAChB,SAAS,EAAE,MAAM,CAAC;CACnB;AAED,wBAAgB,iBAAiB,CAAC,EAAE,EAAE,GAAG,EACvC,IAAI,EAAE,WAAW,EACjB,KAAK,EAAE,EAAE,EACT,GAAG,EAAE,GAAG,EACR,MAAM,EAAE,WAAW,EACnB,OAAO,EAAE,MAAM,GACd,WAAW,CAAC,EAAE,EAAE,GAAG,CAAC,CAwBtB;AAED,wBAAgB,qBAAqB,CAAC,EAAE,EAAE,GAAG,EAAE,GAAG,EAChD,IAAI,EAAE,WAAW,EACjB,KAAK,EAAE,EAAE,EACT,GAAG,EAAE,GAAG,EACR,MAAM,EAAE,GAAG,EACX,KAAK,EAAE,OAAO,EACd,MAAM,EAAE,WAAW,GAClB,eAAe,CAAC,EAAE,EAAE,GAAG,EAAE,GAAG,CAAC,CAiB/B"}
@@ -0,0 +1,123 @@
1
+ function clamp(value, min, max) {
2
+ return Math.max(min, Math.min(max, value));
3
+ }
4
+ function createProgress(step, renderer, options) {
5
+ const bar = {
6
+ total: Math.max(0, options.total),
7
+ value: clamp(options.value ?? 0, 0, Math.max(0, options.total)),
8
+ complete: false,
9
+ };
10
+ if (options.label !== undefined)
11
+ bar.label = options.label;
12
+ step.progress = bar;
13
+ renderer.refresh();
14
+ return {
15
+ get value() {
16
+ return bar.value;
17
+ },
18
+ get total() {
19
+ return bar.total;
20
+ },
21
+ update(value, label) {
22
+ bar.value = clamp(value, 0, bar.total);
23
+ if (label !== undefined)
24
+ bar.label = label;
25
+ renderer.refresh();
26
+ },
27
+ increment(by = 1) {
28
+ bar.value = clamp(bar.value + by, 0, bar.total);
29
+ renderer.refresh();
30
+ },
31
+ setTotal(total) {
32
+ bar.total = Math.max(0, total);
33
+ bar.value = clamp(bar.value, 0, bar.total);
34
+ renderer.refresh();
35
+ },
36
+ setLabel(label) {
37
+ bar.label = label;
38
+ renderer.refresh();
39
+ },
40
+ done() {
41
+ bar.value = bar.total;
42
+ bar.complete = true;
43
+ renderer.refresh();
44
+ },
45
+ };
46
+ }
47
+ function handleFor(task, renderer) {
48
+ const set = (status, text) => {
49
+ if (text !== undefined)
50
+ task.label = text;
51
+ task.status = status;
52
+ renderer.refresh();
53
+ };
54
+ return {
55
+ start: (text) => set("running", text),
56
+ label: (text) => set(task.status, text),
57
+ succeed: (text) => set("done", text),
58
+ fail: (text) => set("failed", text),
59
+ skip: (text) => set("skipped", text),
60
+ };
61
+ }
62
+ function createTask(step, renderer, label) {
63
+ const task = { label, status: "running" };
64
+ step.tasks.push(task);
65
+ renderer.refresh();
66
+ return handleFor(task, renderer);
67
+ }
68
+ function createTaskList(step, renderer, labels) {
69
+ const map = {};
70
+ for (const label of labels) {
71
+ const task = { label, status: "pending" };
72
+ step.tasks.push(task);
73
+ map[label] = handleFor(task, renderer);
74
+ }
75
+ renderer.refresh();
76
+ return {
77
+ tasks: map,
78
+ get: (key) => map[key],
79
+ };
80
+ }
81
+ export function createStepContext(deps, input, ctx, signal, attempt) {
82
+ const { renderer, step, phaseName } = deps;
83
+ const emit = (level) => (message) => renderer.log({ level, message });
84
+ return {
85
+ input,
86
+ ctx,
87
+ signal,
88
+ attempt,
89
+ phase: phaseName,
90
+ step: step.name,
91
+ log: emit("log"),
92
+ info: emit("info"),
93
+ warn: emit("warn"),
94
+ error: emit("error"),
95
+ success: emit("success"),
96
+ status(message) {
97
+ step.statusText = message;
98
+ renderer.refresh();
99
+ },
100
+ progress: (options) => createProgress(step, renderer, options),
101
+ task: (label) => createTask(step, renderer, label),
102
+ tasks: (labels) => createTaskList(step, renderer, labels),
103
+ };
104
+ }
105
+ export function createRollbackContext(deps, input, ctx, output, error, signal) {
106
+ const { renderer, step, phaseName } = deps;
107
+ return {
108
+ input,
109
+ ctx,
110
+ output,
111
+ error,
112
+ signal,
113
+ phase: phaseName,
114
+ step: step.name,
115
+ log: (message) => renderer.log({ level: "warn", message }),
116
+ status(message) {
117
+ step.statusText = message;
118
+ renderer.refresh();
119
+ },
120
+ progress: (options) => createProgress(step, renderer, options),
121
+ };
122
+ }
123
+ //# sourceMappingURL=context.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"context.js","sourceRoot":"","sources":["../src/context.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,26 @@
1
+ /** A step's handler threw. `cause` holds whatever it actually threw. */
2
+ export declare class StepFailedError extends Error {
3
+ readonly phase: string;
4
+ readonly step: string;
5
+ readonly attempts: number;
6
+ constructor(phase: string, step: string, attempts: number, cause: unknown);
7
+ }
8
+ export declare class StepTimeoutError extends Error {
9
+ readonly step: string;
10
+ readonly timeoutMs: number;
11
+ constructor(step: string, timeoutMs: number);
12
+ }
13
+ /** The run was cancelled — Ctrl-C, SIGTERM, or a caller-supplied signal. */
14
+ export declare class ScriptAbortedError extends Error {
15
+ readonly reason: string;
16
+ constructor(reason: string);
17
+ }
18
+ /** A compensation handler itself threw; the original failure is in `cause`. */
19
+ export declare class RollbackFailedError extends Error {
20
+ readonly phase: string;
21
+ readonly step: string;
22
+ readonly rollbackError: unknown;
23
+ constructor(phase: string, step: string, rollbackError: unknown, cause: unknown);
24
+ }
25
+ export declare function isAbort(error: unknown): boolean;
26
+ //# sourceMappingURL=errors.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"errors.d.ts","sourceRoot":"","sources":["../src/errors.ts"],"names":[],"mappings":"AAAA,wEAAwE;AACxE,qBAAa,eAAgB,SAAQ,KAAK;IACxC,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAC;IACvB,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IACtB,QAAQ,CAAC,QAAQ,EAAE,MAAM,CAAC;gBAEd,KAAK,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,EAAE,KAAK,EAAE,OAAO;CAO1E;AAED,qBAAa,gBAAiB,SAAQ,KAAK;IACzC,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IACtB,QAAQ,CAAC,SAAS,EAAE,MAAM,CAAC;gBAEf,IAAI,EAAE,MAAM,EAAE,SAAS,EAAE,MAAM;CAM5C;AAED,4EAA4E;AAC5E,qBAAa,kBAAmB,SAAQ,KAAK;IAC3C,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC;gBAEZ,MAAM,EAAE,MAAM;CAK3B;AAED,+EAA+E;AAC/E,qBAAa,mBAAoB,SAAQ,KAAK;IAC5C,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAC;IACvB,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IACtB,QAAQ,CAAC,aAAa,EAAE,OAAO,CAAC;gBAEpB,KAAK,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,EAAE,aAAa,EAAE,OAAO,EAAE,KAAK,EAAE,OAAO;CAOhF;AAED,wBAAgB,OAAO,CAAC,KAAK,EAAE,OAAO,GAAG,OAAO,CAK/C"}
package/dist/errors.js ADDED
@@ -0,0 +1,50 @@
1
+ /** A step's handler threw. `cause` holds whatever it actually threw. */
2
+ export class StepFailedError extends Error {
3
+ phase;
4
+ step;
5
+ attempts;
6
+ constructor(phase, step, attempts, cause) {
7
+ super(`Step "${step}" in phase "${phase}" failed`, { cause });
8
+ this.name = "StepFailedError";
9
+ this.phase = phase;
10
+ this.step = step;
11
+ this.attempts = attempts;
12
+ }
13
+ }
14
+ export class StepTimeoutError extends Error {
15
+ step;
16
+ timeoutMs;
17
+ constructor(step, timeoutMs) {
18
+ super(`Step "${step}" timed out after ${timeoutMs}ms`);
19
+ this.name = "StepTimeoutError";
20
+ this.step = step;
21
+ this.timeoutMs = timeoutMs;
22
+ }
23
+ }
24
+ /** The run was cancelled — Ctrl-C, SIGTERM, or a caller-supplied signal. */
25
+ export class ScriptAbortedError extends Error {
26
+ reason;
27
+ constructor(reason) {
28
+ super(`Script aborted (${reason})`);
29
+ this.name = "ScriptAbortedError";
30
+ this.reason = reason;
31
+ }
32
+ }
33
+ /** A compensation handler itself threw; the original failure is in `cause`. */
34
+ export class RollbackFailedError extends Error {
35
+ phase;
36
+ step;
37
+ rollbackError;
38
+ constructor(phase, step, rollbackError, cause) {
39
+ super(`Rollback for "${step}" in phase "${phase}" failed`, { cause });
40
+ this.name = "RollbackFailedError";
41
+ this.phase = phase;
42
+ this.step = step;
43
+ this.rollbackError = rollbackError;
44
+ }
45
+ }
46
+ export function isAbort(error) {
47
+ return (error instanceof ScriptAbortedError ||
48
+ (error instanceof Error && error.name === "AbortError"));
49
+ }
50
+ //# sourceMappingURL=errors.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"errors.js","sourceRoot":"","sources":["../src/errors.ts"],"names":[],"mappings":"AAAA,wEAAwE;AACxE,MAAM,OAAO,eAAgB,SAAQ,KAAK;IAC/B,KAAK,CAAS;IACd,IAAI,CAAS;IACb,QAAQ,CAAS;IAE1B,YAAY,KAAa,EAAE,IAAY,EAAE,QAAgB,EAAE,KAAc;QACvE,KAAK,CAAC,SAAS,IAAI,eAAe,KAAK,UAAU,EAAE,EAAE,KAAK,EAAE,CAAC,CAAC;QAC9D,IAAI,CAAC,IAAI,GAAG,iBAAiB,CAAC;QAC9B,IAAI,CAAC,KAAK,GAAG,KAAK,CAAC;QACnB,IAAI,CAAC,IAAI,GAAG,IAAI,CAAC;QACjB,IAAI,CAAC,QAAQ,GAAG,QAAQ,CAAC;IAC3B,CAAC;CACF;AAED,MAAM,OAAO,gBAAiB,SAAQ,KAAK;IAChC,IAAI,CAAS;IACb,SAAS,CAAS;IAE3B,YAAY,IAAY,EAAE,SAAiB;QACzC,KAAK,CAAC,SAAS,IAAI,qBAAqB,SAAS,IAAI,CAAC,CAAC;QACvD,IAAI,CAAC,IAAI,GAAG,kBAAkB,CAAC;QAC/B,IAAI,CAAC,IAAI,GAAG,IAAI,CAAC;QACjB,IAAI,CAAC,SAAS,GAAG,SAAS,CAAC;IAC7B,CAAC;CACF;AAED,4EAA4E;AAC5E,MAAM,OAAO,kBAAmB,SAAQ,KAAK;IAClC,MAAM,CAAS;IAExB,YAAY,MAAc;QACxB,KAAK,CAAC,mBAAmB,MAAM,GAAG,CAAC,CAAC;QACpC,IAAI,CAAC,IAAI,GAAG,oBAAoB,CAAC;QACjC,IAAI,CAAC,MAAM,GAAG,MAAM,CAAC;IACvB,CAAC;CACF;AAED,+EAA+E;AAC/E,MAAM,OAAO,mBAAoB,SAAQ,KAAK;IACnC,KAAK,CAAS;IACd,IAAI,CAAS;IACb,aAAa,CAAU;IAEhC,YAAY,KAAa,EAAE,IAAY,EAAE,aAAsB,EAAE,KAAc;QAC7E,KAAK,CAAC,iBAAiB,IAAI,eAAe,KAAK,UAAU,EAAE,EAAE,KAAK,EAAE,CAAC,CAAC;QACtE,IAAI,CAAC,IAAI,GAAG,qBAAqB,CAAC;QAClC,IAAI,CAAC,KAAK,GAAG,KAAK,CAAC;QACnB,IAAI,CAAC,IAAI,GAAG,IAAI,CAAC;QACjB,IAAI,CAAC,aAAa,GAAG,aAAa,CAAC;IACrC,CAAC;CACF;AAED,MAAM,UAAU,OAAO,CAAC,KAAc;IACpC,OAAO,CACL,KAAK,YAAY,kBAAkB;QACnC,CAAC,KAAK,YAAY,KAAK,IAAI,KAAK,CAAC,IAAI,KAAK,YAAY,CAAC,CACxD,CAAC;AACJ,CAAC"}
@@ -0,0 +1,7 @@
1
+ export { Script, script, stepFor, type RunOptions } from "./script.js";
2
+ export { RollbackFailedError, ScriptAbortedError, StepFailedError, StepTimeoutError, isAbort, } from "./errors.js";
3
+ export type { Awaitable, Merge, PhaseOptions, PhaseStatus, Prettify, ProgressHandle, RetryPolicy, RollbackContext, RollbackReport, RunResult, RunStatus, ScriptOptions, StepContext, StepDef, StepReport, StepStatus, TaskHandle, TaskListHandle, } from "./types.js";
4
+ export { formatDuration } from "./state.js";
5
+ export { setColorEnabled, isColorEnabled } from "./ui/ansi.js";
6
+ export { palette, symbols } from "./ui/theme.js";
7
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,EAAE,MAAM,EAAE,OAAO,EAAE,KAAK,UAAU,EAAE,MAAM,aAAa,CAAC;AAEvE,OAAO,EACL,mBAAmB,EACnB,kBAAkB,EAClB,eAAe,EACf,gBAAgB,EAChB,OAAO,GACR,MAAM,aAAa,CAAC;AAErB,YAAY,EACV,SAAS,EACT,KAAK,EACL,YAAY,EACZ,WAAW,EACX,QAAQ,EACR,cAAc,EACd,WAAW,EACX,eAAe,EACf,cAAc,EACd,SAAS,EACT,SAAS,EACT,aAAa,EACb,WAAW,EACX,OAAO,EACP,UAAU,EACV,UAAU,EACV,UAAU,EACV,cAAc,GACf,MAAM,YAAY,CAAC;AAEpB,OAAO,EAAE,cAAc,EAAE,MAAM,YAAY,CAAC;AAC5C,OAAO,EAAE,eAAe,EAAE,cAAc,EAAE,MAAM,cAAc,CAAC;AAC/D,OAAO,EAAE,OAAO,EAAE,OAAO,EAAE,MAAM,eAAe,CAAC"}
package/dist/index.js ADDED
@@ -0,0 +1,6 @@
1
+ export { Script, script, stepFor } from "./script.js";
2
+ export { RollbackFailedError, ScriptAbortedError, StepFailedError, StepTimeoutError, isAbort, } from "./errors.js";
3
+ export { formatDuration } from "./state.js";
4
+ export { setColorEnabled, isColorEnabled } from "./ui/ansi.js";
5
+ export { palette, symbols } from "./ui/theme.js";
6
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,EAAE,MAAM,EAAE,OAAO,EAAmB,MAAM,aAAa,CAAC;AAEvE,OAAO,EACL,mBAAmB,EACnB,kBAAkB,EAClB,eAAe,EACf,gBAAgB,EAChB,OAAO,GACR,MAAM,aAAa,CAAC;AAuBrB,OAAO,EAAE,cAAc,EAAE,MAAM,YAAY,CAAC;AAC5C,OAAO,EAAE,eAAe,EAAE,cAAc,EAAE,MAAM,cAAc,CAAC;AAC/D,OAAO,EAAE,OAAO,EAAE,OAAO,EAAE,MAAM,eAAe,CAAC"}
@@ -0,0 +1,75 @@
1
+ import type { Merge, PhaseOptions, RunResult, ScriptOptions, StepDef } from "./types.js";
2
+ export interface RunOptions {
3
+ /** Cancel the run from the outside. */
4
+ signal?: AbortSignal;
5
+ }
6
+ /**
7
+ * A saga-style script: phases of steps, each step optionally compensating when
8
+ * a later step fails.
9
+ *
10
+ * The second type parameter is inferred, never written by hand — every
11
+ * `addStep` whose handler returns an object widens it, so later handlers see
12
+ * everything earlier ones produced.
13
+ *
14
+ * ```ts
15
+ * const result = await new Script<{ userId: string }>("provision")
16
+ * .addPhase("Validation")
17
+ * .addStep({
18
+ * name: "load user",
19
+ * handler: async ({ input }) => ({ user: await db.user(input.userId) }),
20
+ * })
21
+ * .addPhase("Provision")
22
+ * .addStep({
23
+ * name: "create tenant",
24
+ * handler: async ({ ctx }) => ({ tenantId: await api.create(ctx.user.org) }),
25
+ * rollback: async ({ output }) => api.destroy(output.tenantId),
26
+ * })
27
+ * .run({ userId: "u_1" });
28
+ * ```
29
+ */
30
+ export declare class Script<In = void, Ctx extends object = {}> {
31
+ private readonly options;
32
+ private readonly definition;
33
+ constructor(options?: ScriptOptions | string);
34
+ /** Open a new phase. Subsequent `addStep` calls land in it. */
35
+ addPhase(name: string, options?: PhaseOptions<In, Ctx>): Script<In, Ctx>;
36
+ /** Open a phase and populate it inside a callback, keeping the type flow. */
37
+ addPhase<Next extends object>(name: string, build: (script: Script<In, Ctx>) => Script<In, Next>): Script<In, Next>;
38
+ addPhase<Next extends object>(name: string, options: PhaseOptions<In, Ctx>, build: (script: Script<In, Ctx>) => Script<In, Next>): Script<In, Next>;
39
+ /**
40
+ * Append a step to the current phase. Whatever the handler resolves to is
41
+ * merged into the context and becomes visible to every later step.
42
+ */
43
+ addStep<Out extends object | void>(def: StepDef<In, Ctx, Out>): Script<In, Merge<Ctx, Out>>;
44
+ /** Every step name, in execution order — handy for tests and docs. */
45
+ outline(): Array<{
46
+ phase: string;
47
+ steps: string[];
48
+ }>;
49
+ private currentPhase;
50
+ run(input: In, runOptions?: RunOptions): Promise<RunResult<Ctx>>;
51
+ /** Retry + timeout wrapper around a single handler invocation. */
52
+ private executeStep;
53
+ /** Compensate completed steps in reverse order. */
54
+ private unwind;
55
+ /**
56
+ * Wire up cancellation. The first interrupt stops the run and lets
57
+ * compensation proceed; a second one abandons compensation too.
58
+ */
59
+ private attachCancellation;
60
+ }
61
+ /**
62
+ * Define a step in its own module while keeping full inference. Bind the input
63
+ * and the context the step expects, then pass the definition to `addStep`.
64
+ *
65
+ * ```ts
66
+ * export const verifyId = stepFor<Input, { user: User }>()({
67
+ * name: "verify id",
68
+ * handler: async ({ ctx }) => ({ verified: ctx.user.id }),
69
+ * });
70
+ * ```
71
+ */
72
+ export declare function stepFor<In, Ctx extends object = {}>(): <Out extends object | void>(def: StepDef<In, Ctx, Out>) => StepDef<In, Ctx, Out>;
73
+ /** Convenience factory so callers can skip `new`. */
74
+ export declare function script<In = void>(options?: ScriptOptions | string): Script<In, {}>;
75
+ //# sourceMappingURL=script.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"script.d.ts","sourceRoot":"","sources":["../src/script.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EACV,KAAK,EACL,YAAY,EAIZ,SAAS,EACT,aAAa,EACb,OAAO,EAER,MAAM,YAAY,CAAC;AAqBpB,MAAM,WAAW,UAAU;IACzB,uCAAuC;IACvC,MAAM,CAAC,EAAE,WAAW,CAAC;CACtB;AAMD;;;;;;;;;;;;;;;;;;;;;;;GAuBG;AACH,qBAAa,MAAM,CAAC,EAAE,GAAG,IAAI,EAAE,GAAG,SAAS,MAAM,GAAG,EAAE;IACpD,OAAO,CAAC,QAAQ,CAAC,OAAO,CAAgB;IACxC,OAAO,CAAC,QAAQ,CAAC,UAAU,CAAyB;gBAExC,OAAO,GAAE,aAAa,GAAG,MAAW;IAIhD,+DAA+D;IAC/D,QAAQ,CAAC,IAAI,EAAE,MAAM,EAAE,OAAO,CAAC,EAAE,YAAY,CAAC,EAAE,EAAE,GAAG,CAAC,GAAG,MAAM,CAAC,EAAE,EAAE,GAAG,CAAC;IACxE,6EAA6E;IAC7E,QAAQ,CAAC,IAAI,SAAS,MAAM,EAC1B,IAAI,EAAE,MAAM,EACZ,KAAK,EAAE,CAAC,MAAM,EAAE,MAAM,CAAC,EAAE,EAAE,GAAG,CAAC,KAAK,MAAM,CAAC,EAAE,EAAE,IAAI,CAAC,GACnD,MAAM,CAAC,EAAE,EAAE,IAAI,CAAC;IACnB,QAAQ,CAAC,IAAI,SAAS,MAAM,EAC1B,IAAI,EAAE,MAAM,EACZ,OAAO,EAAE,YAAY,CAAC,EAAE,EAAE,GAAG,CAAC,EAC9B,KAAK,EAAE,CAAC,MAAM,EAAE,MAAM,CAAC,EAAE,EAAE,GAAG,CAAC,KAAK,MAAM,CAAC,EAAE,EAAE,IAAI,CAAC,GACnD,MAAM,CAAC,EAAE,EAAE,IAAI,CAAC;IAqBnB;;;OAGG;IACH,OAAO,CAAC,GAAG,SAAS,MAAM,GAAG,IAAI,EAAE,GAAG,EAAE,OAAO,CAAC,EAAE,EAAE,GAAG,EAAE,GAAG,CAAC,GAAG,MAAM,CAAC,EAAE,EAAE,KAAK,CAAC,GAAG,EAAE,GAAG,CAAC,CAAC;IAK3F,sEAAsE;IACtE,OAAO,IAAI,KAAK,CAAC;QAAE,KAAK,EAAE,MAAM,CAAC;QAAC,KAAK,EAAE,MAAM,EAAE,CAAA;KAAE,CAAC;IAOpD,OAAO,CAAC,YAAY;IAYd,GAAG,CAAC,KAAK,EAAE,EAAE,EAAE,UAAU,GAAE,UAAe,GAAG,OAAO,CAAC,SAAS,CAAC,GAAG,CAAC,CAAC;IAkL1E,kEAAkE;YACpD,WAAW;IA8DzB,mDAAmD;YACrC,MAAM;IAsDpB;;;OAGG;IACH,OAAO,CAAC,kBAAkB;CA+B3B;AA6CD;;;;;;;;;;GAUG;AACH,wBAAgB,OAAO,CAAC,EAAE,EAAE,GAAG,SAAS,MAAM,GAAG,EAAE,MACzC,GAAG,SAAS,MAAM,GAAG,IAAI,EAAE,KAAK,OAAO,CAAC,EAAE,EAAE,GAAG,EAAE,GAAG,CAAC,KAAG,OAAO,CAAC,EAAE,EAAE,GAAG,EAAE,GAAG,CAAC,CACtF;AAED,qDAAqD;AACrD,wBAAgB,MAAM,CAAC,EAAE,GAAG,IAAI,EAAE,OAAO,CAAC,EAAE,aAAa,GAAG,MAAM,GAAG,MAAM,CAAC,EAAE,EAAE,EAAE,CAAC,CAElF"}