@vosjs/cli 0.42.0 → 0.43.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/README.md +14 -1
- package/dist/{chunk-7RMULTDM.js → chunk-6PJPGBKH.js} +172 -9
- package/dist/chunk-6PJPGBKH.js.map +1 -0
- package/dist/cli.js +3 -3
- package/dist/index.d.ts +53 -0
- package/dist/index.js +1 -1
- package/dist/{run-WN2IO3WL.js → run-ZYROWQ3T.js} +2 -2
- package/package.json +4 -4
- package/schema/actions.schema.json +45 -0
- package/dist/chunk-7RMULTDM.js.map +0 -1
- /package/dist/{run-WN2IO3WL.js.map → run-ZYROWQ3T.js.map} +0 -0
package/README.md
CHANGED
|
@@ -80,7 +80,7 @@ vos plan take --reuse # re-time that cut onto
|
|
|
80
80
|
|
|
81
81
|
| Verb | Flags |
|
|
82
82
|
| -------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
|
|
83
|
-
| `record` | `--actions <file>` (or positional) `--url` `--out take` `--strict` `--dry-run` `--allow-wall` `--keep-frames` `--storage-state <file>` `--browser-arg=<switch>`... `--max-duration <s>` `--background <slug\|url\|none>`
|
|
83
|
+
| `record` | `--actions <file>` (or positional) `--url` `--out take` `--strict` `--dry-run` `--allow-wall` `--keep-frames` `--storage-state <file>` `--header name=value`... `--browser-arg=<switch>`... `--max-duration <s>` `--background <slug\|url\|none>` |
|
|
84
84
|
| `create` | The `record` flags plus the render flags (`--width` `--height` `--fps` `--format` `--parallel` `--draft` `--frame` `--set`), no `--range`. With `--strict` an incomplete recording exits 2 before anything is rendered |
|
|
85
85
|
| `plan` | `--fresh` (discard the current plan) `--reuse` `--from <doc.json>` (defaults to `<take>/doc.prev.json`) `--style <doc.json\|take\|vosId>` `--with <doc.json\|take\|vosId>[@end\|@start\|@step:<id>\|@<seconds>]` (a template, repeatable) `--background` `--motion` (re-propose the motion) `--headline` `--kicker` `--launch` `--brand` `--music` `--entrance` `--transitions slide\|fade\|scale\|none` `--end-card on\|none\|<ref>` `--captions` `--clicks` `--release` |
|
|
86
86
|
| `digest` | `--out <take>/digest` `--full 960` `--crop 640` (image long edges, the token budget) `--no-frames` `--transcript <file>` (Whisper-shaped segments merged as `said`) `--style <ref>` (report a reference document's style fields) |
|
|
@@ -90,6 +90,19 @@ vos plan take --reuse # re-time that cut onto
|
|
|
90
90
|
|
|
91
91
|
**The wall check.** Once the first navigation settles, and before a frame is captured, `record`, `create` and `--dry-run` ask whether the recorder landed where it was sent. A take that met a sign-in instead is refused with exit 4 and a sentence (`asked for /dashboard, landed on /login: no session for app.acme.com`): the asked URL answered 401 or 403, the recorder was sent to an identity provider or a sign-in path, or the page is a sign-in form (one password field, or a one-time-code field) rendered in place. A redirect somewhere else with no sign-in in sight, which is what a site that shows strangers a public page looks like, is refused under `--strict` and in a rehearsal, and said as a warning otherwise. The check runs before a re-record clears anything, so a session that expired since the last take never costs the footage it failed to replace. The way past a wall is a session: `--storage-state <file>`, minted from the test auth the project already has wherever that exists. `--allow-wall` records the page anyway (a video OF a sign-in page is a legitimate take), and the take's `meta.wall` and its digest then say so.
|
|
92
92
|
|
|
93
|
+
**`setup`: the steps that run before the camera rolls.** A sign-in form, a cookie banner, the "choose your editor" modal, an onboarding tour: things a take must get past and must not show. `actions.json` takes `setup: [...]` beside `steps`, with the verbs `goto`, `click`, `type`, `press`, `wait`. They run after the first navigation and before a frame is captured, as plain actions with no cursor, no frames, no pace and nothing in `meta.steps`; then the recorder opens `url` again and the take begins where the setup left it. A `type` step's `text` may be `{ "env": "DEMO_PASSWORD" }`, read from the shell at run time and never logged or stored (the log names the field, never the value; a literal typed into a password field is refused by `validate`, because `actions.json` is committed and pushed with the take). A selector that never appears fails the take before anything is recorded (exit 2), because a take that begins at a half-finished sign-in is the wall by another name; rehearse the setup with `--dry-run` like everything else. This is rung 2 of the session ladder made scriptable: a local or self-hosted instance with a seeded user, no state file needed.
|
|
94
|
+
|
|
95
|
+
```json
|
|
96
|
+
"setup": [
|
|
97
|
+
{ "do": "goto", "url": "http://localhost:3000/login" },
|
|
98
|
+
{ "do": "type", "selector": "#email", "text": "demo@acme.test" },
|
|
99
|
+
{ "do": "type", "selector": "#password", "text": { "env": "DEMO_PASSWORD" } },
|
|
100
|
+
{ "do": "press", "key": "Enter", "ms": 800 }
|
|
101
|
+
]
|
|
102
|
+
```
|
|
103
|
+
|
|
104
|
+
**`--header name=value`**, repeatable: a request header on every request the recording browser makes, the way past a preview deployment protected by a bypass header alone (`--header x-vercel-protection-bypass=$TOKEN`). The rehearsal's `Next:` line carries it.
|
|
105
|
+
|
|
93
106
|
**What the frame shows.** Getting past a login puts the account's own data in the picture, and asking for a demo account does not hold that line: a person asked to sign in signs in as themselves. So the recorder looks. After the page opens and after every step it reads the text visible in the viewport and reports the KIND of thing it saw and where, never the string: an email address (one on `example.com` or a `.test`, `.example`, `.invalid` or `.localhost` domain is demo data and is not reported), something shaped like an API key or a JWT, a card number that passes the Luhn check, a masked card's visible tail. They land in `meta.exposures[]` (`step`, `kind`, `selector`, `rect`, `seen`), in the `record` and `create` done events, at the end of a rehearsal (before anything is recorded), as warnings in `vos validate <take>`, and in the digest's `take.exposures`. They warn; they do not fail a take, because a product may legitimately show addresses. The `selector` reaches that element and no other, so it can be pasted into a mask.
|
|
94
107
|
|
|
95
108
|
**`mask`** in `actions.json` hides a selector BEFORE the first frame is captured and keeps it hidden across navigations and re-renders, so the real value is never in a frame, never in the recording, never pushed:
|
|
@@ -101,8 +101,137 @@ function createReporter(json) {
|
|
|
101
101
|
};
|
|
102
102
|
}
|
|
103
103
|
|
|
104
|
+
// src/plugin/setup.ts
|
|
105
|
+
var VERBS = /* @__PURE__ */ new Set(["wait", "click", "type", "press", "goto"]);
|
|
106
|
+
function validateSetup(value) {
|
|
107
|
+
const errors = [];
|
|
108
|
+
if (!Array.isArray(value)) return ["setup must be an array of steps"];
|
|
109
|
+
value.forEach((raw, i) => {
|
|
110
|
+
const at2 = `setup[${i}]`;
|
|
111
|
+
if (typeof raw !== "object" || raw === null) {
|
|
112
|
+
errors.push(`${at2}: must be an object`);
|
|
113
|
+
return;
|
|
114
|
+
}
|
|
115
|
+
const s = raw;
|
|
116
|
+
if (typeof s.do !== "string" || !VERBS.has(s.do)) {
|
|
117
|
+
errors.push(`${at2}: "do" must be one of ${[...VERBS].join(", ")}`);
|
|
118
|
+
return;
|
|
119
|
+
}
|
|
120
|
+
if ((s.do === "click" || s.do === "type") && typeof s.selector !== "string")
|
|
121
|
+
errors.push(`${at2}: ${s.do} needs a selector`);
|
|
122
|
+
if (s.do === "wait" && typeof s.ms !== "number")
|
|
123
|
+
errors.push(`${at2}: wait needs ms`);
|
|
124
|
+
if (s.do === "press" && typeof s.key !== "string")
|
|
125
|
+
errors.push(`${at2}: press needs a key`);
|
|
126
|
+
if (s.do === "goto" && typeof s.url !== "string")
|
|
127
|
+
errors.push(`${at2}: goto needs a url`);
|
|
128
|
+
if (s.do === "type") {
|
|
129
|
+
const t = s.text;
|
|
130
|
+
const isEnv = typeof t === "object" && t !== null && typeof t.env === "string" && Object.keys(t).length === 1;
|
|
131
|
+
if (typeof t !== "string" && !isEnv)
|
|
132
|
+
errors.push(
|
|
133
|
+
`${at2}: type needs text, a string or { "env": "NAME" } read at run time`
|
|
134
|
+
);
|
|
135
|
+
if (typeof t === "string" && /passw|secret|token/i.test(String(s.selector)) && t.length > 0)
|
|
136
|
+
errors.push(
|
|
137
|
+
`${at2}: a literal value typed into ${String(s.selector)} would live in actions.json, which is committed and pushed. Use { "env": "NAME" }`
|
|
138
|
+
);
|
|
139
|
+
}
|
|
140
|
+
});
|
|
141
|
+
return errors;
|
|
142
|
+
}
|
|
143
|
+
function resolveSetupText(t, env = process.env) {
|
|
144
|
+
if (typeof t === "string") return { value: t, secret: false };
|
|
145
|
+
const v = env[t.env];
|
|
146
|
+
if (v === void 0 || v === "")
|
|
147
|
+
throw new SetupEnvError(
|
|
148
|
+
`setup: the environment variable ${t.env} is not set, and a type step reads it. Export it in the shell that runs vos record; it is never written to a file`
|
|
149
|
+
);
|
|
150
|
+
return { value: v, secret: true };
|
|
151
|
+
}
|
|
152
|
+
async function runSetup(page, steps, opts) {
|
|
153
|
+
const lines = [];
|
|
154
|
+
for (const [i, step] of steps.entries()) {
|
|
155
|
+
const settle = "ms" in step && typeof step.ms === "number" ? step.ms : 150;
|
|
156
|
+
try {
|
|
157
|
+
switch (step.do) {
|
|
158
|
+
case "wait":
|
|
159
|
+
await opts.sleep(step.ms);
|
|
160
|
+
lines.push(`setup #${i} wait ${step.ms}ms`);
|
|
161
|
+
break;
|
|
162
|
+
case "goto":
|
|
163
|
+
await page.goto(step.url, { waitUntil: "networkidle", timeout: 45e3 }).catch(() => {
|
|
164
|
+
});
|
|
165
|
+
lines.push(`setup #${i} goto ${step.url}`);
|
|
166
|
+
break;
|
|
167
|
+
case "press":
|
|
168
|
+
await page.keyboard.press(step.key);
|
|
169
|
+
await opts.sleep(settle);
|
|
170
|
+
lines.push(`setup #${i} press ${step.key}`);
|
|
171
|
+
break;
|
|
172
|
+
case "click": {
|
|
173
|
+
const loc = page.locator(step.selector).first();
|
|
174
|
+
await loc.waitFor({ state: "visible", timeout: 8e3 });
|
|
175
|
+
await loc.click();
|
|
176
|
+
await opts.sleep(settle);
|
|
177
|
+
lines.push(`setup #${i} click ${step.selector}`);
|
|
178
|
+
break;
|
|
179
|
+
}
|
|
180
|
+
case "type": {
|
|
181
|
+
const loc = page.locator(step.selector).first();
|
|
182
|
+
await loc.waitFor({ state: "visible", timeout: 8e3 });
|
|
183
|
+
const { value, secret } = resolveSetupText(step.text, opts.env);
|
|
184
|
+
await loc.fill(value);
|
|
185
|
+
await opts.sleep(settle);
|
|
186
|
+
lines.push(
|
|
187
|
+
`setup #${i} type ${secret ? `\${${step.text.env}}` : `${value.length} chars`} into ${step.selector}`
|
|
188
|
+
);
|
|
189
|
+
break;
|
|
190
|
+
}
|
|
191
|
+
}
|
|
192
|
+
} catch (e) {
|
|
193
|
+
if (e instanceof SetupEnvError) throw e;
|
|
194
|
+
return {
|
|
195
|
+
ran: i,
|
|
196
|
+
lines,
|
|
197
|
+
failed: {
|
|
198
|
+
step: i,
|
|
199
|
+
do: step.do,
|
|
200
|
+
..."selector" in step ? { selector: step.selector } : {}
|
|
201
|
+
}
|
|
202
|
+
};
|
|
203
|
+
}
|
|
204
|
+
}
|
|
205
|
+
return { ran: steps.length, lines };
|
|
206
|
+
}
|
|
207
|
+
var SetupEnvError = class extends Error {
|
|
208
|
+
constructor(message) {
|
|
209
|
+
super(message);
|
|
210
|
+
this.name = "SetupEnvError";
|
|
211
|
+
}
|
|
212
|
+
};
|
|
213
|
+
var SetupError = class extends Error {
|
|
214
|
+
constructor(failed2) {
|
|
215
|
+
super(
|
|
216
|
+
`setup #${failed2.step} ${failed2.do}${failed2.selector ? ` ${failed2.selector}` : ""}: the selector never appeared, so the take would begin at a half-finished setup. Nothing was recorded. Fix the setup step (rehearse with --dry-run), then record.`
|
|
217
|
+
);
|
|
218
|
+
this.failed = failed2;
|
|
219
|
+
this.name = "SetupError";
|
|
220
|
+
}
|
|
221
|
+
failed;
|
|
222
|
+
};
|
|
223
|
+
function parseHeaders(given) {
|
|
224
|
+
const out = {};
|
|
225
|
+
for (const h of given ?? []) {
|
|
226
|
+
const i = h.indexOf("=");
|
|
227
|
+
if (i <= 0) throw new Error(`--header wants name=value, got "${h}"`);
|
|
228
|
+
out[h.slice(0, i).trim()] = h.slice(i + 1);
|
|
229
|
+
}
|
|
230
|
+
return out;
|
|
231
|
+
}
|
|
232
|
+
|
|
104
233
|
// src/plugin/actions.ts
|
|
105
|
-
var
|
|
234
|
+
var VERBS2 = /* @__PURE__ */ new Set([
|
|
106
235
|
"wait",
|
|
107
236
|
"hover",
|
|
108
237
|
"click",
|
|
@@ -129,6 +258,7 @@ function validateActions(value) {
|
|
|
129
258
|
}
|
|
130
259
|
}
|
|
131
260
|
}
|
|
261
|
+
if (obj.setup !== void 0) errors.push(...validateSetup(obj.setup));
|
|
132
262
|
if (obj.mask !== void 0) {
|
|
133
263
|
if (!Array.isArray(obj.mask)) {
|
|
134
264
|
errors.push("mask must be an array of { selector, as?, text? }");
|
|
@@ -159,8 +289,8 @@ function validateActions(value) {
|
|
|
159
289
|
return;
|
|
160
290
|
}
|
|
161
291
|
const s = raw;
|
|
162
|
-
if (typeof s.do !== "string" || !
|
|
163
|
-
errors.push(`${at2}: "do" must be one of ${[...
|
|
292
|
+
if (typeof s.do !== "string" || !VERBS2.has(s.do)) {
|
|
293
|
+
errors.push(`${at2}: "do" must be one of ${[...VERBS2].join(", ")}`);
|
|
164
294
|
return;
|
|
165
295
|
}
|
|
166
296
|
if (s.id !== void 0) {
|
|
@@ -6994,7 +7124,8 @@ async function recordTake(browser, url, actions, paths, log, opts = {}) {
|
|
|
6994
7124
|
const context = await browser.newContext({
|
|
6995
7125
|
viewport: { width: vw, height: vh },
|
|
6996
7126
|
deviceScaleFactor: 1,
|
|
6997
|
-
...opts.storageState ? { storageState: opts.storageState } : {}
|
|
7127
|
+
...opts.storageState ? { storageState: opts.storageState } : {},
|
|
7128
|
+
...opts.headers && Object.keys(opts.headers).length ? { extraHTTPHeaders: opts.headers } : {}
|
|
6998
7129
|
});
|
|
6999
7130
|
const masks = actions.mask ?? [];
|
|
7000
7131
|
if (masks.length) await context.addInitScript(maskInitScript(masks));
|
|
@@ -7009,12 +7140,26 @@ async function recordTake(browser, url, actions, paths, log, opts = {}) {
|
|
|
7009
7140
|
});
|
|
7010
7141
|
log(`goto ${url}`);
|
|
7011
7142
|
let navTimeout = false;
|
|
7012
|
-
|
|
7143
|
+
let response = await page.goto(url, { waitUntil: "networkidle", timeout: 45e3 }).catch(() => {
|
|
7013
7144
|
navTimeout = true;
|
|
7014
7145
|
log(" (networkidle timeout \u2014 continuing)");
|
|
7015
7146
|
return null;
|
|
7016
7147
|
});
|
|
7017
7148
|
await sleep(800);
|
|
7149
|
+
const setup = actions.setup ?? [];
|
|
7150
|
+
if (setup.length) {
|
|
7151
|
+
log(`setup: ${setup.length} step(s), off camera`);
|
|
7152
|
+
const result = await runSetup(page, setup, { sleep: realSleep });
|
|
7153
|
+
for (const line of result.lines) log(` ${line}`);
|
|
7154
|
+
if (result.failed) {
|
|
7155
|
+
await context.close().catch(() => {
|
|
7156
|
+
});
|
|
7157
|
+
throw new SetupError(result.failed);
|
|
7158
|
+
}
|
|
7159
|
+
log(`goto ${url} (after setup)`);
|
|
7160
|
+
response = await page.goto(url, { waitUntil: "networkidle", timeout: 45e3 }).catch(() => null);
|
|
7161
|
+
await sleep(800);
|
|
7162
|
+
}
|
|
7018
7163
|
let wall = null;
|
|
7019
7164
|
if (opts.onArrival) {
|
|
7020
7165
|
const seen = await page.evaluate(WALL_PROBE).catch(() => null);
|
|
@@ -10518,12 +10663,12 @@ var BOOLEAN_FLAGS5 = /* @__PURE__ */ new Set([
|
|
|
10518
10663
|
"dry-run",
|
|
10519
10664
|
"allow-wall"
|
|
10520
10665
|
]);
|
|
10521
|
-
var MULTI_FLAGS2 = /* @__PURE__ */ new Set(["set", "override", "browser-arg"]);
|
|
10666
|
+
var MULTI_FLAGS2 = /* @__PURE__ */ new Set(["set", "override", "browser-arg", "header"]);
|
|
10522
10667
|
var HELP = `vos \u2014 record a browser flow, plan effects, render a product video; sync with vos.so
|
|
10523
10668
|
|
|
10524
10669
|
Take pipeline
|
|
10525
|
-
vos create --actions actions.json [--url <url>] [--out take] [out.webm] [--strict] [--allow-wall] [--keep-frames] [--max-duration <s>] [--storage-state <file>] [--browser-arg=<switch>]... [--background <slug|url|none>] [render flags] [--json]
|
|
10526
|
-
vos record --actions actions.json [--url <url>] [--out take] [--strict] [--dry-run] [--allow-wall] [--keep-frames] [--max-duration <s>] [--storage-state <file>] [--browser-arg=<switch>]... [--background <slug|url|none>] [--json]
|
|
10670
|
+
vos create --actions actions.json [--url <url>] [--out take] [out.webm] [--strict] [--allow-wall] [--keep-frames] [--max-duration <s>] [--storage-state <file>] [--header name=value]... [--browser-arg=<switch>]... [--background <slug|url|none>] [render flags] [--json]
|
|
10671
|
+
vos record --actions actions.json [--url <url>] [--out take] [--strict] [--dry-run] [--allow-wall] [--keep-frames] [--max-duration <s>] [--storage-state <file>] [--header name=value]... [--browser-arg=<switch>]... [--background <slug|url|none>] [--json]
|
|
10527
10672
|
vos plan <take> [--fresh] [--reuse [--from <doc.json>]] [--style <doc.json|vosId>] [--with <doc.json|vosId>[@end|@start|@step:<id>|@<s>]]... [--background <slug|url|none>] [--motion] [--headline "\u2026"] [--kicker "\u2026"] [--launch LAUNCH.md] [--brand BRAND.md] [--music <slug|mood|none>] [--entrance tilt-in|pull-out|rise|fade|slide|none] [--transitions slide|fade|scale|none] [--end-card on|none|<doc.json|vosId>] [--captions none] [--clicks none] [--still <t>] [--release v2.1] [--json]
|
|
10528
10673
|
vos render <take> [out.webm] [--width] [--height] [--fps] [--format webm|mp4] [--parallel N] [--range a..b] [--draft] [--frame <kind>] [--background <url|slug>] [--set <path=value>]... [--json]
|
|
10529
10674
|
vos frames <take> [--times 0,25%,50%,75%,100%] [--frame <t>] [--at-zooms] [--at-moments] [--at-still] [--size WxH] [--out dir] [--background <url|slug>] [--set <path=value>]... [--json]
|
|
@@ -10816,6 +10961,13 @@ function exposureNote(rec) {
|
|
|
10816
10961
|
${rec.exposures.map((e) => ` - ${exposureLine(e)}`).join("\n")}
|
|
10817
10962
|
${EXPOSURE_ADVICE}`;
|
|
10818
10963
|
}
|
|
10964
|
+
function takeHeaders(multi) {
|
|
10965
|
+
try {
|
|
10966
|
+
return parseHeaders(multi.header);
|
|
10967
|
+
} catch (e) {
|
|
10968
|
+
throw new UsageError(e instanceof Error ? e.message : String(e));
|
|
10969
|
+
}
|
|
10970
|
+
}
|
|
10819
10971
|
function takeBrowserArgs(multi) {
|
|
10820
10972
|
const given = multi["browser-arg"];
|
|
10821
10973
|
return (given ?? []).filter(Boolean);
|
|
@@ -10886,6 +11038,7 @@ async function cmdRecord(argv) {
|
|
|
10886
11038
|
const maxDurationSeconds = await maxDuration(flags, r);
|
|
10887
11039
|
const storageState = takeStorageState(flags);
|
|
10888
11040
|
const browserArgs = takeBrowserArgs(multi);
|
|
11041
|
+
const headers = takeHeaders(multi);
|
|
10889
11042
|
if (flags["dry-run"] === true) {
|
|
10890
11043
|
void flags.strict;
|
|
10891
11044
|
void flags["keep-frames"];
|
|
@@ -10902,6 +11055,7 @@ async function cmdRecord(argv) {
|
|
|
10902
11055
|
r.log,
|
|
10903
11056
|
{
|
|
10904
11057
|
storageState,
|
|
11058
|
+
headers,
|
|
10905
11059
|
dryRun: true,
|
|
10906
11060
|
// A rehearsal is always strict, and it touches no directory.
|
|
10907
11061
|
onArrival: wallGate(flags, r, { strict: true })
|
|
@@ -10917,6 +11071,7 @@ async function cmdRecord(argv) {
|
|
|
10917
11071
|
const carried = [
|
|
10918
11072
|
...strFlag(flags, "storage-state") ? [`--storage-state ${strFlag(flags, "storage-state")}`] : [],
|
|
10919
11073
|
...browserArgs.map((a) => `--browser-arg=${a}`),
|
|
11074
|
+
...Object.entries(headers).map(([k, v]) => `--header ${k}=${v}`),
|
|
10920
11075
|
...flags["allow-wall"] === true ? ["--allow-wall"] : []
|
|
10921
11076
|
].join(" ");
|
|
10922
11077
|
const nextOut = strFlag(flags, "out") ?? "take";
|
|
@@ -10958,6 +11113,7 @@ ${lines.join("\n")}
|
|
|
10958
11113
|
const rec = await recordTake(browser, url, actions, paths, r.log, {
|
|
10959
11114
|
maxDurationSeconds,
|
|
10960
11115
|
storageState,
|
|
11116
|
+
headers,
|
|
10961
11117
|
onArrival: wallGate(flags, r, {
|
|
10962
11118
|
strict: flags.strict === true,
|
|
10963
11119
|
prepare
|
|
@@ -11038,6 +11194,7 @@ async function cmdCreate2(argv) {
|
|
|
11038
11194
|
const maxDurationSeconds = await maxDuration(flags, r);
|
|
11039
11195
|
const storageState = takeStorageState(flags);
|
|
11040
11196
|
const browserArgs = takeBrowserArgs(multi);
|
|
11197
|
+
const headers = takeHeaders(multi);
|
|
11041
11198
|
const paths = takePaths(outDir);
|
|
11042
11199
|
const prepare = async () => {
|
|
11043
11200
|
if (existsSync15(join18(outDir, "meta.json"))) {
|
|
@@ -11056,6 +11213,7 @@ async function cmdCreate2(argv) {
|
|
|
11056
11213
|
const rec = await recordTake(browser, url, actions, paths, r.log, {
|
|
11057
11214
|
maxDurationSeconds,
|
|
11058
11215
|
storageState,
|
|
11216
|
+
headers,
|
|
11059
11217
|
onArrival: wallGate(flags, r, {
|
|
11060
11218
|
strict: flags.strict === true,
|
|
11061
11219
|
prepare
|
|
@@ -12196,6 +12354,11 @@ async function run(argv) {
|
|
|
12196
12354
|
} catch (e) {
|
|
12197
12355
|
if (e instanceof UsageError) {
|
|
12198
12356
|
process.stderr.write(`usage error: ${e.message}
|
|
12357
|
+
`);
|
|
12358
|
+
return EXIT_USAGE;
|
|
12359
|
+
}
|
|
12360
|
+
if (e instanceof SetupError || e instanceof SetupEnvError) {
|
|
12361
|
+
process.stderr.write(`${e.message}
|
|
12199
12362
|
`);
|
|
12200
12363
|
return EXIT_USAGE;
|
|
12201
12364
|
}
|
|
@@ -12248,4 +12411,4 @@ export {
|
|
|
12248
12411
|
verbHelp,
|
|
12249
12412
|
run
|
|
12250
12413
|
};
|
|
12251
|
-
//# sourceMappingURL=chunk-
|
|
12414
|
+
//# sourceMappingURL=chunk-6PJPGBKH.js.map
|