@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 +21 -0
- package/README.md +277 -0
- package/dist/context.d.ts +11 -0
- package/dist/context.d.ts.map +1 -0
- package/dist/context.js +123 -0
- package/dist/context.js.map +1 -0
- package/dist/errors.d.ts +26 -0
- package/dist/errors.d.ts.map +1 -0
- package/dist/errors.js +50 -0
- package/dist/errors.js.map +1 -0
- package/dist/index.d.ts +7 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +6 -0
- package/dist/index.js.map +1 -0
- package/dist/script.d.ts +75 -0
- package/dist/script.d.ts.map +1 -0
- package/dist/script.js +410 -0
- package/dist/script.js.map +1 -0
- package/dist/state.d.ts +51 -0
- package/dist/state.d.ts.map +1 -0
- package/dist/state.js +58 -0
- package/dist/state.js.map +1 -0
- package/dist/types.d.ts +176 -0
- package/dist/types.d.ts.map +1 -0
- package/dist/types.js +2 -0
- package/dist/types.js.map +1 -0
- package/dist/ui/ansi.d.ts +43 -0
- package/dist/ui/ansi.d.ts.map +1 -0
- package/dist/ui/ansi.js +166 -0
- package/dist/ui/ansi.js.map +1 -0
- package/dist/ui/frame.d.ts +27 -0
- package/dist/ui/frame.d.ts.map +1 -0
- package/dist/ui/frame.js +291 -0
- package/dist/ui/frame.js.map +1 -0
- package/dist/ui/renderer.d.ts +84 -0
- package/dist/ui/renderer.d.ts.map +1 -0
- package/dist/ui/renderer.js +178 -0
- package/dist/ui/renderer.js.map +1 -0
- package/dist/ui/theme.d.ts +33 -0
- package/dist/ui/theme.d.ts.map +1 -0
- package/dist/ui/theme.js +68 -0
- package/dist/ui/theme.js.map +1 -0
- package/package.json +47 -0
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"}
|
package/dist/context.js
ADDED
|
@@ -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":"AAWA,SAAS,KAAK,CAAC,KAAa,EAAE,GAAW,EAAE,GAAW;IACpD,OAAO,IAAI,CAAC,GAAG,CAAC,GAAG,EAAE,IAAI,CAAC,GAAG,CAAC,GAAG,EAAE,KAAK,CAAC,CAAC,CAAC;AAC7C,CAAC;AAED,SAAS,cAAc,CACrB,IAAe,EACf,QAAkB,EAClB,OAA0D;IAE1D,MAAM,GAAG,GAAkB;QACzB,KAAK,EAAE,IAAI,CAAC,GAAG,CAAC,CAAC,EAAE,OAAO,CAAC,KAAK,CAAC;QACjC,KAAK,EAAE,KAAK,CAAC,OAAO,CAAC,KAAK,IAAI,CAAC,EAAE,CAAC,EAAE,IAAI,CAAC,GAAG,CAAC,CAAC,EAAE,OAAO,CAAC,KAAK,CAAC,CAAC;QAC/D,QAAQ,EAAE,KAAK;KAChB,CAAC;IACF,IAAI,OAAO,CAAC,KAAK,KAAK,SAAS;QAAE,GAAG,CAAC,KAAK,GAAG,OAAO,CAAC,KAAK,CAAC;IAC3D,IAAI,CAAC,QAAQ,GAAG,GAAG,CAAC;IACpB,QAAQ,CAAC,OAAO,EAAE,CAAC;IAEnB,OAAO;QACL,IAAI,KAAK;YACP,OAAO,GAAG,CAAC,KAAK,CAAC;QACnB,CAAC;QACD,IAAI,KAAK;YACP,OAAO,GAAG,CAAC,KAAK,CAAC;QACnB,CAAC;QACD,MAAM,CAAC,KAAK,EAAE,KAAK;YACjB,GAAG,CAAC,KAAK,GAAG,KAAK,CAAC,KAAK,EAAE,CAAC,EAAE,GAAG,CAAC,KAAK,CAAC,CAAC;YACvC,IAAI,KAAK,KAAK,SAAS;gBAAE,GAAG,CAAC,KAAK,GAAG,KAAK,CAAC;YAC3C,QAAQ,CAAC,OAAO,EAAE,CAAC;QACrB,CAAC;QACD,SAAS,CAAC,EAAE,GAAG,CAAC;YACd,GAAG,CAAC,KAAK,GAAG,KAAK,CAAC,GAAG,CAAC,KAAK,GAAG,EAAE,EAAE,CAAC,EAAE,GAAG,CAAC,KAAK,CAAC,CAAC;YAChD,QAAQ,CAAC,OAAO,EAAE,CAAC;QACrB,CAAC;QACD,QAAQ,CAAC,KAAK;YACZ,GAAG,CAAC,KAAK,GAAG,IAAI,CAAC,GAAG,CAAC,CAAC,EAAE,KAAK,CAAC,CAAC;YAC/B,GAAG,CAAC,KAAK,GAAG,KAAK,CAAC,GAAG,CAAC,KAAK,EAAE,CAAC,EAAE,GAAG,CAAC,KAAK,CAAC,CAAC;YAC3C,QAAQ,CAAC,OAAO,EAAE,CAAC;QACrB,CAAC;QACD,QAAQ,CAAC,KAAK;YACZ,GAAG,CAAC,KAAK,GAAG,KAAK,CAAC;YAClB,QAAQ,CAAC,OAAO,EAAE,CAAC;QACrB,CAAC;QACD,IAAI;YACF,GAAG,CAAC,KAAK,GAAG,GAAG,CAAC,KAAK,CAAC;YACtB,GAAG,CAAC,QAAQ,GAAG,IAAI,CAAC;YACpB,QAAQ,CAAC,OAAO,EAAE,CAAC;QACrB,CAAC;KACF,CAAC;AACJ,CAAC;AAED,SAAS,SAAS,CAAC,IAAe,EAAE,QAAkB;IACpD,MAAM,GAAG,GAAG,CAAC,MAA2B,EAAE,IAAa,EAAQ,EAAE;QAC/D,IAAI,IAAI,KAAK,SAAS;YAAE,IAAI,CAAC,KAAK,GAAG,IAAI,CAAC;QAC1C,IAAI,CAAC,MAAM,GAAG,MAAM,CAAC;QACrB,QAAQ,CAAC,OAAO,EAAE,CAAC;IACrB,CAAC,CAAC;IACF,OAAO;QACL,KAAK,EAAE,CAAC,IAAI,EAAE,EAAE,CAAC,GAAG,CAAC,SAAS,EAAE,IAAI,CAAC;QACrC,KAAK,EAAE,CAAC,IAAI,EAAE,EAAE,CAAC,GAAG,CAAC,IAAI,CAAC,MAAM,EAAE,IAAI,CAAC;QACvC,OAAO,EAAE,CAAC,IAAI,EAAE,EAAE,CAAC,GAAG,CAAC,MAAM,EAAE,IAAI,CAAC;QACpC,IAAI,EAAE,CAAC,IAAI,EAAE,EAAE,CAAC,GAAG,CAAC,QAAQ,EAAE,IAAI,CAAC;QACnC,IAAI,EAAE,CAAC,IAAI,EAAE,EAAE,CAAC,GAAG,CAAC,SAAS,EAAE,IAAI,CAAC;KACrC,CAAC;AACJ,CAAC;AAED,SAAS,UAAU,CAAC,IAAe,EAAE,QAAkB,EAAE,KAAa;IACpE,MAAM,IAAI,GAAc,EAAE,KAAK,EAAE,MAAM,EAAE,SAAS,EAAE,CAAC;IACrD,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;IACtB,QAAQ,CAAC,OAAO,EAAE,CAAC;IACnB,OAAO,SAAS,CAAC,IAAI,EAAE,QAAQ,CAAC,CAAC;AACnC,CAAC;AAED,SAAS,cAAc,CACrB,IAAe,EACf,QAAkB,EAClB,MAAS;IAET,MAAM,GAAG,GAAG,EAAmC,CAAC;IAChD,KAAK,MAAM,KAAK,IAAI,MAAM,EAAE,CAAC;QAC3B,MAAM,IAAI,GAAc,EAAE,KAAK,EAAE,MAAM,EAAE,SAAS,EAAE,CAAC;QACrD,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;QACtB,GAAG,CAAC,KAAkB,CAAC,GAAG,SAAS,CAAC,IAAI,EAAE,QAAQ,CAAC,CAAC;IACtD,CAAC;IACD,QAAQ,CAAC,OAAO,EAAE,CAAC;IACnB,OAAO;QACL,KAAK,EAAE,GAAG;QACV,GAAG,EAAE,CAAC,GAAG,EAAE,EAAE,CAAC,GAAG,CAAC,GAAG,CAAC;KACvB,CAAC;AACJ,CAAC;AAQD,MAAM,UAAU,iBAAiB,CAC/B,IAAiB,EACjB,KAAS,EACT,GAAQ,EACR,MAAmB,EACnB,OAAe;IAEf,MAAM,EAAE,QAAQ,EAAE,IAAI,EAAE,SAAS,EAAE,GAAG,IAAI,CAAC;IAC3C,MAAM,IAAI,GAAG,CAAC,KAAe,EAAE,EAAE,CAAC,CAAC,OAAe,EAAE,EAAE,CAAC,QAAQ,CAAC,GAAG,CAAC,EAAE,KAAK,EAAE,OAAO,EAAE,CAAC,CAAC;IAExF,OAAO;QACL,KAAK;QACL,GAAG;QACH,MAAM;QACN,OAAO;QACP,KAAK,EAAE,SAAS;QAChB,IAAI,EAAE,IAAI,CAAC,IAAI;QACf,GAAG,EAAE,IAAI,CAAC,KAAK,CAAC;QAChB,IAAI,EAAE,IAAI,CAAC,MAAM,CAAC;QAClB,IAAI,EAAE,IAAI,CAAC,MAAM,CAAC;QAClB,KAAK,EAAE,IAAI,CAAC,OAAO,CAAC;QACpB,OAAO,EAAE,IAAI,CAAC,SAAS,CAAC;QACxB,MAAM,CAAC,OAAO;YACZ,IAAI,CAAC,UAAU,GAAG,OAAO,CAAC;YAC1B,QAAQ,CAAC,OAAO,EAAE,CAAC;QACrB,CAAC;QACD,QAAQ,EAAE,CAAC,OAAO,EAAE,EAAE,CAAC,cAAc,CAAC,IAAI,EAAE,QAAQ,EAAE,OAAO,CAAC;QAC9D,IAAI,EAAE,CAAC,KAAK,EAAE,EAAE,CAAC,UAAU,CAAC,IAAI,EAAE,QAAQ,EAAE,KAAK,CAAC;QAClD,KAAK,EAAE,CAAC,MAAM,EAAE,EAAE,CAAC,cAAc,CAAC,IAAI,EAAE,QAAQ,EAAE,MAAM,CAAC;KAC1D,CAAC;AACJ,CAAC;AAED,MAAM,UAAU,qBAAqB,CACnC,IAAiB,EACjB,KAAS,EACT,GAAQ,EACR,MAAW,EACX,KAAc,EACd,MAAmB;IAEnB,MAAM,EAAE,QAAQ,EAAE,IAAI,EAAE,SAAS,EAAE,GAAG,IAAI,CAAC;IAC3C,OAAO;QACL,KAAK;QACL,GAAG;QACH,MAAM;QACN,KAAK;QACL,MAAM;QACN,KAAK,EAAE,SAAS;QAChB,IAAI,EAAE,IAAI,CAAC,IAAI;QACf,GAAG,EAAE,CAAC,OAAO,EAAE,EAAE,CAAC,QAAQ,CAAC,GAAG,CAAC,EAAE,KAAK,EAAE,MAAM,EAAE,OAAO,EAAE,CAAC;QAC1D,MAAM,CAAC,OAAO;YACZ,IAAI,CAAC,UAAU,GAAG,OAAO,CAAC;YAC1B,QAAQ,CAAC,OAAO,EAAE,CAAC;QACrB,CAAC;QACD,QAAQ,EAAE,CAAC,OAAO,EAAE,EAAE,CAAC,cAAc,CAAC,IAAI,EAAE,QAAQ,EAAE,OAAO,CAAC;KAC/D,CAAC;AACJ,CAAC"}
|
package/dist/errors.d.ts
ADDED
|
@@ -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"}
|
package/dist/index.d.ts
ADDED
|
@@ -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"}
|
package/dist/script.d.ts
ADDED
|
@@ -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"}
|