diff --git a/package.json b/package.json index 1186c6b1..ea8dbc78 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "browsertrix-crawler", - "version": "1.5.11", + "version": "1.6.0-beta.0", "main": "browsertrix-crawler", "type": "module", "repository": "https://github.com/webrecorder/browsertrix-crawler", @@ -17,8 +17,9 @@ }, "dependencies": { "@novnc/novnc": "1.4.0", + "@puppeteer/replay": "^3.1.1", "@webrecorder/wabac": "^2.22.9", - "browsertrix-behaviors": "^0.8.3", + "browsertrix-behaviors": "^0.8.4", "client-zip": "^2.4.5", "css-selector-parser": "^3.0.5", "fetch-socks": "^1.3.0", @@ -57,8 +58,10 @@ "eslint-plugin-react": "^7.22.0", "http-server": "^14.1.1", "jest": "^29.7.0", + "lighthouse": "^12.5.1", "md5": "^2.3.0", "prettier": "3.0.3", + "puppeteer": "^24.4.0", "typescript": "^5.5.4" }, "jest": { diff --git a/src/crawler.ts b/src/crawler.ts index 282dec2d..e3b00459 100644 --- a/src/crawler.ts +++ b/src/crawler.ts @@ -71,6 +71,7 @@ import { } from "./util/warcwriter.js"; import { isHTMLMime, isRedirectStatus } from "./util/reqresp.js"; import { initProxy } from "./util/proxy.js"; +import { initFlow, nextFlowStep } from "./util/flowbehavior.js"; const btrixBehaviors = fs.readFileSync( new URL( @@ -224,13 +225,6 @@ export class Crawler { logger.setContext(this.params.logContext); logger.setExcludeContext(this.params.logExcludeContext); - // if automatically restarts on error exit code, - // exit with 0 from fatal by default, to avoid unnecessary restart - // otherwise, exit with default fatal exit code - if (this.params.restartsOnError) { - logger.setDefaultFatalExitCode(0); - } - logger.debug("Writing log to: " + this.logFilename, {}, "general"); this.recording = !this.params.dryRun; @@ -380,6 +374,29 @@ export class Crawler { this.params.maxPageRetries, ); + if (this.params.logErrorsToRedis) { + logger.setLogErrorsToRedis(true); + } + + if (this.params.logBehaviorsToRedis) { + logger.setLogBehaviorsToRedis(true); + } + + if (this.params.logErrorsToRedis || this.params.logBehaviorsToRedis) { + logger.setCrawlState(this.crawlState); + } + + // if automatically restarts on error exit code, + // exit with 0 from fatal by default, to avoid unnecessary restart + // otherwise, exit with default fatal exit code + if (this.params.restartsOnError) { + logger.setDefaultFatalExitCode(0); + } + + return this.crawlState; + } + + async loadCrawlState() { // load full state from config if (this.params.state) { await this.crawlState.load(this.params.state, this.seeds, true); @@ -398,20 +415,6 @@ export class Crawler { "state", ); } - - if (this.params.logErrorsToRedis) { - logger.setLogErrorsToRedis(true); - } - - if (this.params.logBehaviorsToRedis) { - logger.setLogBehaviorsToRedis(true); - } - - if (this.params.logErrorsToRedis || this.params.logBehaviorsToRedis) { - logger.setCrawlState(this.crawlState); - } - - return this.crawlState; } async loadExtraSeeds() { @@ -473,6 +476,8 @@ export class Crawler { } async bootstrap() { + await this.initCrawlState(); + if (await isDiskFull(this.params.cwd)) { logger.fatal( "Out of disk space, exiting", @@ -578,6 +583,8 @@ export class Crawler { if (this.params.text && !this.params.dryRun) { this.textWriter = this.createExtraResourceWarcWriter("text"); } + + await this.loadCrawlState(); } extraChromeArgs() { @@ -913,6 +920,15 @@ self.__bx_behaviors.selectMainBehavior(); this.crawlState.addToUserSet(data), ); + // eslint-disable-next-line @typescript-eslint/no-explicit-any + await page.exposeFunction(BxFunctionBindings.InitFlow, (params: any) => { + return initFlow(params, recorder, cdp, this.crawlState, workerid); + }); + + await page.exposeFunction(BxFunctionBindings.NextFlowStep, (id: string) => { + return nextFlowStep(id, page, workerid); + }); + // await page.exposeFunction("__bx_hasSet", (data: string) => this.crawlState.hasUserSet(data)); } @@ -1165,7 +1181,7 @@ self.__bx_behaviors.selectMainBehavior(); if (this.params.behaviorOpts && data.status < 400) { if (data.skipBehaviors) { - logger.info("Skipping behaviors for slow page", logDetails, "behavior"); + logger.warn("Skipping behaviors for slow page", logDetails, "behavior"); } else { const res = await timedRun( this.runBehaviors( @@ -1307,7 +1323,7 @@ self.__bx_behaviors.selectMainBehavior(); try { frames = frames || page.frames(); - logger.info( + logger.debug( "Running behaviors", { frames: frames.length, @@ -1346,7 +1362,7 @@ self.__bx_behaviors.selectMainBehavior(); } } - logger.info( + logger.debug( "Behaviors finished", { finished: results.length, ...logDetails }, "behavior", @@ -1570,8 +1586,6 @@ self.__bx_behaviors.selectMainBehavior(); } } - await this.initCrawlState(); - let initState = await this.crawlState.getStatus(); while (initState === "debug") { @@ -2249,11 +2263,6 @@ self.__bx_behaviors.selectMainBehavior(); async awaitPageLoad(frame: Frame, logDetails: LogDetails) { if (this.params.behaviorOpts) { - logger.debug( - "Waiting for custom page load via behavior", - logDetails, - "behavior", - ); try { await timedRun( frame.evaluate( diff --git a/src/util/browser.ts b/src/util/browser.ts index 143cb65f..f5825ced 100644 --- a/src/util/browser.ts +++ b/src/util/browser.ts @@ -319,7 +319,7 @@ export class Browser { let details: Record = { frameUrl, ...logData }; if (!frameUrl || frame.detached) { - logger.info( + logger.debug( "Run Script Skipped, frame no longer attached or has no URL", details, contextName, @@ -341,7 +341,13 @@ export class Browser { return; } - logger.info("Run Script Started", details, contextName); + const isTopFrame = !frame.parentFrame(); + + if (isTopFrame) { + logger.debug("Run Script Started", details, contextName); + } else { + logger.debug("Run Script Started in iframe", details, contextName); + } // from puppeteer _evaluateInternal() but with includeCommandLineAPI: true //const contextId = context._contextId; @@ -366,7 +372,11 @@ export class Browser { } logger.error("Run Script Failed", details, contextName); } else { - logger.info("Run Script Finished", details, contextName); + if (isTopFrame) { + logger.debug("Run Script Finished", details, contextName); + } else { + logger.debug("Run Script Finished in iframe", details, contextName); + } } return result.value; diff --git a/src/util/constants.ts b/src/util/constants.ts index 023e5b59..0f75df73 100644 --- a/src/util/constants.ts +++ b/src/util/constants.ts @@ -27,6 +27,9 @@ export enum BxFunctionBindings { AddLinkFunc = "__bx_addLink", FetchFunc = "__bx_fetch", AddToSeenSet = "__bx_addSet", + + InitFlow = "__bx_initFlow", + NextFlowStep = "__bx_nextFlowStep", } export const MAX_DEPTH = 1000000; diff --git a/src/util/file_reader.ts b/src/util/file_reader.ts index 9836358f..c111c9c1 100644 --- a/src/util/file_reader.ts +++ b/src/util/file_reader.ts @@ -5,15 +5,16 @@ import { fetch } from "undici"; import util from "util"; import { exec as execCallback } from "child_process"; -import { logger } from "./logger.js"; +import { formatErr, logger } from "./logger.js"; import { getProxyDispatcher } from "./proxy.js"; +import { parseRecorderFlowJson } from "./flowbehavior.js"; const exec = util.promisify(execCallback); const MAX_DEPTH = 5; // Add .ts to allowed extensions when we can support it -const ALLOWED_EXTS = [".js"]; +const ALLOWED_EXTS = [".js", ".json"]; export type FileSource = { path: string; @@ -82,7 +83,7 @@ async function collectGitBehaviors(gitUrl: string): Promise { } async function collectOnlineBehavior(url: string): Promise { - const filename = crypto.randomBytes(4).toString("hex") + ".js"; + const filename = path.basename(new URL(url).pathname); const tmpDir = `/tmp/behaviors-${crypto.randomBytes(4).toString("hex")}`; await fsp.mkdir(tmpDir, { recursive: true }); const behaviorFilepath = path.join(tmpDir, filename); @@ -132,7 +133,19 @@ async function collectLocalPathBehaviors( if (stat.isFile() && ALLOWED_EXTS.includes(path.extname(resolvedPath))) { source = source ?? filename; logger.info("Custom behavior script added", { source }, "behavior"); - const contents = await fsp.readFile(resolvedPath); + let contents = await fsp.readFile(resolvedPath, { encoding: "utf-8" }); + if (path.extname(resolvedPath) === ".json") { + try { + contents = parseRecorderFlowJson(contents, source); + } catch (e) { + logger.fatal( + "Unable to parse recorder flow JSON, ignored", + formatErr(e), + "behavior", + ); + } + } + return [ { path: resolvedPath, diff --git a/src/util/flowbehavior.ts b/src/util/flowbehavior.ts new file mode 100644 index 00000000..898bf232 --- /dev/null +++ b/src/util/flowbehavior.ts @@ -0,0 +1,569 @@ +import crypto from "crypto"; +import { CDPSession, Locator, Page } from "puppeteer-core"; +import { sleep } from "./timing.js"; +import { + ChangeStep, + ClickStep, + CustomStep, + DoubleClickStep, + HoverStep, + ScrollElementStep, + type Step, + StepType, + WaitForElementStep, + mouseButtonMap, + selectorToPElementSelector, +} from "@puppeteer/replay"; +import { logger } from "./logger.js"; +import { Recorder } from "./recorder.js"; +import { deepStrictEqual } from "assert"; +import { basename } from "path"; +import { RedisCrawlState } from "./state.js"; + +type SingleSiteScript = { + id: string; + url: string; + steps: { + type: string; + // eslint-disable-next-line @typescript-eslint/no-explicit-any + params: any; + }[]; +}; + +type FlowStepParams = { + type: StepType; + target: string; + selectors: string[][]; + offsetY?: number; + offsetX?: number; +}; + +type FlowCommand = { + id: string; + steps: FlowStepParams[]; +}; + +enum StepResult { + Success = 0, + NotHandled = 1, + TimedOut = 2, + OtherError = 3, + Repeat = 4, + NotFound = 5, + Done = 6, +} + +export function parseRecorderFlowJson( + contents: string, + source: string, +): string { + const flow = JSON.parse(contents); + + const allScripts: SingleSiteScript[] = []; + + let currScript: SingleSiteScript | null = null; + + let counter = 0; + + for (const step of flow.steps) { + switch (step.type) { + case "setViewport": + // ignore + break; + + case "navigate": + if (currScript) { + allScripts.push(currScript); + } + counter += 1; + currScript = { + url: step.url, + steps: [], + id: source + (counter > 1 ? "_" + counter : ""), + }; + break; + + default: + if (!currScript) { + currScript = { url: "", id: source, steps: [] }; + } + currScript.steps.push(step); + } + } + + if (currScript) { + allScripts.push(currScript); + } + + let content = ""; + + for (const script of allScripts) { + content += formatScript(script); + } + + return content; +} + +function formatScript(script: SingleSiteScript) { + const url = script.url; + const urlJSON = url ? JSON.stringify(url) : ""; + + const id = script.id; + const suffix = + basename(id).replace(/[^\w]/g, "_") + + "_" + + crypto.randomBytes(4).toString("hex"); + + return `\ +class BehaviorScript_${suffix} +{ + static id = "${id}"; + + static isMatch() { + return ${ + urlJSON ? `window.location.href.startsWith(${urlJSON}) &&` : "" + } window === window.top; + } + + static init() { + return {}; + } + + async* run(ctx) { + const { Lib } = ctx; + const { getState, initFlow, nextFlowStep } = Lib; + + const flowId = await initFlow(${formatSteps(id, script.steps)}); + + let steps = 0; + + while (true) { + const {done, state} = await nextFlowStep(flowId); + yield {steps, ...state}; + steps++; + if (done) { + break; + } + } + } +}`; +} + +// eslint-disable-next-line @typescript-eslint/no-explicit-any +function formatSteps(id: string, steps: any[]) { + for (const step of steps) { + if (step.selectors) { + try { + step.selectors = step.selectors.map((x: string) => + selectorToPElementSelector(x), + ); + } catch (_) { + //ignore + } + } + } + const resp = { id, steps }; + return JSON.stringify(resp, null, 2); +} + +// ============================================================================ +class Flow { + lastId = ""; + recorder: Recorder | null; + cdp: CDPSession; + steps: FlowStepParams[]; + repeatSteps = new Map(); + currStep = 0; + count = 0; + state: RedisCrawlState; + + timeoutSec = 5; + pauseSec = 0.5; + flowId: string; + + runOnce = false; + runOncePercentDone = 1.0; + + notFoundCount = 0; + + constructor( + flowId: string, + recorder: Recorder | null, + cdp: CDPSession, + steps: FlowStepParams[], + state: RedisCrawlState, + ) { + this.recorder = recorder; + this.cdp = cdp; + this.steps = steps; + this.currStep = 0; + this.count = 0; + this.state = state; + this.flowId = flowId; + } + + async nextFlowStep(page: Page) { + if (this.currStep >= this.steps.length) { + return { state: { msg: "All Steps Done!" }, done: true }; + } + + const step = this.steps[this.currStep]; + + let msg = `flow step "${step.type}" - `; + + const res = await this.runFlowStep(page, step); + + this.currStep++; + let done = false; + + switch (res) { + case StepResult.Success: + msg += "processed"; + break; + + case StepResult.Repeat: + msg += "processed, repeating"; + this.currStep--; + break; + + case StepResult.NotHandled: + msg += "not supported, ignoring"; + break; + + case StepResult.NotFound: + msg += "not found, stopping"; + done = true; + break; + + case StepResult.Done: + msg += "processed, done"; + done = true; + break; + + case StepResult.TimedOut: + msg += "not found, not stopping"; + break; + + case StepResult.OtherError: + msg += "errored, stopping"; + done = true; + break; + } + + //logger.info(msg, { ...step, count: this.count }, "behaviorScript"); + if (done) { + await this.checkRunOnce(); + } + return { state: { msg, ...step }, done }; + } + + async runFlowStep(page: Page, params: FlowStepParams): Promise { + try { + const res = await this.runStep(page, params as Step, this.timeoutSec); + await sleep(this.pauseSec); + this.notFoundCount = 0; + return res; + + // eslint-disable-next-line @typescript-eslint/no-explicit-any + } catch (e: any) { + if (e.toString().startsWith("TimeoutError")) { + this.notFoundCount++; + return this.notFoundCount >= 4 + ? StepResult.NotFound + : StepResult.TimedOut; + } else { + logger.warn(e.toString(), { params }, "behavior"); + return StepResult.OtherError; + } + } + } + + private async shouldRepeat( + step: ClickStep, + activity: Promise, + page: Page, + // eslint-disable-next-line @typescript-eslint/no-explicit-any + snap: any, + ) { + if (!this.recorder) { + return false; + } + + const id = step.selectors + .map((x: string[] | string) => selectorToPElementSelector(x)) + .join("|"); + // if (id !== this.lastId) { + // //this.repeatSteps.delete(this.lastId); + // } + const count = (this.repeatSteps.get(id) || 0) + 1; + this.repeatSteps.set(id, count); + this.lastId = id; + if (count < 3) { + return false; + } + + let changed = await Promise.race([activity, sleep(this.timeoutSec)]); + + if (!changed) { + const newSnap = await this.getSnap(); + changed = !this.deepEqual(snap, newSnap); + logger.debug("Flow behavior page change check", { changed }, "behavior"); + } + + if (!changed) { + logger.debug( + "Flow Behavior repeat ended, not found / timed out", + "behavior", + ); + } else { + await page.waitForNetworkIdle(); + } + + return changed; + } + + // eslint-disable-next-line @typescript-eslint/no-explicit-any + deepEqual(a: any, b: any) { + try { + deepStrictEqual(a, b); + return true; + } catch (_) { + return false; + } + } + + private async runStep( + page: Page, + step: Step, + timeout: number, + ): Promise { + const localFrame = + step.target === "main" || !step.target + ? page.mainFrame() + : await page.waitForFrame(step.target, { timeout }); + + function locator( + step: + | DoubleClickStep + | ClickStep + | ChangeStep + | ScrollElementStep + | HoverStep + | WaitForElementStep, + ) { + return Locator.race( + step.selectors.map((selector: string[] | string) => { + return localFrame.locator(selectorToPElementSelector(selector)); + }), + ); + } + + switch (step.type) { + case StepType.EmulateNetworkConditions: + case StepType.Navigate: + case StepType.SetViewport: + case StepType.Close: + return StepResult.NotHandled; + + case StepType.DoubleClick: + await locator(step) + .setTimeout(timeout * 1000) + //.on('action', () => startWaitingForEvents()) + .click({ + count: 2, + button: step.button && mouseButtonMap.get(step.button), + delay: step.duration, + offset: { + x: step.offsetX, + y: step.offsetY, + }, + }); + break; + + case StepType.Click: { + // await for new network requests + const activity = new Promise((resolve) => { + this.recorder!.once("fetching", () => { + resolve(true); + }); + }); + + const snap = await this.getSnap(); + + await locator(step) + .setTimeout(timeout * 1000) + //.on('action', () => startWaitingForEvents()) + .click({ + delay: step.duration, + button: step.button && mouseButtonMap.get(step.button), + offset: { + x: step.offsetX, + y: step.offsetY, + }, + }); + if (await this.shouldRepeat(step, activity, page, snap)) { + return StepResult.Repeat; + } + break; + } + + case StepType.Hover: + await locator(step) + .setTimeout(timeout * 1000) + //.on('action', () => startWaitingForEvents()) + .hover(); + break; + + case StepType.KeyDown: + await page.keyboard.down(step.key); + await sleep(0.1); + break; + + case StepType.KeyUp: + await page.keyboard.up(step.key); + await sleep(0.1); + break; + + case StepType.Change: + await locator(step) + //.on('action', () => startWaitingForEvents()) + .setTimeout(timeout * 1000) + .fill(step.value); + break; + + case StepType.Scroll: { + if ("selectors" in step) { + await locator(step) + //.on('action', () => startWaitingForEvents()) + .setTimeout(timeout * 1000) + .scroll({ + scrollLeft: step.x || 0, + scrollTop: step.y || 0, + }); + } else { + //startWaitingForEvents(); + await localFrame.evaluate( + (x, y) => { + /* c8 ignore start */ + window.scroll(x, y); + /* c8 ignore stop */ + }, + step.x || 0, + step.y || 0, + ); + } + break; + } + case StepType.WaitForElement: + await locator(step).wait(); + break; + + case StepType.WaitForExpression: { + //startWaitingForEvents(); + await localFrame.waitForFunction(step.expression, { + timeout, + }); + break; + } + + case StepType.CustomStep: + return await this.handleCustomStep(step); + + default: + return StepResult.NotHandled; + } + + return StepResult.Success; + } + + async getSnap() { + return await this.cdp.send("DOMSnapshot.captureSnapshot", { + computedStyles: [], + }); + } + + async handleCustomStep(step: CustomStep) { + const id = this.flowId; + switch (step.name) { + case "runOncePerCrawl": + if (await this.state.isInUserSet(id)) { + logger.debug( + "Skipping behavior, already ran for crawl", + { id }, + "behavior", + ); + return StepResult.Done; + } + logger.info("Behavior will run once if completed", { id }, "behavior"); + this.runOnce = true; + + this.runOncePercentDone = + // eslint-disable-next-line @typescript-eslint/no-explicit-any + ((step.parameters || {}) as any).percentDone ?? 0.5; + return StepResult.Success; + + default: + return StepResult.NotHandled; + } + } + + async checkRunOnce() { + if (!this.runOnce) { + return; + } + + const id = this.flowId; + + const minSteps = this.steps.length * this.runOncePercentDone; + + if (this.currStep >= minSteps) { + const actualPercentDone = this.currStep / this.steps.length; + await this.state.addToUserSet(id); + logger.info( + "Flow Behavior ran once per crawl to % done, will not run again", + { + id, + currStep: this.currStep, + total: this.steps.length, + minPercentDone: this.runOncePercentDone, + actualPercentDone, + minSteps, + }, + "behavior", + ); + } + } +} + +// ============================================================================ + +const flows = new Map(); + +// ============================================================================ +export async function initFlow( + { id, steps }: FlowCommand, + recorder: Recorder | null, + cdp: CDPSession, + state: RedisCrawlState, + workerid: number, +) { + const uid = id + "-" + workerid; + logger.debug("Init Flow Behavior Called", { id, workerid }, "behavior"); + flows.set(uid, new Flow(id, recorder, cdp, steps, state)); + return id; +} + +// ============================================================================ +export async function nextFlowStep(id: string, page: Page, workerid: number) { + const uid = id + "-" + workerid; + const flow = flows.get(uid); + if (!flow) { + logger.error("Flow Behavior Not Found", { id, workerid }, "behavior"); + return { done: true, msg: "Invalid Flow" }; + } + const res = await flow.nextFlowStep(page); + if (res.done) { + flows.delete(uid); + } + return res; +} diff --git a/src/util/recorder.ts b/src/util/recorder.ts index bc95e37e..bbaffa43 100644 --- a/src/util/recorder.ts +++ b/src/util/recorder.ts @@ -25,6 +25,7 @@ import { CDPSession, Protocol } from "puppeteer-core"; import { Crawler } from "../crawler.js"; import { getProxyDispatcher } from "./proxy.js"; import { ScopedSeed } from "./seeds.js"; +import EventEmitter from "events"; const MAX_BROWSER_DEFAULT_FETCH_SIZE = 5_000_000; const MAX_TEXT_REWRITE_SIZE = 25_000_000; @@ -117,7 +118,7 @@ export type ResponseStreamAsyncFetchOptions = NetworkLoadAsyncFetchOptions & { }; // ================================================================= -export class Recorder { +export class Recorder extends EventEmitter { workerid: WorkerId; crawler: Crawler; @@ -162,6 +163,7 @@ export class Recorder { writer: WARCWriter; crawler: Crawler; }) { + super(); this.workerid = workerid; this.crawler = crawler; this.crawlState = crawler.crawlState; @@ -540,6 +542,7 @@ export class Recorder { !responseErrorReason && !this.shouldSkip(headers, url, method, resourceType) ) { + this.emit("fetching", { url }); continued = await this.handleFetchResponse( params, cdp, diff --git a/src/util/state.ts b/src/util/state.ts index f6f984e7..116dda46 100644 --- a/src/util/state.ts +++ b/src/util/state.ts @@ -926,6 +926,10 @@ return inx; return await this.redis.srem(key, status + "|" + url); } + async isInUserSet(value: string) { + return (await this.redis.sismember(this.key + ":user", value)) === 1; + } + async addToUserSet(value: string) { return (await this.redis.sadd(this.key + ":user", value)) === 1; } diff --git a/tests/custom-behavior-flow.test.js b/tests/custom-behavior-flow.test.js new file mode 100644 index 00000000..efd8b044 --- /dev/null +++ b/tests/custom-behavior-flow.test.js @@ -0,0 +1,49 @@ +import child_process from "child_process"; +import Redis from "ioredis"; + + +async function sleep(time) { + await new Promise((resolve) => setTimeout(resolve, time)); +} + +test("test pushing behavior logs to redis", async () => { + const child = child_process.exec("docker run -p 36398:6379 -v $PWD/test-crawls:/crawls -v $PWD/tests/custom-behaviors/:/custom-behaviors/ -e CRAWL_ID=behavior-logs-flow-test --rm webrecorder/browsertrix-crawler crawl --debugAccessRedis --url https://webrecorder.net/ --customBehaviors /custom-behaviors/custom-flow.json --scopeType page --logBehaviorsToRedis --pageExtraDelay 20"); + + let crawlFinished = false; + + child.on("exit", function () { + crawlFinished = true; + }); + + const redis = new Redis("redis://127.0.0.1:36398/0", { lazyConnect: true, retryStrategy: () => null }); + + await sleep(3000); + + await redis.connect({ maxRetriesPerRequest: 50 }); + + let customLogLineCount = 0; + let done = false; + + while (!crawlFinished) { + let res = null; + try { + res = await redis.rpop("behavior-logs-flow-test:b"); + } catch (e) { + break; + } + if (!res) { + await sleep(500); + continue; + } + const json = JSON.parse(res); + if (json.context === "behaviorScriptCustom") { + customLogLineCount++; + } + if (json.message === "All Steps Done!") { + done = true; + } + } + + expect(customLogLineCount).toEqual(4); + expect(done).toBe(true); +}); diff --git a/tests/custom-behavior.test.js b/tests/custom-behavior.test.js index 16bd7755..b49ea1d8 100644 --- a/tests/custom-behavior.test.js +++ b/tests/custom-behavior.test.js @@ -196,7 +196,6 @@ test("test pushing behavior logs to redis", async () => { expect(["behavior", "behaviorScript", "behaviorScriptCustom"]).toContain(json.context) if (json.context === "behaviorScriptCustom") { - expect(["test-stat", "test-stat-2", "done!"]).toContain(json.message); expect(["TestBehavior", "TestBehavior2"]).toContain(json.details.behavior); expect(["https://specs.webrecorder.net/", "https://old.webrecorder.net/"]).toContain(json.details.page); customLogLineCount++; diff --git a/tests/custom-behaviors/custom-flow.json b/tests/custom-behaviors/custom-flow.json new file mode 100644 index 00000000..9a55b6f5 --- /dev/null +++ b/tests/custom-behaviors/custom-flow.json @@ -0,0 +1,55 @@ +{ + "title": "test WR create click + enter URL", + "steps": [ + { + "type": "navigate", + "url": "https://webrecorder.net/" + }, + { + "type": "click", + "target": "main", + "selectors": [ + [ + "aria/[role=\"main\"]", + "aria/[role=\"textbox\"]" + ], + [ + "#archive-url" + ], + [ + "xpath///*[@id=\"archive-url\"]" + ], + [ + "pierce/#archive-url" + ] + ], + "offsetY": 19.0078125, + "offsetX": 310.5 + }, + { + "type": "change", + "value": "https://example.com/", + "selectors": [ + [ + "aria/[role=\"main\"]", + "aria/[role=\"textbox\"]" + ], + [ + "#archive-url" + ], + [ + "xpath///*[@id=\"archive-url\"]" + ], + [ + "pierce/#archive-url" + ] + ], + "target": "main" + }, + { + "type": "keyDown", + "target": "main", + "key": "Enter" + } + ] +} diff --git a/yarn.lock b/yarn.lock index 90848440..cfbb52dc 100644 --- a/yarn.lock +++ b/yarn.lock @@ -273,6 +273,11 @@ resolved "https://registry.yarnpkg.com/@bcoe/v8-coverage/-/v8-coverage-0.2.3.tgz#75a2e8b51cb758a7553d6804a5932d7aace75c39" integrity sha512-0hYQ8SB4Db5zvZB4axdMHGwEaQjkZzFjQiN9LVYvIFB2nSUHW9tYpxWriPrWDASIxiaXax83REcLxuSdnGPZtw== +"@colors/colors@1.5.0": + version "1.5.0" + resolved "https://registry.yarnpkg.com/@colors/colors/-/colors-1.5.0.tgz#bb504579c1cae923e6576a4f5da43d25f97bdbd9" + integrity sha512-ooWCrlZP11i8GImSjTHYHLkvFDP48nS4+204nGb1RiX/WXYHmJA2III9/e2DWVabCESdW7hBAEzHRqUn9OUVvQ== + "@eslint-community/eslint-utils@^4.2.0", "@eslint-community/eslint-utils@^4.4.0": version "4.4.1" resolved "https://registry.yarnpkg.com/@eslint-community/eslint-utils/-/eslint-utils-4.4.1.tgz#d1145bf2c20132d6400495d6df4bf59362fd9d56" @@ -305,6 +310,47 @@ resolved "https://registry.yarnpkg.com/@eslint/js/-/js-8.57.1.tgz#de633db3ec2ef6a3c89e2f19038063e8a122e2c2" integrity sha512-d9zaMRSTIKDLhctzH12MtXvJKSSUhaHcjV+2Z+GK+EEY7XKpP5yR4x+N3TAcHTcu963nIr+TMcCb4DBCYX1z6Q== +"@formatjs/ecma402-abstract@2.3.4": + version "2.3.4" + resolved "https://registry.yarnpkg.com/@formatjs/ecma402-abstract/-/ecma402-abstract-2.3.4.tgz#e90c5a846ba2b33d92bc400fdd709da588280fbc" + integrity sha512-qrycXDeaORzIqNhBOx0btnhpD1c+/qFIHAN9znofuMJX6QBwtbrmlpWfD4oiUUD2vJUOIYFA/gYtg2KAMGG7sA== + dependencies: + "@formatjs/fast-memoize" "2.2.7" + "@formatjs/intl-localematcher" "0.6.1" + decimal.js "^10.4.3" + tslib "^2.8.0" + +"@formatjs/fast-memoize@2.2.7": + version "2.2.7" + resolved "https://registry.yarnpkg.com/@formatjs/fast-memoize/-/fast-memoize-2.2.7.tgz#707f9ddaeb522a32f6715bb7950b0831f4cc7b15" + integrity sha512-Yabmi9nSvyOMrlSeGGWDiH7rf3a7sIwplbvo/dlz9WCIjzIQAfy1RMf4S0X3yG724n5Ghu2GmEl5NJIV6O9sZQ== + dependencies: + tslib "^2.8.0" + +"@formatjs/icu-messageformat-parser@2.11.2": + version "2.11.2" + resolved "https://registry.yarnpkg.com/@formatjs/icu-messageformat-parser/-/icu-messageformat-parser-2.11.2.tgz#85aea211bea40aa81ee1d44ac7accc3cf5500a73" + integrity sha512-AfiMi5NOSo2TQImsYAg8UYddsNJ/vUEv/HaNqiFjnI3ZFfWihUtD5QtuX6kHl8+H+d3qvnE/3HZrfzgdWpsLNA== + dependencies: + "@formatjs/ecma402-abstract" "2.3.4" + "@formatjs/icu-skeleton-parser" "1.8.14" + tslib "^2.8.0" + +"@formatjs/icu-skeleton-parser@1.8.14": + version "1.8.14" + resolved "https://registry.yarnpkg.com/@formatjs/icu-skeleton-parser/-/icu-skeleton-parser-1.8.14.tgz#b9581d00363908efb29817fdffc32b79f41dabe5" + integrity sha512-i4q4V4qslThK4Ig8SxyD76cp3+QJ3sAqr7f6q9VVfeGtxG9OhiAk3y9XF6Q41OymsKzsGQ6OQQoJNY4/lI8TcQ== + dependencies: + "@formatjs/ecma402-abstract" "2.3.4" + tslib "^2.8.0" + +"@formatjs/intl-localematcher@0.6.1": + version "0.6.1" + resolved "https://registry.yarnpkg.com/@formatjs/intl-localematcher/-/intl-localematcher-0.6.1.tgz#25dc30675320bf65a9d7f73876fc1e4064c0e299" + integrity sha512-ePEgLgVCqi2BBFnTMWPfIghu6FkbZnnBVhO2sSxvLfrdFw7wCHAHiDoM2h4NRgjbaY7+B7HgOLZGkK187pZTZg== + dependencies: + tslib "^2.8.0" + "@humanwhocodes/config-array@^0.13.0": version "0.13.0" resolved "https://registry.yarnpkg.com/@humanwhocodes/config-array/-/config-array-0.13.0.tgz#fb907624df3256d04b9aa2df50d7aa97ec648748" @@ -595,6 +641,13 @@ resolved "https://registry.yarnpkg.com/@novnc/novnc/-/novnc-1.4.0.tgz#68adae81a741624142b518323441e852c1f34281" integrity sha512-kW6ALMc5BuH08e/ond/I1naYcfjc19JYMN1EdtmgjjjzPGCjW8fMtVM3MwM6q7YLRjPlQ3orEvoKMgSS7RkEVQ== +"@paulirish/trace_engine@0.0.50": + version "0.0.50" + resolved "https://registry.yarnpkg.com/@paulirish/trace_engine/-/trace_engine-0.0.50.tgz#888fee52e3c4be18ec7c350ddfa40b1df5cbb2c0" + integrity sha512-ktkbISnr0T9dkOxtnEadjYsbArMcvX2Wp8zwgyIP6KW0eOk2Oe2s49BY4v0qdE3uQdVv/GDdQ6MnoIFuYNJ9pg== + dependencies: + third-party-web latest + "@peculiar/asn1-cms@^2.3.13": version "2.3.13" resolved "https://registry.yarnpkg.com/@peculiar/asn1-cms/-/asn1-cms-2.3.13.tgz#34415f558c16f0a0bc7ac6df31230325a4eb3e59" @@ -732,6 +785,78 @@ tar-fs "^3.0.8" yargs "^17.7.2" +"@puppeteer/browsers@2.8.0": + version "2.8.0" + resolved "https://registry.yarnpkg.com/@puppeteer/browsers/-/browsers-2.8.0.tgz#9d592933cbefc66c37823770844b8cbac52607dd" + integrity sha512-yTwt2KWRmCQAfhvbCRjebaSX8pV1//I0Y3g+A7f/eS7gf0l4eRJoUCvcYdVtboeU4CTOZQuqYbZNS8aBYb8ROQ== + dependencies: + debug "^4.4.0" + extract-zip "^2.0.1" + progress "^2.0.3" + proxy-agent "^6.5.0" + semver "^7.7.1" + tar-fs "^3.0.8" + yargs "^17.7.2" + +"@puppeteer/replay@^3.1.1": + version "3.1.1" + resolved "https://registry.yarnpkg.com/@puppeteer/replay/-/replay-3.1.1.tgz#ada5412c5330ba22e3186ed4b622d26ac89bf564" + integrity sha512-8tW1APEoqkpPVH19wRPqePb+/wbGuSVxE2OeRySKeb2SX1VpL2TuADodETRVGYYe07gBbs8FucaUu09A0QI7+w== + dependencies: + cli-table3 "0.6.5" + colorette "2.0.20" + yargs "17.7.2" + +"@sentry-internal/tracing@7.120.3": + version "7.120.3" + resolved "https://registry.yarnpkg.com/@sentry-internal/tracing/-/tracing-7.120.3.tgz#a54e67c39d23576a72b3f349c1a3fae13e27f2f1" + integrity sha512-Ausx+Jw1pAMbIBHStoQ6ZqDZR60PsCByvHdw/jdH9AqPrNE9xlBSf9EwcycvmrzwyKspSLaB52grlje2cRIUMg== + dependencies: + "@sentry/core" "7.120.3" + "@sentry/types" "7.120.3" + "@sentry/utils" "7.120.3" + +"@sentry/core@7.120.3": + version "7.120.3" + resolved "https://registry.yarnpkg.com/@sentry/core/-/core-7.120.3.tgz#88ae2f8c242afce59e32bdee7f866d8788e86c03" + integrity sha512-vyy11fCGpkGK3qI5DSXOjgIboBZTriw0YDx/0KyX5CjIjDDNgp5AGgpgFkfZyiYiaU2Ww3iFuKo4wHmBusz1uA== + dependencies: + "@sentry/types" "7.120.3" + "@sentry/utils" "7.120.3" + +"@sentry/integrations@7.120.3": + version "7.120.3" + resolved "https://registry.yarnpkg.com/@sentry/integrations/-/integrations-7.120.3.tgz#ea6812b77dea7d0090a5cf85383f154b3bd5b073" + integrity sha512-6i/lYp0BubHPDTg91/uxHvNui427df9r17SsIEXa2eKDwQ9gW2qRx5IWgvnxs2GV/GfSbwcx4swUB3RfEWrXrQ== + dependencies: + "@sentry/core" "7.120.3" + "@sentry/types" "7.120.3" + "@sentry/utils" "7.120.3" + localforage "^1.8.1" + +"@sentry/node@^7.0.0": + version "7.120.3" + resolved "https://registry.yarnpkg.com/@sentry/node/-/node-7.120.3.tgz#59a54e1bfccffd28e7d502a5eefea615f07e13f5" + integrity sha512-t+QtekZedEfiZjbkRAk1QWJPnJlFBH/ti96tQhEq7wmlk3VszDXraZvLWZA0P2vXyglKzbWRGkT31aD3/kX+5Q== + dependencies: + "@sentry-internal/tracing" "7.120.3" + "@sentry/core" "7.120.3" + "@sentry/integrations" "7.120.3" + "@sentry/types" "7.120.3" + "@sentry/utils" "7.120.3" + +"@sentry/types@7.120.3": + version "7.120.3" + resolved "https://registry.yarnpkg.com/@sentry/types/-/types-7.120.3.tgz#25f69ae27f0c8430f1863ad2a9ee9cab7fccf232" + integrity sha512-C4z+3kGWNFJ303FC+FxAd4KkHvxpNFYAFN8iMIgBwJdpIl25KZ8Q/VdGn0MLLUEHNLvjob0+wvwlcRBBNLXOow== + +"@sentry/utils@7.120.3": + version "7.120.3" + resolved "https://registry.yarnpkg.com/@sentry/utils/-/utils-7.120.3.tgz#0cc891c315d3894eb80c2e7298efd7437e939a5d" + integrity sha512-UDAOQJtJDxZHQ5Nm1olycBIsz2wdGX8SdzyGVHmD8EOQYAeDZQyIlQYohDe9nazdIOQLZCIc3fU0G9gqVLkaGQ== + dependencies: + "@sentry/types" "7.120.3" + "@sinclair/typebox@^0.27.8": version "0.27.8" resolved "https://registry.yarnpkg.com/@sinclair/typebox/-/typebox-0.27.8.tgz#6667fac16c436b5434a387a34dedb013198f6e6e" @@ -1083,6 +1208,11 @@ ajv@^6.12.4: json-schema-traverse "^0.4.1" uri-js "^4.2.2" +ansi-colors@^4.1.1: + version "4.1.3" + resolved "https://registry.yarnpkg.com/ansi-colors/-/ansi-colors-4.1.3.tgz#37611340eb2243e70cc604cad35d63270d48781b" + integrity sha512-/6w/C21Pm1A7aZitlI5Ni/2J6FFQN8i1Cvz3kHABAAbw93v/NlvKdVOqz7CCWz/3iv/JplRSEEZ83XION15ovw== + ansi-escapes@^4.2.1: version "4.3.2" resolved "https://registry.yarnpkg.com/ansi-escapes/-/ansi-escapes-4.3.2.tgz#6b2291d1db7d98b6521d5f1efa42d0f3a9feb65e" @@ -1249,6 +1379,11 @@ available-typed-arrays@^1.0.7: dependencies: possible-typed-array-names "^1.0.0" +axe-core@^4.10.3: + version "4.10.3" + resolved "https://registry.yarnpkg.com/axe-core/-/axe-core-4.10.3.tgz#04145965ac7894faddbac30861e5d8f11bfd14fc" + integrity sha512-Xm7bpRXnDSX2YE2YFfBk2FnF0ep6tmG7xPh8iHee8MIcrgq762Nkce856dYtJYLkuIoYZvGfTs/PbZhideTcEg== + b4a@^1.6.4: version "1.6.7" resolved "https://registry.yarnpkg.com/b4a/-/b4a-1.6.7.tgz#a99587d4ebbfbd5a6e3b21bdb5d5fa385767abe4" @@ -1460,10 +1595,10 @@ browserslist@^4.24.0: node-releases "^2.0.18" update-browserslist-db "^1.1.1" -browsertrix-behaviors@^0.8.3: - version "0.8.3" - resolved "https://registry.yarnpkg.com/browsertrix-behaviors/-/browsertrix-behaviors-0.8.3.tgz#3710f8d778c09ab4f46d5b7e1d4ebbfcbc1a8f02" - integrity sha512-ie+fsa45K1kZ2PWvt8ISObgFto9AXzbDB92ts+vgvVJ8erRA9pUKUyOVnK/B/qdNbYO0EQJiSP24GRqNp702tQ== +browsertrix-behaviors@^0.8.4: + version "0.8.4" + resolved "https://registry.yarnpkg.com/browsertrix-behaviors/-/browsertrix-behaviors-0.8.4.tgz#f9fb08281195a811b0082dcddb2d2a06f52b10b2" + integrity sha512-YkX677WR616QoLXB/LGutcYmD037bhzD04yYoSI7IxmDFOVDE0xoVBc6QH0lqeupUWiosihAR7YVmwsrqrWPfQ== dependencies: query-selector-shadow-dom "^1.0.1" @@ -1559,6 +1694,16 @@ chownr@^1.1.1: resolved "https://registry.yarnpkg.com/chownr/-/chownr-1.1.4.tgz#6fc9d7b42d32a583596337666e7d08084da2cc6b" integrity sha512-jJ0bqzaylmJtVnNgzTeSOs8DPavpbYgEr/b0YL8/2GO3xJEhInFmhKMUnEJQjZumK7KXGFhUy89PrsJWlakBVg== +chrome-launcher@^1.1.2: + version "1.1.2" + resolved "https://registry.yarnpkg.com/chrome-launcher/-/chrome-launcher-1.1.2.tgz#52eff6b3fd7f24b65192b2624a108dadbcca4b9d" + integrity sha512-YclTJey34KUm5jB1aEJCq807bSievi7Nb/TU4Gu504fUYi3jw3KCIaH6L7nFWQhdEgH3V+wCh+kKD1P5cXnfxw== + dependencies: + "@types/node" "*" + escape-string-regexp "^4.0.0" + is-wsl "^2.2.0" + lighthouse-logger "^2.0.1" + chromium-bidi@1.2.0: version "1.2.0" resolved "https://registry.yarnpkg.com/chromium-bidi/-/chromium-bidi-1.2.0.tgz#e481b3eee0bf0f2d940a60b83faa79414f4752b8" @@ -1567,6 +1712,14 @@ chromium-bidi@1.2.0: mitt "^3.0.1" zod "^3.24.1" +chromium-bidi@2.1.2: + version "2.1.2" + resolved "https://registry.yarnpkg.com/chromium-bidi/-/chromium-bidi-2.1.2.tgz#b0710279f993128d4e0b41c892209ea093217d97" + integrity sha512-vtRWBK2uImo5/W2oG6/cDkkHSm+2t6VHgnj+Rcwhb0pP74OoUb4GipyRX/T/y39gYQPhioP0DPShn+A7P6CHNw== + dependencies: + mitt "^3.0.1" + zod "^3.24.1" + ci-info@^3.2.0: version "3.9.0" resolved "https://registry.yarnpkg.com/ci-info/-/ci-info-3.9.0.tgz#4279a62028a7b1f262f3473fc9605f5e218c59b4" @@ -1577,6 +1730,15 @@ cjs-module-lexer@^1.0.0: resolved "https://registry.yarnpkg.com/cjs-module-lexer/-/cjs-module-lexer-1.4.1.tgz#707413784dbb3a72aa11c2f2b042a0bef4004170" integrity sha512-cuSVIHi9/9E/+821Qjdvngor+xpnlwnuwIyZOaLmHBVdXL+gP+I6QQB9VkO7RI77YIcTV+S1W9AreJ5eN63JBA== +cli-table3@0.6.5: + version "0.6.5" + resolved "https://registry.yarnpkg.com/cli-table3/-/cli-table3-0.6.5.tgz#013b91351762739c16a9567c21a04632e449bf2f" + integrity sha512-+W/5efTR7y5HRD7gACw9yQjqMVvEMLBHmboM/kPWam+H+Hmyrgjh6YncVKK122YZkXrLudzTuAukUw9FnMf7IQ== + dependencies: + string-width "^4.2.0" + optionalDependencies: + "@colors/colors" "1.5.0" + client-zip@^2.4.5: version "2.4.6" resolved "https://registry.yarnpkg.com/client-zip/-/client-zip-2.4.6.tgz#c797c29d9463b17eca4b623339ccf06e620b2794" @@ -1634,11 +1796,28 @@ color@^4.2.3: color-convert "^2.0.1" color-string "^1.9.0" +colorette@2.0.20: + version "2.0.20" + resolved "https://registry.yarnpkg.com/colorette/-/colorette-2.0.20.tgz#9eb793e6833067f7235902fcd3b09917a000a95a" + integrity sha512-IfEDxwoWIjkeXL1eXcDiow4UbKjhLdq6/EuSVR9GMN7KVH3r9gQ83e73hsz1Nd1T3ijd5xv1wcWRYO+D6kCI2w== + concat-map@0.0.1: version "0.0.1" resolved "https://registry.yarnpkg.com/concat-map/-/concat-map-0.0.1.tgz#d8a96bd77fd68df7793a73036a3ba0d5405d477b" integrity sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg== +configstore@^5.0.1: + version "5.0.1" + resolved "https://registry.yarnpkg.com/configstore/-/configstore-5.0.1.tgz#d365021b5df4b98cdd187d6a3b0e3f6a7cc5ed96" + integrity sha512-aMKprgk5YhBNyH25hj8wGt2+D52Sw1DRRIzqBwLp2Ya9mFmY8KPvvtvmna8SxVR9JMZ4kzMD68N22vlaRpkeFA== + dependencies: + dot-prop "^5.2.0" + graceful-fs "^4.1.2" + make-dir "^3.0.0" + unique-string "^2.0.0" + write-file-atomic "^3.0.0" + xdg-basedir "^4.0.0" + convert-source-map@^2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/convert-source-map/-/convert-source-map-2.0.0.tgz#4b560f649fc4e918dd0ab75cf4961e8bc882d82a" @@ -1649,6 +1828,16 @@ corser@^2.0.1: resolved "https://registry.yarnpkg.com/corser/-/corser-2.0.1.tgz#8eda252ecaab5840dcd975ceb90d9370c819ff87" integrity sha512-utCYNzRSQIZNPIcGZdQc92UVJYAhtGAteCFg0yRaFm8f0P+CPtyGyHXJcGXnffjCybUCEx3FQ2G7U3/o9eIkVQ== +cosmiconfig@^9.0.0: + version "9.0.0" + resolved "https://registry.yarnpkg.com/cosmiconfig/-/cosmiconfig-9.0.0.tgz#34c3fc58287b915f3ae905ab6dc3de258b55ad9d" + integrity sha512-itvL5h8RETACmOTFc4UfIyB2RfEHi71Ax6E/PivVxq9NseKbOWpeyHEOIbmAw1rs8Ak0VursQNww7lf7YtUwzg== + dependencies: + env-paths "^2.2.1" + import-fresh "^3.3.0" + js-yaml "^4.1.0" + parse-json "^5.2.0" + create-jest@^29.7.0: version "29.7.0" resolved "https://registry.yarnpkg.com/create-jest/-/create-jest-29.7.0.tgz#a355c5b3cb1e1af02ba177fe7afd7feee49a5320" @@ -1676,6 +1865,11 @@ crypt@0.0.2: resolved "https://registry.yarnpkg.com/crypt/-/crypt-0.0.2.tgz#88d7ff7ec0dfb86f713dc87bbb42d044d3e6c41b" integrity sha512-mCxBlsHFYh9C+HVpiEacem8FEBnMXgU9gy4zmNC+SXAZNB/1idgp/aulFJ4FgCi7GPEVbfyng092GqL2k2rmow== +crypto-random-string@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/crypto-random-string/-/crypto-random-string-2.0.0.tgz#ef2a7a966ec11083388369baa02ebead229b30d5" + integrity sha512-v1plID3y9r/lPhviJ1wrXpLeyUIGAZ2SHNYTEapm7/8A9nLPoyvVp3RK/EPFqn5kEznyWgYZNsRtYYIWbuG8KA== + crypto-random-string@^4.0.0: version "4.0.0" resolved "https://registry.yarnpkg.com/crypto-random-string/-/crypto-random-string-4.0.0.tgz#5a3cc53d7dd86183df5da0312816ceeeb5bb1fc2" @@ -1683,6 +1877,11 @@ crypto-random-string@^4.0.0: dependencies: type-fest "^1.0.1" +csp_evaluator@1.1.5: + version "1.1.5" + resolved "https://registry.yarnpkg.com/csp_evaluator/-/csp_evaluator-1.1.5.tgz#33788d695b7b539b17d5b6eba494431ce931faff" + integrity sha512-EL/iN9etCTzw/fBnp0/uj0f5BOOGvZut2mzsiiBZ/FdT6gFQCKRO/tmcKOxn5drWZ2Ndm/xBb1SI4zwWbGtmIw== + css-selector-parser@^3.0.5: version "3.0.5" resolved "https://registry.yarnpkg.com/css-selector-parser/-/css-selector-parser-3.0.5.tgz#9b636ebccf7c4bcce5c1ac21ae27de9f01180ae9" @@ -1727,6 +1926,13 @@ debug@4, debug@^4.1.0, debug@^4.1.1, debug@^4.3.1, debug@^4.3.2, debug@^4.3.4: dependencies: ms "^2.1.3" +debug@^2.6.9: + version "2.6.9" + resolved "https://registry.yarnpkg.com/debug/-/debug-2.6.9.tgz#5d128515df134ff327e90a4c93f4e077a536341f" + integrity sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA== + dependencies: + ms "2.0.0" + debug@^3.2.7: version "3.2.7" resolved "https://registry.yarnpkg.com/debug/-/debug-3.2.7.tgz#72580b7e9145fb39b6676f9c5e5fb100b934179a" @@ -1741,6 +1947,11 @@ debug@^4.4.0: dependencies: ms "^2.1.3" +decimal.js@^10.4.3: + version "10.5.0" + resolved "https://registry.yarnpkg.com/decimal.js/-/decimal.js-10.5.0.tgz#0f371c7cf6c4898ce0afb09836db73cd82010f22" + integrity sha512-8vDa8Qxvr/+d94hSh5P3IJwI5t8/c0KsMp+g8bNw9cY2icONa5aPfvKeieW1WlG0WQYwwhJ7mjui2xtiePQSXw== + decode-uri-component@^0.2.2: version "0.2.2" resolved "https://registry.yarnpkg.com/decode-uri-component/-/decode-uri-component-0.2.2.tgz#e69dbe25d37941171dd540e024c444cd5188e1e9" @@ -1782,6 +1993,11 @@ define-data-property@^1.0.1, define-data-property@^1.1.4: es-errors "^1.3.0" gopd "^1.0.1" +define-lazy-prop@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/define-lazy-prop/-/define-lazy-prop-2.0.0.tgz#3f7ae421129bcaaac9bc74905c98a0009ec9ee7f" + integrity sha512-Ds09qNh8yw3khSjiJjiUInaGX9xlqZDY7JVryGxdxV7NPeuqQfplOpQ66yJFZut3jLa5zOwkXw1g9EI2uKh4Og== + define-properties@^1.1.3, define-properties@^1.2.0, define-properties@^1.2.1: version "1.2.1" resolved "https://registry.yarnpkg.com/define-properties/-/define-properties-1.2.1.tgz#10781cc616eb951a80a034bafcaa7377f6af2b6c" @@ -1820,6 +2036,16 @@ devtools-protocol@0.0.1402036: resolved "https://registry.yarnpkg.com/devtools-protocol/-/devtools-protocol-0.0.1402036.tgz#6f55044daed0ae5f0ec5c80c834b7b8edc822441" integrity sha512-JwAYQgEvm3yD45CHB+RmF5kMbWtXBaOGwuxa87sZogHcLCv8c/IqnThaoQ1y60d7pXWjSKWQphPEc+1rAScVdg== +devtools-protocol@0.0.1413902: + version "0.0.1413902" + resolved "https://registry.yarnpkg.com/devtools-protocol/-/devtools-protocol-0.0.1413902.tgz#a0f00fe9eb25ab337a8f9656a29e0a1a69f42401" + integrity sha512-yRtvFD8Oyk7C9Os3GmnFZLu53yAfsnyw1s+mLmHHUK0GQEc9zthHWvS1r67Zqzm5t7v56PILHIVZ7kmFMaL2yQ== + +devtools-protocol@0.0.1436416: + version "0.0.1436416" + resolved "https://registry.yarnpkg.com/devtools-protocol/-/devtools-protocol-0.0.1436416.tgz#ce8af8a210b8bcac83c5c8f095b9f977a9570df0" + integrity sha512-iGLhz2WOrlBLcTcoVsFy5dPPUqILG6cc8MITYd5lV6i38gWG14bMXRH/d8G5KITrWHBnbsOnWHfc9Qs4/jej9Q== + diff-sequences@^29.6.3: version "29.6.3" resolved "https://registry.yarnpkg.com/diff-sequences/-/diff-sequences-29.6.3.tgz#4deaf894d11407c51efc8418012f9e70b84ea921" @@ -1846,6 +2072,13 @@ doctrine@^3.0.0: dependencies: esutils "^2.0.2" +dot-prop@^5.2.0: + version "5.3.0" + resolved "https://registry.yarnpkg.com/dot-prop/-/dot-prop-5.3.0.tgz#90ccce708cd9cd82cc4dc8c3ddd9abdd55b20e88" + integrity sha512-QM8q3zDe58hqUqjraQOmzZ1LIH9SWQJTlEKCH4kJ2oQvLZk7RbQXvtDM2XEq3fwkV9CCvvH4LA0AV+ogFsBM2Q== + dependencies: + is-obj "^2.0.0" + electron-to-chromium@^1.5.41: version "1.5.64" resolved "https://registry.yarnpkg.com/electron-to-chromium/-/electron-to-chromium-1.5.64.tgz#ac8c4c89075d35a1514b620f47dfe48a71ec3697" @@ -1868,11 +2101,24 @@ end-of-stream@^1.1.0, end-of-stream@^1.4.1: dependencies: once "^1.4.0" +enquirer@^2.3.6: + version "2.4.1" + resolved "https://registry.yarnpkg.com/enquirer/-/enquirer-2.4.1.tgz#93334b3fbd74fc7097b224ab4a8fb7e40bf4ae56" + integrity sha512-rRqJg/6gd538VHvR3PSrdRBb/1Vy2YfzHqzvbhGIQpDRKIa4FgV/54b5Q1xYSxOOwKvjXweS26E0Q+nAMwp2pQ== + dependencies: + ansi-colors "^4.1.1" + strip-ansi "^6.0.1" + entities@^4.3.0, entities@^4.5.0: version "4.5.0" resolved "https://registry.yarnpkg.com/entities/-/entities-4.5.0.tgz#5d268ea5e7113ec74c4d033b79ea5a35a488fb48" integrity sha512-V0hjH4dGPh9Ao5p0MoRY6BVqtwCjhz6vI5LT8AJ55H+4g9/4vbHx1I54fS0XuclLhDHArPQCiMjDxjaL8fPxhw== +env-paths@^2.2.1: + version "2.2.1" + resolved "https://registry.yarnpkg.com/env-paths/-/env-paths-2.2.1.tgz#420399d416ce1fbe9bc0a07c62fa68d67fd0f8f2" + integrity sha512-+h1lkLKhZMTYjog1VEpJNG7NZJWcuc2DDk/qsqSTRRCOXiLjeQ1d1/udrUGhqMxUgAlwKNZ0cf2uqan5GLuS2A== + error-ex@^1.3.1: version "1.3.2" resolved "https://registry.yarnpkg.com/error-ex/-/error-ex-1.3.2.tgz#b4ac40648107fdcdcfae242f428bea8a14d4f1bf" @@ -2515,7 +2761,7 @@ gopd@^1.0.1: dependencies: get-intrinsic "^1.1.3" -graceful-fs@^4.1.6, graceful-fs@^4.2.0, graceful-fs@^4.2.9: +graceful-fs@^4.1.2, graceful-fs@^4.1.6, graceful-fs@^4.2.0, graceful-fs@^4.2.9: version "4.2.11" resolved "https://registry.yarnpkg.com/graceful-fs/-/graceful-fs-4.2.11.tgz#4183e4e8bf08bb6e05bbb2f7d2e0c8f712ca40e3" integrity sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ== @@ -2588,7 +2834,7 @@ html-escaper@^2.0.0: resolved "https://registry.yarnpkg.com/html-escaper/-/html-escaper-2.0.2.tgz#dfd60027da36a36dfcbe236262c00a5822681453" integrity sha512-H2iMtd0I4Mt5eYiapRdIDjp+XzelXQ0tFE4JS7YFwFevXXMmOp9myNrUvCg0D6ws8iqkRPBfKHgbwig1SmlLfg== -http-link-header@^1.1.3: +http-link-header@^1.1.1, http-link-header@^1.1.3: version "1.1.3" resolved "https://registry.yarnpkg.com/http-link-header/-/http-link-header-1.1.3.tgz#b367b7a0ad1cf14027953f31aa1df40bb433da2a" integrity sha512-3cZ0SRL8fb9MUlU3mKM61FcQvPfXx2dBrZW3Vbg5CXa8jFlK8OaEpePenLe1oEXQduhz8b0QjsqfS59QP4AJDQ== @@ -2674,6 +2920,16 @@ ignore@^5.2.0, ignore@^5.2.4: resolved "https://registry.yarnpkg.com/ignore/-/ignore-5.3.2.tgz#3cd40e729f3643fd87cb04e50bf0eb722bc596f5" integrity sha512-hsBTNUqQTDwkWtcdYI2i06Y/nUBEsNEDJKjWdigLvegy8kDuJAS8uRlpkkcQpyEXL0Z/pjDy5HBmMjRCJ2gq+g== +image-ssim@^0.2.0: + version "0.2.0" + resolved "https://registry.yarnpkg.com/image-ssim/-/image-ssim-0.2.0.tgz#83b42c7a2e6e4b85505477fe6917f5dbc56420e5" + integrity sha512-W7+sO6/yhxy83L0G7xR8YAc5Z5QFtYEXXRV6EaE8tuYBZJnA3gVgp3q7X7muhLZVodeb9UfvjSbwt9VJwjIYAg== + +immediate@~3.0.5: + version "3.0.6" + resolved "https://registry.yarnpkg.com/immediate/-/immediate-3.0.6.tgz#9db1dbd0faf8de6fbe0f5dd5e56bb606280de69b" + integrity sha512-XXOFtyqDjNDAQxVfYxuF7g9Il/IbWmmlQg2MYKOH8ExIT1qg6xc4zyS3HaEEATgs1btfzxq15ciUiY7gjSXRGQ== + import-fresh@^3.2.1: version "3.3.0" resolved "https://registry.yarnpkg.com/import-fresh/-/import-fresh-3.3.0.tgz#37162c25fcb9ebaa2e6e53d5b4d88ce17d9e0c2b" @@ -2682,6 +2938,14 @@ import-fresh@^3.2.1: parent-module "^1.0.0" resolve-from "^4.0.0" +import-fresh@^3.3.0: + version "3.3.1" + resolved "https://registry.yarnpkg.com/import-fresh/-/import-fresh-3.3.1.tgz#9cecb56503c0ada1f2741dbbd6546e4b13b57ccf" + integrity sha512-TR3KfrTZTYLPB6jUjfx6MF9WcWrHL9su5TObK4ZkYgBdWKPOFoSoQIdEuTuR82pmtxH2spWG9h6etwfr1pLBqQ== + dependencies: + parent-module "^1.0.0" + resolve-from "^4.0.0" + import-local@^3.0.2: version "3.2.0" resolved "https://registry.yarnpkg.com/import-local/-/import-local-3.2.0.tgz#c3d5c745798c02a6f8b897726aba5100186ee260" @@ -2722,6 +2986,16 @@ internal-slot@^1.0.7: hasown "^2.0.0" side-channel "^1.0.4" +intl-messageformat@^10.5.3: + version "10.7.16" + resolved "https://registry.yarnpkg.com/intl-messageformat/-/intl-messageformat-10.7.16.tgz#d909f9f9f4ab857fbe681d559b958dd4dd9f665a" + integrity sha512-UmdmHUmp5CIKKjSoE10la5yfU+AYJAaiYLsodbjL4lji83JNvgOQUjGaGhGrpFCb0Uh7sl7qfP1IyILa8Z40ug== + dependencies: + "@formatjs/ecma402-abstract" "2.3.4" + "@formatjs/fast-memoize" "2.2.7" + "@formatjs/icu-messageformat-parser" "2.11.2" + tslib "^2.8.0" + ioredis@^5.3.2: version "5.4.1" resolved "https://registry.yarnpkg.com/ioredis/-/ioredis-5.4.1.tgz#1c56b70b759f01465913887375ed809134296f40" @@ -2829,6 +3103,11 @@ is-date-object@^1.0.1, is-date-object@^1.0.5: dependencies: has-tostringtag "^1.0.0" +is-docker@^2.0.0, is-docker@^2.1.1: + version "2.2.1" + resolved "https://registry.yarnpkg.com/is-docker/-/is-docker-2.2.1.tgz#33eeabe23cfe86f14bde4408a02c0cfb853acdaa" + integrity sha512-F+i2BKsFrH66iaUFc0woD8sLy8getkwTwtOBjvs56Cx4CgJDeKQeqfz8wAYiSb8JOprWhHH5p77PbmYCvvUuXQ== + is-extglob@^2.1.1: version "2.1.1" resolved "https://registry.yarnpkg.com/is-extglob/-/is-extglob-2.1.1.tgz#a88c02535791f02ed37c76a1b9ea9773c833f8c2" @@ -2887,6 +3166,11 @@ is-number@^7.0.0: resolved "https://registry.yarnpkg.com/is-number/-/is-number-7.0.0.tgz#7535345b896734d5f80c4d06c50955527a14f12b" integrity sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng== +is-obj@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/is-obj/-/is-obj-2.0.0.tgz#473fb05d973705e3fd9620545018ca8e22ef4982" + integrity sha512-drqDG3cbczxxEJRoOXcOjtdp1J/lyp1mNn0xaznRs8+muBhgQcrnbspox5X5fOw0HnMnbfDzvnEMEtqDEJEo8w== + is-path-inside@^3.0.3: version "3.0.3" resolved "https://registry.yarnpkg.com/is-path-inside/-/is-path-inside-3.0.3.tgz#d231362e53a07ff2b0e0ea7fed049161ffd16283" @@ -2943,6 +3227,11 @@ is-typed-array@^1.1.13, is-typed-array@^1.1.3: dependencies: which-typed-array "^1.1.14" +is-typedarray@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/is-typedarray/-/is-typedarray-1.0.0.tgz#e479c80858df0c1b11ddda6940f96011fcda4a9a" + integrity sha512-cyA56iCMHAh5CdzjJIa4aohJyeO1YbwLi3Jc35MmRU6poroFjIGZzUzupGiRPOjgHg9TLu43xbpwXk523fMxKA== + is-weakmap@^2.0.2: version "2.0.2" resolved "https://registry.yarnpkg.com/is-weakmap/-/is-weakmap-2.0.2.tgz#bf72615d649dfe5f699079c54b83e47d1ae19cfd" @@ -2963,6 +3252,13 @@ is-weakset@^2.0.3: call-bind "^1.0.7" get-intrinsic "^1.2.4" +is-wsl@^2.2.0: + version "2.2.0" + resolved "https://registry.yarnpkg.com/is-wsl/-/is-wsl-2.2.0.tgz#74a4c76e77ca9fd3f932f290c17ea326cd157271" + integrity sha512-fKzAra0rGJUUBwGBgNkHZuToZcn+TtXHpeCgmkMJMMYx1sQDYaCSyjJBSCa2nH1DGm7s3n1oBnohoVTBaN7Lww== + dependencies: + is-docker "^2.0.0" + isarray@^2.0.5: version "2.0.5" resolved "https://registry.yarnpkg.com/isarray/-/isarray-2.0.5.tgz#8af1e4c1221244cc62459faf38940d4e644a5723" @@ -3395,11 +3691,21 @@ jest@^29.7.0: import-local "^3.0.2" jest-cli "^29.7.0" +jpeg-js@^0.4.1, jpeg-js@^0.4.4: + version "0.4.4" + resolved "https://registry.yarnpkg.com/jpeg-js/-/jpeg-js-0.4.4.tgz#a9f1c6f1f9f0fa80cdb3484ed9635054d28936aa" + integrity sha512-WZzeDOEtTOBK4Mdsar0IqEU5sMr3vSV2RqkAIzUEV2BHnUfKGyswWFPFwK5EeDo93K3FohSHbLAjj0s1Wzd+dg== + js-levenshtein@^1.1.6: version "1.1.6" resolved "https://registry.yarnpkg.com/js-levenshtein/-/js-levenshtein-1.1.6.tgz#c6cee58eb3550372df8deb85fad5ce66ce01d59d" integrity sha512-X2BB11YZtrRqY4EnQcLX5Rh373zbK4alC1FW7D7MBhL2gtcC17cTnr6DmfHZeS0s2rTHjUTMMHfG7gO8SSdw+g== +js-library-detector@^6.7.0: + version "6.7.0" + resolved "https://registry.yarnpkg.com/js-library-detector/-/js-library-detector-6.7.0.tgz#5075c71fcf835b71133bca13363b91509a39235a" + integrity sha512-c80Qupofp43y4cJ7+8TTDN/AsDwLi5oOm/plBrWI+iQt485vKXCco+yVmOwEgdo9VOdsYTuV0UlTeetVPTriXA== + "js-tokens@^3.0.0 || ^4.0.0", js-tokens@^4.0.0: version "4.0.0" resolved "https://registry.yarnpkg.com/js-tokens/-/js-tokens-4.0.0.tgz#19203fb59991df98e3a287050d4647cdeaf32499" @@ -3499,11 +3805,72 @@ levn@^0.4.1: prelude-ls "^1.2.1" type-check "~0.4.0" +lie@3.1.1: + version "3.1.1" + resolved "https://registry.yarnpkg.com/lie/-/lie-3.1.1.tgz#9a436b2cc7746ca59de7a41fa469b3efb76bd87e" + integrity sha512-RiNhHysUjhrDQntfYSfY4MU24coXXdEOgw9WGcKHNeEwffDYbF//u87M1EWaMGzuFoSbqW0C9C6lEEhDOAswfw== + dependencies: + immediate "~3.0.5" + +lighthouse-logger@^2.0.1: + version "2.0.1" + resolved "https://registry.yarnpkg.com/lighthouse-logger/-/lighthouse-logger-2.0.1.tgz#48895f639b61cca89346bb6f47f7403a3895fa02" + integrity sha512-ioBrW3s2i97noEmnXxmUq7cjIcVRjT5HBpAYy8zE11CxU9HqlWHHeRxfeN1tn8F7OEMVPIC9x1f8t3Z7US9ehQ== + dependencies: + debug "^2.6.9" + marky "^1.2.2" + +lighthouse-stack-packs@1.12.2: + version "1.12.2" + resolved "https://registry.yarnpkg.com/lighthouse-stack-packs/-/lighthouse-stack-packs-1.12.2.tgz#dbe0ccdbc381784ef176f4f8c2367ac5b077d6ca" + integrity sha512-Ug8feS/A+92TMTCK6yHYLwaFMuelK/hAKRMdldYkMNwv+d9PtWxjXEg6rwKtsUXTADajhdrhXyuNCJ5/sfmPFw== + +lighthouse@^12.5.1: + version "12.5.1" + resolved "https://registry.yarnpkg.com/lighthouse/-/lighthouse-12.5.1.tgz#92895d83355ef7e34cdeb9eac471b74e43b4d734" + integrity sha512-ooOIqtBxOEnuX3yKtc8WiMPI/fPqHtXHaXU4ey87icRcY5I2B9+imk8i6U7duIO+yrU0WwbIwhmCs8s/FFNRgA== + dependencies: + "@paulirish/trace_engine" "0.0.50" + "@sentry/node" "^7.0.0" + axe-core "^4.10.3" + chrome-launcher "^1.1.2" + configstore "^5.0.1" + csp_evaluator "1.1.5" + devtools-protocol "0.0.1436416" + enquirer "^2.3.6" + http-link-header "^1.1.1" + intl-messageformat "^10.5.3" + jpeg-js "^0.4.4" + js-library-detector "^6.7.0" + lighthouse-logger "^2.0.1" + lighthouse-stack-packs "1.12.2" + lodash-es "^4.17.21" + lookup-closest-locale "6.2.0" + metaviewport-parser "0.3.0" + open "^8.4.0" + parse-cache-control "1.0.1" + puppeteer-core "^24.4.0" + robots-parser "^3.0.1" + semver "^5.3.0" + speedline-core "^1.4.3" + third-party-web "^0.26.5" + tldts-icann "^6.1.16" + ws "^7.0.0" + yargs "^17.3.1" + yargs-parser "^21.0.0" + lines-and-columns@^1.1.6: version "1.2.4" resolved "https://registry.yarnpkg.com/lines-and-columns/-/lines-and-columns-1.2.4.tgz#eca284f75d2965079309dc0ad9255abb2ebc1632" integrity sha512-7ylylesZQ/PV29jhEDl3Ufjo6ZX7gCqJr5F7PKrqc93v7fzSymt1BpwEU8nAUXs8qzzvqhbjhK5QZg6Mt/HkBg== +localforage@^1.8.1: + version "1.10.0" + resolved "https://registry.yarnpkg.com/localforage/-/localforage-1.10.0.tgz#5c465dc5f62b2807c3a84c0c6a1b1b3212781dd4" + integrity sha512-14/H1aX7hzBBmmh7sGPd+AOMkkIrHM3Z1PAyGgZigA1H1p5O5ANnMyWzvpAETtG68/dC4pC0ncy3+PPGzXZHPg== + dependencies: + lie "3.1.1" + locate-path@^5.0.0: version "5.0.0" resolved "https://registry.yarnpkg.com/locate-path/-/locate-path-5.0.0.tgz#1afba396afd676a6d42504d0a67a3a7eb9f62aa0" @@ -3518,6 +3885,11 @@ locate-path@^6.0.0: dependencies: p-locate "^5.0.0" +lodash-es@^4.17.21: + version "4.17.21" + resolved "https://registry.yarnpkg.com/lodash-es/-/lodash-es-4.17.21.tgz#43e626c46e6591b7750beb2b50117390c609e3ee" + integrity sha512-mKnC+QJ9pWVzv+C4/U3rRsHapFfHvQFoFB92e52xeyGMcX6/OlIl78je1u8vePzYZSkkogMPJ2yjxxsb89cxyw== + lodash.defaults@^4.2.0: version "4.2.0" resolved "https://registry.yarnpkg.com/lodash.defaults/-/lodash.defaults-4.2.0.tgz#d09178716ffea4dde9e5fb7b37f6f0802274580c" @@ -3538,6 +3910,11 @@ lodash@^4.17.14, lodash@^4.17.21: resolved "https://registry.yarnpkg.com/lodash/-/lodash-4.17.21.tgz#679591c564c3bffaae8454cf0b3df370c3d6911c" integrity sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg== +lookup-closest-locale@6.2.0: + version "6.2.0" + resolved "https://registry.yarnpkg.com/lookup-closest-locale/-/lookup-closest-locale-6.2.0.tgz#57f665e604fd26f77142d48152015402b607bcf3" + integrity sha512-/c2kL+Vnp1jnV6K6RpDTHK3dgg0Tu2VVp+elEiJpjfS1UyY7AjOYHohRug6wT0OpoX2qFgNORndE9RqesfVxWQ== + loose-envify@^1.4.0: version "1.4.0" resolved "https://registry.yarnpkg.com/loose-envify/-/loose-envify-1.4.0.tgz#71ee51fa7be4caec1a63839f7e682d8132d30caf" @@ -3557,6 +3934,13 @@ lru-cache@^7.14.1: resolved "https://registry.yarnpkg.com/lru-cache/-/lru-cache-7.18.3.tgz#f793896e0fd0e954a59dfdd82f0773808df6aa89" integrity sha512-jumlc0BIUrS3qJGgIkWZsyfAM7NCWiBcCDhnd+3NNM5KbBmLTgHVfWBcg6W+rLUsIpzpERPsvwUP7CckAQSOoA== +make-dir@^3.0.0: + version "3.1.0" + resolved "https://registry.yarnpkg.com/make-dir/-/make-dir-3.1.0.tgz#415e967046b3a7f1d185277d84aa58203726a13f" + integrity sha512-g3FeP20LNwhALb/6Cz6Dd4F2ngze0jz7tbzrD2wAV+o9FeNHe4rL+yK2md0J/fiSf1sa1ADhXqi5+oVwOM/eGw== + dependencies: + semver "^6.0.0" + make-dir@^4.0.0: version "4.0.0" resolved "https://registry.yarnpkg.com/make-dir/-/make-dir-4.0.0.tgz#c3c2307a771277cd9638305f915c29ae741b614e" @@ -3571,6 +3955,11 @@ makeerror@1.0.12: dependencies: tmpl "1.0.5" +marky@^1.2.2: + version "1.2.5" + resolved "https://registry.yarnpkg.com/marky/-/marky-1.2.5.tgz#55796b688cbd72390d2d399eaaf1832c9413e3c0" + integrity sha512-q9JtQJKjpsVxCRVgQ+WapguSbKC3SQ5HEzFGPAJMStgh3QjCawp00UKv3MTTAArTmGmmPUvllHZoNbZ3gs0I+Q== + md5@^2.3.0: version "2.3.0" resolved "https://registry.yarnpkg.com/md5/-/md5-2.3.0.tgz#c3da9a6aae3a30b46b7b0c349b87b110dc3bda4f" @@ -3590,6 +3979,11 @@ merge2@^1.3.0, merge2@^1.4.1: resolved "https://registry.yarnpkg.com/merge2/-/merge2-1.4.1.tgz#4368892f885e907455a6fd7dc55c0c9d404990ae" integrity sha512-8q7VEgMJW4J8tcfVPy8g09NcQwZdbwFEqhe/WZkoIzjn/3TGDwtOCYtXGxA3O8tPzpczCCDgv+P2P5y00ZJOOg== +metaviewport-parser@0.3.0: + version "0.3.0" + resolved "https://registry.yarnpkg.com/metaviewport-parser/-/metaviewport-parser-0.3.0.tgz#6af1e99b5eaf250c049e0af1e84143a39750dea6" + integrity sha512-EoYJ8xfjQ6kpe9VbVHvZTZHiOl4HL1Z18CrZ+qahvLXT7ZO4YTC2JMyt5FaUp9JJp6J4Ybb/z7IsCXZt86/QkQ== + micromatch@^4.0.4: version "4.0.8" resolved "https://registry.yarnpkg.com/micromatch/-/micromatch-4.0.8.tgz#d66fa18f3a47076789320b9b1af32bd86d9fa202" @@ -3681,6 +4075,11 @@ mkdirp@^0.5.6: dependencies: minimist "^1.2.6" +ms@2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/ms/-/ms-2.0.0.tgz#5608aeadfc00be6c2901df5f9861788de0d597c8" + integrity sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A== + ms@^2.1.1, ms@^2.1.3: version "2.1.3" resolved "https://registry.yarnpkg.com/ms/-/ms-2.1.3.tgz#574c8138ce1d2b5861f0b44579dbadd60c6615b2" @@ -3802,6 +4201,15 @@ onetime@^5.1.2: dependencies: mimic-fn "^2.1.0" +open@^8.4.0: + version "8.4.2" + resolved "https://registry.yarnpkg.com/open/-/open-8.4.2.tgz#5b5ffe2a8f793dcd2aad73e550cb87b59cb084f9" + integrity sha512-7x81NCL719oNbsq/3mh+hVrAWmFuEYUqrq/Iw3kUzH8ReypT9QQ0BLoJS7/G9k6N81XjW4qHWtjWwe/9eLy1EQ== + dependencies: + define-lazy-prop "^2.0.0" + is-docker "^2.1.1" + is-wsl "^2.2.0" + opener@^1.5.1: version "1.5.2" resolved "https://registry.yarnpkg.com/opener/-/opener-1.5.2.tgz#5d37e1f35077b9dcac4301372271afdeb2a13598" @@ -3899,6 +4307,11 @@ parent-module@^1.0.0: dependencies: callsites "^3.0.0" +parse-cache-control@1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/parse-cache-control/-/parse-cache-control-1.0.1.tgz#8eeab3e54fa56920fe16ba38f77fa21aacc2d74e" + integrity sha512-60zvsJReQPX5/QP0Kzfd/VrpjScIQ7SHBW6bFCYfEP+fp0Eppr1SHhIO5nd1PjZtvclzSzES9D/p5nFJurwfWg== + parse-json@^5.2.0: version "5.2.0" resolved "https://registry.yarnpkg.com/parse-json/-/parse-json-5.2.0.tgz#c76fc66dee54231c962b22bcc8a72cf2f99753cd" @@ -4119,6 +4532,18 @@ punycode@^2.1.0: resolved "https://registry.yarnpkg.com/punycode/-/punycode-2.3.1.tgz#027422e2faec0b25e1549c3e1bd8309b9133b6e5" integrity sha512-vYt7UD1U9Wg6138shLtLOvdAu+8DsC/ilFtEVHcH+wydcSpNE20AfSOduf6MkRFahL5FY7X1oU7nKVZFtfq8Fg== +puppeteer-core@24.4.0, puppeteer-core@^24.4.0: + version "24.4.0" + resolved "https://registry.yarnpkg.com/puppeteer-core/-/puppeteer-core-24.4.0.tgz#a301c58344fe939b487704593681ea9f913fe6f8" + integrity sha512-eFw66gCnWo0X8Hyf9KxxJtms7a61NJVMiSaWfItsFPzFBsjsWdmcNlBdsA1WVwln6neoHhsG+uTVesKmTREn/g== + dependencies: + "@puppeteer/browsers" "2.8.0" + chromium-bidi "2.1.2" + debug "^4.4.0" + devtools-protocol "0.0.1413902" + typed-query-selector "^2.12.0" + ws "^8.18.1" + puppeteer-core@^24.2.0: version "24.2.0" resolved "https://registry.yarnpkg.com/puppeteer-core/-/puppeteer-core-24.2.0.tgz#4f935d1417777b335ca747bf1c3ae997989ed6e4" @@ -4131,6 +4556,18 @@ puppeteer-core@^24.2.0: typed-query-selector "^2.12.0" ws "^8.18.0" +puppeteer@^24.4.0: + version "24.4.0" + resolved "https://registry.yarnpkg.com/puppeteer/-/puppeteer-24.4.0.tgz#fb45a67e72f4e6e34db8f404ef61cdd42099e6e6" + integrity sha512-E4JhJzjS8AAI+6N/b+Utwarhz6zWl3+MR725fal+s3UlOlX2eWdsvYYU+Q5bXMjs9eZEGkNQroLkn7j11s2k1Q== + dependencies: + "@puppeteer/browsers" "2.8.0" + chromium-bidi "2.1.2" + cosmiconfig "^9.0.0" + devtools-protocol "0.0.1413902" + puppeteer-core "24.4.0" + typed-query-selector "^2.12.0" + pure-rand@^6.0.0: version "6.1.0" resolved "https://registry.yarnpkg.com/pure-rand/-/pure-rand-6.1.0.tgz#d173cf23258231976ccbdb05247c9787957604f2" @@ -4311,6 +4748,11 @@ rimraf@^3.0.2: dependencies: glob "^7.1.3" +robots-parser@^3.0.1: + version "3.0.1" + resolved "https://registry.yarnpkg.com/robots-parser/-/robots-parser-3.0.1.tgz#3d8a3cdfa8ac240cbb062a4bd16fcc0e0fb9ed23" + integrity sha512-s+pyvQeIKIZ0dx5iJiQk1tPLJAWln39+MI5jtM8wnyws+G5azk+dMnMX0qfbqNetKKNgcWWOdi0sfm+FbQbgdQ== + run-parallel@^1.1.9: version "1.2.0" resolved "https://registry.yarnpkg.com/run-parallel/-/run-parallel-1.2.0.tgz#66d1368da7bdf921eb9d95bd1a9229e7f21a43ee" @@ -4367,7 +4809,12 @@ secure-compare@3.0.1: resolved "https://registry.yarnpkg.com/secure-compare/-/secure-compare-3.0.1.tgz#f1a0329b308b221fae37b9974f3d578d0ca999e3" integrity sha512-AckIIV90rPDcBcglUwXPF3kg0P0qmPsPXAj6BBEENQE1p5yA1xfmDJzfi1Tappj37Pv2mVbKpL3Z1T+Nn7k1Qw== -semver@^6.3.0, semver@^6.3.1: +semver@^5.3.0: + version "5.7.2" + resolved "https://registry.yarnpkg.com/semver/-/semver-5.7.2.tgz#48d55db737c3287cd4835e17fa13feace1c41ef8" + integrity sha512-cBznnQ9KjJqU67B52RMC65CMarK2600WFnbkcaiwWq3xy/5haFJlshgnpjovMVJ+Hff49d8GEn0b87C5pDQ10g== + +semver@^6.0.0, semver@^6.3.0, semver@^6.3.1: version "6.3.1" resolved "https://registry.yarnpkg.com/semver/-/semver-6.3.1.tgz#556d2ef8689146e46dcea4bfdd095f3434dffcb4" integrity sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA== @@ -4377,7 +4824,7 @@ semver@^7.3.5, semver@^7.5.3, semver@^7.5.4: resolved "https://registry.yarnpkg.com/semver/-/semver-7.6.3.tgz#980f7b5550bc175fb4dc09403085627f9eb33143" integrity sha512-oVekP1cKtI+CTDvHWYFUcMtsK/00wmAEfyqKfNdARm8u1wNVhSgaX7A8d4UuIlUI5e84iEwOhs7ZPYRmzU9U6A== -semver@^7.7.0: +semver@^7.7.0, semver@^7.7.1: version "7.7.1" resolved "https://registry.yarnpkg.com/semver/-/semver-7.7.1.tgz#abd5098d82b18c6c81f6074ff2647fd3e7220c9f" integrity sha512-hlq8tAfn0m/61p4BVRcPzIGr6LKiMwo4VM6dGi6pt4qcRkmNzTcWq6eCEjEh+qXjkMDvPlOFFSGwQjoEa6gyMA== @@ -4440,7 +4887,7 @@ side-channel@^1.0.4, side-channel@^1.0.6: get-intrinsic "^1.2.4" object-inspect "^1.13.1" -signal-exit@^3.0.3, signal-exit@^3.0.7: +signal-exit@^3.0.2, signal-exit@^3.0.3, signal-exit@^3.0.7: version "3.0.7" resolved "https://registry.yarnpkg.com/signal-exit/-/signal-exit-3.0.7.tgz#a9a1767f8af84155114eaabd73f99273c8f59ad9" integrity sha512-wnD2ZE+l+SPC/uoS0vXeE9L1+0wuaMqKlfz9AMUo38JsyLSBWSFcHR1Rri62LZc12vLr1gb3jl7iwQhgwpAbGQ== @@ -4511,6 +4958,15 @@ source-map@^0.6.0, source-map@^0.6.1, source-map@~0.6.1: resolved "https://registry.yarnpkg.com/source-map/-/source-map-0.6.1.tgz#74722af32e9614e9c287a8d0bbde48b5e2f1a263" integrity sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g== +speedline-core@^1.4.3: + version "1.4.3" + resolved "https://registry.yarnpkg.com/speedline-core/-/speedline-core-1.4.3.tgz#4d6e7276e2063c2d36a375cb25a523ac73475319" + integrity sha512-DI7/OuAUD+GMpR6dmu8lliO2Wg5zfeh+/xsdyJZCzd8o5JgFUjCeLsBDuZjIQJdwXS3J0L/uZYrELKYqx+PXog== + dependencies: + "@types/node" "*" + image-ssim "^0.2.0" + jpeg-js "^0.4.1" + split-on-first@^1.0.0: version "1.1.0" resolved "https://registry.yarnpkg.com/split-on-first/-/split-on-first-1.1.0.tgz#f610afeee3b12bce1d0c30425e76398b78249a5f" @@ -4789,6 +5245,11 @@ text-table@^0.2.0: resolved "https://registry.yarnpkg.com/text-table/-/text-table-0.2.0.tgz#7f5ee823ae805207c00af2df4a84ec3fcfa570b4" integrity sha512-N+8UisAXDGk8PFXP4HAzVR9nbfmVJ3zYLAWiTIoqC5v5isinhr+r5uaO8+7r3BMfuNIufIsA7RdpVgacC2cSpw== +third-party-web@^0.26.5, third-party-web@latest: + version "0.26.5" + resolved "https://registry.yarnpkg.com/third-party-web/-/third-party-web-0.26.5.tgz#c442b2a16db66a6064e05e0f060c9ed780f31709" + integrity sha512-tDuKQJUTfjvi9Fcrs1s6YAQAB9mzhTSbBZMfNgtWNmJlHuoFeXO6dzBFdGeCWRvYL50jQGK0jPsBZYxqZQJ2SA== + through2@^4.0.2: version "4.0.2" resolved "https://registry.yarnpkg.com/through2/-/through2-4.0.2.tgz#a7ce3ac2a7a8b0b966c80e7c49f0484c3b239764" @@ -4796,6 +5257,18 @@ through2@^4.0.2: dependencies: readable-stream "3" +tldts-core@^6.1.85: + version "6.1.85" + resolved "https://registry.yarnpkg.com/tldts-core/-/tldts-core-6.1.85.tgz#6f6b795468c0b5f7660a11c7306ff2766ceaea7e" + integrity sha512-DTjUVvxckL1fIoPSb3KE7ISNtkWSawZdpfxGxwiIrZoO6EbHVDXXUIlIuWympPaeS+BLGyggozX/HTMsRAdsoA== + +tldts-icann@^6.1.16: + version "6.1.85" + resolved "https://registry.yarnpkg.com/tldts-icann/-/tldts-icann-6.1.85.tgz#9eb8794c20805c29e59c7ee491ba138652fd776e" + integrity sha512-LIL8koGz5n2ni5wym7qw5vjeZxCgh5uI0Vs4LQu6M8k1IoknMttui/WTVI58jXBqRRSx76IniSJdeZDVFdALdw== + dependencies: + tldts-core "^6.1.85" + tmpl@1.0.5: version "1.0.5" resolved "https://registry.yarnpkg.com/tmpl/-/tmpl-1.0.5.tgz#8683e0b902bb9c20c4f726e3c0b69f36518c07cc" @@ -4828,7 +5301,7 @@ tslib@^1.10.0, tslib@^1.9.3: resolved "https://registry.yarnpkg.com/tslib/-/tslib-1.14.1.tgz#cf2d38bdc34a134bcaf1091c41f6619e2f672d00" integrity sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg== -tslib@^2.0.1, tslib@^2.4.0, tslib@^2.6.2, tslib@^2.7.0, tslib@^2.8.1: +tslib@^2.0.1, tslib@^2.4.0, tslib@^2.6.2, tslib@^2.7.0, tslib@^2.8.0, tslib@^2.8.1: version "2.8.1" resolved "https://registry.yarnpkg.com/tslib/-/tslib-2.8.1.tgz#612efe4ed235d567e8aba5f2a5fab70280ade83f" integrity sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w== @@ -4929,6 +5402,13 @@ typed-query-selector@^2.12.0: resolved "https://registry.yarnpkg.com/typed-query-selector/-/typed-query-selector-2.12.0.tgz#92b65dbc0a42655fccf4aeb1a08b1dddce8af5f2" integrity sha512-SbklCd1F0EiZOyPiW192rrHZzZ5sBijB6xM+cpmrwDqObvdtunOHHIk9fCGsoK5JVIYXoyEp4iEdE3upFH3PAg== +typedarray-to-buffer@^3.1.5: + version "3.1.5" + resolved "https://registry.yarnpkg.com/typedarray-to-buffer/-/typedarray-to-buffer-3.1.5.tgz#a97ee7a9ff42691b9f783ff1bc5112fe3fca9080" + integrity sha512-zdu8XMNEDepKKR+XYOXAVPtWui0ly0NtohUscw+UmaHiAWT8hrV1rr//H6V+0DvJ3OQ19S979M0laLfX8rm82Q== + dependencies: + is-typedarray "^1.0.0" + typescript@^5.5.4: version "5.7.2" resolved "https://registry.yarnpkg.com/typescript/-/typescript-5.7.2.tgz#3169cf8c4c8a828cde53ba9ecb3d2b1d5dd67be6" @@ -4961,6 +5441,13 @@ union@~0.5.0: dependencies: qs "^6.4.0" +unique-string@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/unique-string/-/unique-string-2.0.0.tgz#39c6451f81afb2749de2b233e3f7c5e8843bd89d" + integrity sha512-uNaeirEPvpZWSgzwsPGtU2zVSTrn/8L5q/IexZmH0eH6SA73CmAA5U4GwORTxQAZs95TAXLNqeLoPPNO5gZfWg== + dependencies: + crypto-random-string "^2.0.0" + unique-string@^3.0.0: version "3.0.0" resolved "https://registry.yarnpkg.com/unique-string/-/unique-string-3.0.0.tgz#84a1c377aff5fd7a8bc6b55d8244b2bd90d75b9a" @@ -5142,6 +5629,16 @@ wrappy@1: resolved "https://registry.yarnpkg.com/wrappy/-/wrappy-1.0.2.tgz#b5243d8f3ec1aa35f1364605bc0d1036e30ab69f" integrity sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ== +write-file-atomic@^3.0.0: + version "3.0.3" + resolved "https://registry.yarnpkg.com/write-file-atomic/-/write-file-atomic-3.0.3.tgz#56bd5c5a5c70481cd19c571bd39ab965a5de56e8" + integrity sha512-AvHcyZ5JnSfq3ioSyjrBkH9yW4m7Ayk8/9My/DD9onKeu/94fwrMocemO2QAJFAlnnDN+ZDS+ZjAR5ua1/PV/Q== + dependencies: + imurmurhash "^0.1.4" + is-typedarray "^1.0.0" + signal-exit "^3.0.2" + typedarray-to-buffer "^3.1.5" + write-file-atomic@^4.0.2: version "4.0.2" resolved "https://registry.yarnpkg.com/write-file-atomic/-/write-file-atomic-4.0.2.tgz#a9df01ae5b77858a027fd2e80768ee433555fcfd" @@ -5150,7 +5647,7 @@ write-file-atomic@^4.0.2: imurmurhash "^0.1.4" signal-exit "^3.0.7" -ws@^7.4.4: +ws@^7.0.0, ws@^7.4.4: version "7.5.10" resolved "https://registry.yarnpkg.com/ws/-/ws-7.5.10.tgz#58b5c20dc281633f6c19113f39b349bd8bd558d9" integrity sha512-+dbF1tHwZpXcbOJdVOkzLDxZP1ailvSxM6ZweXTegylPny803bFhA+vqBYw4s31NSAk4S2Qz+AKXK9a4wkdjcQ== @@ -5160,6 +5657,16 @@ ws@^8.18.0: resolved "https://registry.yarnpkg.com/ws/-/ws-8.18.0.tgz#0d7505a6eafe2b0e712d232b42279f53bc289bbc" integrity sha512-8VbfWfHLbbwu3+N6OKsOMpBdT4kXPDDB9cJk2bJ6mh9ucxdlnNvH1e+roYkKmN9Nxw2yjz7VzeO9oOz2zJ04Pw== +ws@^8.18.1: + version "8.18.1" + resolved "https://registry.yarnpkg.com/ws/-/ws-8.18.1.tgz#ea131d3784e1dfdff91adb0a4a116b127515e3cb" + integrity sha512-RKW2aJZMXeMxVpnZ6bck+RswznaxmzdULiBr6KY7XkTnW8uvt0iT9H5DkHUChXrc+uurzwa0rVI16n/Xzjdz1w== + +xdg-basedir@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/xdg-basedir/-/xdg-basedir-4.0.0.tgz#4bc8d9984403696225ef83a1573cbbcb4e79db13" + integrity sha512-PSNhEJDejZYV7h50BohL09Er9VaIefr2LMAf3OEmpCkjOi34eYyQYAXUTjEQtZJTKcF0E2UKTh+osDLsgNim9Q== + xml2js@^0.5.0: version "0.5.0" resolved "https://registry.yarnpkg.com/xml2js/-/xml2js-0.5.0.tgz#d9440631fbb2ed800203fad106f2724f62c493b7" @@ -5183,12 +5690,12 @@ yallist@^3.0.2: resolved "https://registry.yarnpkg.com/yallist/-/yallist-3.1.1.tgz#dbb7daf9bfd8bac9ab45ebf602b8cbad0d5d08fd" integrity sha512-a4UGQaWPH59mOXUYnAG2ewncQS4i4F43Tv3JoAM+s2VDAmS9NsK8GpDMLrCHPksFT7h3K6TOoUNn2pb7RoXx4g== -yargs-parser@^21.1.1: +yargs-parser@^21.0.0, yargs-parser@^21.1.1: version "21.1.1" resolved "https://registry.yarnpkg.com/yargs-parser/-/yargs-parser-21.1.1.tgz#9096bceebf990d21bb31fa9516e0ede294a77d35" integrity sha512-tVpsJW7DdjecAiFpbIB1e3qxIQsE6NoPc5/eTdrbbIC4h0LVsWhnoa3g+m2HclBIujHzsxZ4VJVA+GUuc2/LBw== -yargs@^17.3.1, yargs@^17.7.2: +yargs@17.7.2, yargs@^17.3.1, yargs@^17.7.2: version "17.7.2" resolved "https://registry.yarnpkg.com/yargs/-/yargs-17.7.2.tgz#991df39aca675a192b816e1e0363f9d75d2aa269" integrity sha512-7dSzzRQ++CKnNI/krKnYRV7JKKPUXMEh61soaHKg9mrWEhzFWhFnxPxGl+69cD1Ou63C13NUPCnmIcrvqCuM6w==