@bloom-perf/yaml-pptr 2.0.1 → 3.0.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 CHANGED
@@ -11,9 +11,11 @@
11
11
  ## Installation
12
12
 
13
13
  ```bash
14
- npm install @bloom-perf/yaml-pptr
14
+ npm install @bloom-perf/yaml-pptr puppeteer
15
15
  ```
16
16
 
17
+ `puppeteer` is a peer dependency (`^25.0.0`): your project controls its version.
18
+
17
19
  ## Quick Start
18
20
 
19
21
  ```typescript
@@ -108,7 +110,71 @@ readYamlAndInterpret(yaml)
108
110
  ### 3. Run it
109
111
 
110
112
  ```bash
111
- npx ts-node src/runner.ts
113
+ npx tsx src/runner.ts
114
+ ```
115
+
116
+ ## API Options
117
+
118
+ ```typescript
119
+ await readYamlAndInterpret(yaml, {
120
+ headless: true, // default: true
121
+ launchOptions: { // extra Puppeteer launch options, per browser
122
+ firefox: { executablePath: '/path/to/firefox' },
123
+ },
124
+ browsers: { chrome: myBrowser }, // reuse already launched browsers (not closed)
125
+ logger: myLogger,
126
+ onPage: async (page, ctx) => { /* page hook */ },
127
+ });
128
+ ```
129
+
130
+ | Option | Default | Description |
131
+ | ------ | ------- | ----------- |
132
+ | `headless` | `true` | Run launched browsers headless |
133
+ | `launchOptions` | `{}` | Puppeteer `LaunchOptions` per browser; `args` are appended to the defaults |
134
+ | `browsers` | `{}` | Pre-launched browsers to use instead of launching new ones |
135
+ | `logger` | console | Custom logger (`debug`, `info`, `warn`, `error`) |
136
+ | `onPage` | - | Callback invoked on every new page with `{ scenarioName, workerIndex, iteration }` |
137
+
138
+ ### Firefox
139
+
140
+ Puppeteer drives Firefox through WebDriver BiDi, which requires a recent Firefox. Install the version matching your Puppeteer release with:
141
+
142
+ ```bash
143
+ npx puppeteer browsers install firefox
144
+ ```
145
+
146
+ To use another Firefox installed on the machine, pass its path with `launchOptions.firefox.executablePath`.
147
+
148
+ ### Error handling
149
+
150
+ The configuration is fully checked before anything runs: YAML syntax, schema (an unknown key such as a typo is an error), and environment variables. If it is invalid, `readYamlAndInterpret` rejects with a `ConfigurationError` listing every problem with its location, and no browser page is opened:
151
+
152
+ ```text
153
+ ConfigurationError: Invalid scenario configuration:
154
+ ✖ Unrecognized key: "iteration"
155
+ → at scenarios[0]
156
+ ✖ Invalid input: expected int, received number
157
+ → at scenarios[0].workers
158
+ ```
159
+
160
+ Then every scenario, worker and iteration always runs to completion: a failed iteration does not stop the next iterations nor the other workers, and its page is always closed. If anything failed, `readYamlAndInterpret` then rejects with an `AggregateError` whose `errors` contain:
161
+
162
+ - `WorkerError` — an iteration failed (`scenarioName`, `workerIndex`, `iteration`, original error in `cause`)
163
+ - `BrowserLaunchError` — a browser could not be launched (`browser`, original error in `cause`)
164
+
165
+ ```typescript
166
+ import { readYamlAndInterpret, ConfigurationError } from '@bloom-perf/yaml-pptr';
167
+
168
+ try {
169
+ await readYamlAndInterpret(yaml);
170
+ } catch (e) {
171
+ if (e instanceof ConfigurationError) {
172
+ console.error(e.message); // invalid YAML, unknown key, missing variable...
173
+ } else if (e instanceof AggregateError) {
174
+ for (const err of e.errors) console.error(err.message); // WorkerError / BrowserLaunchError
175
+ }
176
+ process.exit(1);
177
+ }
112
178
  ```
113
179
 
114
180
  ## YAML Reference
@@ -119,13 +185,15 @@ npx ts-node src/runner.ts
119
185
  | -------- | ---- | ------- | ----------- |
120
186
  | `name` | string | `Scenario N` | Scenario name |
121
187
  | `browser` | `chrome` \| `firefox` | `chrome` | Browser to use |
122
- | `run` | `PARALLEL` \| `SEQUENTIAL` | `PARALLEL` | Worker start strategy |
123
- | `initialDelaySeconds` | number | `0` | Delay before starting |
124
- | `workers` | number | `1` | Number of parallel workers |
125
- | `iterations` | number | `1` | Repetitions per worker |
188
+ | `run` | `PARALLEL` \| `SEQUENTIAL` | `PARALLEL` | Worker start strategy: `PARALLEL` starts all workers after `initialDelaySeconds`; `SEQUENTIAL` starts worker *n* after *n* × `initialDelaySeconds` |
189
+ | `initialDelaySeconds` | number | `0` | Start delay, applied once per worker before its first iteration (see `run`) |
190
+ | `workers` | integer ≥ 1 | `1` | Number of parallel workers |
191
+ | `iterations` | integer ≥ 1 | `1` | Repetitions per worker |
126
192
  | `location` | string | - | Starting URL |
127
- | `steps` | array | - | Simplified syntax |
128
- | `actions` | array | - | Full syntax with options |
193
+ | `steps` | array | - | Simplified syntax (full actions are accepted too) |
194
+ | `actions` | array | - | Full syntax with options, run after `steps` |
195
+
196
+ All the scenarios of a file start at the same time, whatever their browser: each one is a population of users with its own `workers`, `iterations` and start strategy. Unknown keys are rejected (see [Error handling](#error-handling)).
129
197
 
130
198
  ### Steps (Simplified Syntax)
131
199
 
@@ -164,7 +232,17 @@ npx ts-node src/runner.ts
164
232
 
165
233
  ### Actions (Full Syntax)
166
234
 
167
- Use `actions` instead of `steps` when you need advanced options.
235
+ Use the full syntax when you need advanced options. Full actions can be listed in `actions` (run after `steps`), or written directly among `steps` to mix both syntaxes in the order you need:
236
+
237
+ ```yaml
238
+ steps:
239
+ - click: "#open-menu"
240
+ - type: WAIT_FOR_SELECTOR
241
+ selector: ".menu"
242
+ options:
243
+ visible: true
244
+ - click: ".menu .logout"
245
+ ```
168
246
 
169
247
  #### GOTO
170
248
 
@@ -248,6 +326,8 @@ Use `actions` instead of `steps` when you need advanced options.
248
326
  script: "document.title"
249
327
  ```
250
328
 
329
+ The script is never interpolated with environment variables (injecting values into code would be unsafe).
330
+
251
331
  #### SET_VIEWPORT
252
332
 
253
333
  ```yaml
@@ -262,6 +342,8 @@ Use `actions` instead of `steps` when you need advanced options.
262
342
  - type: PAUSE # Press Enter to continue
263
343
  ```
264
344
 
345
+ Meant for debugging in an interactive terminal. When there is none (CI, container, piped input), the PAUSE is ignored with a warning instead of blocking forever.
346
+
265
347
  #### CLOSE
266
348
 
267
349
  ```yaml
@@ -270,19 +352,37 @@ Use `actions` instead of `steps` when you need advanced options.
270
352
 
271
353
  ## Environment Variables
272
354
 
273
- Use `$VAR_NAME` syntax in `location` or `navigate`:
355
+ Keep URLs and credentials out of the YAML with `${VAR_NAME}` placeholders. They are resolved before anything runs: a missing variable is a `ConfigurationError`.
274
356
 
275
357
  ```yaml
276
- location: "$BASE_URL"
358
+ scenarios:
359
+ - name: Login
360
+ location: "${BASE_URL}/login"
361
+ steps:
362
+ - input:
363
+ selector: "#username"
364
+ text: "${APP_USER}"
365
+ - input:
366
+ selector: "#password"
367
+ text: "${APP_PASSWORD}"
368
+ - click: "#login-button"
277
369
  ```
278
370
 
279
371
  ```bash
280
- BASE_URL=https://example.com npx ts-node runner.ts
372
+ BASE_URL=https://example.com APP_USER=alice APP_PASSWORD=... npx tsx runner.ts
281
373
  ```
282
374
 
375
+ | Syntax | Where | Notes |
376
+ | ------ | ----- | ----- |
377
+ | `${VAR}` | Anywhere in `location`, `navigate`, GOTO `url`/`referer`, selectors, typed `text`, SCREENSHOT `path` | `$${` produces a literal `${` |
378
+ | `$VAR` | As the whole value of `location`, `navigate`, GOTO `url`, SCREENSHOT `path` | Elsewhere a `$` is kept as is (e.g. a password like `$ecret`) |
379
+ | `$VAR[workerIndex]` | As the whole value of `location`, `navigate` | One value per worker, see below |
380
+
381
+ `EVALUATE` scripts are never interpolated. Typed texts and resolved values are never logged.
382
+
283
383
  ### Indexed Variables
284
384
 
285
- Assign different values to each worker using `$VAR[workerIndex]`:
385
+ Assign different values to each worker using `$VAR[workerIndex]` (comma-separated values). There must be at least one non-empty value per worker, otherwise it is a `ConfigurationError`:
286
386
 
287
387
  ```yaml
288
388
  scenarios:
@@ -294,7 +394,7 @@ scenarios:
294
394
  ```
295
395
 
296
396
  ```bash
297
- URLS="https://site1.com,https://site2.com,https://site3.com" npx ts-node runner.ts
397
+ URLS="https://site1.com,https://site2.com,https://site3.com" npx tsx runner.ts
298
398
  ```
299
399
 
300
400
  Worker 0 gets `site1.com`, worker 1 gets `site2.com`, etc.
@@ -324,6 +424,9 @@ npm test
324
424
  # Run tests with coverage
325
425
  npm run test:coverage
326
426
 
427
+ # Type check
428
+ npm run typecheck
429
+
327
430
  # Build
328
431
  npm run build
329
432
  ```
@@ -0,0 +1,26 @@
1
+ /**
2
+ * Raised before anything runs when the configuration is invalid: YAML syntax,
3
+ * schema validation (unknown key, wrong type...) or environment variable
4
+ * resolution (missing variable, not enough per-worker values...).
5
+ */
6
+ export declare class ConfigurationError extends Error {
7
+ constructor(message: string, options?: ErrorOptions);
8
+ }
9
+ /**
10
+ * Raised when an iteration of a scenario worker fails. Carries the scenario
11
+ * name, the worker index and the iteration so the caller knows exactly where
12
+ * the failure happened.
13
+ */
14
+ export declare class WorkerError extends Error {
15
+ readonly scenarioName: string;
16
+ readonly workerIndex: number;
17
+ readonly iteration: number;
18
+ constructor(scenarioName: string, workerIndex: number, iteration: number, cause: unknown);
19
+ }
20
+ /**
21
+ * Raised when a browser could not be launched (missing binary, bad options...).
22
+ */
23
+ export declare class BrowserLaunchError extends Error {
24
+ readonly browser: string;
25
+ constructor(browser: string, cause: unknown);
26
+ }
@@ -103,7 +103,7 @@ export interface CloseAction extends BaseAction {
103
103
  }
104
104
  export interface EvaluateAction extends BaseAction {
105
105
  actionType: ActionType.Evaluate;
106
- script: string | ((...args: any[]) => any);
106
+ script: string;
107
107
  }
108
108
  export interface SetViewportAction extends BaseAction {
109
109
  actionType: ActionType.SetViewport;
package/dist/index.d.ts CHANGED
@@ -1,12 +1,32 @@
1
1
  import * as p from 'puppeteer';
2
- import { SupportedBrowser, OnPageCallback } from './core/model';
3
- import { YpLogger } from './core/logger';
4
- export type { ScenarioContext, OnPageCallback } from './core/model';
2
+ import { SupportedBrowser, OnPageCallback } from './core/model.js';
3
+ import { YpLogger } from './core/logger.js';
4
+ export type { ScenarioContext, OnPageCallback } from './core/model.js';
5
+ export { WorkerError, BrowserLaunchError, ConfigurationError } from './core/errors.js';
5
6
  export type ReadYamlOptions = {
7
+ /** Already launched browsers to use instead of launching new ones. They are not closed. */
6
8
  browsers?: {
7
9
  [key in SupportedBrowser]?: p.Browser;
8
10
  };
9
11
  logger?: YpLogger;
10
12
  onPage?: OnPageCallback;
13
+ /** Run launched browsers in headless mode. Defaults to `true`. */
14
+ headless?: boolean;
15
+ /** Extra Puppeteer launch options per browser (e.g. `executablePath`). `args` are appended to the defaults. */
16
+ launchOptions?: {
17
+ [key in SupportedBrowser]?: p.LaunchOptions;
18
+ };
11
19
  };
20
+ /**
21
+ * Parses and validates the YAML, resolves environment variables, then runs
22
+ * every scenario. All scenarios start at the same time (each one with its own
23
+ * workers and start strategy), whatever the browser they target.
24
+ *
25
+ * - An invalid configuration (YAML syntax, unknown key, missing environment
26
+ * variable...) rejects with a `ConfigurationError` before anything runs.
27
+ * - Otherwise all scenarios are always run to completion. If anything failed
28
+ * (browser launch or iteration), the promise rejects with an `AggregateError`
29
+ * whose `errors` are `BrowserLaunchError` / `WorkerError` instances, in
30
+ * scenario order.
31
+ */
12
32
  export declare const readYamlAndInterpret: (yamlContent: string, options?: ReadYamlOptions) => Promise<void>;
package/dist/index.js CHANGED
@@ -1 +1,2 @@
1
- "use strict";var L=Object.create;var w=Object.defineProperty;var B=Object.getOwnPropertyDescriptor;var j=Object.getOwnPropertyNames;var U=Object.getPrototypeOf,V=Object.prototype.hasOwnProperty;var _=(o,t)=>{for(var n in t)w(o,n,{get:t[n],enumerable:!0})},$=(o,t,n,i)=>{if(t&&typeof t=="object"||typeof t=="function")for(let r of j(t))!V.call(o,r)&&r!==n&&w(o,r,{get:()=>t[r],enumerable:!(i=B(t,r))||i.enumerable});return o};var z=(o,t,n)=>(n=o!=null?L(U(o)):{},$(t||!o||!o.__esModule?w(n,"default",{value:o,enumerable:!0}):n,o)),G=o=>$(w({},"__esModule",{value:!0}),o);var wt={};_(wt,{readYamlAndInterpret:()=>bt});module.exports=G(wt);var R=z(require("puppeteer"),1);var x=z(require("js-yaml"),1);var e=z(require("zod"),1),k=e.enum(["load","domcontentloaded","networkidle0","networkidle2"]),I=e.enum(["left","right","middle"]),N=e.enum(["chrome","firefox"]),M=e.object({timeout:e.number().optional(),waitUntil:e.union([k,k.array()]).optional(),referer:e.string().optional()}).optional(),D=e.object({type:e.literal("WAIT"),milliseconds:e.number()}),q=e.object({button:I.optional(),clickCount:e.number().optional(),delay:e.number().optional()}).optional(),H=e.object({delay:e.number().optional()}).optional(),K=e.object({visible:e.boolean().optional(),hidden:e.boolean().optional(),timeout:e.number().optional()}).optional(),J=e.object({type:e.enum(["png","jpeg"]).optional(),quality:e.number().optional(),fullPage:e.boolean().optional(),clip:e.object({x:e.number(),y:e.number(),width:e.number(),height:e.number()}).optional(),omitBackground:e.boolean().optional(),encoding:e.enum(["base64","binary"]).optional()}).optional(),Q=e.object({type:e.literal("GOTO"),url:e.string(),options:M}),Z=e.object({type:e.literal("CLICK"),selector:e.string(),options:q}),X=e.object({type:e.literal("TYPE"),selector:e.string(),text:e.string(),options:H}),Y=e.object({type:e.literal("WAIT_FOR_SELECTOR"),selector:e.string(),options:K}),tt=e.object({type:e.literal("WAIT_FOR_TIMEOUT"),timeout:e.number()}),et=e.object({type:e.literal("PAUSE")}),ot=e.object({type:e.literal("SCREENSHOT"),path:e.string(),options:J}),it=e.object({type:e.literal("EVALUATE"),script:e.union([e.string(),e.function()])}),nt=e.object({type:e.literal("SET_VIEWPORT"),width:e.number(),height:e.number()}),rt=e.object({type:e.literal("CLOSE")}),E=[Q,Z,X,Y,tt,et,ot,it,nt,rt,D];if(E.length===0)throw new Error("Le tableau des sch\xE9mas d'actions est vide.");var st=E,at=e.discriminatedUnion("type",st),ct=e.object({navigate:e.string()}),pt=e.literal("waitForever"),lt=e.object({wait:e.number()}),ut=e.object({click:e.string()}),gt=e.object({input:e.object({selector:e.string(),text:e.string()})}),mt=e.union([ct,pt,lt,ut,gt]),dt=e.object({name:e.string().optional(),browser:N.optional(),run:e.enum(["PARALLEL","SEQUENTIAL"]).optional(),initialDelaySeconds:e.number().nonnegative().optional(),workers:e.number().positive().optional(),iterations:e.number().positive().optional(),location:e.string().optional(),steps:e.array(mt).optional(),actions:e.array(at).optional()}),W=e.object({scenarios:e.array(dt)});var O=o=>{let t=x.load(o);return W.parse(t)};var A={debug(o){console.log(o)},info(o){console.log(o)},warn(o){console.log(o)},error(o){console.error(o)}};var v=class{envVarResolve;logger;constructor(t,n=A){this.envVarResolve=i=>{let r=i.startsWith("$")?i.substring(1):i;return t(r)},this.logger=n}resolve(t){return{scenarios:t.scenarios.map((n,i)=>this.resolveScenario(n,i+1))}}resolveScenario(t,n){this.logger.debug(`Resolving YAML scenario: ${JSON.stringify(t)}`);let i=[];t.location&&i.push(this.createNavigateAction(t.location)),t.steps&&i.push(...t.steps.map(s=>this.resolveStep(s))),t.actions&&i.push(...t.actions.map(s=>this.resolveAction(s)));let r=t.run==="SEQUENTIAL"?{delaySecondsBetweenWorkerInits:t.initialDelaySeconds||0}:{initialDelaySeconds:t.initialDelaySeconds||0};return{name:t.name||`Scenario ${n}`,browser:t.browser||"chrome",run:r,workers:t.workers||1,iterations:t.iterations||1,actions:i}}resolveStep(t){if(t==="waitForever")return this.logger.debug("Resolving step: waitForever"),{actionType:"WaitForever"};if("wait"in t)return this.logger.debug(`Resolving step: wait ${t.wait} seconds`),{actionType:"Wait",milliseconds:t.wait*1e3};if("navigate"in t)return this.logger.debug("Resolving step: navigate"),this.createNavigateAction(t.navigate);if("click"in t)return this.logger.debug(`Resolving step: click "${t.click}"`),{actionType:"CLICK",selector:t.click};if("input"in t)return this.logger.debug(`Resolving step: input into "${t.input.selector}"`),{actionType:"TYPE",selector:t.input.selector,text:t.input.text};throw new Error(`Unknown step format: ${JSON.stringify(t)}`)}resolveAction(t){switch(this.logger.debug(`Resolving action: ${JSON.stringify(t)}`),t.type){case"GOTO":return{actionType:"GOTO",url:this.resolveStringOrEnv(t.url),options:t.options};case"WAIT":return{actionType:"Wait",milliseconds:t.milliseconds*1e3};case"CLICK":return{actionType:"CLICK",selector:t.selector,options:t.options};case"TYPE":return{actionType:"TYPE",selector:t.selector,text:t.text,options:t.options};case"WAIT_FOR_SELECTOR":return{actionType:"WAIT_FOR_SELECTOR",selector:t.selector,options:t.options};case"WAIT_FOR_TIMEOUT":return{actionType:"WAIT_FOR_TIMEOUT",timeout:t.timeout};case"PAUSE":return{actionType:"PAUSE"};case"SCREENSHOT":return{actionType:"SCREENSHOT",path:this.resolveStringOrEnv(t.path),options:t.options};case"EVALUATE":return{actionType:"EVALUATE",script:t.script};case"SET_VIEWPORT":return{actionType:"SET_VIEWPORT",width:t.width,height:t.height};case"CLOSE":return{actionType:"CLOSE"};default:return t}}createNavigateAction(t){return{actionType:"Navigate",location:this.resolveUrlOrEnv(t)}}resolveUrlOrEnv(t){let n="[workerIndex]";if(t.startsWith("$")){if(t.endsWith(n)){this.logger.debug(`Resolving indexed environment variable: "${t}"`);let i=t.substring(1,t.length-n.length);return{workerIndex:this.envVarResolve(i).split(",").map(c=>c.trim())}}return this.logger.debug(`Resolving environment variable: "${t}"`),{url:this.envVarResolve(t.substring(1))}}return this.logger.debug(`Using direct URL: "${t}"`),{url:t}}resolveStringOrEnv(t){return t.startsWith("$")?(this.logger.debug(`Resolving environment variable: "${t}"`),this.envVarResolve(t.substring(1))):t}};function At(o,t){let n=t||"png";return o.endsWith(".png")||o.endsWith(".jpeg")||o.endsWith(".jpg")||o.endsWith(".webp")?o:`${o}.${n}`}var C=async(o,t,n=A,i)=>await yt(t.workers,t.name,async r=>{for(let s=0;s<t.iterations;s++){let c=t.run;"delaySecondsBetweenWorkerInits"in c?(n.info(`Scenario "${t.name}" (worker ${r}) > Choosing SEQUENTIAL start with ${c.delaySecondsBetweenWorkerInits} seconds between workers`),await new Promise(u=>setTimeout(u,c.delaySecondsBetweenWorkerInits*r*1e3))):(n.info(`Scenario "${t.name}" (worker ${r}) > Choosing PARALLEL start with ${c.initialDelaySeconds} seconds of initial delay`),await new Promise(u=>setTimeout(u,c.initialDelaySeconds*1e3)));let l=await o.newPage();i&&await i(l,{scenarioName:t.name,workerIndex:r,iteration:s}),await ht(t.name,t.actions,l,r,n),await l.close()}},n),yt=async(o,t,n,i=A)=>Promise.all(Array.from({length:o},async(r,s)=>{try{i.info(`Scenario "${t}" (worker ${s}) started.`),await n(s)}catch(c){i.error(`Scenario ${t} (worker ${s}) failed: ${c}`)}})),ht=async(o,t,n,i,r=A)=>{for(let s of t){let{actionType:c}=s;switch(c){case"Navigate":let l=s;"url"in l.location?(r.info(`Scenario "${o}" (worker ${i}) > Navigating to location "${l.location.url}"`),await n.goto(l.location.url)):(r.info(`Scenario "${o}" (worker ${i}) > Navigating to indexed location "${l.location.workerIndex[i]}"`),await n.goto(l.location.workerIndex[i]));break;case"Wait":let u=s;r.info(`Scenario "${o}" (worker ${i}) > Waiting ${u.milliseconds} milliseconds...`),await n.evaluate(y=>new Promise(T=>setTimeout(T,y)),u.milliseconds);break;case"WaitForever":for(r.info(`Scenario "${o}" (worker ${i}) > Waiting forever...`);;)await new Promise(y=>setTimeout(y,3600*1e3));break;case"GOTO":let d=s;r.info(`Scenario "${o}" (worker ${i}) > GOTO "${d.url}"`);let f={timeout:d.options?.timeout,waitUntil:d.options?.waitUntil,referer:d.options?.referer};await n.goto(d.url,f);break;case"CLICK":let a=s;r.info(`Scenario "${o}" (worker ${i}) > CLICK on "${a.selector}"`);let g={button:a.options?.button,clickCount:a.options?.clickCount,delay:a.options?.delay};await n.click(a.selector,g);break;case"TYPE":let S=s;r.info(`Scenario "${o}" (worker ${i}) > TYPE into "${S.selector}"`),await n.type(S.selector,S.text,S.options);break;case"WAIT_FOR_SELECTOR":let m=s;r.info(`Scenario "${o}" (worker ${i}) > WAIT_FOR_SELECTOR "${m.selector}"`),await n.waitForSelector(m.selector,m.options);break;case"WAIT_FOR_TIMEOUT":let h=s;r.info(`Scenario "${o}" (worker ${i}) > WAIT_FOR_TIMEOUT ${h.timeout} milliseconds`),await n.evaluate(y=>new Promise(T=>setTimeout(T,y)),h.timeout);break;case"PAUSE":r.info(`Scenario "${o}" (worker ${i}) > PAUSE, press Enter to continue...`),await new Promise(y=>{process.stdin.resume(),process.stdin.once("data",()=>{process.stdin.pause(),y()})});break;case"SCREENSHOT":let p=s;r.info(`Scenario "${o}" (worker ${i}) > SCREENSHOT "${p.path}"`);let P={path:At(p.path,p.options?.type),type:p.options?.type,quality:p.options?.quality,fullPage:p.options?.fullPage,clip:p.options?.clip,omitBackground:p.options?.omitBackground,encoding:p.options?.encoding};await n.screenshot(P);break;case"EVALUATE":let F=s;r.info(`Scenario "${o}" (worker ${i}) > EVALUATE script`),await n.evaluate(F.script);break;case"SET_VIEWPORT":let b=s;r.info(`Scenario "${o}" (worker ${i}) > SET_VIEWPORT width=${b.width}, height=${b.height}`),await n.setViewport({width:b.width,height:b.height});break;case"CLOSE":r.info(`Scenario "${o}" (worker ${i}) > CLOSE page`),await n.close();break;default:throw new Error(`Unhandled action type "${c}" while evaluating scenario "${o}" on worker ${i}`)}}};var bt=async(o,t={})=>{let{browsers:n={},logger:i=A,onPage:r}=t,s=O(o),l=new v(a=>{let g=process.env[a];if(i.debug(`Resolving env variable "${a}" with value ***`),g)return g;throw new Error(`Tried to resolve env variable ${a} but was empty.`)},i).resolve(s),u={};for(let a of l.scenarios){let g=a.browser||"chrome";u[g]||(u[g]=[]),u[g]?.push(a)}let d=["chrome","firefox"],f=Object.entries(u).map(async([a,g])=>{if(!g)return;if(!d.includes(a)){console.error(`Navigateur non support\xE9: ${a}. Les navigateurs support\xE9s sont: ${d.join(", ")}`);return}let S=["--no-sandbox","--disable-setuid-sandbox","--disable-dev-shm-usage","--disable-accelerated-2d-canvas","--disable-gpu","--ignore-certificate-errors"];a==="chrome"&&S.push("--start-maximized"),a==="firefox"&&S.push("--private");let m=n[a],h=!1;m||(m=await R.launch({headless:!1,channel:a,acceptInsecureCerts:!0,args:S}),h=!0);try{for(let p of g)await C(m,p,i,r)}catch(p){console.error(`Erreur lors de l'ex\xE9cution des sc\xE9narios pour ${a}:`,p)}finally{h&&m&&await m.close()}});await Promise.all(f)};0&&(module.exports={readYamlAndInterpret});
1
+ import*as B from"js-yaml";import*as F from"zod";import*as e from"zod";var b=e.number().int().nonnegative(),v=e.number().int().positive(),C=e.enum(["load","domcontentloaded","networkidle0","networkidle2"]),G=e.enum(["left","right","middle"]),N=e.enum(["chrome","firefox"]),M=e.strictObject({timeout:b.optional(),waitUntil:e.union([C,C.array()]).optional(),referer:e.string().optional()}).optional(),Z=e.strictObject({button:G.optional(),clickCount:v.optional(),delay:b.optional()}).optional(),D=e.strictObject({delay:b.optional()}).optional(),H=e.strictObject({visible:e.boolean().optional(),hidden:e.boolean().optional(),timeout:b.optional()}).optional(),K=e.strictObject({type:e.enum(["png","jpeg"]).optional(),quality:e.number().int().min(0).max(100).optional(),fullPage:e.boolean().optional(),clip:e.strictObject({x:e.number(),y:e.number(),width:e.number().positive(),height:e.number().positive()}).optional(),omitBackground:e.boolean().optional(),encoding:e.enum(["base64","binary"]).optional()}).optional(),q=e.strictObject({type:e.literal("GOTO"),url:e.string(),options:M}),Q=e.strictObject({type:e.literal("CLICK"),selector:e.string(),options:Z}),J=e.strictObject({type:e.literal("TYPE"),selector:e.string(),text:e.string(),options:D}),X=e.strictObject({type:e.literal("WAIT_FOR_SELECTOR"),selector:e.string(),options:H}),Y=e.strictObject({type:e.literal("WAIT_FOR_TIMEOUT"),timeout:b}),tt=e.strictObject({type:e.literal("WAIT"),milliseconds:b}),et=e.strictObject({type:e.literal("PAUSE")}),ot=e.strictObject({type:e.literal("SCREENSHOT"),path:e.string(),options:K}),rt=e.strictObject({type:e.literal("EVALUATE"),script:e.string()}),nt=e.strictObject({type:e.literal("SET_VIEWPORT"),width:v,height:v}),it=e.strictObject({type:e.literal("CLOSE")}),R=e.discriminatedUnion("type",[q,Q,J,X,Y,tt,et,ot,rt,nt,it]),st=e.strictObject({navigate:e.string()}),at=e.literal("waitForever"),ct=e.strictObject({wait:e.number().nonnegative()}),pt=e.strictObject({click:e.string()}),lt=e.strictObject({input:e.strictObject({selector:e.string(),text:e.string()})}),ut=e.union([st,at,ct,pt,lt,R]),gt=e.strictObject({name:e.string().optional(),browser:N.optional(),run:e.enum(["PARALLEL","SEQUENTIAL"]).optional(),initialDelaySeconds:e.number().nonnegative().optional(),workers:v.optional(),iterations:v.optional(),location:e.string().optional(),steps:e.array(ut).optional(),actions:e.array(R).optional()}),P=e.strictObject({scenarios:e.array(gt)});var L=r=>r instanceof Error?r.message:String(r),S=class extends Error{constructor(t,o){super(t,o),this.name="ConfigurationError"}},$=class extends Error{scenarioName;workerIndex;iteration;constructor(t,o,n,i){super(`Scenario "${t}" (worker ${o}, iteration ${n}) failed: ${L(i)}`,{cause:i}),this.name="WorkerError",this.scenarioName=t,this.workerIndex=o,this.iteration=n}},T=class extends Error{browser;constructor(t,o){super(`Failed to launch browser "${t}": ${L(o)}`,{cause:o}),this.name="BrowserLaunchError",this.browser=t}};var V=r=>{let t;try{t=B.load(r)}catch(n){throw new S(`Invalid YAML syntax: ${n instanceof Error?n.message:String(n)}`,{cause:n})}let o=P.safeParse(t);if(!o.success)throw new S(`Invalid scenario configuration:
2
+ ${F.prettifyError(o.error)}`,{cause:o.error});return o.data};var A={debug(r){console.log(r)},info(r){console.log(r)},warn(r){console.log(r)},error(r){console.error(r)}};var dt=/^[A-Za-z_][A-Za-z0-9_]*$/,ht=/^\$([A-Za-z_][A-Za-z0-9_]*)$/,wt=/^\$([A-Za-z_][A-Za-z0-9_]*)\[workerIndex\]$/,St=/\$\$\{|\$\{([^}]*)\}/g,_='per-worker values ("$VAR[workerIndex]") are only supported as the whole value of location and navigate',O=class{envVarResolve;logger;constructor(t,o=A){this.envVarResolve=t,this.logger=o}resolve(t){return{scenarios:t.scenarios.map((o,n)=>this.resolveScenario(o,n+1))}}resolveScenario(t,o){let n={name:t.name||`Scenario ${o}`,workers:t.workers||1};this.logger.debug(`Resolving scenario "${n.name}" (${t.steps?.length??0} step(s), ${t.actions?.length??0} action(s))`);let i=[];try{t.location&&i.push(this.createNavigateAction(t.location,n));for(let s of t.steps??[])i.push(this.resolveStep(s,n));for(let s of t.actions??[])i.push(this.resolveAction(s))}catch(s){throw new S(`Scenario "${n.name}": ${s instanceof Error?s.message:String(s)}`,{cause:s})}let a=t.run==="SEQUENTIAL"?{delaySecondsBetweenWorkerInits:t.initialDelaySeconds||0}:{initialDelaySeconds:t.initialDelaySeconds||0};return{name:n.name,browser:t.browser||"chrome",run:a,workers:n.workers,iterations:t.iterations||1,actions:i}}resolveStep(t,o){return t==="waitForever"?{actionType:"WaitForever"}:"type"in t?this.resolveAction(t):"wait"in t?{actionType:"Wait",milliseconds:t.wait*1e3}:"navigate"in t?this.createNavigateAction(t.navigate,o):"click"in t?{actionType:"CLICK",selector:this.interpolate(t.click)}:{actionType:"TYPE",selector:this.interpolate(t.input.selector),text:this.interpolate(t.input.text)}}resolveAction(t){switch(this.logger.debug(`Resolving action: ${t.type}`),t.type){case"GOTO":return{actionType:"GOTO",url:this.resolveWholeValueOrInterpolate(t.url),options:t.options&&{...t.options,referer:t.options.referer&&this.interpolate(t.options.referer)}};case"WAIT":return{actionType:"Wait",milliseconds:t.milliseconds};case"CLICK":return{actionType:"CLICK",selector:this.interpolate(t.selector),options:t.options};case"TYPE":return{actionType:"TYPE",selector:this.interpolate(t.selector),text:this.interpolate(t.text),options:t.options};case"WAIT_FOR_SELECTOR":return{actionType:"WAIT_FOR_SELECTOR",selector:this.interpolate(t.selector),options:t.options};case"WAIT_FOR_TIMEOUT":return{actionType:"WAIT_FOR_TIMEOUT",timeout:t.timeout};case"PAUSE":return{actionType:"PAUSE"};case"SCREENSHOT":return{actionType:"SCREENSHOT",path:this.resolveWholeValueOrInterpolate(t.path),options:t.options};case"EVALUATE":return{actionType:"EVALUATE",script:t.script};case"SET_VIEWPORT":return{actionType:"SET_VIEWPORT",width:t.width,height:t.height};case"CLOSE":return{actionType:"CLOSE"};default:return t}}createNavigateAction(t,o){let n=wt.exec(t);if(n){let i=n[1],a=this.env(i).split(",").map(s=>s.trim());if(a.some(s=>s===""))throw new Error(`environment variable "${i}" (used as "${t}") contains an empty value`);if(a.length<o.workers)throw new Error(`environment variable "${i}" (used as "${t}") provides ${a.length} value(s) for ${o.workers} worker(s)`);return{actionType:"Navigate",location:{workerIndex:a}}}return{actionType:"Navigate",location:{url:this.resolveWholeValueOrInterpolate(t)}}}resolveWholeValueOrInterpolate(t){let o=ht.exec(t);if(o)return this.env(o[1]);if(/^\$[A-Za-z_]/.test(t))throw new Error(`unsupported environment variable reference "${t}": use "$VAR" for the whole value or "\${VAR}" inside a value`+(t.endsWith("[workerIndex]")?`; ${_}`:""));return this.interpolate(t)}interpolate(t){return t.replace(St,(o,n)=>{if(o==="$${")return"${";if(n===void 0||!dt.test(n))throw new Error(`invalid placeholder "${o}": expected \${VAR_NAME}`+(n?.endsWith("[workerIndex]")?`; ${_}`:""));return this.env(n)})}env(t){return this.logger.debug(`Resolving environment variable "${t}"`),this.envVarResolve(t)}};import{setTimeout as k}from"node:timers/promises";function yt(r,t){let o=t||"png";return r.endsWith(".png")||r.endsWith(".jpeg")||r.endsWith(".jpg")||r.endsWith(".webp")?r:`${r}.${o}`}var At=(r,t)=>"delaySecondsBetweenWorkerInits"in r?r.delaySecondsBetweenWorkerInits*t:r.initialDelaySeconds,j=async(r,t,o=A,n)=>{let i=[],a=async s=>{let p=At(t.run,s),h="delaySecondsBetweenWorkerInits"in t.run?"SEQUENTIAL":"PARALLEL";o.info(`Scenario "${t.name}" (worker ${s}) started (${h}, starting in ${p}s).`),await k(p*1e3);for(let u=0;u<t.iterations;u++)try{await ft(r,t,s,u,o,n)}catch(y){let m=new $(t.name,s,u,y);o.error(m.message),i.push(m)}};if(await Promise.all(Array.from({length:t.workers},(s,p)=>a(p))),i.length>0){i.sort((p,h)=>p.workerIndex-h.workerIndex||p.iteration-h.iteration);let s=t.workers*t.iterations;throw new AggregateError(i,`Scenario "${t.name}": ${i.length}/${s} iteration(s) failed`)}},ft=async(r,t,o,n,i,a)=>{let s;try{s=await r.newPage(),a&&await a(s,{scenarioName:t.name,workerIndex:o,iteration:n}),await bt(t.name,t.actions,s,o,i)}finally{s&&!s.isClosed()&&await s.close().catch(p=>i.warn(`Scenario "${t.name}" (worker ${o}, iteration ${n}) > failed to close page: ${p}`))}},bt=async(r,t,o,n,i=A)=>{for(let a of t){let{actionType:s}=a;switch(s){case"Navigate":let p=a;"url"in p.location?(i.info(`Scenario "${r}" (worker ${n}) > Navigating to location "${p.location.url}"`),await o.goto(p.location.url)):(i.info(`Scenario "${r}" (worker ${n}) > Navigating to indexed location "${p.location.workerIndex[n]}"`),await o.goto(p.location.workerIndex[n]));break;case"Wait":let h=a;i.info(`Scenario "${r}" (worker ${n}) > Waiting ${h.milliseconds} milliseconds...`),await k(h.milliseconds);break;case"WaitForever":for(i.info(`Scenario "${r}" (worker ${n}) > Waiting forever...`);;)await k(3600*1e3);break;case"GOTO":let u=a;i.info(`Scenario "${r}" (worker ${n}) > GOTO "${u.url}"`);let y={timeout:u.options?.timeout,waitUntil:u.options?.waitUntil,referer:u.options?.referer};await o.goto(u.url,y);break;case"CLICK":let m=a;i.info(`Scenario "${r}" (worker ${n}) > CLICK on "${m.selector}"`);let W={button:m.options?.button,clickCount:m.options?.clickCount,delay:m.options?.delay};await o.click(m.selector,W);break;case"TYPE":let w=a;i.info(`Scenario "${r}" (worker ${n}) > TYPE into "${w.selector}"`),await o.type(w.selector,w.text,w.options);break;case"WAIT_FOR_SELECTOR":let c=a;i.info(`Scenario "${r}" (worker ${n}) > WAIT_FOR_SELECTOR "${c.selector}"`),await o.waitForSelector(c.selector,c.options);break;case"WAIT_FOR_TIMEOUT":let g=a;i.info(`Scenario "${r}" (worker ${n}) > WAIT_FOR_TIMEOUT ${g.timeout} milliseconds`),await k(g.timeout);break;case"PAUSE":if(!process.stdin.isTTY){i.warn(`Scenario "${r}" (worker ${n}) > PAUSE ignored: no interactive terminal`);break}i.info(`Scenario "${r}" (worker ${n}) > PAUSE, press Enter to continue...`),await new Promise(f=>{process.stdin.resume(),process.stdin.once("data",()=>{process.stdin.pause(),f()})});break;case"SCREENSHOT":let l=a;i.info(`Scenario "${r}" (worker ${n}) > SCREENSHOT "${l.path}"`);let z={path:yt(l.path,l.options?.type),type:l.options?.type,quality:l.options?.quality,fullPage:l.options?.fullPage,clip:l.options?.clip,omitBackground:l.options?.omitBackground,encoding:l.options?.encoding};await o.screenshot(z);break;case"EVALUATE":let E=a;i.info(`Scenario "${r}" (worker ${n}) > EVALUATE script`),await o.evaluate(E.script);break;case"SET_VIEWPORT":let d=a;i.info(`Scenario "${r}" (worker ${n}) > SET_VIEWPORT width=${d.width}, height=${d.height}`),await o.setViewport({width:d.width,height:d.height});break;case"CLOSE":i.info(`Scenario "${r}" (worker ${n}) > CLOSE page`),await o.close();break;default:throw new Error(`Unhandled action type "${s}" while evaluating scenario "${r}" on worker ${n}`)}}};import*as I from"puppeteer";var vt=(r,t)=>{if(r==="firefox")return[];let o=["--no-sandbox","--disable-setuid-sandbox","--disable-dev-shm-usage","--disable-accelerated-2d-canvas","--disable-gpu","--ignore-certificate-errors"];return t||o.push("--start-maximized"),o},$t=(r,t,o={})=>({browser:r,headless:t,acceptInsecureCerts:!0,...o,args:[...vt(r,t),...o.args??[]]}),U=(r,t,o)=>I.launch($t(r,t,o));var he=async(r,t={})=>{let{browsers:o={},logger:n=A,onPage:i,headless:a=!0,launchOptions:s={}}=t,p=V(r),u=new O(c=>{let g=process.env[c];if(g)return g;throw new Error(`environment variable "${c}" is not set (or empty)`)},n).resolve(p),y=new Map;for(let c of u.scenarios){let g=y.get(c.browser)??[];g.push(c),y.set(c.browser,g)}let m=async(c,g)=>{let l=o[c],z=!l;if(!l)try{n.info(`Launching ${c} (headless: ${a})`),l=await U(c,a,s[c])}catch(d){let f=new T(c,d);return n.error(f.message),[f]}let E=l;try{return(await Promise.all(g.map(async f=>{try{return await j(E,f,n,i),[]}catch(x){return x instanceof AggregateError?x.errors:[x]}}))).flat()}finally{z&&await E.close().catch(d=>n.warn(`Failed to close ${c}: ${d}`))}},w=(await Promise.all([...y].map(([c,g])=>m(c,g)))).flat();if(w.length>0)throw new AggregateError(w,`${w.length} error(s) occurred while running scenarios`)};export{T as BrowserLaunchError,S as ConfigurationError,$ as WorkerError,he as readYamlAndInterpret};
@@ -1,4 +1,10 @@
1
1
  import * as p from 'puppeteer';
2
- import { YpLogger } from '../core/logger';
3
- import { OnPageCallback, Scenario } from '../core/model';
4
- export declare const evalScenario: (browser: p.Browser, scenario: Scenario, logger?: YpLogger, onPage?: OnPageCallback) => Promise<void[]>;
2
+ import { YpLogger } from '../core/logger.js';
3
+ import { OnPageCallback, Scenario } from '../core/model.js';
4
+ /**
5
+ * Runs every worker of the scenario, each one running all its iterations.
6
+ * A failing iteration interrupts neither the next iterations of the worker
7
+ * nor the other workers. Once everything is done, the promise rejects with an
8
+ * `AggregateError` of `WorkerError` (one per failed iteration) if anything failed.
9
+ */
10
+ export declare const evalScenario: (browser: p.Browser, scenario: Scenario, logger?: YpLogger, onPage?: OnPageCallback) => Promise<void>;
@@ -0,0 +1,9 @@
1
+ import * as p from 'puppeteer';
2
+ import { SupportedBrowser } from '../core/model.js';
3
+ /**
4
+ * Builds Puppeteer launch options for the given browser. The browser is
5
+ * selected with `browser` (not `channel`, which only accepts Chrome release
6
+ * channels). User options override defaults; user `args` are appended.
7
+ */
8
+ export declare const buildLaunchOptions: (browser: SupportedBrowser, headless: boolean, extra?: p.LaunchOptions) => p.LaunchOptions;
9
+ export declare const launchBrowser: (browser: SupportedBrowser, headless: boolean, extra?: p.LaunchOptions) => Promise<p.Browser>;
@@ -1,2 +1,2 @@
1
- import { RootYaml } from './validator';
1
+ import { RootYaml } from './validator.js';
2
2
  export declare const parseYaml: (yamlContent: string) => RootYaml;
@@ -1,10 +1,19 @@
1
- import { YpLogger } from '../core/logger';
2
- import { Scenario } from '../core/model';
3
- import { RootYaml } from './validator';
4
- type EnvVarResolve = (arg: string) => string;
1
+ import { YpLogger } from '../core/logger.js';
2
+ import { Scenario } from '../core/model.js';
3
+ import { RootYaml } from './validator.js';
4
+ type EnvVarResolve = (name: string) => string;
5
+ /**
6
+ * Transforms the validated YAML into the domain model and resolves
7
+ * environment variables:
8
+ * - `${VAR}` anywhere in URLs, selectors, typed texts and screenshot paths;
9
+ * - `$VAR` as the whole value of location, navigate, GOTO url and SCREENSHOT path;
10
+ * - `$VAR[workerIndex]` as the whole value of location and navigate.
11
+ *
12
+ * Resolved values are never logged: they may contain credentials.
13
+ */
5
14
  export declare class Resolver {
6
- private envVarResolve;
7
- private logger;
15
+ private readonly envVarResolve;
16
+ private readonly logger;
8
17
  constructor(envVarResolve: EnvVarResolve, logger?: YpLogger);
9
18
  resolve(yaml: RootYaml): {
10
19
  scenarios: Scenario[];
@@ -13,7 +22,10 @@ export declare class Resolver {
13
22
  private resolveStep;
14
23
  private resolveAction;
15
24
  private createNavigateAction;
16
- private resolveUrlOrEnv;
17
- private resolveStringOrEnv;
25
+ /** `$VAR` as the whole value, or `${VAR}` placeholders anywhere. */
26
+ private resolveWholeValueOrInterpolate;
27
+ /** Replaces `${VAR}` placeholders; `$${` produces a literal `${`. */
28
+ private interpolate;
29
+ private env;
18
30
  }
19
31
  export {};
@@ -1,64 +1,64 @@
1
1
  import * as z from 'zod';
2
2
  declare const actionSchema: z.ZodDiscriminatedUnion<[z.ZodObject<{
3
- type: z.ZodLiteral<"WAIT">;
4
- milliseconds: z.ZodNumber;
5
- }, z.core.$strip> | z.ZodObject<{
6
3
  type: z.ZodLiteral<"GOTO">;
7
4
  url: z.ZodString;
8
5
  options: z.ZodOptional<z.ZodObject<{
9
6
  timeout: z.ZodOptional<z.ZodNumber>;
10
7
  waitUntil: z.ZodOptional<z.ZodUnion<readonly [z.ZodEnum<{
11
- load: "load";
12
8
  domcontentloaded: "domcontentloaded";
9
+ load: "load";
13
10
  networkidle0: "networkidle0";
14
11
  networkidle2: "networkidle2";
15
12
  }>, z.ZodArray<z.ZodEnum<{
16
- load: "load";
17
13
  domcontentloaded: "domcontentloaded";
14
+ load: "load";
18
15
  networkidle0: "networkidle0";
19
16
  networkidle2: "networkidle2";
20
17
  }>>]>>;
21
18
  referer: z.ZodOptional<z.ZodString>;
22
- }, z.core.$strip>>;
23
- }, z.core.$strip> | z.ZodObject<{
19
+ }, z.core.$strict>>;
20
+ }, z.core.$strict>, z.ZodObject<{
24
21
  type: z.ZodLiteral<"CLICK">;
25
22
  selector: z.ZodString;
26
23
  options: z.ZodOptional<z.ZodObject<{
27
24
  button: z.ZodOptional<z.ZodEnum<{
28
25
  left: "left";
29
- right: "right";
30
26
  middle: "middle";
27
+ right: "right";
31
28
  }>>;
32
29
  clickCount: z.ZodOptional<z.ZodNumber>;
33
30
  delay: z.ZodOptional<z.ZodNumber>;
34
- }, z.core.$strip>>;
35
- }, z.core.$strip> | z.ZodObject<{
31
+ }, z.core.$strict>>;
32
+ }, z.core.$strict>, z.ZodObject<{
36
33
  type: z.ZodLiteral<"TYPE">;
37
34
  selector: z.ZodString;
38
35
  text: z.ZodString;
39
36
  options: z.ZodOptional<z.ZodObject<{
40
37
  delay: z.ZodOptional<z.ZodNumber>;
41
- }, z.core.$strip>>;
42
- }, z.core.$strip> | z.ZodObject<{
38
+ }, z.core.$strict>>;
39
+ }, z.core.$strict>, z.ZodObject<{
43
40
  type: z.ZodLiteral<"WAIT_FOR_SELECTOR">;
44
41
  selector: z.ZodString;
45
42
  options: z.ZodOptional<z.ZodObject<{
46
43
  visible: z.ZodOptional<z.ZodBoolean>;
47
44
  hidden: z.ZodOptional<z.ZodBoolean>;
48
45
  timeout: z.ZodOptional<z.ZodNumber>;
49
- }, z.core.$strip>>;
50
- }, z.core.$strip> | z.ZodObject<{
46
+ }, z.core.$strict>>;
47
+ }, z.core.$strict>, z.ZodObject<{
51
48
  type: z.ZodLiteral<"WAIT_FOR_TIMEOUT">;
52
49
  timeout: z.ZodNumber;
53
- }, z.core.$strip> | z.ZodObject<{
50
+ }, z.core.$strict>, z.ZodObject<{
51
+ type: z.ZodLiteral<"WAIT">;
52
+ milliseconds: z.ZodNumber;
53
+ }, z.core.$strict>, z.ZodObject<{
54
54
  type: z.ZodLiteral<"PAUSE">;
55
- }, z.core.$strip> | z.ZodObject<{
55
+ }, z.core.$strict>, z.ZodObject<{
56
56
  type: z.ZodLiteral<"SCREENSHOT">;
57
57
  path: z.ZodString;
58
58
  options: z.ZodOptional<z.ZodObject<{
59
59
  type: z.ZodOptional<z.ZodEnum<{
60
- png: "png";
61
60
  jpeg: "jpeg";
61
+ png: "png";
62
62
  }>>;
63
63
  quality: z.ZodOptional<z.ZodNumber>;
64
64
  fullPage: z.ZodOptional<z.ZodBoolean>;
@@ -67,82 +67,95 @@ declare const actionSchema: z.ZodDiscriminatedUnion<[z.ZodObject<{
67
67
  y: z.ZodNumber;
68
68
  width: z.ZodNumber;
69
69
  height: z.ZodNumber;
70
- }, z.core.$strip>>;
70
+ }, z.core.$strict>>;
71
71
  omitBackground: z.ZodOptional<z.ZodBoolean>;
72
72
  encoding: z.ZodOptional<z.ZodEnum<{
73
73
  base64: "base64";
74
74
  binary: "binary";
75
75
  }>>;
76
- }, z.core.$strip>>;
77
- }, z.core.$strip> | z.ZodObject<{
76
+ }, z.core.$strict>>;
77
+ }, z.core.$strict>, z.ZodObject<{
78
78
  type: z.ZodLiteral<"EVALUATE">;
79
- script: z.ZodUnion<readonly [z.ZodString, z.ZodFunction<z.core.$ZodFunctionArgs, z.core.$ZodFunctionOut>]>;
80
- }, z.core.$strip> | z.ZodObject<{
79
+ script: z.ZodString;
80
+ }, z.core.$strict>, z.ZodObject<{
81
81
  type: z.ZodLiteral<"SET_VIEWPORT">;
82
82
  width: z.ZodNumber;
83
83
  height: z.ZodNumber;
84
- }, z.core.$strip> | z.ZodObject<{
84
+ }, z.core.$strict>, z.ZodObject<{
85
85
  type: z.ZodLiteral<"CLOSE">;
86
- }, z.core.$strip>, ...(z.ZodObject<{
87
- type: z.ZodLiteral<"WAIT">;
88
- milliseconds: z.ZodNumber;
89
- }, z.core.$strip> | z.ZodObject<{
86
+ }, z.core.$strict>], "type">;
87
+ export type ActionYaml = z.infer<typeof actionSchema>;
88
+ declare const stepSchema: z.ZodUnion<readonly [z.ZodObject<{
89
+ navigate: z.ZodString;
90
+ }, z.core.$strict>, z.ZodLiteral<"waitForever">, z.ZodObject<{
91
+ wait: z.ZodNumber;
92
+ }, z.core.$strict>, z.ZodObject<{
93
+ click: z.ZodString;
94
+ }, z.core.$strict>, z.ZodObject<{
95
+ input: z.ZodObject<{
96
+ selector: z.ZodString;
97
+ text: z.ZodString;
98
+ }, z.core.$strict>;
99
+ }, z.core.$strict>, z.ZodDiscriminatedUnion<[z.ZodObject<{
90
100
  type: z.ZodLiteral<"GOTO">;
91
101
  url: z.ZodString;
92
102
  options: z.ZodOptional<z.ZodObject<{
93
103
  timeout: z.ZodOptional<z.ZodNumber>;
94
104
  waitUntil: z.ZodOptional<z.ZodUnion<readonly [z.ZodEnum<{
95
- load: "load";
96
105
  domcontentloaded: "domcontentloaded";
106
+ load: "load";
97
107
  networkidle0: "networkidle0";
98
108
  networkidle2: "networkidle2";
99
109
  }>, z.ZodArray<z.ZodEnum<{
100
- load: "load";
101
110
  domcontentloaded: "domcontentloaded";
111
+ load: "load";
102
112
  networkidle0: "networkidle0";
103
113
  networkidle2: "networkidle2";
104
114
  }>>]>>;
105
115
  referer: z.ZodOptional<z.ZodString>;
106
- }, z.core.$strip>>;
107
- }, z.core.$strip> | z.ZodObject<{
116
+ }, z.core.$strict>>;
117
+ }, z.core.$strict>, z.ZodObject<{
108
118
  type: z.ZodLiteral<"CLICK">;
109
119
  selector: z.ZodString;
110
120
  options: z.ZodOptional<z.ZodObject<{
111
121
  button: z.ZodOptional<z.ZodEnum<{
112
122
  left: "left";
113
- right: "right";
114
123
  middle: "middle";
124
+ right: "right";
115
125
  }>>;
116
126
  clickCount: z.ZodOptional<z.ZodNumber>;
117
127
  delay: z.ZodOptional<z.ZodNumber>;
118
- }, z.core.$strip>>;
119
- }, z.core.$strip> | z.ZodObject<{
128
+ }, z.core.$strict>>;
129
+ }, z.core.$strict>, z.ZodObject<{
120
130
  type: z.ZodLiteral<"TYPE">;
121
131
  selector: z.ZodString;
122
132
  text: z.ZodString;
123
133
  options: z.ZodOptional<z.ZodObject<{
124
134
  delay: z.ZodOptional<z.ZodNumber>;
125
- }, z.core.$strip>>;
126
- }, z.core.$strip> | z.ZodObject<{
135
+ }, z.core.$strict>>;
136
+ }, z.core.$strict>, z.ZodObject<{
127
137
  type: z.ZodLiteral<"WAIT_FOR_SELECTOR">;
128
138
  selector: z.ZodString;
129
139
  options: z.ZodOptional<z.ZodObject<{
130
140
  visible: z.ZodOptional<z.ZodBoolean>;
131
141
  hidden: z.ZodOptional<z.ZodBoolean>;
132
142
  timeout: z.ZodOptional<z.ZodNumber>;
133
- }, z.core.$strip>>;
134
- }, z.core.$strip> | z.ZodObject<{
143
+ }, z.core.$strict>>;
144
+ }, z.core.$strict>, z.ZodObject<{
135
145
  type: z.ZodLiteral<"WAIT_FOR_TIMEOUT">;
136
146
  timeout: z.ZodNumber;
137
- }, z.core.$strip> | z.ZodObject<{
147
+ }, z.core.$strict>, z.ZodObject<{
148
+ type: z.ZodLiteral<"WAIT">;
149
+ milliseconds: z.ZodNumber;
150
+ }, z.core.$strict>, z.ZodObject<{
138
151
  type: z.ZodLiteral<"PAUSE">;
139
- }, z.core.$strip> | z.ZodObject<{
152
+ }, z.core.$strict>, z.ZodObject<{
140
153
  type: z.ZodLiteral<"SCREENSHOT">;
141
154
  path: z.ZodString;
142
155
  options: z.ZodOptional<z.ZodObject<{
143
156
  type: z.ZodOptional<z.ZodEnum<{
144
- png: "png";
145
157
  jpeg: "jpeg";
158
+ png: "png";
146
159
  }>>;
147
160
  quality: z.ZodOptional<z.ZodNumber>;
148
161
  fullPage: z.ZodOptional<z.ZodBoolean>;
@@ -151,36 +164,23 @@ declare const actionSchema: z.ZodDiscriminatedUnion<[z.ZodObject<{
151
164
  y: z.ZodNumber;
152
165
  width: z.ZodNumber;
153
166
  height: z.ZodNumber;
154
- }, z.core.$strip>>;
167
+ }, z.core.$strict>>;
155
168
  omitBackground: z.ZodOptional<z.ZodBoolean>;
156
169
  encoding: z.ZodOptional<z.ZodEnum<{
157
170
  base64: "base64";
158
171
  binary: "binary";
159
172
  }>>;
160
- }, z.core.$strip>>;
161
- }, z.core.$strip> | z.ZodObject<{
173
+ }, z.core.$strict>>;
174
+ }, z.core.$strict>, z.ZodObject<{
162
175
  type: z.ZodLiteral<"EVALUATE">;
163
- script: z.ZodUnion<readonly [z.ZodString, z.ZodFunction<z.core.$ZodFunctionArgs, z.core.$ZodFunctionOut>]>;
164
- }, z.core.$strip> | z.ZodObject<{
176
+ script: z.ZodString;
177
+ }, z.core.$strict>, z.ZodObject<{
165
178
  type: z.ZodLiteral<"SET_VIEWPORT">;
166
179
  width: z.ZodNumber;
167
180
  height: z.ZodNumber;
168
- }, z.core.$strip> | z.ZodObject<{
181
+ }, z.core.$strict>, z.ZodObject<{
169
182
  type: z.ZodLiteral<"CLOSE">;
170
- }, z.core.$strip>)[]], "type">;
171
- export type ActionYaml = z.infer<typeof actionSchema>;
172
- declare const stepSchema: z.ZodUnion<readonly [z.ZodObject<{
173
- navigate: z.ZodString;
174
- }, z.core.$strip>, z.ZodLiteral<"waitForever">, z.ZodObject<{
175
- wait: z.ZodNumber;
176
- }, z.core.$strip>, z.ZodObject<{
177
- click: z.ZodString;
178
- }, z.core.$strip>, z.ZodObject<{
179
- input: z.ZodObject<{
180
- selector: z.ZodString;
181
- text: z.ZodString;
182
- }, z.core.$strip>;
183
- }, z.core.$strip>]>;
183
+ }, z.core.$strict>], "type">]>;
184
184
  export type StepYaml = z.infer<typeof stepSchema>;
185
185
  declare const scenarioSchema: z.ZodObject<{
186
186
  name: z.ZodOptional<z.ZodString>;
@@ -198,76 +198,75 @@ declare const scenarioSchema: z.ZodObject<{
198
198
  location: z.ZodOptional<z.ZodString>;
199
199
  steps: z.ZodOptional<z.ZodArray<z.ZodUnion<readonly [z.ZodObject<{
200
200
  navigate: z.ZodString;
201
- }, z.core.$strip>, z.ZodLiteral<"waitForever">, z.ZodObject<{
201
+ }, z.core.$strict>, z.ZodLiteral<"waitForever">, z.ZodObject<{
202
202
  wait: z.ZodNumber;
203
- }, z.core.$strip>, z.ZodObject<{
203
+ }, z.core.$strict>, z.ZodObject<{
204
204
  click: z.ZodString;
205
- }, z.core.$strip>, z.ZodObject<{
205
+ }, z.core.$strict>, z.ZodObject<{
206
206
  input: z.ZodObject<{
207
207
  selector: z.ZodString;
208
208
  text: z.ZodString;
209
- }, z.core.$strip>;
210
- }, z.core.$strip>]>>>;
211
- actions: z.ZodOptional<z.ZodArray<z.ZodDiscriminatedUnion<[z.ZodObject<{
212
- type: z.ZodLiteral<"WAIT">;
213
- milliseconds: z.ZodNumber;
214
- }, z.core.$strip> | z.ZodObject<{
209
+ }, z.core.$strict>;
210
+ }, z.core.$strict>, z.ZodDiscriminatedUnion<[z.ZodObject<{
215
211
  type: z.ZodLiteral<"GOTO">;
216
212
  url: z.ZodString;
217
213
  options: z.ZodOptional<z.ZodObject<{
218
214
  timeout: z.ZodOptional<z.ZodNumber>;
219
215
  waitUntil: z.ZodOptional<z.ZodUnion<readonly [z.ZodEnum<{
220
- load: "load";
221
216
  domcontentloaded: "domcontentloaded";
217
+ load: "load";
222
218
  networkidle0: "networkidle0";
223
219
  networkidle2: "networkidle2";
224
220
  }>, z.ZodArray<z.ZodEnum<{
225
- load: "load";
226
221
  domcontentloaded: "domcontentloaded";
222
+ load: "load";
227
223
  networkidle0: "networkidle0";
228
224
  networkidle2: "networkidle2";
229
225
  }>>]>>;
230
226
  referer: z.ZodOptional<z.ZodString>;
231
- }, z.core.$strip>>;
232
- }, z.core.$strip> | z.ZodObject<{
227
+ }, z.core.$strict>>;
228
+ }, z.core.$strict>, z.ZodObject<{
233
229
  type: z.ZodLiteral<"CLICK">;
234
230
  selector: z.ZodString;
235
231
  options: z.ZodOptional<z.ZodObject<{
236
232
  button: z.ZodOptional<z.ZodEnum<{
237
233
  left: "left";
238
- right: "right";
239
234
  middle: "middle";
235
+ right: "right";
240
236
  }>>;
241
237
  clickCount: z.ZodOptional<z.ZodNumber>;
242
238
  delay: z.ZodOptional<z.ZodNumber>;
243
- }, z.core.$strip>>;
244
- }, z.core.$strip> | z.ZodObject<{
239
+ }, z.core.$strict>>;
240
+ }, z.core.$strict>, z.ZodObject<{
245
241
  type: z.ZodLiteral<"TYPE">;
246
242
  selector: z.ZodString;
247
243
  text: z.ZodString;
248
244
  options: z.ZodOptional<z.ZodObject<{
249
245
  delay: z.ZodOptional<z.ZodNumber>;
250
- }, z.core.$strip>>;
251
- }, z.core.$strip> | z.ZodObject<{
246
+ }, z.core.$strict>>;
247
+ }, z.core.$strict>, z.ZodObject<{
252
248
  type: z.ZodLiteral<"WAIT_FOR_SELECTOR">;
253
249
  selector: z.ZodString;
254
250
  options: z.ZodOptional<z.ZodObject<{
255
251
  visible: z.ZodOptional<z.ZodBoolean>;
256
252
  hidden: z.ZodOptional<z.ZodBoolean>;
257
253
  timeout: z.ZodOptional<z.ZodNumber>;
258
- }, z.core.$strip>>;
259
- }, z.core.$strip> | z.ZodObject<{
254
+ }, z.core.$strict>>;
255
+ }, z.core.$strict>, z.ZodObject<{
260
256
  type: z.ZodLiteral<"WAIT_FOR_TIMEOUT">;
261
257
  timeout: z.ZodNumber;
262
- }, z.core.$strip> | z.ZodObject<{
258
+ }, z.core.$strict>, z.ZodObject<{
259
+ type: z.ZodLiteral<"WAIT">;
260
+ milliseconds: z.ZodNumber;
261
+ }, z.core.$strict>, z.ZodObject<{
263
262
  type: z.ZodLiteral<"PAUSE">;
264
- }, z.core.$strip> | z.ZodObject<{
263
+ }, z.core.$strict>, z.ZodObject<{
265
264
  type: z.ZodLiteral<"SCREENSHOT">;
266
265
  path: z.ZodString;
267
266
  options: z.ZodOptional<z.ZodObject<{
268
267
  type: z.ZodOptional<z.ZodEnum<{
269
- png: "png";
270
268
  jpeg: "jpeg";
269
+ png: "png";
271
270
  }>>;
272
271
  quality: z.ZodOptional<z.ZodNumber>;
273
272
  fullPage: z.ZodOptional<z.ZodBoolean>;
@@ -276,82 +275,83 @@ declare const scenarioSchema: z.ZodObject<{
276
275
  y: z.ZodNumber;
277
276
  width: z.ZodNumber;
278
277
  height: z.ZodNumber;
279
- }, z.core.$strip>>;
278
+ }, z.core.$strict>>;
280
279
  omitBackground: z.ZodOptional<z.ZodBoolean>;
281
280
  encoding: z.ZodOptional<z.ZodEnum<{
282
281
  base64: "base64";
283
282
  binary: "binary";
284
283
  }>>;
285
- }, z.core.$strip>>;
286
- }, z.core.$strip> | z.ZodObject<{
284
+ }, z.core.$strict>>;
285
+ }, z.core.$strict>, z.ZodObject<{
287
286
  type: z.ZodLiteral<"EVALUATE">;
288
- script: z.ZodUnion<readonly [z.ZodString, z.ZodFunction<z.core.$ZodFunctionArgs, z.core.$ZodFunctionOut>]>;
289
- }, z.core.$strip> | z.ZodObject<{
287
+ script: z.ZodString;
288
+ }, z.core.$strict>, z.ZodObject<{
290
289
  type: z.ZodLiteral<"SET_VIEWPORT">;
291
290
  width: z.ZodNumber;
292
291
  height: z.ZodNumber;
293
- }, z.core.$strip> | z.ZodObject<{
292
+ }, z.core.$strict>, z.ZodObject<{
294
293
  type: z.ZodLiteral<"CLOSE">;
295
- }, z.core.$strip>, ...(z.ZodObject<{
296
- type: z.ZodLiteral<"WAIT">;
297
- milliseconds: z.ZodNumber;
298
- }, z.core.$strip> | z.ZodObject<{
294
+ }, z.core.$strict>], "type">]>>>;
295
+ actions: z.ZodOptional<z.ZodArray<z.ZodDiscriminatedUnion<[z.ZodObject<{
299
296
  type: z.ZodLiteral<"GOTO">;
300
297
  url: z.ZodString;
301
298
  options: z.ZodOptional<z.ZodObject<{
302
299
  timeout: z.ZodOptional<z.ZodNumber>;
303
300
  waitUntil: z.ZodOptional<z.ZodUnion<readonly [z.ZodEnum<{
304
- load: "load";
305
301
  domcontentloaded: "domcontentloaded";
302
+ load: "load";
306
303
  networkidle0: "networkidle0";
307
304
  networkidle2: "networkidle2";
308
305
  }>, z.ZodArray<z.ZodEnum<{
309
- load: "load";
310
306
  domcontentloaded: "domcontentloaded";
307
+ load: "load";
311
308
  networkidle0: "networkidle0";
312
309
  networkidle2: "networkidle2";
313
310
  }>>]>>;
314
311
  referer: z.ZodOptional<z.ZodString>;
315
- }, z.core.$strip>>;
316
- }, z.core.$strip> | z.ZodObject<{
312
+ }, z.core.$strict>>;
313
+ }, z.core.$strict>, z.ZodObject<{
317
314
  type: z.ZodLiteral<"CLICK">;
318
315
  selector: z.ZodString;
319
316
  options: z.ZodOptional<z.ZodObject<{
320
317
  button: z.ZodOptional<z.ZodEnum<{
321
318
  left: "left";
322
- right: "right";
323
319
  middle: "middle";
320
+ right: "right";
324
321
  }>>;
325
322
  clickCount: z.ZodOptional<z.ZodNumber>;
326
323
  delay: z.ZodOptional<z.ZodNumber>;
327
- }, z.core.$strip>>;
328
- }, z.core.$strip> | z.ZodObject<{
324
+ }, z.core.$strict>>;
325
+ }, z.core.$strict>, z.ZodObject<{
329
326
  type: z.ZodLiteral<"TYPE">;
330
327
  selector: z.ZodString;
331
328
  text: z.ZodString;
332
329
  options: z.ZodOptional<z.ZodObject<{
333
330
  delay: z.ZodOptional<z.ZodNumber>;
334
- }, z.core.$strip>>;
335
- }, z.core.$strip> | z.ZodObject<{
331
+ }, z.core.$strict>>;
332
+ }, z.core.$strict>, z.ZodObject<{
336
333
  type: z.ZodLiteral<"WAIT_FOR_SELECTOR">;
337
334
  selector: z.ZodString;
338
335
  options: z.ZodOptional<z.ZodObject<{
339
336
  visible: z.ZodOptional<z.ZodBoolean>;
340
337
  hidden: z.ZodOptional<z.ZodBoolean>;
341
338
  timeout: z.ZodOptional<z.ZodNumber>;
342
- }, z.core.$strip>>;
343
- }, z.core.$strip> | z.ZodObject<{
339
+ }, z.core.$strict>>;
340
+ }, z.core.$strict>, z.ZodObject<{
344
341
  type: z.ZodLiteral<"WAIT_FOR_TIMEOUT">;
345
342
  timeout: z.ZodNumber;
346
- }, z.core.$strip> | z.ZodObject<{
343
+ }, z.core.$strict>, z.ZodObject<{
344
+ type: z.ZodLiteral<"WAIT">;
345
+ milliseconds: z.ZodNumber;
346
+ }, z.core.$strict>, z.ZodObject<{
347
347
  type: z.ZodLiteral<"PAUSE">;
348
- }, z.core.$strip> | z.ZodObject<{
348
+ }, z.core.$strict>, z.ZodObject<{
349
349
  type: z.ZodLiteral<"SCREENSHOT">;
350
350
  path: z.ZodString;
351
351
  options: z.ZodOptional<z.ZodObject<{
352
352
  type: z.ZodOptional<z.ZodEnum<{
353
- png: "png";
354
353
  jpeg: "jpeg";
354
+ png: "png";
355
355
  }>>;
356
356
  quality: z.ZodOptional<z.ZodNumber>;
357
357
  fullPage: z.ZodOptional<z.ZodBoolean>;
@@ -360,24 +360,24 @@ declare const scenarioSchema: z.ZodObject<{
360
360
  y: z.ZodNumber;
361
361
  width: z.ZodNumber;
362
362
  height: z.ZodNumber;
363
- }, z.core.$strip>>;
363
+ }, z.core.$strict>>;
364
364
  omitBackground: z.ZodOptional<z.ZodBoolean>;
365
365
  encoding: z.ZodOptional<z.ZodEnum<{
366
366
  base64: "base64";
367
367
  binary: "binary";
368
368
  }>>;
369
- }, z.core.$strip>>;
370
- }, z.core.$strip> | z.ZodObject<{
369
+ }, z.core.$strict>>;
370
+ }, z.core.$strict>, z.ZodObject<{
371
371
  type: z.ZodLiteral<"EVALUATE">;
372
- script: z.ZodUnion<readonly [z.ZodString, z.ZodFunction<z.core.$ZodFunctionArgs, z.core.$ZodFunctionOut>]>;
373
- }, z.core.$strip> | z.ZodObject<{
372
+ script: z.ZodString;
373
+ }, z.core.$strict>, z.ZodObject<{
374
374
  type: z.ZodLiteral<"SET_VIEWPORT">;
375
375
  width: z.ZodNumber;
376
376
  height: z.ZodNumber;
377
- }, z.core.$strip> | z.ZodObject<{
377
+ }, z.core.$strict>, z.ZodObject<{
378
378
  type: z.ZodLiteral<"CLOSE">;
379
- }, z.core.$strip>)[]], "type">>>;
380
- }, z.core.$strip>;
379
+ }, z.core.$strict>], "type">>>;
380
+ }, z.core.$strict>;
381
381
  export type ScenarioYaml = z.infer<typeof scenarioSchema>;
382
382
  export declare const rootZod: z.ZodObject<{
383
383
  scenarios: z.ZodArray<z.ZodObject<{
@@ -396,76 +396,75 @@ export declare const rootZod: z.ZodObject<{
396
396
  location: z.ZodOptional<z.ZodString>;
397
397
  steps: z.ZodOptional<z.ZodArray<z.ZodUnion<readonly [z.ZodObject<{
398
398
  navigate: z.ZodString;
399
- }, z.core.$strip>, z.ZodLiteral<"waitForever">, z.ZodObject<{
399
+ }, z.core.$strict>, z.ZodLiteral<"waitForever">, z.ZodObject<{
400
400
  wait: z.ZodNumber;
401
- }, z.core.$strip>, z.ZodObject<{
401
+ }, z.core.$strict>, z.ZodObject<{
402
402
  click: z.ZodString;
403
- }, z.core.$strip>, z.ZodObject<{
403
+ }, z.core.$strict>, z.ZodObject<{
404
404
  input: z.ZodObject<{
405
405
  selector: z.ZodString;
406
406
  text: z.ZodString;
407
- }, z.core.$strip>;
408
- }, z.core.$strip>]>>>;
409
- actions: z.ZodOptional<z.ZodArray<z.ZodDiscriminatedUnion<[z.ZodObject<{
410
- type: z.ZodLiteral<"WAIT">;
411
- milliseconds: z.ZodNumber;
412
- }, z.core.$strip> | z.ZodObject<{
407
+ }, z.core.$strict>;
408
+ }, z.core.$strict>, z.ZodDiscriminatedUnion<[z.ZodObject<{
413
409
  type: z.ZodLiteral<"GOTO">;
414
410
  url: z.ZodString;
415
411
  options: z.ZodOptional<z.ZodObject<{
416
412
  timeout: z.ZodOptional<z.ZodNumber>;
417
413
  waitUntil: z.ZodOptional<z.ZodUnion<readonly [z.ZodEnum<{
418
- load: "load";
419
414
  domcontentloaded: "domcontentloaded";
415
+ load: "load";
420
416
  networkidle0: "networkidle0";
421
417
  networkidle2: "networkidle2";
422
418
  }>, z.ZodArray<z.ZodEnum<{
423
- load: "load";
424
419
  domcontentloaded: "domcontentloaded";
420
+ load: "load";
425
421
  networkidle0: "networkidle0";
426
422
  networkidle2: "networkidle2";
427
423
  }>>]>>;
428
424
  referer: z.ZodOptional<z.ZodString>;
429
- }, z.core.$strip>>;
430
- }, z.core.$strip> | z.ZodObject<{
425
+ }, z.core.$strict>>;
426
+ }, z.core.$strict>, z.ZodObject<{
431
427
  type: z.ZodLiteral<"CLICK">;
432
428
  selector: z.ZodString;
433
429
  options: z.ZodOptional<z.ZodObject<{
434
430
  button: z.ZodOptional<z.ZodEnum<{
435
431
  left: "left";
436
- right: "right";
437
432
  middle: "middle";
433
+ right: "right";
438
434
  }>>;
439
435
  clickCount: z.ZodOptional<z.ZodNumber>;
440
436
  delay: z.ZodOptional<z.ZodNumber>;
441
- }, z.core.$strip>>;
442
- }, z.core.$strip> | z.ZodObject<{
437
+ }, z.core.$strict>>;
438
+ }, z.core.$strict>, z.ZodObject<{
443
439
  type: z.ZodLiteral<"TYPE">;
444
440
  selector: z.ZodString;
445
441
  text: z.ZodString;
446
442
  options: z.ZodOptional<z.ZodObject<{
447
443
  delay: z.ZodOptional<z.ZodNumber>;
448
- }, z.core.$strip>>;
449
- }, z.core.$strip> | z.ZodObject<{
444
+ }, z.core.$strict>>;
445
+ }, z.core.$strict>, z.ZodObject<{
450
446
  type: z.ZodLiteral<"WAIT_FOR_SELECTOR">;
451
447
  selector: z.ZodString;
452
448
  options: z.ZodOptional<z.ZodObject<{
453
449
  visible: z.ZodOptional<z.ZodBoolean>;
454
450
  hidden: z.ZodOptional<z.ZodBoolean>;
455
451
  timeout: z.ZodOptional<z.ZodNumber>;
456
- }, z.core.$strip>>;
457
- }, z.core.$strip> | z.ZodObject<{
452
+ }, z.core.$strict>>;
453
+ }, z.core.$strict>, z.ZodObject<{
458
454
  type: z.ZodLiteral<"WAIT_FOR_TIMEOUT">;
459
455
  timeout: z.ZodNumber;
460
- }, z.core.$strip> | z.ZodObject<{
456
+ }, z.core.$strict>, z.ZodObject<{
457
+ type: z.ZodLiteral<"WAIT">;
458
+ milliseconds: z.ZodNumber;
459
+ }, z.core.$strict>, z.ZodObject<{
461
460
  type: z.ZodLiteral<"PAUSE">;
462
- }, z.core.$strip> | z.ZodObject<{
461
+ }, z.core.$strict>, z.ZodObject<{
463
462
  type: z.ZodLiteral<"SCREENSHOT">;
464
463
  path: z.ZodString;
465
464
  options: z.ZodOptional<z.ZodObject<{
466
465
  type: z.ZodOptional<z.ZodEnum<{
467
- png: "png";
468
466
  jpeg: "jpeg";
467
+ png: "png";
469
468
  }>>;
470
469
  quality: z.ZodOptional<z.ZodNumber>;
471
470
  fullPage: z.ZodOptional<z.ZodBoolean>;
@@ -474,82 +473,83 @@ export declare const rootZod: z.ZodObject<{
474
473
  y: z.ZodNumber;
475
474
  width: z.ZodNumber;
476
475
  height: z.ZodNumber;
477
- }, z.core.$strip>>;
476
+ }, z.core.$strict>>;
478
477
  omitBackground: z.ZodOptional<z.ZodBoolean>;
479
478
  encoding: z.ZodOptional<z.ZodEnum<{
480
479
  base64: "base64";
481
480
  binary: "binary";
482
481
  }>>;
483
- }, z.core.$strip>>;
484
- }, z.core.$strip> | z.ZodObject<{
482
+ }, z.core.$strict>>;
483
+ }, z.core.$strict>, z.ZodObject<{
485
484
  type: z.ZodLiteral<"EVALUATE">;
486
- script: z.ZodUnion<readonly [z.ZodString, z.ZodFunction<z.core.$ZodFunctionArgs, z.core.$ZodFunctionOut>]>;
487
- }, z.core.$strip> | z.ZodObject<{
485
+ script: z.ZodString;
486
+ }, z.core.$strict>, z.ZodObject<{
488
487
  type: z.ZodLiteral<"SET_VIEWPORT">;
489
488
  width: z.ZodNumber;
490
489
  height: z.ZodNumber;
491
- }, z.core.$strip> | z.ZodObject<{
490
+ }, z.core.$strict>, z.ZodObject<{
492
491
  type: z.ZodLiteral<"CLOSE">;
493
- }, z.core.$strip>, ...(z.ZodObject<{
494
- type: z.ZodLiteral<"WAIT">;
495
- milliseconds: z.ZodNumber;
496
- }, z.core.$strip> | z.ZodObject<{
492
+ }, z.core.$strict>], "type">]>>>;
493
+ actions: z.ZodOptional<z.ZodArray<z.ZodDiscriminatedUnion<[z.ZodObject<{
497
494
  type: z.ZodLiteral<"GOTO">;
498
495
  url: z.ZodString;
499
496
  options: z.ZodOptional<z.ZodObject<{
500
497
  timeout: z.ZodOptional<z.ZodNumber>;
501
498
  waitUntil: z.ZodOptional<z.ZodUnion<readonly [z.ZodEnum<{
502
- load: "load";
503
499
  domcontentloaded: "domcontentloaded";
500
+ load: "load";
504
501
  networkidle0: "networkidle0";
505
502
  networkidle2: "networkidle2";
506
503
  }>, z.ZodArray<z.ZodEnum<{
507
- load: "load";
508
504
  domcontentloaded: "domcontentloaded";
505
+ load: "load";
509
506
  networkidle0: "networkidle0";
510
507
  networkidle2: "networkidle2";
511
508
  }>>]>>;
512
509
  referer: z.ZodOptional<z.ZodString>;
513
- }, z.core.$strip>>;
514
- }, z.core.$strip> | z.ZodObject<{
510
+ }, z.core.$strict>>;
511
+ }, z.core.$strict>, z.ZodObject<{
515
512
  type: z.ZodLiteral<"CLICK">;
516
513
  selector: z.ZodString;
517
514
  options: z.ZodOptional<z.ZodObject<{
518
515
  button: z.ZodOptional<z.ZodEnum<{
519
516
  left: "left";
520
- right: "right";
521
517
  middle: "middle";
518
+ right: "right";
522
519
  }>>;
523
520
  clickCount: z.ZodOptional<z.ZodNumber>;
524
521
  delay: z.ZodOptional<z.ZodNumber>;
525
- }, z.core.$strip>>;
526
- }, z.core.$strip> | z.ZodObject<{
522
+ }, z.core.$strict>>;
523
+ }, z.core.$strict>, z.ZodObject<{
527
524
  type: z.ZodLiteral<"TYPE">;
528
525
  selector: z.ZodString;
529
526
  text: z.ZodString;
530
527
  options: z.ZodOptional<z.ZodObject<{
531
528
  delay: z.ZodOptional<z.ZodNumber>;
532
- }, z.core.$strip>>;
533
- }, z.core.$strip> | z.ZodObject<{
529
+ }, z.core.$strict>>;
530
+ }, z.core.$strict>, z.ZodObject<{
534
531
  type: z.ZodLiteral<"WAIT_FOR_SELECTOR">;
535
532
  selector: z.ZodString;
536
533
  options: z.ZodOptional<z.ZodObject<{
537
534
  visible: z.ZodOptional<z.ZodBoolean>;
538
535
  hidden: z.ZodOptional<z.ZodBoolean>;
539
536
  timeout: z.ZodOptional<z.ZodNumber>;
540
- }, z.core.$strip>>;
541
- }, z.core.$strip> | z.ZodObject<{
537
+ }, z.core.$strict>>;
538
+ }, z.core.$strict>, z.ZodObject<{
542
539
  type: z.ZodLiteral<"WAIT_FOR_TIMEOUT">;
543
540
  timeout: z.ZodNumber;
544
- }, z.core.$strip> | z.ZodObject<{
541
+ }, z.core.$strict>, z.ZodObject<{
542
+ type: z.ZodLiteral<"WAIT">;
543
+ milliseconds: z.ZodNumber;
544
+ }, z.core.$strict>, z.ZodObject<{
545
545
  type: z.ZodLiteral<"PAUSE">;
546
- }, z.core.$strip> | z.ZodObject<{
546
+ }, z.core.$strict>, z.ZodObject<{
547
547
  type: z.ZodLiteral<"SCREENSHOT">;
548
548
  path: z.ZodString;
549
549
  options: z.ZodOptional<z.ZodObject<{
550
550
  type: z.ZodOptional<z.ZodEnum<{
551
- png: "png";
552
551
  jpeg: "jpeg";
552
+ png: "png";
553
553
  }>>;
554
554
  quality: z.ZodOptional<z.ZodNumber>;
555
555
  fullPage: z.ZodOptional<z.ZodBoolean>;
@@ -558,24 +558,24 @@ export declare const rootZod: z.ZodObject<{
558
558
  y: z.ZodNumber;
559
559
  width: z.ZodNumber;
560
560
  height: z.ZodNumber;
561
- }, z.core.$strip>>;
561
+ }, z.core.$strict>>;
562
562
  omitBackground: z.ZodOptional<z.ZodBoolean>;
563
563
  encoding: z.ZodOptional<z.ZodEnum<{
564
564
  base64: "base64";
565
565
  binary: "binary";
566
566
  }>>;
567
- }, z.core.$strip>>;
568
- }, z.core.$strip> | z.ZodObject<{
567
+ }, z.core.$strict>>;
568
+ }, z.core.$strict>, z.ZodObject<{
569
569
  type: z.ZodLiteral<"EVALUATE">;
570
- script: z.ZodUnion<readonly [z.ZodString, z.ZodFunction<z.core.$ZodFunctionArgs, z.core.$ZodFunctionOut>]>;
571
- }, z.core.$strip> | z.ZodObject<{
570
+ script: z.ZodString;
571
+ }, z.core.$strict>, z.ZodObject<{
572
572
  type: z.ZodLiteral<"SET_VIEWPORT">;
573
573
  width: z.ZodNumber;
574
574
  height: z.ZodNumber;
575
- }, z.core.$strip> | z.ZodObject<{
575
+ }, z.core.$strict>, z.ZodObject<{
576
576
  type: z.ZodLiteral<"CLOSE">;
577
- }, z.core.$strip>)[]], "type">>>;
578
- }, z.core.$strip>>;
579
- }, z.core.$strip>;
577
+ }, z.core.$strict>], "type">>>;
578
+ }, z.core.$strict>>;
579
+ }, z.core.$strict>;
580
580
  export type RootYaml = z.infer<typeof rootZod>;
581
581
  export {};
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@bloom-perf/yaml-pptr",
3
- "version": "2.0.1",
3
+ "version": "3.0.0",
4
4
  "description": "A library to generate puppeteer browser controls through a YAML api.",
5
5
  "type": "module",
6
6
  "main": "dist/index.js",
@@ -8,32 +8,35 @@
8
8
  "files": [
9
9
  "dist"
10
10
  ],
11
+ "engines": {
12
+ "node": ">=22.12.0"
13
+ },
11
14
  "devDependencies": {
12
- "@testdeck/mocha": "0.3.3",
13
15
  "@types/chai": "5.2.3",
14
- "@types/js-yaml": "4.0.9",
15
16
  "@types/mocha": "10.0.10",
16
- "c8": "11.0.0",
17
- "chai": "6.2.2",
18
- "cross-env": "10.1.0",
19
- "esbuild": "0.27.3",
20
- "esbuild-node-externals": "1.20.1",
21
- "mocha": "11.7.5",
22
- "prettier": "3.8.1",
23
- "puppeteer": "24.38.0",
24
- "ts-mockito": "2.6.1",
25
- "ts-node": "10.9.2",
26
- "tsx": "4.21.0",
27
- "typescript": "5.9.3"
17
+ "@types/node": "22.20.5",
18
+ "c8": "12.0.0",
19
+ "chai": "6.3.0",
20
+ "esbuild": "0.28.2",
21
+ "esbuild-node-externals": "2.0.0",
22
+ "mocha": "12.0.3",
23
+ "prettier": "3.9.10",
24
+ "puppeteer": "25.17.0",
25
+ "tsx": "4.23.15",
26
+ "typescript": "7.0.2"
28
27
  },
29
28
  "dependencies": {
30
- "js-yaml": "^4.1.0",
29
+ "js-yaml": "^5.0.0",
31
30
  "zod": "^4.0.0"
32
31
  },
32
+ "peerDependencies": {
33
+ "puppeteer": "^25.0.0"
34
+ },
33
35
  "scripts": {
34
36
  "build": "rm -rf dist && node esbuild.js && tsc -p tsconfig.build.json",
35
- "test": "mocha --loader ts-node/esm -r ts-node/register test/**/*.spec.ts",
36
- "test:coverage": "c8 npm run test",
37
+ "typecheck": "tsc -p tsconfig.json",
38
+ "test": "mocha",
39
+ "test:coverage": "c8 mocha",
37
40
  "example:login": "tsx examples/login-demo/run.ts",
38
41
  "example:load": "tsx examples/load-test/run.ts"
39
42
  },