From eff6efd632ae98667a1512a5f44356af2d270659 Mon Sep 17 00:00:00 2001 From: Amine Saissi Hassani Date: Wed, 1 Jan 2025 01:24:08 +0100 Subject: [PATCH 1/2] add native mobile app support --- packages/shortest/package.json | 1 + packages/shortest/src/core/runner/index.ts | 355 +++-- packages/shortest/src/mobile/actions/index.ts | 34 + .../src/mobile/core/drivers/base-driver.ts | 26 + .../mobile/core/drivers/uiautomator-driver.ts | 125 ++ .../mobile/core/drivers/xcuitest-driver.ts | 125 ++ packages/shortest/src/mobile/core/index.ts | 1 + .../shortest/src/mobile/core/mobile-driver.ts | 51 + .../shortest/src/mobile/core/mobile-tool.ts | 42 + packages/shortest/src/mobile/manager/index.ts | 30 + packages/shortest/src/types/config.ts | 26 +- packages/shortest/src/types/index.ts | 1 + packages/shortest/src/types/mobile.ts | 35 + packages/shortest/src/types/test.ts | 9 +- pnpm-lock.yaml | 1320 ++++++++++++++++- 15 files changed, 2000 insertions(+), 181 deletions(-) create mode 100644 packages/shortest/src/mobile/actions/index.ts create mode 100644 packages/shortest/src/mobile/core/drivers/base-driver.ts create mode 100644 packages/shortest/src/mobile/core/drivers/uiautomator-driver.ts create mode 100644 packages/shortest/src/mobile/core/drivers/xcuitest-driver.ts create mode 100644 packages/shortest/src/mobile/core/index.ts create mode 100644 packages/shortest/src/mobile/core/mobile-driver.ts create mode 100644 packages/shortest/src/mobile/core/mobile-tool.ts create mode 100644 packages/shortest/src/mobile/manager/index.ts create mode 100644 packages/shortest/src/types/mobile.ts diff --git a/packages/shortest/package.json b/packages/shortest/package.json index d87441bb..98b3d0c7 100644 --- a/packages/shortest/package.json +++ b/packages/shortest/package.json @@ -57,6 +57,7 @@ }, "peerDependencies": { "@anthropic-ai/sdk": "0.32.0", + "webdriverio": "^9.5.0", "mailosaur": "^8.7.0", "dotenv": "^16.4.5", "esbuild": "^0.20.1", diff --git a/packages/shortest/src/core/runner/index.ts b/packages/shortest/src/core/runner/index.ts index c9cf6126..1e6b1e00 100644 --- a/packages/shortest/src/core/runner/index.ts +++ b/packages/shortest/src/core/runner/index.ts @@ -8,6 +8,7 @@ import { request, APIRequestContext } from "playwright"; import { AIClient } from "../../ai/client"; import { BrowserTool } from "../../browser/core/browser-tool"; import { BrowserManager } from "../../browser/manager"; +import { MobileManager } from "../../mobile/manager"; import { BaseCache } from "../../cache/cache"; import { initialize, getConfig } from "../../index"; import { @@ -15,11 +16,13 @@ import { TestContext, ShortestConfig, BrowserActionEnum, + MobileRunnerConfig, } from "../../types"; import { CacheEntry } from "../../types/cache"; import { hashData } from "../../utils/crypto"; import { Logger } from "../../utils/logger"; import { TestCompiler } from "../compiler"; +import { MobileDriver } from "../../mobile/core"; interface TestResult { result: "pass" | "fail"; @@ -34,13 +37,16 @@ export class TestRunner { private targetUrl: string | undefined; private compiler: TestCompiler; private browserManager!: BrowserManager; + private mobileManager: MobileManager | null = null; private logger: Logger; private debugAI: boolean; private noCache: boolean; private testContext: TestContext | null = null; private cache: BaseCache; + private driver: MobileDriver | null = null; constructor( + config: MobileRunnerConfig, cwd: string, exitOnSuccess = true, forceHeadless = false, @@ -57,6 +63,10 @@ export class TestRunner { this.compiler = new TestCompiler(); this.logger = new Logger(); this.cache = new BaseCache(); + + if (config.platform === 'ios' || config.platform === 'android') { + this.mobileManager = new MobileManager(config); + } } async initialize() { @@ -64,22 +74,25 @@ export class TestRunner { await initialize(); this.config = getConfig(); - // Override with CLI options - if (this.forceHeadless) { - this.config = { - ...this.config, - headless: true, - }; - } - - if (this.targetUrl) { - this.config = { - ...this.config, - baseUrl: this.targetUrl, - }; + if (this.mobileManager) { + this.driver = await this.mobileManager.launch(); + } else { + // Override with CLI options + if (this.forceHeadless) { + this.config = { + ...this.config, + headless: true, + }; + } + + if (this.targetUrl) { + this.config = { + ...this.config, + baseUrl: this.targetUrl, + }; + } + this.browserManager = new BrowserManager(this.config); } - - this.browserManager = new BrowserManager(this.config); } private async findTestFiles(pattern?: string): Promise { @@ -159,171 +172,191 @@ export class TestRunner { private async executeTest( test: TestFunction, - context: BrowserContext, + context: BrowserContext | null, config: { noCache: boolean } = { noCache: false }, ) { - // If it's direct execution, skip AI - if (test.directExecution) { + if (this.driver) { + // Mobile test execution try { - const testContext = await this.createTestContext(context); - await test.fn?.(testContext); + const testContext = { + driver: this.driver, + platform: this.config.platform as 'ios' | 'android' + } + await test.fn?.(testContext) return { result: "pass" as const, - reason: "Direct execution successful", - }; + reason: "Mobile test execution successful" + } } catch (error) { return { result: "fail" as const, - reason: - error instanceof Error ? error.message : "Direct execution failed", - }; + reason: error instanceof Error ? error.message : "Mobile test execution failed" + } } - } - - // Use the shared context - const testContext = await this.createTestContext(context); - const browserTool = new BrowserTool(testContext.page, this.browserManager, { - width: 1920, - height: 1080, - testContext: { - ...testContext, - currentTest: test, - currentStepIndex: 0, - }, - }); - - const aiClient = new AIClient( - { - apiKey: this.config.anthropicKey, - model: "claude-3-5-sonnet-20241022", - maxMessages: 10, - debug: this.debugAI, - }, - this.debugAI, - ); - - // First get page state - const initialState = await browserTool.execute({ - action: "screenshot", - }); - - // Build prompt with initial state and screenshot - const prompt = [ - `Test: "${test.name}"`, - test.payload ? `Context: ${JSON.stringify(test.payload)}` : "", - `Callback function: ${test.fn ? " [HAS_CALLBACK]" : " [NO_CALLBACK]"}`, - - // Add expectations if they exist - ...(test.expectations?.length - ? [ - "\nExpect:", - ...test.expectations.map( - (exp, i) => - `${i + 1}. ${exp.description}${ - exp.fn ? " [HAS_CALLBACK]" : "[NO_CALLBACK]" - }`, - ), - ] - : []), - - "\nCurrent Page State:", - `URL: ${initialState.metadata?.window_info?.url || "unknown"}`, - `Title: ${initialState.metadata?.window_info?.title || "unknown"}`, - ] - .filter(Boolean) - .join("\n"); - - // check if CLI option is not specified - if (!this.noCache && !config.noCache) { - // if test hasn't changed and is already in cache, replay steps from cache - if (await this.cache.get(test)) { + } else if (context) { + // If it's direct execution, skip AI + if (test.directExecution) { try { - const result = await this.runCachedTest(test, browserTool); - - if (test.afterFn) { - try { - await test.afterFn(testContext); - } catch (error) { - return { - result: "fail" as const, - reason: - result?.result === "fail" - ? `AI: ${result.reason}, After: ${ - error instanceof Error ? error.message : String(error) - }` - : error instanceof Error - ? error.message - : String(error), - }; + const testContext = await this.createTestContext(context); + await test.fn?.(testContext); + return { + result: "pass" as const, + reason: "Direct execution successful", + }; + } catch (error) { + return { + result: "fail" as const, + reason: + error instanceof Error ? error.message : "Direct execution failed", + }; + } + } + + // Use the shared context + const testContext = await this.createTestContext(context); + const browserTool = new BrowserTool(testContext.page, this.browserManager, { + width: 1920, + height: 1080, + testContext: { + ...testContext, + currentTest: test, + currentStepIndex: 0, + }, + }); + + const aiClient = new AIClient( + { + apiKey: this.config.anthropicKey, + model: "claude-3-5-sonnet-20241022", + maxMessages: 10, + debug: this.debugAI, + }, + this.debugAI, + ); + + // First get page state + const initialState = await browserTool.execute({ + action: "screenshot", + }); + + // Build prompt with initial state and screenshot + const prompt = [ + `Test: "${test.name}"`, + test.payload ? `Context: ${JSON.stringify(test.payload)}` : "", + `Callback function: ${test.fn ? " [HAS_CALLBACK]" : " [NO_CALLBACK]"}`, + + // Add expectations if they exist + ...(test.expectations?.length + ? [ + "\nExpect:", + ...test.expectations.map( + (exp, i) => + `${i + 1}. ${exp.description}${ + exp.fn ? " [HAS_CALLBACK]" : "[NO_CALLBACK]" + }`, + ), + ] + : []), + + "\nCurrent Page State:", + `URL: ${initialState.metadata?.window_info?.url || "unknown"}`, + `Title: ${initialState.metadata?.window_info?.title || "unknown"}`, + ] + .filter(Boolean) + .join("\n"); + + // check if CLI option is not specified + if (!this.noCache && !config.noCache) { + // if test hasn't changed and is already in cache, replay steps from cache + if (await this.cache.get(test)) { + try { + const result = await this.runCachedTest(test, browserTool); + + if (test.afterFn) { + try { + await test.afterFn(testContext); + } catch (error) { + return { + result: "fail" as const, + reason: + result?.result === "fail" + ? `AI: ${result.reason}, After: ${ + error instanceof Error ? error.message : String(error) + }` + : error instanceof Error + ? error.message + : String(error), + }; + } } + return result; + } catch { + // delete stale cached test entry + await this.cache.delete(test); + // reset window state + const page = browserTool.getPage(); + await page.goto(initialState.metadata?.window_info?.url!); + await this.executeTest(test, context, { + noCache: true, + }); } - return result; - } catch { - // delete stale cached test entry - await this.cache.delete(test); - // reset window state - const page = browserTool.getPage(); - await page.goto(initialState.metadata?.window_info?.url!); - await this.executeTest(test, context, { - noCache: true, - }); } } - } - // Execute test with enhanced prompt - const result = await aiClient.processAction(prompt, browserTool); + // Execute test with enhanced prompt + const result = await aiClient.processAction(prompt, browserTool); - if (!result) { - throw new Error("AI processing failed: no result returned"); - } + if (!result) { + throw new Error("AI processing failed: no result returned"); + } - // Parse AI result first - const finalMessage = result.finalResponse.content.find( - (block) => - block.type === "text" && - (block as Anthropic.Beta.Messages.BetaTextBlock).text.includes( - '"result":', - ), - ); - - if (!finalMessage || finalMessage.type !== "text") { - throw new Error("No test result found in AI response"); - } + // Parse AI result first + const finalMessage = result.finalResponse.content.find( + (block) => + block.type === "text" && + (block as Anthropic.Beta.Messages.BetaTextBlock).text.includes( + '"result":', + ), + ); - const jsonMatch = ( - finalMessage as Anthropic.Beta.Messages.BetaTextBlock - ).text.match(/{[\s\S]*}/); - if (!jsonMatch) { - throw new Error("Invalid test result format"); - } + if (!finalMessage || finalMessage.type !== "text") { + throw new Error("No test result found in AI response"); + } - const aiResult = JSON.parse(jsonMatch[0]) as TestResult; + const jsonMatch = ( + finalMessage as Anthropic.Beta.Messages.BetaTextBlock + ).text.match(/{[\s\S]*}/); + if (!jsonMatch) { + throw new Error("Invalid test result format"); + } - // Execute after function if present - if (test.afterFn) { - try { - await test.afterFn(testContext); - } catch (error) { - return { - result: "fail" as const, - reason: - aiResult.result === "fail" - ? `AI: ${aiResult.reason}, After: ${ - error instanceof Error ? error.message : String(error) - }` - : error instanceof Error - ? error.message - : String(error), - }; + const aiResult = JSON.parse(jsonMatch[0]) as TestResult; + + // Execute after function if present + if (test.afterFn) { + try { + await test.afterFn(testContext); + } catch (error) { + return { + result: "fail" as const, + reason: + aiResult.result === "fail" + ? `AI: ${aiResult.reason}, After: ${ + error instanceof Error ? error.message : String(error) + }` + : error instanceof Error + ? error.message + : String(error), + }; + } } - } - if (aiResult.result === "pass") { - // batch set new chache if test is successful - await this.cache.set(test, result.pendingCache); + if (aiResult.result === "pass") { + // batch set new chache if test is successful + await this.cache.set(test, result.pendingCache); + } + return aiResult; } - return aiResult; } private async executeTestFile(file: string) { @@ -484,4 +517,12 @@ export class TestRunner { reason: "All actions successfully replayed from cache", }; } + + async cleanup() { + if (this.mobileManager) { + await this.mobileManager.quit(); + } else if (this.browserManager) { + await this.browserManager.close(); + } + } } diff --git a/packages/shortest/src/mobile/actions/index.ts b/packages/shortest/src/mobile/actions/index.ts new file mode 100644 index 00000000..aa4b3b4a --- /dev/null +++ b/packages/shortest/src/mobile/actions/index.ts @@ -0,0 +1,34 @@ +import { MobileElement } from '../core' +import { MobileDriver } from '../core' + +export async function tap(driver: MobileDriver, element: MobileElement): Promise { + await driver.tap(element) +} + +export async function type(driver: MobileDriver, element: MobileElement, text: string): Promise { + await driver.type(element, text) +} + +export async function scroll( + driver: MobileDriver, + direction: 'up' | 'down', + amount: number = 0.5 +): Promise { + await driver.scroll(direction, amount) +} + +export async function swipe( + driver: MobileDriver, + direction: 'left' | 'right' | 'up' | 'down', + element?: MobileElement +): Promise { + // Implementation coming soon +} + +export async function longPress( + driver: MobileDriver, + element: MobileElement, + duration: number = 1000 +): Promise { + // Implementation coming soon +} \ No newline at end of file diff --git a/packages/shortest/src/mobile/core/drivers/base-driver.ts b/packages/shortest/src/mobile/core/drivers/base-driver.ts new file mode 100644 index 00000000..691f5cb5 --- /dev/null +++ b/packages/shortest/src/mobile/core/drivers/base-driver.ts @@ -0,0 +1,26 @@ +import { MobileElement } from '../mobile-driver' +import { MobileRunnerConfig } from '../../../types' + +export interface BaseMobileDriver { + init(): Promise + findElement(selector: string): Promise + tap(element: MobileElement): Promise + type(element: MobileElement, text: string): Promise + scroll(direction: 'up' | 'down', amount: number): Promise + quit(): Promise +} + +export abstract class AbstractMobileDriver implements BaseMobileDriver { + protected config: MobileRunnerConfig + + constructor(config: MobileRunnerConfig) { + this.config = config + } + + abstract init(): Promise + abstract findElement(selector: string): Promise + abstract tap(element: MobileElement): Promise + abstract type(element: MobileElement, text: string): Promise + abstract scroll(direction: 'up' | 'down', amount: number): Promise + abstract quit(): Promise +} \ No newline at end of file diff --git a/packages/shortest/src/mobile/core/drivers/uiautomator-driver.ts b/packages/shortest/src/mobile/core/drivers/uiautomator-driver.ts new file mode 100644 index 00000000..aef0da71 --- /dev/null +++ b/packages/shortest/src/mobile/core/drivers/uiautomator-driver.ts @@ -0,0 +1,125 @@ +import { remote, Browser } from 'webdriverio' +import { AbstractMobileDriver } from './base-driver' +import { MobileElement } from '../mobile-driver' +import { MobileRunnerConfig } from '../../../types' + +export class UIAutomatorDriver extends AbstractMobileDriver { + private driver: Browser | null = null + + constructor(config: MobileRunnerConfig) { + super(config) + } + + async init(): Promise { + const capabilities = { + platformName: 'Android', + 'appium:automationName': 'UiAutomator2', + 'appium:deviceName': this.config.capabilities?.deviceName || 'Android Emulator', + 'appium:platformVersion': this.config.capabilities?.platformVersion || '11.0', + 'appium:app': this.config.capabilities?.app, + 'appium:noReset': this.config.capabilities?.noReset ?? false, + 'appium:fullReset': this.config.capabilities?.fullReset ?? false, + ...this.config.capabilities + } + + try { + this.driver = await remote({ + path: '/wd/hub', + port: 4723, + capabilities, + logLevel: 'error' + }) + } catch (error) { + throw new Error(`Failed to initialize UIAutomator driver: ${error}`) + } + } + + async findElement(selector: string): Promise { + try { + const strategy = this.config.selectorStrategy || 'testID' + let element: Awaited> // TODO: WebdriverIO.Element ??? let's see + + switch (strategy) { + case 'testID': + element = await this.driver!.$(`*[@resource-id="${selector}"]`) + break + case 'accessibilityLabel': + element = await this.driver!.$(`*[@content-desc="${selector}"]`) + break + case 'text': + element = await this.driver!.$(`*[@text="${selector}"]`) + break + default: + element = await this.driver!.$(`*[@resource-id="${selector}"]`) + } + + const isDisplayed = await element.isDisplayed() + const isEnabled = await element.isEnabled() + + if (!isDisplayed) return null + + return { + id: await element.elementId, + type: await element.getTagName(), + text: await element.getText(), + enabled: isEnabled, + visible: isDisplayed + } + } catch (error) { + return null + } + } + + async tap(element: MobileElement): Promise { + try { + const el = await this.driver!.$(`element=${element.id}`) + await el.click() + } catch (error) { + throw new Error(`Failed to tap element: ${error}`) + } + } + + async type(element: MobileElement, text: string): Promise { + try { + const el = await this.driver!.$(`element=${element.id}`) + await el.setValue(text) + } catch (error) { + throw new Error(`Failed to type text: ${error}`) + } + } + + async scroll(direction: 'up' | 'down', amount: number): Promise { + try { + const { width, height } = await this.driver!.getWindowSize() + const startX = width / 2 + const endX = startX + + let startY: number + let endY: number + + if (direction === 'up') { + startY = height * 0.8 + endY = height * (0.8 - amount) + } else { + startY = height * 0.2 + endY = height * (0.2 + amount) + } + + await this.driver!.touchAction([ + { action: 'press', x: startX, y: startY }, + { action: 'wait', ms: 100 }, + { action: 'moveTo', x: endX, y: endY }, + { action: 'release' } + ]) + } catch (error) { + throw new Error(`Failed to scroll: ${error}`) + } + } + + async quit(): Promise { + if (this.driver) { + await this.driver.deleteSession() + this.driver = null + } + } +} \ No newline at end of file diff --git a/packages/shortest/src/mobile/core/drivers/xcuitest-driver.ts b/packages/shortest/src/mobile/core/drivers/xcuitest-driver.ts new file mode 100644 index 00000000..384f1dc7 --- /dev/null +++ b/packages/shortest/src/mobile/core/drivers/xcuitest-driver.ts @@ -0,0 +1,125 @@ +import { remote, Browser } from 'webdriverio' +import { AbstractMobileDriver } from './base-driver' +import { MobileElement } from '../mobile-driver' +import { MobileRunnerConfig } from '../../../types' + +export class XCUITestDriver extends AbstractMobileDriver { + private driver: Browser | null = null + + constructor(config: MobileRunnerConfig) { + super(config) + } + + async init(): Promise { + const capabilities = { + platformName: 'iOS', + 'appium:automationName': 'XCUITest', + 'appium:deviceName': this.config.capabilities?.deviceName || 'iPhone Simulator', + 'appium:platformVersion': this.config.capabilities?.platformVersion || '16.0', + 'appium:app': this.config.capabilities?.app, + 'appium:noReset': this.config.capabilities?.noReset ?? false, + 'appium:fullReset': this.config.capabilities?.fullReset ?? false, + ...this.config.capabilities + } + + try { + this.driver = await remote({ + path: '/wd/hub', + port: 4723, + capabilities, + logLevel: 'error' + }) + } catch (error) { + throw new Error(`Failed to initialize XCUITest driver: ${error}`) + } + } + + async findElement(selector: string): Promise { + try { + const strategy = this.config.selectorStrategy || 'testID' + let element: Awaited> + + switch (strategy) { + case 'testID': + element = await this.driver!.$(`~${selector}`) + break + case 'accessibilityLabel': + element = await this.driver!.$(`-ios predicate string:label == "${selector}"`) + break + case 'text': + element = await this.driver!.$(`-ios predicate string:name == "${selector}"`) + break + default: + element = await this.driver!.$(`~${selector}`) + } + + const isDisplayed = await element.isDisplayed() + const isEnabled = await element.isEnabled() + + if (!isDisplayed) return null + + return { + id: await element.elementId, + type: await element.getTagName(), + text: await element.getText(), + enabled: isEnabled, + visible: isDisplayed + } + } catch (error) { + return null + } + } + + async tap(element: MobileElement): Promise { + try { + const el = await this.driver!.$(`element=${element.id}`) + await el.click() + } catch (error) { + throw new Error(`Failed to tap element: ${error}`) + } + } + + async type(element: MobileElement, text: string): Promise { + try { + const el = await this.driver!.$(`element=${element.id}`) + await el.setValue(text) + } catch (error) { + throw new Error(`Failed to type text: ${error}`) + } + } + + async scroll(direction: 'up' | 'down', amount: number): Promise { + try { + const { width, height } = await this.driver!.getWindowSize() + const startX = width / 2 + const endX = startX + + let startY: number + let endY: number + + if (direction === 'up') { + startY = height * 0.8 + endY = height * (0.8 - amount) + } else { + startY = height * 0.2 + endY = height * (0.2 + amount) + } + + await this.driver!.touchAction([ + { action: 'press', x: startX, y: startY }, + { action: 'wait', ms: 100 }, + { action: 'moveTo', x: endX, y: endY }, + { action: 'release' } + ]) + } catch (error) { + throw new Error(`Failed to scroll: ${error}`) + } + } + + async quit(): Promise { + if (this.driver) { + await this.driver.deleteSession() + this.driver = null + } + } +} \ No newline at end of file diff --git a/packages/shortest/src/mobile/core/index.ts b/packages/shortest/src/mobile/core/index.ts new file mode 100644 index 00000000..c5b30a8b --- /dev/null +++ b/packages/shortest/src/mobile/core/index.ts @@ -0,0 +1 @@ +export { MobileDriver, MobileElement } from './mobile-driver' \ No newline at end of file diff --git a/packages/shortest/src/mobile/core/mobile-driver.ts b/packages/shortest/src/mobile/core/mobile-driver.ts new file mode 100644 index 00000000..05d58697 --- /dev/null +++ b/packages/shortest/src/mobile/core/mobile-driver.ts @@ -0,0 +1,51 @@ +import { MobileRunnerConfig } from '../../types' +import { UIAutomatorDriver } from './drivers/uiautomator-driver' +import { XCUITestDriver } from './drivers/xcuitest-driver' +import { BaseMobileDriver } from './drivers/base-driver' + +export interface MobileElement { + id: string + type: string + text?: string + enabled: boolean + visible: boolean +} + +export class MobileDriver { + private config: MobileRunnerConfig + private driver: BaseMobileDriver + + constructor(config: MobileRunnerConfig) { + this.config = config + + if (config.platform === 'android') { + this.driver = new UIAutomatorDriver(config) + } else { + this.driver = new XCUITestDriver(config) + } + } + + async init(): Promise { + await this.driver.init() + } + + async findElement(selector: string): Promise { + return await this.driver.findElement(selector) + } + + async tap(element: MobileElement): Promise { + await this.driver.tap(element) + } + + async type(element: MobileElement, text: string): Promise { + await this.driver.type(element, text) + } + + async scroll(direction: 'up' | 'down', amount: number): Promise { + await this.driver.scroll(direction, amount) + } + + async quit(): Promise { + await this.driver.quit() + } +} \ No newline at end of file diff --git a/packages/shortest/src/mobile/core/mobile-tool.ts b/packages/shortest/src/mobile/core/mobile-tool.ts new file mode 100644 index 00000000..4b694a65 --- /dev/null +++ b/packages/shortest/src/mobile/core/mobile-tool.ts @@ -0,0 +1,42 @@ +import { MobileDriver, MobileElement } from './mobile-driver' +import { MobileManager } from '../manager' +import { MobileToolConfig } from '../../types' +import * as actions from '../actions' + +export class MobileTool { + private driver: MobileDriver + private manager: MobileManager + + constructor(driver: MobileDriver, manager: MobileManager, config: MobileToolConfig) { + this.driver = driver + this.manager = manager + } + + async findElement(selector: string): Promise { + return await this.driver.findElement(selector) + } + + async tap(element: MobileElement): Promise { + await actions.tap(this.driver, element) + } + + async type(element: MobileElement, text: string): Promise { + await actions.type(this.driver, element, text) + } + + async scroll(direction: 'up' | 'down', amount?: number): Promise { + await actions.scroll(this.driver, direction, amount) + } + + async swipe(direction: 'left' | 'right' | 'up' | 'down', element?: MobileElement): Promise { + await actions.swipe(this.driver, direction, element) + } + + async longPress(element: MobileElement, duration?: number): Promise { + await actions.longPress(this.driver, element, duration) + } + + getDriver(): MobileDriver { + return this.driver + } +} \ No newline at end of file diff --git a/packages/shortest/src/mobile/manager/index.ts b/packages/shortest/src/mobile/manager/index.ts new file mode 100644 index 00000000..73637215 --- /dev/null +++ b/packages/shortest/src/mobile/manager/index.ts @@ -0,0 +1,30 @@ +import { MobileRunnerConfig } from '../../types' +import { MobileDriver } from '../core' + +export class MobileManager { + private driver: MobileDriver | null = null + private config: MobileRunnerConfig + + constructor(config: MobileRunnerConfig) { + this.config = config + } + + async launch(): Promise { + if (!this.driver) { + this.driver = new MobileDriver(this.config) + await this.driver.init() + } + return this.driver + } + + async quit(): Promise { + if (this.driver) { + await this.driver.quit() + this.driver = null + } + } + + getDriver(): MobileDriver | null { + return this.driver + } +} \ No newline at end of file diff --git a/packages/shortest/src/types/config.ts b/packages/shortest/src/types/config.ts index fdcd23ab..3e9c12b8 100644 --- a/packages/shortest/src/types/config.ts +++ b/packages/shortest/src/types/config.ts @@ -1,10 +1,28 @@ -export interface ShortestConfig { - headless: boolean; - baseUrl: string; +export interface BaseConfig { + baseUrl?: string + headless?: boolean + timeout?: number + retries?: number +} + +export interface ShortestConfig extends BaseConfig { + platform?: 'ios' | 'android' | 'web' + capabilities?: { + platformName?: 'iOS' | 'Android' + platformVersion?: string + deviceName?: string + app?: string + automationName?: string + noReset?: boolean + fullReset?: boolean + [key: string]: any + } + baseUrl: string + headless: boolean testDir: string | string[]; anthropicKey: string; mailosaur?: { apiKey: string; serverId: string; }; -} +} \ No newline at end of file diff --git a/packages/shortest/src/types/index.ts b/packages/shortest/src/types/index.ts index 6dae2df6..5a04c257 100644 --- a/packages/shortest/src/types/index.ts +++ b/packages/shortest/src/types/index.ts @@ -3,3 +3,4 @@ export * from "./globals"; export * from "./browser"; export * from "./ai"; export * from "./config"; +export * from "./mobile"; \ No newline at end of file diff --git a/packages/shortest/src/types/mobile.ts b/packages/shortest/src/types/mobile.ts new file mode 100644 index 00000000..9af9d0d1 --- /dev/null +++ b/packages/shortest/src/types/mobile.ts @@ -0,0 +1,35 @@ +import { MobileDriver } from '../mobile/core/mobile-driver' +import { MobileTool } from '../mobile/core/mobile-tool' +import { BaseConfig } from './config' + +export interface MobileToolConfig { + platform: 'ios' | 'android' + appPackage?: string + appActivity?: string + bundleId?: string + deviceName?: string + platformVersion?: string + automationName?: 'XCUITest' | 'UiAutomator2' + noReset?: boolean +} + +export interface MobileContext { + driver: MobileDriver + platform: 'ios' | 'android' + tool: MobileTool +} + +export interface MobileRunnerConfig extends BaseConfig { + platform: 'ios' | 'android' + selectorStrategy?: 'testID' | 'accessibilityLabel' | 'text' + capabilities?: { + platformName: 'iOS' | 'Android' + platformVersion: string + deviceName: string + app?: string + automationName?: string + noReset?: boolean + fullReset?: boolean + [key: string]: any + } +} \ No newline at end of file diff --git a/packages/shortest/src/types/test.ts b/packages/shortest/src/types/test.ts index b2be7208..5af287c8 100644 --- a/packages/shortest/src/types/test.ts +++ b/packages/shortest/src/types/test.ts @@ -1,5 +1,6 @@ import type { Page, Browser, APIRequest, APIRequestContext } from "playwright"; import type * as playwright from "playwright"; +import { MobileDriver } from "../mobile/core"; export interface AssertionError extends Error { matcherResult?: { @@ -29,15 +30,17 @@ export class AssertionCallbackError extends CallbackError { } export type TestContext = { - page: Page; - browser: Browser; - playwright: typeof playwright & { + page?: Page; + browser?: Browser; + playwright?: typeof playwright & { request: APIRequest & { newContext: (options?: { extraHTTPHeaders?: Record; }) => Promise; }; }; + driver?: MobileDriver; + platform?: 'ios' | 'android'; currentTest?: TestFunction; currentStepIndex?: number; }; diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 89a706d8..b6918df1 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -157,13 +157,13 @@ importers: version: 2.6.0 tailwindcss: specifier: ^3.4.11 - version: 3.4.17 + version: 3.4.17(ts-node@9.1.1(typescript@5.6.3)) tailwindcss-animate: specifier: ^1.0.7 - version: 1.0.7(tailwindcss@3.4.17) + version: 1.0.7(tailwindcss@3.4.17(ts-node@9.1.1(typescript@5.6.3))) tailwindcss-react-aria-components: specifier: 1.1.5 - version: 1.1.5(tailwindcss@3.4.17) + version: 1.1.5(tailwindcss@3.4.17(ts-node@9.1.1(typescript@5.6.3))) typescript: specifier: ^5.6.2 version: 5.6.3 @@ -245,7 +245,7 @@ importers: version: 0.32.0 chromium-bidi: specifier: ^0.5.2 - version: 0.5.24(devtools-protocol@0.0.1400418) + version: 0.5.24(devtools-protocol@0.0.1359167) dotenv: specifier: ^16.4.5 version: 16.4.7 @@ -270,6 +270,9 @@ importers: playwright: specifier: ^1.48.2 version: 1.49.1 + webdriverio: + specifier: ^9.5.0 + version: 9.5.0(bufferutil@4.0.9) devDependencies: '@types/jest': specifier: ^29.5.12 @@ -1653,6 +1656,14 @@ packages: engines: {node: '>=18'} hasBin: true + '@promptbook/utils@0.69.5': + resolution: {integrity: sha512-xm5Ti/Hp3o4xHrsK9Yy3MS6KbDxYbq485hDsFvxqaNA7equHLPdo8H8faTitTeb14QCDfLW4iwCxdVYu5sn6YQ==} + + '@puppeteer/browsers@2.6.1': + resolution: {integrity: sha512-aBSREisdsGH890S2rQqK82qmQYU3uFpSH8wcZWHgHzl3LfzsxAKbLNiAG9mO8v1Y0UICBeClICxPJvyr0rcuxg==} + engines: {node: '>=18'} + hasBin: true + '@radix-ui/number@1.1.0': resolution: {integrity: sha512-V3gRzhVNU1ldS5XhAPTom1fOIo4ccrjjJgmE+LI2h/WaFpHmx0MQApT+KZHnx8abG6Avtfcz4WoEciMnpFT3HQ==} @@ -2349,6 +2360,9 @@ packages: '@types/react-dom': optional: true + '@tootallnate/quickjs-emscripten@0.23.0': + resolution: {integrity: sha512-C5Mc6rdnsaJDjO3UpGW/CQTHtCKaYlScZTly4JIu97Jxo/odCiH0ITnDXSJPTOrEKk/ycSZ0AOgTmkDtkOsvIA==} + '@types/adm-zip@0.5.7': resolution: {integrity: sha512-DNEs/QvmyRLurdQPChqq0Md4zGvPwHerAJYWk9l2jCbD1VPpnzRJorOdiq4zsw09NFbYnhfsoEhWtxIzXpn2yw==} @@ -2429,15 +2443,27 @@ packages: '@types/react@19.0.2': resolution: {integrity: sha512-USU8ZI/xyKJwFTpjSVIrSeHBVAGagkHQKPNbxeWwql/vDmnTIBgx+TJnhFnj1NXgz8XfprU0egV2dROLGpsBEg==} + '@types/sinonjs__fake-timers@8.1.5': + resolution: {integrity: sha512-mQkU2jY8jJEF7YHjHvsQO8+3ughTL1mcnn96igfhONmR+fUPSKIkefQYpSe8bsly2Ep7oQbn/6VG5/9/0qcArQ==} + '@types/stack-utils@2.0.3': resolution: {integrity: sha512-9aEbYZ3TbYMznPdcdr3SmIrLXwC/AKZXQeCf9Pgao5CKb8CyHuEX5jzWPTkvregvhRJHcpRO6BFoGW9ycaOkYw==} + '@types/which@2.0.2': + resolution: {integrity: sha512-113D3mDkZDjo+EeUEHCFy0qniNc1ZpecGiAU7WSo7YDoSzolZIQKpYFHrPpjkB2nuyahcKfrmLXeQlh7gqJYdw==} + + '@types/ws@8.5.13': + resolution: {integrity: sha512-osM/gWBTPKgHV8XkTunnegTRIsvF6owmf5w+JtAfOw472dptdm0dlGv4xCt6GwQRcC2XVOvvRE/0bAoQcL2QkA==} + '@types/yargs-parser@21.0.3': resolution: {integrity: sha512-I4q9QU9MQv4oEOz4tAHJtNz1cwuLxn2F3xcc2iV5WdqLPpUnj30aUuxt1mAxYTG+oe8CZMV/+6rU4S4gRDzqtQ==} '@types/yargs@17.0.33': resolution: {integrity: sha512-WpxBCKWPLr4xSsHgz511rFJAM+wS28w2zEO1QDNY5zM/S8ok70NNfztH0xwhqKyaK0OHCbN98LDAZuy1ctxDkA==} + '@types/yauzl@2.10.3': + resolution: {integrity: sha512-oJoftv0LSuaDZE3Le4DbKX+KS9G36NzOeSap90UIK0yMA/NhKJhqlSGtNDORNRaIbQfzjXDrQa0ytJ6mNRGz/Q==} + '@typescript-eslint/eslint-plugin@8.18.2': resolution: {integrity: sha512-adig4SzPLjeQ0Tm+jvsozSGiCliI2ajeURDGHjZ2llnA+A67HihCQ+a3amtPhUakd1GlwHxSRvzOZktbEvhPPg==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} @@ -2524,6 +2550,33 @@ packages: '@vue/shared@3.5.13': resolution: {integrity: sha512-/hnE/qP5ZoGpol0a5mDi45bOd7t3tjYJBjsgCsivow7D48cJeV5l05RD82lPqi7gRiphZM37rnhW1l6ZoCNNnQ==} + '@wdio/config@9.5.0': + resolution: {integrity: sha512-ty0laZy9J6pYpPd9BzNS4/P9RcRFCQfiacQuJFCkaM0NXjOtkWnyMnrqLP09nyUEQYhOGwANwShbsS+EaUkmSQ==} + engines: {node: '>=18.20.0'} + + '@wdio/logger@9.4.4': + resolution: {integrity: sha512-BXx8RXFUW2M4dcO6t5Le95Hi2ZkTQBRsvBQqLekT2rZ6Xmw8ZKZBPf0FptnoftFGg6dYmwnDidYv/0+4PiHjpQ==} + engines: {node: '>=18.20.0'} + + '@wdio/protocols@9.4.4': + resolution: {integrity: sha512-IqbAWe5feY3xOwjbiW/2iwcbDU+nm5CX5Om835mxaNWqEoQiaZuTin4YgtgsPeSEBcSFtQ+2ooswr/6vIZdxSw==} + + '@wdio/repl@9.4.4': + resolution: {integrity: sha512-kchPRhoG/pCn4KhHGiL/ocNhdpR8OkD2e6sANlSUZ4TGBVi86YSIEjc2yXUwLacHknC/EnQk/SFnqd4MsNjGGg==} + engines: {node: '>=18.20.0'} + + '@wdio/types@9.5.0': + resolution: {integrity: sha512-sX1vH6VebVHvgdpySTOXzKNazHBu+yFr5bMvveJ2T4vKjJTJOAwO6nPftjKcgGDfhyYxM3xOCvboKICdQKFgEg==} + engines: {node: '>=18.20.0'} + + '@wdio/utils@9.5.0': + resolution: {integrity: sha512-Lrom21pIdp60IiKznecJT6Za0GGeXxKikPyWHH5z9SY5TmuSoIhuG/bq40lfUjeSW7doiL1JEsFHbRbzt0bHYA==} + engines: {node: '>=18.20.0'} + + '@zip.js/zip.js@2.7.54': + resolution: {integrity: sha512-qMrJVg2hoEsZJjMJez9yI2+nZlBUxgYzGV3mqcb2B/6T1ihXp0fWBDYlVHlHquuorgNUQP5a8qSmX6HF5rFJNg==} + engines: {bun: '>=0.7.0', deno: '>=1.0.0', node: '>=16.5.0'} + abort-controller@3.0.0: resolution: {integrity: sha512-h8lQ8tacZYnR3vNQTgibj+tODHI5/+l06Au2Pcriv/Gmet0eaj4TwWH41sO9wnHDiQsEj19q0drzdWdeAHtweg==} engines: {node: '>=6.5'} @@ -2610,6 +2663,17 @@ packages: resolution: {integrity: sha512-KMReFUr0B4t+D+OBkjR3KYqvocp2XaSzO55UcB6mgQMd3KbcE+mWTyvVV7D/zsdEbNnV6acZUutkiHQXvTr1Rw==} engines: {node: '>= 8'} + archiver-utils@5.0.2: + resolution: {integrity: sha512-wuLJMmIBQYCsGZgYLTy5FIB2pF6Lfb6cXMSF8Qywwk3t20zWnAi7zLcQFdKQmIB8wyZpY5ER38x08GbwtR2cLA==} + engines: {node: '>= 14'} + + archiver@7.0.1: + resolution: {integrity: sha512-ZcbTaIqJOfCc03QwD468Unz/5Ir8ATtvAHsK+FdXbDIbGfihqh9mrvdcYunQzqn4HrvWWaFyaxJhGZagaJJpPQ==} + engines: {node: '>= 14'} + + arg@4.1.3: + resolution: {integrity: sha512-58S9QDqG0Xx27YwPSt9fJxivjYl432YCwfDMfZ+71RAqUrZef7LrKQZ3LHLOwCS4FLNBplP533Zx895SeOCHvA==} + arg@5.0.2: resolution: {integrity: sha512-PYjyFOLKQ9y57JvQ6QLo8dAgNqswh8M1RMJYdQduT6xbWSgK36P/Z/v+p888pM69jMMfS8Xd8F6I1kQ/I9HUGg==} @@ -2659,6 +2723,13 @@ packages: resolution: {integrity: sha512-BNoCY6SXXPQ7gF2opIP4GBE+Xw7U+pHMYKuzjgCN3GwiaIR09UUeKfheyIry77QtrCBlC0KK0q5/TER/tYh3PQ==} engines: {node: '>= 0.4'} + ast-types@0.13.4: + resolution: {integrity: sha512-x1FCFnFifvYDDzTaLII71vG5uvDwgtmDTEVWAxrgeiR8VjMONcCXJx7E+USjDtHlwFmt9MysbqgF9b9Vjr6w+w==} + engines: {node: '>=4'} + + async@3.2.6: + resolution: {integrity: sha512-htCUDlxyyCLMgaM3xXg0C0LW2xqfuQ6p05pCEIsXuyQ+a1koYKTuBMzRNwmybfLgvJDMd0r1LTn4+E0Ti6C2AA==} + asynckit@0.4.0: resolution: {integrity: sha512-Oei9OH4tRh0YqU3GxhX79dM/mwVgvbZJaSNaRk+bshkj0S5cfHcgYakreBjrHwatXKbz+IoIdYLxrKim2MjW0Q==} @@ -2677,6 +2748,9 @@ packages: resolution: {integrity: sha512-qIj0G9wZbMGNLjLmg1PT6v2mE9AH2zlnADJD/2tC6E00hgmhUOfEB6greHPAfLRSufHqROIUTkw6E+M3lH0PTQ==} engines: {node: '>= 0.4'} + b4a@1.6.7: + resolution: {integrity: sha512-OnAYlL5b7LEkALw87fUVafQw5rVR9RjwGd4KUwNQ6DrrNmaVaUCgLipfVlzrPQ4tWOR9P0IXGNOx50jYCCdSJg==} + babel-plugin-emotion@10.2.2: resolution: {integrity: sha512-SMSkGoqTbTyUTDeuVuPIWifPdUGkTk1Kf9BWRiXIOIcuyMfsdp2EjeiiFvOzX8NOBvEh/ypKYvUh2rkgAJMCLA==} @@ -2689,6 +2763,28 @@ packages: balanced-match@1.0.2: resolution: {integrity: sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==} + bare-events@2.5.0: + resolution: {integrity: sha512-/E8dDe9dsbLyh2qrZ64PEPadOQ0F4gbl1sUJOrmph7xOiIxfY8vwab/4bFLh4Y88/Hk/ujKcrQKc+ps0mv873A==} + + bare-fs@2.3.5: + resolution: {integrity: sha512-SlE9eTxifPDJrT6YgemQ1WGFleevzwY+XAP1Xqgl56HtcrisC2CHCZ2tq6dBpcH2TnNxwUEUGhweo+lrQtYuiw==} + + bare-os@2.4.4: + resolution: {integrity: sha512-z3UiI2yi1mK0sXeRdc4O1Kk8aOa/e+FNWZcTiPB/dfTWyLypuE99LibgRaQki914Jq//yAWylcAt+mknKdixRQ==} + + bare-path@2.1.3: + resolution: {integrity: sha512-lh/eITfU8hrj9Ru5quUp0Io1kJWIk1bTjzo7JH1P5dWmQ2EL4hFUlfI8FonAhSlgIfhn63p84CDY/x+PisgcXA==} + + bare-stream@2.6.1: + resolution: {integrity: sha512-eVZbtKM+4uehzrsj49KtCy3Pbg7kO1pJ3SKZ1SFrIH/0pnj9scuGGgUlNDf/7qS8WKtGdiJY5Kyhs/ivYPTB/g==} + + base64-js@1.5.1: + resolution: {integrity: sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA==} + + basic-ftp@5.0.5: + resolution: {integrity: sha512-4Bcg1P8xhUuqcii/S0Z9wiHIrQVPMermM1any+MX5GeGD7faD3/msQUDGLol9wOcz4/jbg/WJnGqoJF6LiBdtg==} + engines: {node: '>=10.0.0'} + bcryptjs@2.4.3: resolution: {integrity: sha512-V/Hy/X9Vt7f3BbPJEi8BdVFMByHi+jNXrYkW3huaybV/kQ0KJg0Y6PkEMbn+zeT+i+SiKZ/HMqJGIIt4LZDqNQ==} @@ -2699,6 +2795,9 @@ packages: resolution: {integrity: sha512-Ceh+7ox5qe7LJuLHoY0feh3pHuUDHAcRUeyL2VYghZwfpkNIy/+8Ocg0a3UuSoYzavmylwuLWQOf3hl0jjMMIw==} engines: {node: '>=8'} + boolbase@1.0.0: + resolution: {integrity: sha512-JZOSA7Mo9sNGB8+UjSgzdLtokWAky1zbztM3WRLCbZ70/3cTANmQmOdR7y2g+J0e2WXywy1yS468tY+IruqEww==} + brace-expansion@1.1.11: resolution: {integrity: sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==} @@ -2719,9 +2818,22 @@ packages: engines: {node: ^6 || ^7 || ^8 || ^9 || ^10 || ^11 || ^12 || >=13.7} hasBin: true + buffer-crc32@0.2.13: + resolution: {integrity: sha512-VO9Ht/+p3SN7SKWqcrgEzjGbRSJYTx+Q1pTQC0wrWqHx0vpJraQ6GtHx8tvcg1rlK1byhU5gccxgOgj7B0TDkQ==} + + buffer-crc32@1.0.0: + resolution: {integrity: sha512-Db1SbgBS/fg/392AblrMJk97KggmvYhr4pB5ZIMTWtaivCPMWLkmb7m21cJvpvgK+J3nsU2CmmixNBZx4vFj/w==} + engines: {node: '>=8.0.0'} + buffer-from@1.1.2: resolution: {integrity: sha512-E+XQCRwSbaaiChtv6k6Dwgc+bx+Bs6vuKJHHl5kox/BaKbhiXzqQOwK4cO22yElGp2OCmjwVhT3HmxgyPGnJfQ==} + buffer@5.7.1: + resolution: {integrity: sha512-EHcyIPBQ4BSGlvjB16k5KgAJ27CIsHY/2JBmCRReo48y9rQ3MaUzWX3KVlBa4U7MyX02HdVj0K7C3WaB3ju7FQ==} + + buffer@6.0.3: + resolution: {integrity: sha512-FTiCpNxtwiZZHEZbcbTIcZjERVICn9yq/pDFkTl95/AxzD1naBctN7YO68riM/gLSDY7sdrMby8hofADYuuqOA==} + bufferutil@4.0.9: resolution: {integrity: sha512-WDtdLmJvAuNNPzByAYpRo2rF1Mmradw6gvWsQKf63476DDXmomT9zUiGypLcG4ibIM67vhAj8jJRdbmEws2Aqw==} engines: {node: '>=6.14.2'} @@ -2765,6 +2877,13 @@ packages: resolution: {integrity: sha512-zgVZuo2WcZgfUEmsn6eO3kINexW8RAE4maiQ8QNs8CtpPCSyMiYsULR3HQYkm3w8FIA3SberyMJMSldGsW+U3w==} engines: {node: ^12.17.0 || ^14.13 || >=16.0.0} + cheerio-select@2.1.0: + resolution: {integrity: sha512-9v9kG0LvzrlcungtnJtpGNxY+fzECQKhK4EGJX2vByejiMX84MFNQw4UxPJl3bFbTMw+Dfs37XaIkCwTZfLh4g==} + + cheerio@1.0.0: + resolution: {integrity: sha512-quS9HgjQpdaXOvsZz82Oz7uxtXiy6UIsIQcpBj7HRw2M63Skasm9qlDocAM7jNuaxdhpPU7c4kJN+gA5MCu4ww==} + engines: {node: '>=18.17'} + chokidar@3.6.0: resolution: {integrity: sha512-7VT13fmjotKpGipCW9JEQAusEPE+Ei8nl6/g4FBAmIm0GOOLMua9NDDo/DWp0ZAxCr3cPq5ZpBqmPAQgDda2Pw==} engines: {node: '>= 8.10.0'} @@ -2787,6 +2906,10 @@ packages: client-only@0.0.1: resolution: {integrity: sha512-IV3Ou0jSMzZrd3pZ48nLkT9DA7Ag1pnPzaiQhpW7c3RbcqqzvzzVu+L8gfqMp/8IM2MQtSiqaCxrrcfu8I8rMA==} + cliui@8.0.1: + resolution: {integrity: sha512-BSeNnyus75C4//NQ9gQt1/csTXyo/8Sb+afLAkzAptFuMsod9HFokGNudZpi/oQV73hnVK+sR+5PVRMd+Dr7YQ==} + engines: {node: '>=12'} + clsx@2.1.1: resolution: {integrity: sha512-eYm0QWBtUrBWZWG0d386OGAw16Z995PiOVo2B7bjWSbHedGl5e0ZWaq65kOGgUSNesEIDkB9ISbTg/JK9dhCZA==} engines: {node: '>=6'} @@ -2823,6 +2946,14 @@ packages: resolution: {integrity: sha512-NOKm8xhkzAjzFx8B2v5OAHT+u5pRQc2UCa2Vq9jYL/31o2wi9mxBA7LIFs3sV5VSC49z6pEhfbMULvShKj26WA==} engines: {node: '>= 6'} + commander@9.5.0: + resolution: {integrity: sha512-KRs7WVDKg86PWiuAqhDrAQnTXZKraVcCc6vFdL14qrZ/DcWwuRo7VoiYXalXO7S5GKpqYiVEwCbgFDfxNHKJBQ==} + engines: {node: ^12.20.0 || >=14} + + compress-commons@6.0.2: + resolution: {integrity: sha512-6FqVXeETqWPoGcfzrXb37E50NP0LXT8kAMu5ooZayhWWdgEY4lBEEcbQNXtkuKQsGduxiIcI4gOTsxTmuq/bSg==} + engines: {node: '>= 14'} + concat-map@0.0.1: resolution: {integrity: sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==} @@ -2836,13 +2967,28 @@ packages: resolution: {integrity: sha512-qCf+V4dtlNhSRXGAZatc1TasyFO6GjohcOul807YOb5ik3+kQSnb4d7iajeCL8QHaJ4uZEjCgiCJerKXwdRVlQ==} engines: {node: '>= 0.6'} + core-util-is@1.0.3: + resolution: {integrity: sha512-ZQBvi1DcpJ4GDqanjucZ2Hj3wEO5pZDS89BWbkcrvdxksJorwUDDZamX9ldFkp9aw2lmBDLgkObEA4DWNJ9FYQ==} + cosmiconfig@6.0.0: resolution: {integrity: sha512-xb3ZL6+L8b9JLLCx3ZdoZy4+2ECphCMo2PwqgP1tlfVq6M6YReyzBJtvWWtbDSpNr9hn96pkCiZqUcFEc+54Qg==} engines: {node: '>=8'} + crc-32@1.2.2: + resolution: {integrity: sha512-ROmzCKrTnOwybPcJApAA6WBWij23HVfGVNKqqrZpuyZOHqK2CwHSvpGuyt/UNNvaIjEd8X5IFGp4Mh+Ie1IHJQ==} + engines: {node: '>=0.8'} + hasBin: true + + crc32-stream@6.0.0: + resolution: {integrity: sha512-piICUB6ei4IlTv1+653yq5+KoqfBYmj9bw6LqXoOneTMDXk5nM1qt12mFW1caG3LlJXEKW1Bp0WggEmIfQB34g==} + engines: {node: '>= 14'} + create-emotion@10.0.27: resolution: {integrity: sha512-fIK73w82HPPn/RsAij7+Zt8eCE8SptcJ3WoRMfxMtjteYxud8GDTKKld7MYwAX2TVhrw29uR1N/bVGxeStHILg==} + create-require@1.1.1: + resolution: {integrity: sha512-dcKFX3jn0MpIaXjisoRvexIJVEKzaq7z2rZKxf+MSr9TkdmHmsU4m2lcLojrj/FHl8mk5VxMmYA+ftRkP/3oKQ==} + cross-spawn@7.0.6: resolution: {integrity: sha512-uV2QOWP2nWzsy2aMp8aRibhi9dlzF5Hgh5SHaB9OiTGEyDTiJJyx0uy51QXdyWbtAHNua4XJzUKca3OzKUd3vA==} engines: {node: '>= 8'} @@ -2853,6 +2999,19 @@ packages: css-box-model@1.2.1: resolution: {integrity: sha512-a7Vr4Q/kd/aw96bnJG332W9V9LkJO69JRcaCYDUqjp6/z0w6VcZjgAcTbgFxEPfBgdnAwlh3iwu+hLopa+flJw==} + css-select@5.1.0: + resolution: {integrity: sha512-nwoRF1rvRRnnCqqY7updORDsuqKzqYJ28+oSMaJMMgOauh3fvwHqMS7EZpIPqK8GL+g9mKxF1vP/ZjSeNjEVHg==} + + css-shorthand-properties@1.1.2: + resolution: {integrity: sha512-C2AugXIpRGQTxaCW0N7n5jD/p5irUmCrwl03TrnMFBHDbdq44CFWR2zO7rK9xPN4Eo3pUxC4vQzQgbIpzrD1PQ==} + + css-value@0.0.1: + resolution: {integrity: sha512-FUV3xaJ63buRLgHrLQVlVgQnQdR4yqdLGaDu7g8CQcWjInDfM9plBTPI9FRfpahju1UBSaMckeb2/46ApS/V1Q==} + + css-what@6.1.0: + resolution: {integrity: sha512-HTUrgRJ7r4dsZKU6GjmpfRK1O76h97Z8MfS1G0FozR+oF2kG6Vfe8JE6zwrkbxigziPHinCJ+gCPjA9EaBDtRw==} + engines: {node: '>= 6'} + css.escape@1.5.1: resolution: {integrity: sha512-YUifsXXuknHlUsmlgyY0PKzgPOr7/FjCePfHNt0jxm83wHZi44VDMQ7/fGNkjY3/jV1MC+1CmZbaHzugyeRtpg==} @@ -2874,6 +3033,14 @@ packages: csstype@3.1.3: resolution: {integrity: sha512-M1uQkMl8rQK/szD0LNhtqxIPLpimGm8sOBwU7lLnCpSbTyY3yeU1Vc7l4KT5zT4s/yOxHH5O7tIuuLOCnLADRw==} + data-uri-to-buffer@4.0.1: + resolution: {integrity: sha512-0R9ikRb668HB7QDxT1vkpuUBtqc53YyAwMwGeUFKRojY/NWKvdZ+9UYtRfGmhqNbRkTSVpMbmyhXipFFv2cb/A==} + engines: {node: '>= 12'} + + data-uri-to-buffer@6.0.2: + resolution: {integrity: sha512-7hvf7/GW8e86rW0ptuwS3OcBGDjIi6SZva7hCyWC0yYry2cOPmLIjXAUHI6DK2HsnwJd9ifmt57i8eV2n4YNpw==} + engines: {node: '>= 14'} + data-urls@5.0.0: resolution: {integrity: sha512-ZYP5VBHshaDAiVZxjbRVcFJpc+4xGgT0bK3vzy1HLN8jTO975HEbuYzZJcHoQEY5K1a0z8YayJkyVETa08eNTg==} engines: {node: '>=18'} @@ -2907,12 +3074,20 @@ packages: supports-color: optional: true + decamelize@6.0.0: + resolution: {integrity: sha512-Fv96DCsdOgB6mdGl67MT5JaTNKRzrzill5OH5s8bjYJXVlcXyPYGyPsUkWyGV5p1TXI5esYIYMMeDJL0hEIwaA==} + engines: {node: ^12.20.0 || ^14.13.1 || >=16.0.0} + decimal.js@10.4.3: resolution: {integrity: sha512-VBBaLc1MgL5XpzgIP7ny5Z6Nx3UrRkIViUkPUdtl9aya5amy3De1gsUUSB1g3+3sExYNjCAsAznmukyxCb1GRA==} deep-is@0.1.4: resolution: {integrity: sha512-oIPzksmTg4/MriiaYGO+okXDT7ztn/w3Eptv/+gSIdMdKsJo0u4CfYNFJPy+4SKMuCqGw2wxnA+URMg3t8a/bQ==} + deepmerge-ts@7.1.3: + resolution: {integrity: sha512-qCSH6I0INPxd9Y1VtAiLpnYvz5O//6rCfJXKk0z66Up9/VOSr+1yS8XSKA5IWRxjocFGlzPyaZYe+jxq7OOLtQ==} + engines: {node: '>=16.0.0'} + define-data-property@1.1.4: resolution: {integrity: sha512-rBMvIzlpA8v6E+SJZoo++HAYqsLrkg7MSfIinMPFhmkorw7X+dOXVJQs+QT69zGkzMyfDnIMN2Wid1+NbL3T+A==} engines: {node: '>= 0.4'} @@ -2921,6 +3096,10 @@ packages: resolution: {integrity: sha512-8QmQKqEASLd5nx0U1B1okLElbUuuttJ/AnYmRXbbbGDWh6uS208EjD4Xqq/I9wK7u0v6O08XhTWnt5XtEbR6Dg==} engines: {node: '>= 0.4'} + degenerator@5.0.1: + resolution: {integrity: sha512-TllpMR/t0M5sqCXfj85i4XaAzxmS5tVA16dqvdkMwGmzI+dXLXnw3J+3Vdv7VKw+ThlTMboK6i9rnZ6Nntj5CQ==} + engines: {node: '>= 14'} + delayed-stream@1.0.0: resolution: {integrity: sha512-ZySD7Nf91aLB0RxL4KGrKHBXl7Eds1DAmEdcoVawXnLD7SDhpNgtuII2aAkg7a7QS41jxPSZ17p4VdGnMHk3MQ==} engines: {node: '>=0.4.0'} @@ -2936,8 +3115,8 @@ packages: detect-node-es@1.1.0: resolution: {integrity: sha512-ypdmJU/TbBby2Dxibuv7ZLW3Bs1QEmM7nHjEANfohJLvE0XVujisn1qPJcZxg+qDucsr+bP6fLD1rPS3AhJ7EQ==} - devtools-protocol@0.0.1400418: - resolution: {integrity: sha512-U8j75zDOXF8IP3o0Cgb7K4tFA9uUHEOru2Wx64+EUqL4LNOh9dRe1i8WKR1k3mSpjcCe3aIkTDvEwq0YkI4hfw==} + devtools-protocol@0.0.1359167: + resolution: {integrity: sha512-f/9PeTaSH3weS/WAwrQb5/s9R3KMOeTGe+Jkhg5952yInub7iDPjdlzRdrDgpLZfxHbTrBuG9aUkAMM+ocVkXQ==} didyoumean@1.2.2: resolution: {integrity: sha512-gxtyfqMg7GKyhQmb056K7M3xszy/myH8w+B4RT+QXBQsvAOdc3XymqDDPHx1BgPgsdAA5SIifona89YtRATDzw==} @@ -2966,6 +3145,19 @@ packages: dom-accessibility-api@0.6.3: resolution: {integrity: sha512-7ZgogeTnjuHbo+ct10G9Ffp0mif17idi0IyWNVA/wcwcm7NPOD/WEHVP3n7n3MhXqxoIYm8d6MuZohYWIZ4T3w==} + dom-serializer@2.0.0: + resolution: {integrity: sha512-wIkAryiqt/nV5EQKqQpo3SToSOV9J0DnbJqwK7Wv/Trc92zIAYZ4FlMu+JPFW1DfGFt81ZTCGgDEabffXeLyJg==} + + domelementtype@2.3.0: + resolution: {integrity: sha512-OLETBj6w0OsagBwdXnPdN0cnMfF9opN69co+7ZrbfPGrdpPVNBUj02spi6B1N7wChLQiPn4CSH/zJvXw56gmHw==} + + domhandler@5.0.3: + resolution: {integrity: sha512-cgwlv/1iFQiFnU96XXgROh8xTeetsnJiDsTc7TYCLFd9+/WNkIqPTxiM/8pSd8VIrhXGTf1Ny1q1hquVqDJB5w==} + engines: {node: '>= 4'} + + domutils@3.2.1: + resolution: {integrity: sha512-xWXmuRnN9OMP6ptPd2+H0cCbcYBULa5YDTbMm/2lvkWvNA3O4wcW+GvzooqBuNM8yy6pl3VIAeJTUUWUbfI5Fw==} + dot-case@3.0.4: resolution: {integrity: sha512-Kv5nKlh6yRrdrGvxeJ2e5y2eRUpkUosIW4A2AS38zwSz27zu7ufDwQPi5Jhs3XAlGNetl3bmnGhQsMtkKJnj3w==} @@ -3077,6 +3269,15 @@ packages: eastasianwidth@0.2.0: resolution: {integrity: sha512-I88TYZWc9XiYHRQ4/3c5rjjfgkjhLyW2luGIheGERbNQ6OY7yTybanSpDXZa8y7VUP9YmDcYa+eyq4ca7iLqWA==} + edge-paths@3.0.5: + resolution: {integrity: sha512-sB7vSrDnFa4ezWQk9nZ/n0FdpdUuC6R1EOrlU3DL+bovcNFK28rqu2emmAUjujYEJTWIgQGqgVVWUZXMnc8iWg==} + engines: {node: '>=14.0.0'} + + edgedriver@6.1.1: + resolution: {integrity: sha512-/dM/PoBf22Xg3yypMWkmRQrBKEnSyNaZ7wHGCT9+qqT14izwtFT+QvdR89rjNkMfXwW+bSFoqOfbcvM+2Cyc7w==} + engines: {node: '>=18.0.0'} + hasBin: true + electron-to-chromium@1.5.76: resolution: {integrity: sha512-CjVQyG7n7Sr+eBXE86HIulnL5N8xZY1sgmOPGuq/F0Rr0FJq63lg0kEtOIDfZBk44FnDLf6FUJ+dsJcuiUDdDQ==} @@ -3089,6 +3290,12 @@ packages: emotion@10.0.27: resolution: {integrity: sha512-2xdDzdWWzue8R8lu4G76uWX5WhyQuzATon9LmNeCy/2BHVC6dsEpfhN1a0qhELgtDVdjyEA6J8Y/VlI5ZnaH0g==} + encoding-sniffer@0.2.0: + resolution: {integrity: sha512-ju7Wq1kg04I3HtiYIOrUrdfdDvkyO9s5XM8QAj/bN61Yo/Vb4vgJxy5vi4Yxk01gWHbrofpPtpxM8bKger9jhg==} + + end-of-stream@1.4.4: + resolution: {integrity: sha512-+uw1inIHVPQoaVuHzRyXd21icM+cnt4CzD5rW+NC1wjOUSTOs+Te7FOv7AhN7vS9x/oIyhLP5PR1H+phQAHu5Q==} + entities@4.5.0: resolution: {integrity: sha512-V0hjH4dGPh9Ao5p0MoRY6BVqtwCjhz6vI5LT8AJ55H+4g9/4vbHx1I54fS0XuclLhDHArPQCiMjDxjaL8fPxhw==} engines: {node: '>=0.12'} @@ -3173,6 +3380,11 @@ packages: resolution: {integrity: sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA==} engines: {node: '>=10'} + escodegen@2.1.0: + resolution: {integrity: sha512-2NlIDTwUWJN0mRPQOdtQBzbUHvdGY2P1VXSyU83Q3xKxM7WHX2Ql8dKq782Q9TgQUNOLEzEYu9bzLNj1q88I5w==} + engines: {node: '>=6.0'} + hasBin: true + eslint-config-prettier@9.1.0: resolution: {integrity: sha512-NSWl5BFQWEPi1j4TjVNItzYV7dZXZ+wP6I6ZhrBGpChQhZRUaElihE9uRRkcbRnNb76UMKDF3r+WTmNcGPKsqw==} hasBin: true @@ -3268,6 +3480,11 @@ packages: resolution: {integrity: sha512-0QYC8b24HWY8zjRnDTL6RiHfDbAWn63qb4LMj1Z4b076A4une81+z03Kg7l7mn/48PUTqoLptSXez8oknU8Clg==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} + esprima@4.0.1: + resolution: {integrity: sha512-eGuFFw7Upda+g4p+QHvnW0RyTX/SVeJBDM/gCtMARO0cLuT2HcEKnTPvhjV6aGeqrCB/sbNop0Kszm0jsaWU4A==} + engines: {node: '>=4'} + hasBin: true + esquery@1.6.0: resolution: {integrity: sha512-ca9pw9fomFcKPvFLXhBKUK90ZvGibiGOvRJNbjljY7s7uq/5YO4BOzcYtJqExdx99rF6aAcnRxHmcUHcz6sQsg==} engines: {node: '>=0.10'} @@ -3294,6 +3511,10 @@ packages: resolution: {integrity: sha512-i/2XbnSz/uxRCU6+NdVJgKWDTM427+MqYbkQzD321DuCQJUqOuJKIA0IM2+W2xtYHdKOmZ4dR6fExsd4SXL+WQ==} engines: {node: '>=6'} + events@3.3.0: + resolution: {integrity: sha512-mQw+2fkQbALzQ7V0MY0IqdnXNOeTtP4r0lN9z7AAawCXgqea7bDii20AYrIBrFd/Hx0M2Ocz6S111CaFkUcb0Q==} + engines: {node: '>=0.8.x'} + eventsource-parser@1.1.2: resolution: {integrity: sha512-v0eOBUbiaFojBu2s2NPBfYUoRR9GjcDNvCXVaqEf5vVfpIAh9f8RCo4vXTP8c63QRKCFwoLpMpTdPwwhEKVgzA==} engines: {node: '>=14.18'} @@ -3306,12 +3527,23 @@ packages: resolution: {integrity: sha512-2Zks0hf1VLFYI1kbh0I5jP3KHHyCHpkfyHBzsSXRFgl/Bg9mWYfMW8oD+PdMPlEwy5HNsR9JutYy6pMeOh61nw==} engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} + extract-zip@2.0.1: + resolution: {integrity: sha512-GDhU9ntwuKyGXdZBUgTIe+vXnWj0fppUEtMDL0+idd5Sta8TGpHssn/eusA9mrPr9qNDym6SxAYZjNvCn/9RBg==} + engines: {node: '>= 10.17.0'} + hasBin: true + + fast-deep-equal@2.0.1: + resolution: {integrity: sha512-bCK/2Z4zLidyB4ReuIsvALH6w31YfAQDmXMqMx6FyfHqvBxtjC0eRumeSu4Bs3XtXwpyIywtSTrVT99BxY1f9w==} + fast-deep-equal@3.1.3: resolution: {integrity: sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==} fast-diff@1.3.0: resolution: {integrity: sha512-VxPP4NqbUjj6MaAOafWeUn2cXWLcCtljklUtZf0Ind4XQ+QPtmA0b18zZy0jIQx+ExRVCR/ZQpBmik5lXshNsw==} + fast-fifo@1.3.2: + resolution: {integrity: sha512-/d9sfos4yxzpwkDkuN7k2SqFKtYNmCTzgfEpz82x34IM9/zc8KGxQoXg1liNC/izpRM/MBdt44Nmx41ZWqk+FQ==} + fast-glob@3.3.2: resolution: {integrity: sha512-oX2ruAFQwf/Orj8m737Y5adxDQO0LAB7/S5MnxCdTNDd4p6BsyIVsv9JQsATbTSq8KHRpLwIHbVlUNatxd+1Ow==} engines: {node: '>=8.6.0'} @@ -3322,9 +3554,20 @@ packages: fast-levenshtein@2.0.6: resolution: {integrity: sha512-DCXu6Ifhqcks7TZKY3Hxp3y6qphY5SJZmrWMDrKcERSOXWQdMhU9Ig/PYrzyw/ul9jOIyh0N4M0tbC5hodg8dw==} + fast-xml-parser@4.5.1: + resolution: {integrity: sha512-y655CeyUQ+jj7KBbYMc4FG01V8ZQqjN+gDYGJ50RtfsUB8iG9AmwmwoAgeKLJdmueKKMrH1RJ7yXHTSoczdv5w==} + hasBin: true + fastq@1.18.0: resolution: {integrity: sha512-QKHXPW0hD8g4UET03SdOdunzSouc9N4AuHdsX8XNcTsuz+yYFILVNIX4l9yHABMhiEI9Db0JTTIpu0wB+Y1QQw==} + fd-slicer@1.1.0: + resolution: {integrity: sha512-cE1qsB/VwyQozZ+q1dGxR8LBYNZeofhEdUNGSMbQD3Gw2lAzX9Zb3uIU6Ebc/Fmyjo9AWWfnn0AUCHqtevs/8g==} + + fetch-blob@3.2.0: + resolution: {integrity: sha512-7yAQpD2UMJzLi1Dqv7qFYnPbaPx7ZfFK6PiIxQ4PfkGPyNyl2Ugx+a/umUonmKqjhM4DnfbMvdX6otXq83soQQ==} + engines: {node: ^12.20 || >= 14.13} + file-entry-cache@8.0.0: resolution: {integrity: sha512-XXTUwCvisa5oacNGRP9SfNtYBNAMi+RPwBFmblZEF7N7swHYQS6/Zfk7SRwx4D5j3CH211YNRco1DEMNVfZCnQ==} engines: {node: '>=16.0.0'} @@ -3365,6 +3608,10 @@ packages: resolution: {integrity: sha512-0iirZp3uVDjVGt9p49aTaqjk84TrglENEDuqfdlZQ1roC9CWlPk6Avf8EEnZNcAqPonwkG35x4n3ww/1THYAeQ==} engines: {node: '>= 12.20'} + formdata-polyfill@4.0.10: + resolution: {integrity: sha512-buewHzMvYL29jdeQTVILecSaZKnt/RJWjoZCF5OW60Z67/GmSLBkOFM7qh1PI3zFNtJbaZL5eQu1vLfazOwj4g==} + engines: {node: '>=12.20.0'} + fraction.js@4.3.7: resolution: {integrity: sha512-ZsDfxO51wGAXREY55a7la9LScWpwv9RxIrYABrlvOFBlH/ShPnrtsXeuUIfXKKOVicNxQ+o8JTbJvjS4M89yew==} @@ -3388,10 +3635,19 @@ packages: functions-have-names@1.2.3: resolution: {integrity: sha512-xckBUXyTIqT97tq2x2AMb+g163b5JFysYk0x4qxNFwbfQkmNZoiRHb6sPzI9/QV33WeuvVYBUIiD4NzNIyqaRQ==} + geckodriver@5.0.0: + resolution: {integrity: sha512-vn7TtQ3b9VMJtVXsyWtQQl1fyBVFhQy7UvJF96kPuuJ0or5THH496AD3eUyaDD11+EqCxH9t6V+EP9soZQk4YQ==} + engines: {node: '>=18.0.0'} + hasBin: true + gensync@1.0.0-beta.2: resolution: {integrity: sha512-3hN7NaskYvMDLQY55gnW3NQ+mesEAepTqlg+VEbj7zzqEMBVNhzcGYYeqFo/TlYz6eQiFcp1HcsCZO+nGgS8zg==} engines: {node: '>=6.9.0'} + get-caller-file@2.0.5: + resolution: {integrity: sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg==} + engines: {node: 6.* || 8.* || >= 10.*} + get-intrinsic@1.2.6: resolution: {integrity: sha512-qxsEs+9A+u85HhllWJJFicJfPDhRmjzoYdl64aMWW9yRIJmSyxdn8IEkuIM530/7T+lv0TIHd8L6Q/ra0tEoeA==} engines: {node: '>= 0.4'} @@ -3400,6 +3656,14 @@ packages: resolution: {integrity: sha512-FJhYRoDaiatfEkUK8HKlicmu/3SGFD51q3itKDGoSTysQJBnfOcxU5GxnhE1E6soB76MbT0MBtnKJuXyAx+96Q==} engines: {node: '>=6'} + get-port@7.1.0: + resolution: {integrity: sha512-QB9NKEeDg3xxVwCCwJQ9+xycaz6pBB6iQ76wiWMl1927n0Kir6alPiP+yuiICLLU4jpMe08dXfpebuQppFA2zw==} + engines: {node: '>=16'} + + get-stream@5.2.0: + resolution: {integrity: sha512-nBF+F1rAZVCu/p7rjzgA+Yb4lfYXrpl7a6VmJrU8wF9I1CKvP/QwPNZHnOlwbTkY6dvtFIzFMSyQXbLoTQPRpA==} + engines: {node: '>=8'} + get-symbol-description@1.1.0: resolution: {integrity: sha512-w9UMqWwJxHNOvoNzSJ2oPF5wvYcvP7jUvYzhp67yEhTi17ZDBBC1z9pTdGuzjD+EFIqLSYRweZjqfiPzQ06Ebg==} engines: {node: '>= 0.4'} @@ -3407,6 +3671,10 @@ packages: get-tsconfig@4.8.1: resolution: {integrity: sha512-k9PN+cFBmaLWtVz29SkUoqU5O0slLuHJXt/2P+tMVFT+phsSGXGkp9t3rQIqdz0e+06EHNGs3oM6ZX1s2zHxRg==} + get-uri@6.0.4: + resolution: {integrity: sha512-E1b1lFFLvLgak2whF2xDBcOy6NLVGZBqqjJjsIhvopKfWWEi64pLVTWWehV8KlLerZkfNTA95sTe2OdJKm1OzQ==} + engines: {node: '>= 14'} + glob-parent@5.1.2: resolution: {integrity: sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==} engines: {node: '>= 6'} @@ -3444,6 +3712,9 @@ packages: graceful-fs@4.2.11: resolution: {integrity: sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ==} + grapheme-splitter@1.0.4: + resolution: {integrity: sha512-bzh50DW9kTPM00T8y4o8vQg89Di9oLJVLW/KaOGIXJWP/iqCN6WKYkbNOF04vFLJhwcpYUh9ydh/+5vpOqV4YQ==} + graphemer@1.4.0: resolution: {integrity: sha512-EtKwoO6kxCL9WO5xipiHTZlSzBm7WLT627TqC/uVRd0HKmq8NXyebnNYxDoBi7wt8eTWrUrKXCOVaFq9x1kgag==} @@ -3485,6 +3756,12 @@ packages: resolution: {integrity: sha512-Y22oTqIU4uuPgEemfz7NDJz6OeKf12Lsu+QC+s3BVpda64lTiMYCyGwg5ki4vFxkMwQdeZDl2adZoqUgdFuTgQ==} engines: {node: '>=18'} + htmlfy@0.5.0: + resolution: {integrity: sha512-/g4imybF9k7eJT+VEsjtpx1i3BHYxFxv6/RS0Lf8veh1+pw0HzAEndGTdjvrlVRqUSu7YurJZkfnLXpVZ2yrEw==} + + htmlparser2@9.1.0: + resolution: {integrity: sha512-5zfg6mHUoaer/97TxnGpxmbR7zJtPwIYFMZ/H5ucTlPZhKvtum05yiPK3Mgai3a0DyVxv7qYqoweaEd2nrYQzQ==} + http-proxy-agent@7.0.2: resolution: {integrity: sha512-T1gkAiYYDWYx3V5Bmyu7HcfcvL7mUrTWiM6yOfa3PIphViJ/gFPbvidQ+veqSOHci/PxBcDabeUNCzpOODJZig==} engines: {node: '>= 14'} @@ -3504,14 +3781,23 @@ packages: resolution: {integrity: sha512-4fCk79wshMdzMp2rH06qWrJE4iolqLhCUH+OiuIgU++RB0+94NlDL81atO7GX55uUKueo0txHNtvEyI6D7WdMw==} engines: {node: '>=0.10.0'} + ieee754@1.2.1: + resolution: {integrity: sha512-dcyqhDvX1C46lXZcVqCpK+FtMRQVdIMN6/Df5js2zouUsqG7I6sFxitIC+7KYK29KdXOLHdu9zL4sFnoVQnqaA==} + ignore@5.3.2: resolution: {integrity: sha512-hsBTNUqQTDwkWtcdYI2i06Y/nUBEsNEDJKjWdigLvegy8kDuJAS8uRlpkkcQpyEXL0Z/pjDy5HBmMjRCJ2gq+g==} engines: {node: '>= 4'} + immediate@3.0.6: + resolution: {integrity: sha512-XXOFtyqDjNDAQxVfYxuF7g9Il/IbWmmlQg2MYKOH8ExIT1qg6xc4zyS3HaEEATgs1btfzxq15ciUiY7gjSXRGQ==} + import-fresh@3.3.0: resolution: {integrity: sha512-veYYhQa+D1QBKznvhUHxb8faxlrwUnxseDAbAp457E0wLNio2bOSKnjYDhMj+YiAq61xrMGhQk9iXVk5FzgQMw==} engines: {node: '>=6'} + import-meta-resolve@4.1.0: + resolution: {integrity: sha512-I6fiaX09Xivtk+THaMfAwnA3MVA5Big1WHF1Dfx9hFuvNIWpXnorlkzhcQf6ehrqQiiZECRt1poOAkPmer3ruw==} + imurmurhash@0.1.4: resolution: {integrity: sha512-JmXMZ6wuvDmLiHEml9ykzqO6lwFbof0GG4IkcGaENdCRDDmMVnny7s5HsIgHCbaq0w2MyPhDqkhTUgS2LU2PHA==} engines: {node: '>=0.8.19'} @@ -3520,10 +3806,17 @@ packages: resolution: {integrity: sha512-EdDDZu4A2OyIK7Lr/2zG+w5jmbuk1DVBnEwREQvBzspBJkCEbRa8GxU1lghYcaGJCnRWibjDXlq779X1/y5xwg==} engines: {node: '>=8'} + inherits@2.0.4: + resolution: {integrity: sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==} + internal-slot@1.1.0: resolution: {integrity: sha512-4gd7VpWNQNB4UKKCFFVcp1AVv+FMOgs9NKzjHKusc8jTMhd5eL1NqQqOpE0KzMds804/yHlglp3uxgluOqAPLw==} engines: {node: '>= 0.4'} + ip-address@9.0.5: + resolution: {integrity: sha512-zHtQzGojZXTwZTHQqra+ETKd4Sn3vgi7uBmlPoXVWZqYvuKmtI0l/VZTjqGmJY9x88GGOaZ9+G9ES8hC4T4X8g==} + engines: {node: '>= 12'} + is-array-buffer@3.0.5: resolution: {integrity: sha512-DDfANUiiG2wC1qawP66qlTugJeL5HyzMpfr8lLK+jMQirGzNod0B12cFB/9q838Ru27sBwfw78/rdoU7RERz6A==} engines: {node: '>= 0.4'} @@ -3598,6 +3891,10 @@ packages: resolution: {integrity: sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==} engines: {node: '>=0.12.0'} + is-plain-obj@4.1.0: + resolution: {integrity: sha512-+Pgi+vMuUNkJyExiMBt5IlFoMyKnr5zhJ4Uspz58WOhBF5QoIZkFyNHIbBAtHwzVAgk5RtndVNsDRN61/mmDqg==} + engines: {node: '>=12'} + is-potential-custom-element-name@1.0.1: resolution: {integrity: sha512-bCYeRA2rVibKZd+s2625gGnGF/t7DSqDs4dP7CrLA1m7jKWz6pps0LpYLJN8Q64HtmPKJ1hrN3nzPNKFEKOUiQ==} @@ -3616,6 +3913,10 @@ packages: resolution: {integrity: sha512-ISWac8drv4ZGfwKl5slpHG9OwPNty4jOWPRIhBpxOoD+hqITiwuipOQ2bNthAzwA3B4fIjO4Nln74N0S9byq8A==} engines: {node: '>= 0.4'} + is-stream@2.0.1: + resolution: {integrity: sha512-hFoiJiTl63nn+kstHGBtewWSKnQLpyb155KHheA1l39uvtO9nWIop1p3udqPcUd/xbF1VLMO4n7OI6p7RbngDg==} + engines: {node: '>=8'} + is-string@1.1.1: resolution: {integrity: sha512-BtEeSsoaQjlSPBemMQIrY1MY0uM6vnS1g5fmufYOtnxLGUZM2178PKbhsk7Ffv58IX+ZtcvoGwccYsh0PglkAA==} engines: {node: '>= 0.4'} @@ -3640,12 +3941,19 @@ packages: resolution: {integrity: sha512-mfcwb6IzQyOKTs84CQMrOwW4gQcaTOAWJ0zzJCl2WSPDrWk/OzDaImWFH3djXhb24g4eudZfLRozAvPGw4d9hQ==} engines: {node: '>= 0.4'} + isarray@1.0.0: + resolution: {integrity: sha512-VLghIWNM6ELQzo7zwmcg0NmTVyWKYjvIeM83yjp0wRDTmUnrM678fQbcKBo6n2CJEF0szoG//ytg+TKla89ALQ==} + isarray@2.0.5: resolution: {integrity: sha512-xHjhDr3cNBK0BzdUJSPXZntQUx/mwMS5Rw4A7lPJ90XGAO6ISP/ePDNuo0vhqOZU+UD5JoodwCAAoZQd3FeAKw==} isexe@2.0.0: resolution: {integrity: sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==} + isexe@3.1.1: + resolution: {integrity: sha512-LpB/54B+/2J5hqQ7imZHfdU31OlgQqx7ZicVlkm9kzg9/w8GKLEcFfJl/t7DCEDueOyBAD6zCCwTO6Fzs0NoEQ==} + engines: {node: '>=16'} + iterator.prototype@1.1.4: resolution: {integrity: sha512-x4WH0BWmrMmg4oHHl+duwubhrvczGlyuGAZu3nvrf0UXOfPu8IhZObFEr7DE/iv01YgVZrsOiRcqw2srkKEDIA==} engines: {node: '>= 0.4'} @@ -3691,6 +3999,9 @@ packages: resolution: {integrity: sha512-wpxZs9NoxZaJESJGIZTyDEaYpl0FKSA+FB9aJiyemKhMwkxQg63h4T1KJgUGHpTqPDNRcmmYLugrRjJlBtWvRA==} hasBin: true + jsbn@1.1.0: + resolution: {integrity: sha512-4bYVV3aAMtDTTu4+xsDYa6sy9GyJ69/amsu9sYF2zqjiEoZA5xJi3BrfX3uY+/IekIu7MwdObdbDWpoZdBv3/A==} + jsdom@25.0.1: resolution: {integrity: sha512-8i7LzZj7BF8uplX+ZyOlIz86V6TAsSs+np6m1kpW9u0JWi4z/1t+FzcK1aek+ybTnAC4KhBL4uXCNT0wcUIeCw==} engines: {node: '>=18'} @@ -3738,13 +4049,23 @@ packages: resolution: {integrity: sha512-ZZow9HBI5O6EPgSJLUb8n2NKgmVWTwCvHGwFuJlMjvLFqlGG6pjirPhtdsseaLZjSibD8eegzmYpUZwoIlj2cQ==} engines: {node: '>=4.0'} + jszip@3.10.1: + resolution: {integrity: sha512-xXDvecyTpGLrqFrvkrUSoxxfJI5AH7U8zxxtVclpsUtMCq4JQ290LY8AW5c7Ggnr/Y/oK+bQMbqK2qmtk3pN4g==} + keyv@4.5.4: resolution: {integrity: sha512-oxVHkHR/EJf2CNXnWxRLW6mg7JyCCUcG0DtEGmL2ctUo1PNTin1PUil+r/+4r5MpVgC/fn1kjsx7mjSujKqIpw==} + lazystream@1.0.1: + resolution: {integrity: sha512-b94GiNHQNy6JNTrt5w6zNyffMrNkXZb3KTkCZJb2V1xaEGCk093vkZ2jk3tpaeP33/OiXC+WvK9AxUebnf5nbw==} + engines: {node: '>= 0.6.3'} + levn@0.4.1: resolution: {integrity: sha512-+bT2uH4E5LGE7h/n3evcS/sQlJXCpIp6ym8OWJ5eV6+67Dsql/LaaT7qJBAt2rzfoa/5QBGBhxDix1dMt2kQKQ==} engines: {node: '>= 0.8.0'} + lie@3.3.0: + resolution: {integrity: sha512-UaiMJzeWRlEujzAuw5LokY1L5ecNQYZKfmyZ9L7wDHb/p5etKaxXhohBcrw0EYby+G/NA52vRSN4N39dxHAIwQ==} + lilconfig@3.1.3: resolution: {integrity: sha512-/vlFKAoH5Cgt3Ie+JLhRbwOsCQePABiU3tJ1egGvyQ+33R/vcwM2Zl2QR/LzjsBeItPt3oSVXapn+m4nQDvpzw==} engines: {node: '>=14'} @@ -3752,6 +4073,9 @@ packages: lines-and-columns@1.2.4: resolution: {integrity: sha512-7ylylesZQ/PV29jhEDl3Ufjo6ZX7gCqJr5F7PKrqc93v7fzSymt1BpwEU8nAUXs8qzzvqhbjhK5QZg6Mt/HkBg==} + locate-app@2.5.0: + resolution: {integrity: sha512-xIqbzPMBYArJRmPGUZD9CzV9wOqmVtQnaAn3wrj3s6WYW0bQvPI7x+sPYUGmDTYMHefVK//zc6HEYZ1qnxIK+Q==} + locate-character@3.0.0: resolution: {integrity: sha512-SW13ws7BjaeJ6p7Q6CO2nchbYEc3X3J6WrmTTDto7yMPqVSZTUyY5Tjbid+Ab8gLnATtygYtiDIJGQRRn2ZOiA==} @@ -3759,12 +4083,25 @@ packages: resolution: {integrity: sha512-iPZK6eYjbxRu3uB4/WZ3EsEIMJFMqAoopl3R+zuq0UjcAm/MO6KCweDgPfP3elTztoKP3KtnVHxTn2NHBSDVUw==} engines: {node: '>=10'} + lodash.clonedeep@4.5.0: + resolution: {integrity: sha512-H5ZhCF25riFd9uB5UCkVKo61m3S/xZk1x4wA6yp/L3RFP6Z/eHH1ymQcGLo7J3GMPfm0V/7m1tryHuGVxpqEBQ==} + lodash.merge@4.6.2: resolution: {integrity: sha512-0KpjqXRVvrYyCsX1swR/XTK0va6VQkQM6MNo7PqW77ByjAhoARA8EfrP1N4+KlKj8YS0ZUCtRT/YUuhyYDujIQ==} + lodash.zip@4.2.0: + resolution: {integrity: sha512-C7IOaBBK/0gMORRBd8OETNx3kmOkgIWIPvyDpZSCTwUrpYmgZwJkjZeOD8ww4xbOUOs4/attY+pciKvadNfFbg==} + lodash@4.17.21: resolution: {integrity: sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==} + loglevel-plugin-prefix@0.8.4: + resolution: {integrity: sha512-WpG9CcFAOjz/FtNht+QJeGpvVl/cdR6P0z6OcXSkr8wFJOsV2GRj2j10JLfjuA4aYkcKCNIEqRGCyTife9R8/g==} + + loglevel@1.9.2: + resolution: {integrity: sha512-HgMmCqIJSAKqo68l0rS2AanEWfkxaZ5wNiEFb5ggm08lDs9Xl2KxBlX3PTcaD2chBM1gXAYf491/M2Rv8Jwayg==} + engines: {node: '>= 0.6.0'} + loose-envify@1.4.0: resolution: {integrity: sha512-lyuxPGr/Wfhrlem2CL/UcnUc1zcqKAImBDzukY7Y5F/yQiNdko6+fRLevlw1HgMySw7f611UIY408EtxRSoK3Q==} hasBin: true @@ -3778,6 +4115,10 @@ packages: lru-cache@5.1.1: resolution: {integrity: sha512-KpNARQA3Iwv+jTA0utUVVbrh+Jlrr1Fv0e56GGzAFOXN7dk/FviaDW8LHmK52DlcH4WP2n6gI8vN1aesBFgo9w==} + lru-cache@7.18.3: + resolution: {integrity: sha512-jumlc0BIUrS3qJGgIkWZsyfAM7NCWiBcCDhnd+3NNM5KbBmLTgHVfWBcg6W+rLUsIpzpERPsvwUP7CckAQSOoA==} + engines: {node: '>=12'} + lucide-react@0.439.0: resolution: {integrity: sha512-PafSWvDTpxdtNEndS2HIHxcNAbd54OaqSYJO90/b63rab2HWYqDbH194j0i82ZFdWOAcf0AHinRykXRRK2PJbw==} peerDependencies: @@ -3794,6 +4135,9 @@ packages: resolution: {integrity: sha512-yBrq7MZCUfSwiPi4Un0LX8nwATyHXxCVB5iJoZpvIOK5MsGSOnO44do4+DGuIocQcI8t+lvWbBl8TvmsA6F69Q==} engines: {node: '>= v6.0.0'} + make-error@1.3.6: + resolution: {integrity: sha512-s8UhlNe7vPKomQhC1qFelMokr/Sc3AgNbso3n74mVPA5LTZwkB9NlXf4XPamLxJE8h0gh73rM94xvwRT2CVInw==} + map-obj@4.3.0: resolution: {integrity: sha512-hdN1wVrZbb29eBGiGjJbeP8JbKjq1urkHJ/LIP/NY48MZ1QVXUsQBV1G1zvYFHn1XE06cwjBsOI2K3Ulnj1YXQ==} engines: {node: '>=8'} @@ -3832,6 +4176,10 @@ packages: minimatch@3.1.2: resolution: {integrity: sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==} + minimatch@5.1.6: + resolution: {integrity: sha512-lKwV/1brpG6mBUFHtb7NUmtABCb2WZZmm2wNiOA5hAb8VdCS4B3dtMWyvcoViccwAW/COERjXLt0zP1zXUN26g==} + engines: {node: '>=10'} + minimatch@9.0.5: resolution: {integrity: sha512-G6T0ZX48xgozx7587koeX9Ys2NYy6Gmv//P89sEte9V9whIapMNF4idKxnW2QtCcLiTWlb/wfCabAtAFWhhBow==} engines: {node: '>=16 || 14 >=14.17'} @@ -3865,6 +4213,10 @@ packages: natural-compare@1.4.0: resolution: {integrity: sha512-OWND8ei3VtNC9h7V60qff3SVobHr996CTwgxubgyQYEpg290h9J0buyECNNJexkFm5sOajh5G116RYA1c8ZMSw==} + netmask@2.0.2: + resolution: {integrity: sha512-dBpDMdxv9Irdq66304OLfEmQ9tbNRFnFTuZiLo+bD+r332bBmMJ8GBLXklIXXgxd3+v9+KUnZaUR5PJMa75Gsg==} + engines: {node: '>= 0.4.0'} + next@15.0.0-canary.152: resolution: {integrity: sha512-r0u1MXGuBKnrhZmtwUY6Wggisgj73Yel9D66shvZ3L4XnXNN7MVw25dtitKYHfYnd1ZktZb6fyt28nXCHKG7lQ==} engines: {node: '>=18.18.0'} @@ -3902,6 +4254,10 @@ packages: encoding: optional: true + node-fetch@3.3.2: + resolution: {integrity: sha512-dRB78srN/l6gqWulah9SrxeYnxeddIG30+GOqK/9OlLVyLg3HPnr6SqOWTWOXKRwC2eGYCkZ59NNuSgvSrpgOA==} + engines: {node: ^12.20.0 || ^14.13.1 || >=16.0.0} + node-gyp-build@4.8.4: resolution: {integrity: sha512-LA4ZjwlnUblHVgq0oBF3Jl/6h/Nvs5fzBLwdEF4nuxnFdsfajde4WfxtJr3CaiH+F6ewcIB/q4jQ4UzPyid+CQ==} hasBin: true @@ -3917,6 +4273,9 @@ packages: resolution: {integrity: sha512-bdok/XvKII3nUpklnV6P2hxtMNrCboOjAcyBuQnWEhO665FwrSNRxU+AqpsyvO6LgGYPspN+lu5CLtw4jPRKNA==} engines: {node: '>=0.10.0'} + nth-check@2.1.1: + resolution: {integrity: sha512-lqjrjmaOoAnWfMmBPL+XNnynZh2+swxiX3WUE0s4yEHI6m+AwrK2UZOimIRl3X/4QctVqS8AiZjFqyOGrMXb/w==} + nwsapi@2.2.16: resolution: {integrity: sha512-F1I/bimDpj3ncaNDhfyMWuFqmQDBwDB0Fogc2qpL3BWvkQteFD/8BzWuIRl83rq0DXfm8SGt/HFhLXZyljTXcQ==} @@ -3959,6 +4318,9 @@ packages: obuf@1.1.2: resolution: {integrity: sha512-PX1wu0AmAdPqOL1mWhqmlOd8kOIZQwGZw6rh7uby9fTc5lhaOWFLX3I6R1hrF9k3zUY40e6igsLGkDXK92LJNg==} + once@1.4.0: + resolution: {integrity: sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w==} + optionator@0.9.4: resolution: {integrity: sha512-6IpQ7mKUxRcZNLIObR0hz7lxsapSSIYNZJwXPGeF0mTVqGKFIXj1DQcMoT22S3ROcLyY/rz0PWaWZ9ayWmad9g==} engines: {node: '>= 0.8.0'} @@ -3978,12 +4340,23 @@ packages: resolution: {integrity: sha512-LaNjtRWUBY++zB5nE/NwcaoMylSPk+S+ZHNB1TzdbMJMny6dynpAGt7X/tl/QYq3TIeE6nxHppbo2LGymrG5Pw==} engines: {node: '>=10'} + pac-proxy-agent@7.1.0: + resolution: {integrity: sha512-Z5FnLVVZSnX7WjBg0mhDtydeRZ1xMcATZThjySQUHqr+0ksP8kqaw23fNKkaaN/Z8gwLUs/W7xdl0I75eP2Xyw==} + engines: {node: '>= 14'} + + pac-resolver@7.0.1: + resolution: {integrity: sha512-5NPgf87AT2STgwa2ntRMr45jTKrYBGkVU36yT0ig/n/GMAa3oPqhZfIQ2kMEimReg0+t9kZViDVZ83qfVUlckg==} + engines: {node: '>= 14'} + package-json-from-dist@1.0.1: resolution: {integrity: sha512-UEZIS3/by4OC8vL3P2dTXRETpebLI2NiI5vIrjaD/5UtrkFX/tNbwjTSRAGC/+7CAo2pIcBaRgWmcBBHcsaCIw==} package-manager-detector@0.2.8: resolution: {integrity: sha512-ts9KSdroZisdvKMWVAVCXiKqnqNfXz4+IbrBG8/BWx/TR5le+jfenvoBuIZ6UWM9nz47W7AbD9qYfAwfWMIwzA==} + pako@1.0.11: + resolution: {integrity: sha512-4hLB8Py4zZce5s4yd9XzopqwVv/yGNhV1Bl8NTmCq1763HeK2+EwVTv+leGeL13Dnh2wfbqowVPXCIO0z4taYw==} + parent-module@1.0.1: resolution: {integrity: sha512-GQ2EWRpQV8/o+Aw8YqtfZZPfNRWZYkbidE9k5rpl/hC3vtHHBfGm2Ifi6qWV+coDGkrUKZAxE3Lot5kcsRlh+g==} engines: {node: '>=6'} @@ -3992,6 +4365,12 @@ packages: resolution: {integrity: sha512-ayCKvm/phCGxOkYRSCM82iDwct8/EonSEgCSxWxD7ve6jHggsFl4fZVQBPRNgQoKiuV/odhFrGzQXZwbifC8Rg==} engines: {node: '>=8'} + parse5-htmlparser2-tree-adapter@7.1.0: + resolution: {integrity: sha512-ruw5xyKs6lrpo9x9rCZqZZnIUntICjQAd0Wsmp396Ul9lN/h+ifgVV1x1gZHi8euej6wTfpqX8j+BFQxF0NS/g==} + + parse5-parser-stream@7.1.2: + resolution: {integrity: sha512-JyeQc9iwFLn5TbvvqACIF/VXG6abODeB3Fwmv/TGdLk2LfbWkaySGY72at4+Ty7EkPZj854u4CrICqNk2qIbow==} + parse5@7.2.1: resolution: {integrity: sha512-BuBYQYlv1ckiPdQi/ohiivi9Sagc9JG+Ozs0r7b/0iK3sKmrb0b9FdWdBbOdx6hBCM/F9Ir82ofnBhtZOjCRPQ==} @@ -4014,6 +4393,9 @@ packages: resolution: {integrity: sha512-gDKb8aZMDeD/tZWs9P6+q0J9Mwkdl6xMV8TjnGP3qJVJ06bdMgkbBlLU8IdfOsIsFz2BW1rNVT3XuNEl8zPAvw==} engines: {node: '>=8'} + pend@1.2.0: + resolution: {integrity: sha512-F3asv42UuXchdzt+xXqfW1OGlVBe+mxa2mqI0pg5yAHZPvFmY3Y6drSf/GQ1A86WgWEN9Kzh/WrgKa6iGcHXLg==} + pg-int8@1.0.1: resolution: {integrity: sha512-WCtabS6t3c8SkpDBUlb1kjOs7l66xsGdKpIPZsg4wR+B3+u9UAum2odSsF9tnvxg80h4ZxLWMy4pRjOsFIqQpw==} engines: {node: '>=4.0.0'} @@ -4147,9 +4529,30 @@ packages: resolution: {integrity: sha512-Pdlw/oPxN+aXdmM9R00JVC9WVFoCLTKJvDVLgmJ+qAffBMxsV85l/Lu7sNx4zSzPyoL2euImuEwHhOXdEgNFZQ==} engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} + process-nextick-args@2.0.1: + resolution: {integrity: sha512-3ouUOpQhtgrbOa17J7+uxOTpITYWaGP7/AhoR3+A+/1e9skrzelGi/dXzEYyvbxubEF6Wn2ypscTKiKJFFn1ag==} + + process@0.11.10: + resolution: {integrity: sha512-cdGef/drWFoydD1JsMzuFf8100nZl+GT+yacc2bEced5f9Rjk4z+WtFUTBu9PhOi9j/jfmBPu0mMEY4wIdAF8A==} + engines: {node: '>= 0.6.0'} + + progress@2.0.3: + resolution: {integrity: sha512-7PiHtLll5LdnKIMw100I+8xJXR5gW2QwWYkT6iJva0bXitZKa/XMrSbdmg3r2Xnaidz9Qumd0VPaMrZlF9V9sA==} + engines: {node: '>=0.4.0'} + prop-types@15.8.1: resolution: {integrity: sha512-oj87CgZICdulUohogVAR7AjlC0327U4el4L6eAvOqCeudMDVU0NThNaV+b9Df4dXgSP1gXMTnPdhfe/2qDH5cg==} + proxy-agent@6.5.0: + resolution: {integrity: sha512-TmatMXdr2KlRiA2CyDu8GqR8EjahTG3aY3nXjdzFyoZbmB8hrBsTyMezhULIXKnC0jpfjlmiZ3+EaCzoInSu/A==} + engines: {node: '>= 14'} + + proxy-from-env@1.1.0: + resolution: {integrity: sha512-D+zkORCbA9f1tdWRK0RaCR3GPv50cMxcrz4X8k5LTSUD1Dkw47mKJEZQNunItRTkWwgtaUSo1RVFRIG9ZXiFYg==} + + pump@3.0.2: + resolution: {integrity: sha512-tUPXtzlGM8FE3P0ZL6DVs/3P58k9nk8/jZeQCurTJylQA8qFYzHFfhBJkuqyE0FifOsQ0uKWekiZ5g8wtr28cw==} + punycode@2.3.1: resolution: {integrity: sha512-vYt7UD1U9Wg6138shLtLOvdAu+8DsC/ilFtEVHcH+wydcSpNE20AfSOduf6MkRFahL5FY7X1oU7nKVZFtfq8Fg==} engines: {node: '>=6'} @@ -4158,9 +4561,15 @@ packages: resolution: {integrity: sha512-EJPeIn0CYrGu+hli1xilKAPXODtJ12T0sP63Ijx2/khC2JtuaN3JyNIpvmnkmaEtha9ocbG4A4cMcr+TvqvwQg==} engines: {node: '>=0.6'} + query-selector-shadow-dom@1.0.1: + resolution: {integrity: sha512-lT5yCqEBgfoMYpf3F2xQRK7zEr1rhIIZuceDK6+xRkJQ4NMbHTwXqk4NkwDwQMNqXgG9r9fyHnzwNVs6zV5KRw==} + queue-microtask@1.2.3: resolution: {integrity: sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A==} + queue-tick@1.0.1: + resolution: {integrity: sha512-kJt5qhMxoszgU/62PLP1CJytzd2NKetjSRnyuj31fDd3Rlcz3fzlFdFLD1SItunPwyqEOkca6GbV612BWfaBag==} + raf-schd@4.0.3: resolution: {integrity: sha512-tQkJl2GRWh83ui2DiPTJz9wEiMN20syf+5oKfB03yYP7ioZcJwsIK8FjrtLwH1m7C7e+Tt2yYBlrOpdT+dyeIQ==} @@ -4255,6 +4664,16 @@ packages: read-cache@1.0.0: resolution: {integrity: sha512-Owdv/Ft7IjOgm/i0xvNDZ1LrRANRfew4b2prF3OWMQLxLfu3bS8FVhCsrSCMK4lR56Y9ya+AThoTpDCTxCmpRA==} + readable-stream@2.3.8: + resolution: {integrity: sha512-8p0AUk4XODgIewSi0l8Epjs+EVnWiK7NoDIEGU0HhE7+ZyY8D1IMY7odu5lRrFXGg71L15KG8QrPmum45RTtdA==} + + readable-stream@4.6.0: + resolution: {integrity: sha512-cbAdYt0VcnpN2Bekq7PU+k363ZRsPwJoEEJOEtSJQlJXzwaxt3FIo/uL+KeDSGIjJqtkwyge4KQgD2S2kd+CQw==} + engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} + + readdir-glob@1.1.3: + resolution: {integrity: sha512-v05I2k7xN8zXvPD9N+z/uhXPaj0sUFCe2rcWZIpBsqxfP7xXFQ0tipAd/wjj1YxWyWtUS5IDJpOG82JKt2EAVA==} + readdirp@3.6.0: resolution: {integrity: sha512-hOS089on8RduqdbhvQ5Z37A0ESjsqz6qnRcffsMU3495FuTdqSm+7bhJ29JvIOsBDEEnan5DPu9t3To9VRlMzA==} engines: {node: '>=8.10.0'} @@ -4277,6 +4696,10 @@ packages: resolution: {integrity: sha512-vqlC04+RQoFalODCbCumG2xIOvapzVMHwsyIGM/SIE8fRhFFsXeH8/QQ+s0T0kDAhKc4k30s73/0ydkHQz6HlQ==} engines: {node: '>= 0.4'} + require-directory@2.1.1: + resolution: {integrity: sha512-fGxEI7+wsG9xrvdjsrlmL22OMTTiHRwAMroiEeMgq8gzoLC/PQr7RsRDSTLUg/bZAZtF+TVIkHc6/4RIKrui+Q==} + engines: {node: '>=0.10.0'} + resolve-from@4.0.0: resolution: {integrity: sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g==} engines: {node: '>=4'} @@ -4293,10 +4716,16 @@ packages: resolution: {integrity: sha512-U7WjGVG9sH8tvjW5SmGbQuui75FiyjAX72HX15DwBBwF9dNiQZRQAg9nnPhYy+TUnE0+VcrttuvNI8oSxZcocA==} hasBin: true + resq@1.11.0: + resolution: {integrity: sha512-G10EBz+zAAy3zUd/CDoBbXRL6ia9kOo3xRHrMDsHljI0GDkhYlyjwoCx5+3eCC4swi1uCoZQhskuJkj7Gp57Bw==} + reusify@1.0.4: resolution: {integrity: sha512-U9nH88a3fc/ekCF1l0/UP1IosiuIjyTh7hBvXVMHYgVcfGvt897Xguj2UOLDeI5BG2m7/uwyaLVT6fbtCwTyzw==} engines: {iojs: '>=1.0.0', node: '>=0.10.0'} + rgb2hex@0.2.5: + resolution: {integrity: sha512-22MOP1Rh7sAo1BZpDG6R5RFYzR2lYEgwq7HEmyW2qcsOqR2lQKmn+O//xV3YG/0rrhMC6KVX2hU+ZXuaw9a5bw==} + rollup@4.29.1: resolution: {integrity: sha512-RaJ45M/kmJUzSWDs1Nnd5DdV4eerC98idtUOVr6FfKcgxqvjwHmxc5upLF9qZU9EpsVzzhleFahrT3shLuJzIw==} engines: {node: '>=18.0.0', npm: '>=8.0.0'} @@ -4313,10 +4742,20 @@ packages: engines: {node: '>=v0.9.0'} hasBin: true + safaridriver@1.0.0: + resolution: {integrity: sha512-J92IFbskyo7OYB3Dt4aTdyhag1GlInrfbPCmMteb7aBK7PwlnGz1HI0+oyNN97j7pV9DqUAVoVgkNRMrfY47mQ==} + engines: {node: '>=18.0.0'} + safe-array-concat@1.1.3: resolution: {integrity: sha512-AURm5f0jYEOydBj7VQlVvDrjeFgthDdEF5H1dP+6mNpoXOMo1quQqJ4wvJDyRZ9+pO3kGWoOdmV08cSv2aJV6Q==} engines: {node: '>=0.4'} + safe-buffer@5.1.2: + resolution: {integrity: sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==} + + safe-buffer@5.2.1: + resolution: {integrity: sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==} + safe-push-apply@1.0.0: resolution: {integrity: sha512-iKE9w/Z7xCzUMIZqdBsp6pEQvwuEebH4vdpjcDWnyzaI6yl6O9FHvVpmGelvEHNsoY6wGblkxR6Zty/h00WiSA==} engines: {node: '>= 0.4'} @@ -4347,6 +4786,10 @@ packages: engines: {node: '>=10'} hasBin: true + serialize-error@11.0.3: + resolution: {integrity: sha512-2G2y++21dhj2R7iHAdd0FIzjGwuKZld+7Pl/bTU6YIkrC2ZMbVUjm+luj6A6V34Rv9XfKJDKpTWu9W4Gse1D9g==} + engines: {node: '>=14.16'} + server-only@0.0.1: resolution: {integrity: sha512-qepMx2JxAa5jjfzxG79yPPq+8BuFToHd1hm7kI+Z4zAq1ftQiP7HcxMhDDItrbtwVeLg/cY2JnKnrcFkmiswNA==} @@ -4358,6 +4801,9 @@ packages: resolution: {integrity: sha512-7PGFlmtwsEADb0WYyvCMa1t+yke6daIG4Wirafur5kcf+MhUnPms1UeR0CKQdTZD81yESwMHbtn+TR+dMviakQ==} engines: {node: '>= 0.4'} + setimmediate@1.0.5: + resolution: {integrity: sha512-MATJdZp8sLqDl/68LfQmbP8zKPLQNV6BIZoIgrscFDQ+RsvK/BxeDQOgyxKKoh0y/8h3BqVFnCqQ/gd+reiIXA==} + sharp@0.33.5: resolution: {integrity: sha512-haPVm1EkS9pgvHrQ/F3Xy+hgcuMV0Wm9vfIBSiwZ05k+xgb0PkBQpGsAA/oWdDobNaZTH5ppvHtzCFbnSEwHVw==} engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0} @@ -4397,6 +4843,10 @@ packages: resolution: {integrity: sha512-g9Q1haeby36OSStwb4ntCGGGaKsaVSjQ68fBxoQcutl5fS1vuY18H3wSt3jFyFtrkx+Kz0V1G85A4MyAdDMi2Q==} engines: {node: '>=8'} + smart-buffer@4.2.0: + resolution: {integrity: sha512-94hK0Hh8rPqQl2xXc3HsaBoOXKV20MToPkcXvwbISWLEs+64sBq5kFgn2kJDHb1Pry9yrP0dxrCI9RRci7RXKg==} + engines: {node: '>= 6.0.0', npm: '>= 3.0.0'} + smee-client@2.0.4: resolution: {integrity: sha512-RxXCs0mfaxpI8JF4SeTM51XtRiprzW5g20HVt4aTQ36EB+RaN0aj0m/4EbXLGdfPlqahQ09d3UnJYmALN2CbYw==} hasBin: true @@ -4408,6 +4858,14 @@ packages: resolution: {integrity: sha512-YTywJG93yxwHLgrYLZjlC75moVEX04LZM4FHfihjHe1FCXm+QaLOFfSf535aXOAd0ArVQMWUAe8ZPm4VtWyXaA==} engines: {node: '>=12'} + socks-proxy-agent@8.0.5: + resolution: {integrity: sha512-HehCEsotFqbPW9sJ8WVYB6UbmIMv7kUUORIF2Nncq4VQvBfNBLibW9YZR5dlYCSUhwcD628pRllm7n+E+YTzJw==} + engines: {node: '>= 14'} + + socks@2.8.3: + resolution: {integrity: sha512-l5x7VUUWbjVFbafGLxPWkYsHIhEvmF85tbIeFZWc8ZPtoMyybuEhL7Jye/ooC4/d48FgOjSJXgsF/AJPYCW8Zw==} + engines: {node: '>= 10.0.0', npm: '>= 3.0.0'} + source-map-js@1.2.1: resolution: {integrity: sha512-UXWMKhLOwVKb728IUtQPXxfYU+usdybtUrK/8uGE8CQMvrhOpwvzDBwj0QhSL7MQc7vIsISBG8VQ8+IDQxpfQA==} engines: {node: '>=0.10.0'} @@ -4423,6 +4881,16 @@ packages: resolution: {integrity: sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==} engines: {node: '>=0.10.0'} + spacetrim@0.11.59: + resolution: {integrity: sha512-lLYsktklSRKprreOm7NXReW8YiX2VBjbgmXYEziOoGf/qsJqAEACaDvoTtUOycwjpaSh+bT8eu0KrJn7UNxiCg==} + + split2@4.2.0: + resolution: {integrity: sha512-UcjcJOWknrNkF6PLX83qcHM6KHgVKNkV62Y8a5uYDVv9ydGQVwAHMKqHdJje1VTWpljG0WYpCDhrCdAOYH4TWg==} + engines: {node: '>= 10.x'} + + sprintf-js@1.1.3: + resolution: {integrity: sha512-Oo+0REFV59/rz3gfJNKQiBlwfHaSESl1pcGyABQsnnIfWOFt6JNj5gCog2U6MLZ//IGYD+nA8nI+mTShREReaA==} + sswr@2.1.0: resolution: {integrity: sha512-Cqc355SYlTAaUt8iDPaC/4DPPXK925PePLMxyBKuWd5kKc5mwsG3nT9+Mq2tyguL5s7b4Jg+IRMpTRsNTAfpSQ==} peerDependencies: @@ -4439,6 +4907,9 @@ packages: resolution: {integrity: sha512-Mcc5wHehp9aXz1ax6bZUyY5afg9u2rv5cqQI3mRrYkGC8rW2hM02jWuwjtL++LS5qinSyhj2QfLyNsuc+VsExg==} engines: {node: '>=10.0.0'} + streamx@2.21.1: + resolution: {integrity: sha512-PhP9wUnFLa+91CPy3N6tiQsK+gnYyUNuk15S3YG/zjYE7RuPeCjJngqnzpC31ow0lzBHQ+QGO4cNJnd0djYUsw==} + string-width@4.2.3: resolution: {integrity: sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==} engines: {node: '>=8'} @@ -4466,6 +4937,12 @@ packages: resolution: {integrity: sha512-UXSH262CSZY1tfu3G3Secr6uGLCFVPMhIqHjlgCUtCCcgihYc/xKs9djMTMUOb2j1mVSeU8EU6NWc/iQKU6Gfg==} engines: {node: '>= 0.4'} + string_decoder@1.1.1: + resolution: {integrity: sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==} + + string_decoder@1.3.0: + resolution: {integrity: sha512-hkRX8U1WjJFd8LsDJ2yQ/wWWxaopEsABU1XfkM8A+j0+85JAGppt16cr1Whg6KIbb4okU6Mql6BOj+uup/wKeA==} + strip-ansi@6.0.1: resolution: {integrity: sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==} engines: {node: '>=8'} @@ -4490,6 +4967,9 @@ packages: resolution: {integrity: sha512-H7eFVLDxeTNNSn4JTRfL2//LzCbDrMSZ+2q1c7CanVWgK2qIW5TwS+0V7N9KcKZZNpYh/uCqK0PyZh/2UsaAtQ==} engines: {node: '>=12.*'} + strnum@1.0.5: + resolution: {integrity: sha512-J8bbNyKKXl5qYcR36TIO8W3mVGVHrmmxsd5PAItGkmyzwJvybiw2IVq5nqd0i4LSNSkB/sx9VHllbfFdr9k1JA==} + styled-jsx@5.1.6: resolution: {integrity: sha512-qSVyDTeMotdvQYoHWLNGwRFJHC+i+ZvdBRYosOFgC+Wg1vx4frN2/RG/NA7SYqqvKNLf39P2LSRA2pu6n0XYZA==} engines: {node: '>= 12.0.0'} @@ -4558,6 +5038,15 @@ packages: engines: {node: '>=14.0.0'} hasBin: true + tar-fs@3.0.6: + resolution: {integrity: sha512-iokBDQQkUyeXhgPYaZxmczGPhnhXZ0CmrqI+MOb/WFGS9DW5wnfrLgtjUJBvz50vQ3qfRwJ62QVoCFu8mPVu5w==} + + tar-stream@3.1.7: + resolution: {integrity: sha512-qJj60CXt7IU1Ffyc3NJMjh6EkuCFej46zUqJ4J7pqYlThyd9bO0XBTmcOIhSzZJVWfsLks0+nle/j538YAW9RQ==} + + text-decoder@1.2.3: + resolution: {integrity: sha512-3/o9z3X0X0fTupwsYvR03pJ/DjWuqqrfwBgTQzdWDiQSm9KitAyz/9WqsT2JQW7KV2m+bC2ol/zqpW37NHxLaA==} + thenify-all@1.6.0: resolution: {integrity: sha512-RNxQH/qI8/t3thXJDwcstUO4zeqo64+Uy/+sNVRBx4Xn2OX+OZ9oP+iJnNFqplFra2ZUVeKCSa2oVWi3T4uVmA==} engines: {node: '>=0.8'} @@ -4573,6 +5062,9 @@ packages: resolution: {integrity: sha512-nt6AMGKW1p/70DF/hGBdJB57B8Tspmbp5gfJ8ilhLnt7kkr2ye7hzD6NVG8GGErk2HWF34igrL2CXmNIkzKqKw==} engines: {node: '>=18'} + through@2.3.8: + resolution: {integrity: sha512-w89qg7PI8wAdvX60bMDP+bFoD5Dvhm9oLheFp5O4a2QF0cSBGsBX4qZmadPMvVqlLJBBci+WqGGOAPvcDeNSVg==} + tiny-invariant@1.3.3: resolution: {integrity: sha512-+FbBPE1o9QAYvviau/qC5SE3caw21q3xkvWKBtja5vgqOWIHHJ3ioaq1VPfn/Szqctz2bU/oYeKd9/z5BL+PVg==} @@ -4607,6 +5099,13 @@ packages: ts-interface-checker@0.1.13: resolution: {integrity: sha512-Y/arvbn+rrz3JCKl9C4kVNfTfSm2/mEp5FSz5EsZSANGPSlQrpRI5M4PKF+mJnE52jOO90PnPSc3Ur3bTQw0gA==} + ts-node@9.1.1: + resolution: {integrity: sha512-hPlt7ZACERQGf03M253ytLY3dHbGNGrAq9qIHWUY9XHYl1z7wYngSr3OQ5xmui8o2AaxsONxIzjafLUiWBo1Fg==} + engines: {node: '>=10.0.0'} + hasBin: true + peerDependencies: + typescript: '>=2.7' + tsconfck@3.1.4: resolution: {integrity: sha512-kdqWFGVJqe+KGYvlSO9NIaWn9jT1Ny4oKVzAJsKii5eoE9snzTJzL4+MMVOMn+fikWGFmKEylcXL710V/kIPJQ==} engines: {node: ^18 || >=20} @@ -4639,6 +5138,10 @@ packages: resolution: {integrity: sha512-RAH822pAdBgcNMAfWnCBU3CFZcfZ/i1eZjwFU/dsLKumyuuP3niueg2UAukXYF0E2AAoc82ZSSf9J0WQBinzHA==} engines: {node: '>=12.20'} + type-fest@4.26.0: + resolution: {integrity: sha512-OduNjVJsFbifKb57UqZ2EMP1i4u64Xwow3NYXUtBbD4vIwJdQd4+xl8YDou1dlm4DVrtwT/7Ky8z8WyCULVfxw==} + engines: {node: '>=16'} + typed-array-buffer@1.0.3: resolution: {integrity: sha512-nAYYwfY3qnzX30IkA6AQZjVbtK6duGontcQm1WSG1MD94YLqK0515GNApXkoxKOWMusVssAHWLh9SeaoefYFGw==} engines: {node: '>= 0.4'} @@ -4664,6 +5167,9 @@ packages: resolution: {integrity: sha512-nWJ91DjeOkej/TA8pXQ3myruKpKEYgqvpw9lz4OPHj/NWFNluYrjbz9j01CJ8yKQd2g4jFoOkINCTW2I5LEEyw==} engines: {node: '>= 0.4'} + unbzip2-stream@1.4.3: + resolution: {integrity: sha512-mlExGW4w71ebDJviH16lQLtZS32VKqsSfk80GCfUlwT/4/hNRFsoscrF/c++9xinkMzECL1uL9DDwXqFWkruPg==} + undici-types@5.26.5: resolution: {integrity: sha512-JlCMO+ehdEIKqlFxk6IfVoAUVmgz7cU7zD/h9XZ0qzeosSHmUJVOzSQvvYSYWXkFXC+IfLKSIffhv0sVZup6pA==} @@ -4673,6 +5179,10 @@ packages: undici-types@6.20.0: resolution: {integrity: sha512-Ny6QZ2Nju20vw1SRHe3d9jVu6gJ+4e3+MMpqu7pqE5HT6WsTSlce++GQmK5UXS8mzV8DSYHrQH+Xrf2jVcuKNg==} + undici@6.21.0: + resolution: {integrity: sha512-BUgJXc752Kou3oOIuU1i+yZZypyZRqNPW0vqoMPl8VaoalSfeR0D8/t4iAS3yirs79SSMTxTag+ZC86uswv+Cw==} + engines: {node: '>=18.17'} + universal-user-agent@7.0.2: resolution: {integrity: sha512-0JCqzSKnStlRRQfCdowvqy3cy0Dvtlb8xecj/H8JFZuCze4rwjPZQOgvFvn0Ws/usCHQFGpyr+pB9adaGwXn4Q==} @@ -4718,6 +5228,10 @@ packages: peerDependencies: react: ^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0 + userhome@1.0.1: + resolution: {integrity: sha512-5cnLm4gseXjAclKowC4IjByaGsjtAoV6PrOQOljplNB54ReUYJP8HdAFq2muHinSDAh09PPX/uXDPfdxRHvuSA==} + engines: {node: '>= 0.8.0'} + util-deprecate@1.0.2: resolution: {integrity: sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw==} @@ -4791,10 +5305,32 @@ packages: resolution: {integrity: sha512-o8qghlI8NZHU1lLPrpi2+Uq7abh4GGPpYANlalzWxyWteJOCsr/P+oPBA49TOLu5FTZO4d3F9MnWJfiMo4BkmA==} engines: {node: '>=18'} + wait-port@1.1.0: + resolution: {integrity: sha512-3e04qkoN3LxTMLakdqeWth8nih8usyg+sf1Bgdf9wwUkp05iuK1eSY/QpLvscT/+F/gA89+LpUmmgBtesbqI2Q==} + engines: {node: '>=10'} + hasBin: true + + web-streams-polyfill@3.3.3: + resolution: {integrity: sha512-d2JWLCivmZYTSIoge9MsgFCZrt571BikcWGYkjC1khllbTeDlGqZ2D8vD8E/lJa8WGWbb7Plm8/XJYV7IJHZZw==} + engines: {node: '>= 8'} + web-streams-polyfill@4.0.0-beta.3: resolution: {integrity: sha512-QW95TCTaHmsYfHDybGMwO5IJIM93I/6vTRk+daHTWFPhwh+C8Cg7j7XyKrwrj8Ib6vYXe0ocYNrmzY4xAAN6ug==} engines: {node: '>= 14'} + webdriver@9.5.0: + resolution: {integrity: sha512-w57Cb+N9VjSoYEFosytqDrICF3W5GqP0ldxiUMrhwaGSe2CfqE666CyRhy533Y3oYg1gZvVMc7jq6CMbfSBoTg==} + engines: {node: '>=18.20.0'} + + webdriverio@9.5.0: + resolution: {integrity: sha512-74QK4lDH5zkD/oEO/zHs2GqjrTj/d012+4zuZKAIqAnO46E+um50gw4AMmNp7Bc5xcGdU9CoB5EGDMpt2Fwf9g==} + engines: {node: '>=18.20.0'} + peerDependencies: + puppeteer-core: ^22.3.0 + peerDependenciesMeta: + puppeteer-core: + optional: true + webidl-conversions@3.0.1: resolution: {integrity: sha512-2JAn3z8AR6rjK8Sm8orRC0h/bcl/DqL7tRPdGZ4I1CjdF+EaMLmYxBHyXuKL849eucPFhvBoxMsflfOb8kxaeQ==} @@ -4842,6 +5378,11 @@ packages: engines: {node: '>= 8'} hasBin: true + which@5.0.0: + resolution: {integrity: sha512-JEdGzHwwkrbWoGOlIHqQ5gtprKGOenpDHpxE9zVR1bWbOtYRyPPHMe9FaP6x61CmNaTThSkb0DAJte5jD+DmzQ==} + engines: {node: ^18.17.0 || >=20.5.0} + hasBin: true + word-wrap@1.2.5: resolution: {integrity: sha512-BN22B5eaMMI9UMtjrGd5g5eCYPpCPDUy0FJXbYsaT5zYxjFOckS53SQDE3pWkVoWpHXVb3BrYcEN4Twa55B5cA==} engines: {node: '>=0.10.0'} @@ -4854,6 +5395,9 @@ packages: resolution: {integrity: sha512-si7QWI6zUMq56bESFvagtmzMdGOtoxfR+Sez11Mobfc7tm+VkUckk9bW2UeffTGVUbOksxmSw0AA2gs8g71NCQ==} engines: {node: '>=12'} + wrappy@1.0.2: + resolution: {integrity: sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==} + ws@8.18.0: resolution: {integrity: sha512-8VbfWfHLbbwu3+N6OKsOMpBdT4kXPDDB9cJk2bJ6mh9ucxdlnNvH1e+roYkKmN9Nxw2yjz7VzeO9oOz2zJ04Pw==} engines: {node: '>=10.0.0'} @@ -4873,6 +5417,10 @@ packages: xmlchars@2.2.0: resolution: {integrity: sha512-JZnDKK8B0RCDw84FNdDAIpZK+JuJw+s7Lz8nksI7SIuU3UXJJslUthsi+uWBUYOwPFwW7W7PRLRfUKpxjtjFCw==} + y18n@5.0.8: + resolution: {integrity: sha512-0pfFzegeDWJHJIAmTLRP2DwHjdF5s7jo9tuztdQxAhINCdvS+3nGINqPd00AphqJR/0LhANUS6/+7SCb98YOfA==} + engines: {node: '>=10'} + yallist@3.1.1: resolution: {integrity: sha512-a4UGQaWPH59mOXUYnAG2ewncQS4i4F43Tv3JoAM+s2VDAmS9NsK8GpDMLrCHPksFT7h3K6TOoUNn2pb7RoXx4g==} @@ -4885,6 +5433,21 @@ packages: engines: {node: '>= 14'} hasBin: true + yargs-parser@21.1.1: + resolution: {integrity: sha512-tVpsJW7DdjecAiFpbIB1e3qxIQsE6NoPc5/eTdrbbIC4h0LVsWhnoa3g+m2HclBIujHzsxZ4VJVA+GUuc2/LBw==} + engines: {node: '>=12'} + + yargs@17.7.2: + resolution: {integrity: sha512-7dSzzRQ++CKnNI/krKnYRV7JKKPUXMEh61soaHKg9mrWEhzFWhFnxPxGl+69cD1Ou63C13NUPCnmIcrvqCuM6w==} + engines: {node: '>=12'} + + yauzl@2.10.0: + resolution: {integrity: sha512-p4a9I6X6nu6IhoGmBqAcbJy1mlC4j27vEPZX9F4L4/vZT3Lyq1VkFHw/V/PUcB9Buo+DG3iHkT0x3Qya58zc3g==} + + yn@3.1.1: + resolution: {integrity: sha512-Ux4ygGWsu2c7isFWe8Yu1YluJmqVhxqK2cLXNQA5AcC3QfbGNpM7fu0Y8b/z16pXLnFxZYvWhd3fhBY9DLmC6Q==} + engines: {node: '>=6'} + yocto-queue@0.1.0: resolution: {integrity: sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q==} engines: {node: '>=10'} @@ -4892,6 +5455,10 @@ packages: zimmerframe@1.1.2: resolution: {integrity: sha512-rAbqEGa8ovJy4pyBxZM70hg4pE6gDgaQ0Sl9M3enG3I0d6H4XSAM3GeNGLKnsBpuijUow064sf7ww1nutC5/3w==} + zip-stream@6.0.1: + resolution: {integrity: sha512-zK7YHHz4ZXpW89AHXUPbQVGKI7uvkd3hzusTdotCg1UxyaVtg0zFJSTfW/Dq5f7OBBVnq6cZIaC8Ti4hb6dtCA==} + engines: {node: '>= 14'} + zod-to-json-schema@3.24.1: resolution: {integrity: sha512-3h08nf3Vw3Wl3PK+q3ow/lIil81IT2Oa7YpQyUUDsEWbXveMesdfK1xBd2RhCkynwZndAxixji/7SYJJowr62w==} peerDependencies: @@ -5941,6 +6508,23 @@ snapshots: dependencies: playwright: 1.49.1 + '@promptbook/utils@0.69.5': + dependencies: + spacetrim: 0.11.59 + + '@puppeteer/browsers@2.6.1': + dependencies: + debug: 4.4.0 + extract-zip: 2.0.1 + progress: 2.0.3 + proxy-agent: 6.5.0 + semver: 7.6.3 + tar-fs: 3.0.6 + unbzip2-stream: 1.4.3 + yargs: 17.7.2 + transitivePeerDependencies: + - supports-color + '@radix-ui/number@1.1.0': {} '@radix-ui/primitive@1.0.1': @@ -6589,6 +7173,8 @@ snapshots: '@types/react': 19.0.2 '@types/react-dom': 19.0.2(@types/react@19.0.2) + '@tootallnate/quickjs-emscripten@0.23.0': {} + '@types/adm-zip@0.5.7': dependencies: '@types/node': 22.10.2 @@ -6688,14 +7274,27 @@ snapshots: dependencies: csstype: 3.1.3 + '@types/sinonjs__fake-timers@8.1.5': {} + '@types/stack-utils@2.0.3': {} + '@types/which@2.0.2': {} + + '@types/ws@8.5.13': + dependencies: + '@types/node': 22.10.2 + '@types/yargs-parser@21.0.3': {} '@types/yargs@17.0.33': dependencies: '@types/yargs-parser': 21.0.3 + '@types/yauzl@2.10.3': + dependencies: + '@types/node': 22.10.2 + optional: true + '@typescript-eslint/eslint-plugin@8.18.2(@typescript-eslint/parser@8.18.2(eslint@9.17.0(jiti@1.21.7))(typescript@5.6.3))(eslint@9.17.0(jiti@1.21.7))(typescript@5.6.3)': dependencies: '@eslint-community/regexpp': 4.12.1 @@ -6846,6 +7445,54 @@ snapshots: '@vue/shared@3.5.13': {} + '@wdio/config@9.5.0': + dependencies: + '@wdio/logger': 9.4.4 + '@wdio/types': 9.5.0 + '@wdio/utils': 9.5.0 + deepmerge-ts: 7.1.3 + glob: 10.4.5 + import-meta-resolve: 4.1.0 + transitivePeerDependencies: + - supports-color + + '@wdio/logger@9.4.4': + dependencies: + chalk: 5.4.1 + loglevel: 1.9.2 + loglevel-plugin-prefix: 0.8.4 + strip-ansi: 7.1.0 + + '@wdio/protocols@9.4.4': {} + + '@wdio/repl@9.4.4': + dependencies: + '@types/node': 20.17.10 + + '@wdio/types@9.5.0': + dependencies: + '@types/node': 20.17.10 + + '@wdio/utils@9.5.0': + dependencies: + '@puppeteer/browsers': 2.6.1 + '@wdio/logger': 9.4.4 + '@wdio/types': 9.5.0 + decamelize: 6.0.0 + deepmerge-ts: 7.1.3 + edgedriver: 6.1.1 + geckodriver: 5.0.0 + get-port: 7.1.0 + import-meta-resolve: 4.1.0 + locate-app: 2.5.0 + safaridriver: 1.0.0 + split2: 4.2.0 + wait-port: 1.1.0 + transitivePeerDependencies: + - supports-color + + '@zip.js/zip.js@2.7.54': {} + abort-controller@3.0.0: dependencies: event-target-shim: 5.0.1 @@ -6924,7 +7571,30 @@ snapshots: normalize-path: 3.0.0 picomatch: 2.3.1 - arg@5.0.2: {} + archiver-utils@5.0.2: + dependencies: + glob: 10.4.5 + graceful-fs: 4.2.11 + is-stream: 2.0.1 + lazystream: 1.0.1 + lodash: 4.17.21 + normalize-path: 3.0.0 + readable-stream: 4.6.0 + + archiver@7.0.1: + dependencies: + archiver-utils: 5.0.2 + async: 3.2.6 + buffer-crc32: 1.0.0 + readable-stream: 4.6.0 + readdir-glob: 1.1.3 + tar-stream: 3.1.7 + zip-stream: 6.0.1 + + arg@4.1.3: + optional: true + + arg@5.0.2: {} argparse@2.0.1: {} @@ -7002,6 +7672,12 @@ snapshots: get-intrinsic: 1.2.6 is-array-buffer: 3.0.5 + ast-types@0.13.4: + dependencies: + tslib: 2.8.1 + + async@3.2.6: {} + asynckit@0.4.0: {} autoprefixer@10.4.20(postcss@8.4.49): @@ -7020,6 +7696,8 @@ snapshots: axobject-query@4.1.0: {} + b4a@1.6.7: {} + babel-plugin-emotion@10.2.2: dependencies: '@babel/helper-module-imports': 7.25.9 @@ -7045,12 +7723,41 @@ snapshots: balanced-match@1.0.2: {} + bare-events@2.5.0: + optional: true + + bare-fs@2.3.5: + dependencies: + bare-events: 2.5.0 + bare-path: 2.1.3 + bare-stream: 2.6.1 + optional: true + + bare-os@2.4.4: + optional: true + + bare-path@2.1.3: + dependencies: + bare-os: 2.4.4 + optional: true + + bare-stream@2.6.1: + dependencies: + streamx: 2.21.1 + optional: true + + base64-js@1.5.1: {} + + basic-ftp@5.0.5: {} + bcryptjs@2.4.3: {} before-after-hook@3.0.2: {} binary-extensions@2.3.0: {} + boolbase@1.0.0: {} + brace-expansion@1.1.11: dependencies: balanced-match: 1.0.2 @@ -7077,8 +7784,22 @@ snapshots: node-releases: 2.0.19 update-browserslist-db: 1.1.1(browserslist@4.24.3) + buffer-crc32@0.2.13: {} + + buffer-crc32@1.0.0: {} + buffer-from@1.1.2: {} + buffer@5.7.1: + dependencies: + base64-js: 1.5.1 + ieee754: 1.2.1 + + buffer@6.0.3: + dependencies: + base64-js: 1.5.1 + ieee754: 1.2.1 + bufferutil@4.0.9: dependencies: node-gyp-build: 4.8.4 @@ -7122,6 +7843,29 @@ snapshots: chalk@5.4.1: {} + cheerio-select@2.1.0: + dependencies: + boolbase: 1.0.0 + css-select: 5.1.0 + css-what: 6.1.0 + domelementtype: 2.3.0 + domhandler: 5.0.3 + domutils: 3.2.1 + + cheerio@1.0.0: + dependencies: + cheerio-select: 2.1.0 + dom-serializer: 2.0.0 + domhandler: 5.0.3 + domutils: 3.2.1 + encoding-sniffer: 0.2.0 + htmlparser2: 9.1.0 + parse5: 7.2.1 + parse5-htmlparser2-tree-adapter: 7.1.0 + parse5-parser-stream: 7.1.2 + undici: 6.21.0 + whatwg-mimetype: 4.0.0 + chokidar@3.6.0: dependencies: anymatch: 3.1.3 @@ -7134,9 +7878,9 @@ snapshots: optionalDependencies: fsevents: 2.3.3 - chromium-bidi@0.5.24(devtools-protocol@0.0.1400418): + chromium-bidi@0.5.24(devtools-protocol@0.0.1359167): dependencies: - devtools-protocol: 0.0.1400418 + devtools-protocol: 0.0.1359167 mitt: 3.0.1 urlpattern-polyfill: 10.0.0 zod: 3.23.8 @@ -7151,6 +7895,12 @@ snapshots: client-only@0.0.1: {} + cliui@8.0.1: + dependencies: + string-width: 4.2.3 + strip-ansi: 6.0.1 + wrap-ansi: 7.0.0 + clsx@2.1.1: {} cmdk@1.0.0(@types/react-dom@19.0.2(@types/react@19.0.2))(@types/react@19.0.2)(react-dom@19.0.0-rc-7771d3a7-20240827(react@19.0.0-rc-7771d3a7-20240827))(react@19.0.0-rc-7771d3a7-20240827): @@ -7189,6 +7939,16 @@ snapshots: commander@4.1.1: {} + commander@9.5.0: {} + + compress-commons@6.0.2: + dependencies: + crc-32: 1.2.2 + crc32-stream: 6.0.0 + is-stream: 2.0.1 + normalize-path: 3.0.0 + readable-stream: 4.6.0 + concat-map@0.0.1: {} convert-source-map@1.9.0: {} @@ -7197,6 +7957,8 @@ snapshots: cookie@0.7.0: {} + core-util-is@1.0.3: {} + cosmiconfig@6.0.0: dependencies: '@types/parse-json': 4.0.2 @@ -7205,6 +7967,13 @@ snapshots: path-type: 4.0.0 yaml: 1.10.2 + crc-32@1.2.2: {} + + crc32-stream@6.0.0: + dependencies: + crc-32: 1.2.2 + readable-stream: 4.6.0 + create-emotion@10.0.27: dependencies: '@emotion/cache': 10.0.29 @@ -7212,6 +7981,9 @@ snapshots: '@emotion/sheet': 0.9.4 '@emotion/utils': 0.11.3 + create-require@1.1.1: + optional: true + cross-spawn@7.0.6: dependencies: path-key: 3.1.1 @@ -7224,6 +7996,20 @@ snapshots: dependencies: tiny-invariant: 1.3.3 + css-select@5.1.0: + dependencies: + boolbase: 1.0.0 + css-what: 6.1.0 + domhandler: 5.0.3 + domutils: 3.2.1 + nth-check: 2.1.1 + + css-shorthand-properties@1.1.2: {} + + css-value@0.0.1: {} + + css-what@6.1.0: {} + css.escape@1.5.1: {} cssesc@3.0.0: {} @@ -7238,6 +8024,10 @@ snapshots: csstype@3.1.3: {} + data-uri-to-buffer@4.0.1: {} + + data-uri-to-buffer@6.0.2: {} + data-urls@5.0.0: dependencies: whatwg-mimetype: 4.0.0 @@ -7269,10 +8059,14 @@ snapshots: dependencies: ms: 2.1.3 + decamelize@6.0.0: {} + decimal.js@10.4.3: {} deep-is@0.1.4: {} + deepmerge-ts@7.1.3: {} + define-data-property@1.1.4: dependencies: es-define-property: 1.0.1 @@ -7285,6 +8079,12 @@ snapshots: has-property-descriptors: 1.0.2 object-keys: 1.1.1 + degenerator@5.0.1: + dependencies: + ast-types: 0.13.4 + escodegen: 2.1.0 + esprima: 4.0.1 + delayed-stream@1.0.0: {} dequal@2.0.3: {} @@ -7294,7 +8094,7 @@ snapshots: detect-node-es@1.1.0: {} - devtools-protocol@0.0.1400418: {} + devtools-protocol@0.0.1359167: {} didyoumean@1.2.2: {} @@ -7314,6 +8114,24 @@ snapshots: dom-accessibility-api@0.6.3: {} + dom-serializer@2.0.0: + dependencies: + domelementtype: 2.3.0 + domhandler: 5.0.3 + entities: 4.5.0 + + domelementtype@2.3.0: {} + + domhandler@5.0.3: + dependencies: + domelementtype: 2.3.0 + + domutils@3.2.1: + dependencies: + dom-serializer: 2.0.0 + domelementtype: 2.3.0 + domhandler: 5.0.3 + dot-case@3.0.4: dependencies: no-case: 3.0.4 @@ -7350,6 +8168,25 @@ snapshots: eastasianwidth@0.2.0: {} + edge-paths@3.0.5: + dependencies: + '@types/which': 2.0.2 + which: 2.0.2 + + edgedriver@6.1.1: + dependencies: + '@wdio/logger': 9.4.4 + '@zip.js/zip.js': 2.7.54 + decamelize: 6.0.0 + edge-paths: 3.0.5 + fast-xml-parser: 4.5.1 + http-proxy-agent: 7.0.2 + https-proxy-agent: 7.0.6 + node-fetch: 3.3.2 + which: 5.0.0 + transitivePeerDependencies: + - supports-color + electron-to-chromium@1.5.76: {} emoji-regex@8.0.0: {} @@ -7363,6 +8200,15 @@ snapshots: transitivePeerDependencies: - supports-color + encoding-sniffer@0.2.0: + dependencies: + iconv-lite: 0.6.3 + whatwg-encoding: 3.1.1 + + end-of-stream@1.4.4: + dependencies: + once: 1.4.0 + entities@4.5.0: {} error-ex@1.3.2: @@ -7611,6 +8457,14 @@ snapshots: escape-string-regexp@4.0.0: {} + escodegen@2.1.0: + dependencies: + esprima: 4.0.1 + estraverse: 5.3.0 + esutils: 2.0.3 + optionalDependencies: + source-map: 0.6.1 + eslint-config-prettier@9.1.0(eslint@9.17.0(jiti@1.21.7)): dependencies: eslint: 9.17.0(jiti@1.21.7) @@ -7755,6 +8609,8 @@ snapshots: acorn-jsx: 5.3.2(acorn@8.14.0) eslint-visitor-keys: 4.2.0 + esprima@4.0.1: {} + esquery@1.6.0: dependencies: estraverse: 5.3.0 @@ -7775,6 +8631,8 @@ snapshots: event-target-shim@5.0.1: {} + events@3.3.0: {} + eventsource-parser@1.1.2: {} eventsource@2.0.2: {} @@ -7787,10 +8645,24 @@ snapshots: jest-message-util: 29.7.0 jest-util: 29.7.0 + extract-zip@2.0.1: + dependencies: + debug: 4.4.0 + get-stream: 5.2.0 + yauzl: 2.10.0 + optionalDependencies: + '@types/yauzl': 2.10.3 + transitivePeerDependencies: + - supports-color + + fast-deep-equal@2.0.1: {} + fast-deep-equal@3.1.3: {} fast-diff@1.3.0: {} + fast-fifo@1.3.2: {} + fast-glob@3.3.2: dependencies: '@nodelib/fs.stat': 2.0.5 @@ -7803,10 +8675,23 @@ snapshots: fast-levenshtein@2.0.6: {} + fast-xml-parser@4.5.1: + dependencies: + strnum: 1.0.5 + fastq@1.18.0: dependencies: reusify: 1.0.4 + fd-slicer@1.1.0: + dependencies: + pend: 1.2.0 + + fetch-blob@3.2.0: + dependencies: + node-domexception: 1.0.0 + web-streams-polyfill: 3.3.3 + file-entry-cache@8.0.0: dependencies: flat-cache: 4.0.1 @@ -7851,6 +8736,10 @@ snapshots: node-domexception: 1.0.0 web-streams-polyfill: 4.0.0-beta.3 + formdata-polyfill@4.0.10: + dependencies: + fetch-blob: 3.2.0 + fraction.js@4.3.7: {} fsevents@2.3.2: @@ -7872,8 +8761,23 @@ snapshots: functions-have-names@1.2.3: {} + geckodriver@5.0.0: + dependencies: + '@wdio/logger': 9.4.4 + '@zip.js/zip.js': 2.7.54 + decamelize: 6.0.0 + http-proxy-agent: 7.0.2 + https-proxy-agent: 7.0.6 + node-fetch: 3.3.2 + tar-fs: 3.0.6 + which: 5.0.0 + transitivePeerDependencies: + - supports-color + gensync@1.0.0-beta.2: {} + get-caller-file@2.0.5: {} + get-intrinsic@1.2.6: dependencies: call-bind-apply-helpers: 1.0.1 @@ -7889,6 +8793,12 @@ snapshots: get-nonce@1.0.1: {} + get-port@7.1.0: {} + + get-stream@5.2.0: + dependencies: + pump: 3.0.2 + get-symbol-description@1.1.0: dependencies: call-bound: 1.0.3 @@ -7899,6 +8809,14 @@ snapshots: dependencies: resolve-pkg-maps: 1.0.0 + get-uri@6.0.4: + dependencies: + basic-ftp: 5.0.5 + data-uri-to-buffer: 6.0.2 + debug: 4.4.0 + transitivePeerDependencies: + - supports-color + glob-parent@5.1.2: dependencies: is-glob: 4.0.3 @@ -7933,6 +8851,8 @@ snapshots: graceful-fs@4.2.11: {} + grapheme-splitter@1.0.4: {} + graphemer@1.4.0: {} happy-dom@15.11.7: @@ -7971,6 +8891,15 @@ snapshots: dependencies: whatwg-encoding: 3.1.1 + htmlfy@0.5.0: {} + + htmlparser2@9.1.0: + dependencies: + domelementtype: 2.3.0 + domhandler: 5.0.3 + domutils: 3.2.1 + entities: 4.5.0 + http-proxy-agent@7.0.2: dependencies: agent-base: 7.1.3 @@ -8000,23 +8929,36 @@ snapshots: dependencies: safer-buffer: 2.1.2 + ieee754@1.2.1: {} + ignore@5.3.2: {} + immediate@3.0.6: {} + import-fresh@3.3.0: dependencies: parent-module: 1.0.1 resolve-from: 4.0.0 + import-meta-resolve@4.1.0: {} + imurmurhash@0.1.4: {} indent-string@4.0.0: {} + inherits@2.0.4: {} + internal-slot@1.1.0: dependencies: es-errors: 1.3.0 hasown: 2.0.2 side-channel: 1.1.0 + ip-address@9.0.5: + dependencies: + jsbn: 1.1.0 + sprintf-js: 1.1.3 + is-array-buffer@3.0.5: dependencies: call-bind: 1.0.8 @@ -8087,6 +9029,8 @@ snapshots: is-number@7.0.0: {} + is-plain-obj@4.1.0: {} + is-potential-custom-element-name@1.0.1: {} is-reference@3.0.3: @@ -8106,6 +9050,8 @@ snapshots: dependencies: call-bound: 1.0.3 + is-stream@2.0.1: {} + is-string@1.1.1: dependencies: call-bound: 1.0.3 @@ -8132,10 +9078,14 @@ snapshots: call-bound: 1.0.3 get-intrinsic: 1.2.6 + isarray@1.0.0: {} + isarray@2.0.5: {} isexe@2.0.0: {} + isexe@3.1.1: {} + iterator.prototype@1.1.4: dependencies: define-data-property: 1.1.4 @@ -8200,6 +9150,8 @@ snapshots: dependencies: argparse: 2.0.1 + jsbn@1.1.0: {} + jsdom@25.0.1(bufferutil@4.0.9): dependencies: cssstyle: 4.1.0 @@ -8259,29 +9211,58 @@ snapshots: object.assign: 4.1.7 object.values: 1.2.1 + jszip@3.10.1: + dependencies: + lie: 3.3.0 + pako: 1.0.11 + readable-stream: 2.3.8 + setimmediate: 1.0.5 + keyv@4.5.4: dependencies: json-buffer: 3.0.1 + lazystream@1.0.1: + dependencies: + readable-stream: 2.3.8 + levn@0.4.1: dependencies: prelude-ls: 1.2.1 type-check: 0.4.0 + lie@3.3.0: + dependencies: + immediate: 3.0.6 + lilconfig@3.1.3: {} lines-and-columns@1.2.4: {} + locate-app@2.5.0: + dependencies: + '@promptbook/utils': 0.69.5 + type-fest: 4.26.0 + userhome: 1.0.1 + locate-character@3.0.0: {} locate-path@6.0.0: dependencies: p-locate: 5.0.0 + lodash.clonedeep@4.5.0: {} + lodash.merge@4.6.2: {} + lodash.zip@4.2.0: {} + lodash@4.17.21: {} + loglevel-plugin-prefix@0.8.4: {} + + loglevel@1.9.2: {} + loose-envify@1.4.0: dependencies: js-tokens: 4.0.0 @@ -8296,6 +9277,8 @@ snapshots: dependencies: yallist: 3.1.1 + lru-cache@7.18.3: {} + lucide-react@0.439.0(react@19.0.0-rc-7771d3a7-20240827): dependencies: react: 19.0.0-rc-7771d3a7-20240827 @@ -8312,6 +9295,9 @@ snapshots: transitivePeerDependencies: - supports-color + make-error@1.3.6: + optional: true + map-obj@4.3.0: {} math-intrinsics@1.1.0: {} @@ -8341,6 +9327,10 @@ snapshots: dependencies: brace-expansion: 1.1.11 + minimatch@5.1.6: + dependencies: + brace-expansion: 2.0.1 + minimatch@9.0.5: dependencies: brace-expansion: 2.0.1 @@ -8365,6 +9355,8 @@ snapshots: natural-compare@1.4.0: {} + netmask@2.0.2: {} + next@15.0.0-canary.152(@babel/core@7.26.0)(@opentelemetry/api@1.9.0)(@playwright/test@1.49.1)(react-dom@19.0.0-rc-7771d3a7-20240827(react@19.0.0-rc-7771d3a7-20240827))(react@19.0.0-rc-7771d3a7-20240827): dependencies: '@next/env': 15.0.0-canary.152 @@ -8405,6 +9397,12 @@ snapshots: dependencies: whatwg-url: 5.0.0 + node-fetch@3.3.2: + dependencies: + data-uri-to-buffer: 4.0.1 + fetch-blob: 3.2.0 + formdata-polyfill: 4.0.10 + node-gyp-build@4.8.4: {} node-releases@2.0.19: {} @@ -8413,6 +9411,10 @@ snapshots: normalize-range@0.1.2: {} + nth-check@2.1.1: + dependencies: + boolbase: 1.0.0 + nwsapi@2.2.16: {} object-assign@4.1.1: {} @@ -8460,6 +9462,10 @@ snapshots: obuf@1.1.2: {} + once@1.4.0: + dependencies: + wrappy: 1.0.2 + optionator@0.9.4: dependencies: deep-is: 0.1.4 @@ -8489,10 +9495,30 @@ snapshots: dependencies: p-limit: 3.1.0 + pac-proxy-agent@7.1.0: + dependencies: + '@tootallnate/quickjs-emscripten': 0.23.0 + agent-base: 7.1.3 + debug: 4.4.0 + get-uri: 6.0.4 + http-proxy-agent: 7.0.2 + https-proxy-agent: 7.0.6 + pac-resolver: 7.0.1 + socks-proxy-agent: 8.0.5 + transitivePeerDependencies: + - supports-color + + pac-resolver@7.0.1: + dependencies: + degenerator: 5.0.1 + netmask: 2.0.2 + package-json-from-dist@1.0.1: {} package-manager-detector@0.2.8: {} + pako@1.0.11: {} + parent-module@1.0.1: dependencies: callsites: 3.1.0 @@ -8504,6 +9530,15 @@ snapshots: json-parse-even-better-errors: 2.3.1 lines-and-columns: 1.2.4 + parse5-htmlparser2-tree-adapter@7.1.0: + dependencies: + domhandler: 5.0.3 + parse5: 7.2.1 + + parse5-parser-stream@7.1.2: + dependencies: + parse5: 7.2.1 + parse5@7.2.1: dependencies: entities: 4.5.0 @@ -8521,6 +9556,8 @@ snapshots: path-type@4.0.0: {} + pend@1.2.0: {} + pg-int8@1.0.1: {} pg-numeric@1.0.2: {} @@ -8567,12 +9604,13 @@ snapshots: camelcase-css: 2.0.1 postcss: 8.4.49 - postcss-load-config@4.0.2(postcss@8.4.49): + postcss-load-config@4.0.2(postcss@8.4.49)(ts-node@9.1.1(typescript@5.6.3)): dependencies: lilconfig: 3.1.3 yaml: 2.6.1 optionalDependencies: postcss: 8.4.49 + ts-node: 9.1.1(typescript@5.6.3) postcss-nested@6.2.0(postcss@8.4.49): dependencies: @@ -8632,20 +9670,50 @@ snapshots: ansi-styles: 5.2.0 react-is: 18.3.1 + process-nextick-args@2.0.1: {} + + process@0.11.10: {} + + progress@2.0.3: {} + prop-types@15.8.1: dependencies: loose-envify: 1.4.0 object-assign: 4.1.1 react-is: 16.13.1 + proxy-agent@6.5.0: + dependencies: + agent-base: 7.1.3 + debug: 4.4.0 + http-proxy-agent: 7.0.2 + https-proxy-agent: 7.0.6 + lru-cache: 7.18.3 + pac-proxy-agent: 7.1.0 + proxy-from-env: 1.1.0 + socks-proxy-agent: 8.0.5 + transitivePeerDependencies: + - supports-color + + proxy-from-env@1.1.0: {} + + pump@3.0.2: + dependencies: + end-of-stream: 1.4.4 + once: 1.4.0 + punycode@2.3.1: {} qs@6.13.1: dependencies: side-channel: 1.1.0 + query-selector-shadow-dom@1.0.1: {} + queue-microtask@1.2.3: {} + queue-tick@1.0.1: {} + raf-schd@4.0.3: {} react-beautiful-dnd@13.1.1(react-dom@19.0.0-rc-7771d3a7-20240827(react@19.0.0-rc-7771d3a7-20240827))(react@19.0.0-rc-7771d3a7-20240827): @@ -8744,6 +9812,28 @@ snapshots: dependencies: pify: 2.3.0 + readable-stream@2.3.8: + dependencies: + core-util-is: 1.0.3 + inherits: 2.0.4 + isarray: 1.0.0 + process-nextick-args: 2.0.1 + safe-buffer: 5.1.2 + string_decoder: 1.1.1 + util-deprecate: 1.0.2 + + readable-stream@4.6.0: + dependencies: + abort-controller: 3.0.0 + buffer: 6.0.3 + events: 3.3.0 + process: 0.11.10 + string_decoder: 1.3.0 + + readdir-glob@1.1.3: + dependencies: + minimatch: 5.1.6 + readdirp@3.6.0: dependencies: picomatch: 2.3.1 @@ -8777,6 +9867,8 @@ snapshots: es-errors: 1.3.0 set-function-name: 2.0.2 + require-directory@2.1.1: {} + resolve-from@4.0.0: {} resolve-pkg-maps@1.0.0: {} @@ -8793,8 +9885,14 @@ snapshots: path-parse: 1.0.7 supports-preserve-symlinks-flag: 1.0.0 + resq@1.11.0: + dependencies: + fast-deep-equal: 2.0.1 + reusify@1.0.4: {} + rgb2hex@0.2.5: {} + rollup@4.29.1: dependencies: '@types/estree': 1.0.6 @@ -8830,6 +9928,8 @@ snapshots: dependencies: minimatch: 10.0.1 + safaridriver@1.0.0: {} + safe-array-concat@1.1.3: dependencies: call-bind: 1.0.8 @@ -8838,6 +9938,10 @@ snapshots: has-symbols: 1.1.0 isarray: 2.0.5 + safe-buffer@5.1.2: {} + + safe-buffer@5.2.1: {} + safe-push-apply@1.0.0: dependencies: es-errors: 1.3.0 @@ -8863,6 +9967,10 @@ snapshots: semver@7.6.3: {} + serialize-error@11.0.3: + dependencies: + type-fest: 2.19.0 + server-only@0.0.1: {} set-function-length@1.2.2: @@ -8881,6 +9989,8 @@ snapshots: functions-have-names: 1.2.3 has-property-descriptors: 1.0.2 + setimmediate@1.0.5: {} + sharp@0.33.5: dependencies: color: 4.2.3 @@ -8951,6 +10061,8 @@ snapshots: slash@3.0.0: {} + smart-buffer@4.2.0: {} + smee-client@2.0.4: dependencies: commander: 12.1.0 @@ -8968,6 +10080,19 @@ snapshots: snake-case: 3.0.4 type-fest: 2.19.0 + socks-proxy-agent@8.0.5: + dependencies: + agent-base: 7.1.3 + debug: 4.4.0 + socks: 2.8.3 + transitivePeerDependencies: + - supports-color + + socks@2.8.3: + dependencies: + ip-address: 9.0.5 + smart-buffer: 4.2.0 + source-map-js@1.2.1: {} source-map-support@0.5.21: @@ -8979,6 +10104,12 @@ snapshots: source-map@0.6.1: {} + spacetrim@0.11.59: {} + + split2@4.2.0: {} + + sprintf-js@1.1.3: {} + sswr@2.1.0(svelte@5.16.0): dependencies: svelte: 5.16.0 @@ -8992,6 +10123,14 @@ snapshots: streamsearch@1.1.0: {} + streamx@2.21.1: + dependencies: + fast-fifo: 1.3.2 + queue-tick: 1.0.1 + text-decoder: 1.2.3 + optionalDependencies: + bare-events: 2.5.0 + string-width@4.2.3: dependencies: emoji-regex: 8.0.0 @@ -9048,6 +10187,14 @@ snapshots: define-properties: 1.2.1 es-object-atoms: 1.0.0 + string_decoder@1.1.1: + dependencies: + safe-buffer: 5.1.2 + + string_decoder@1.3.0: + dependencies: + safe-buffer: 5.2.1 + strip-ansi@6.0.1: dependencies: ansi-regex: 5.0.1 @@ -9069,6 +10216,8 @@ snapshots: '@types/node': 22.10.2 qs: 6.13.1 + strnum@1.0.5: {} + styled-jsx@5.1.6(@babel/core@7.26.0)(react@19.0.0-rc-7771d3a7-20240827): dependencies: client-only: 0.0.1 @@ -9130,15 +10279,15 @@ snapshots: tailwind-merge@2.6.0: {} - tailwindcss-animate@1.0.7(tailwindcss@3.4.17): + tailwindcss-animate@1.0.7(tailwindcss@3.4.17(ts-node@9.1.1(typescript@5.6.3))): dependencies: - tailwindcss: 3.4.17 + tailwindcss: 3.4.17(ts-node@9.1.1(typescript@5.6.3)) - tailwindcss-react-aria-components@1.1.5(tailwindcss@3.4.17): + tailwindcss-react-aria-components@1.1.5(tailwindcss@3.4.17(ts-node@9.1.1(typescript@5.6.3))): dependencies: - tailwindcss: 3.4.17 + tailwindcss: 3.4.17(ts-node@9.1.1(typescript@5.6.3)) - tailwindcss@3.4.17: + tailwindcss@3.4.17(ts-node@9.1.1(typescript@5.6.3)): dependencies: '@alloc/quick-lru': 5.2.0 arg: 5.0.2 @@ -9157,7 +10306,7 @@ snapshots: postcss: 8.4.49 postcss-import: 15.1.0(postcss@8.4.49) postcss-js: 4.0.1(postcss@8.4.49) - postcss-load-config: 4.0.2(postcss@8.4.49) + postcss-load-config: 4.0.2(postcss@8.4.49)(ts-node@9.1.1(typescript@5.6.3)) postcss-nested: 6.2.0(postcss@8.4.49) postcss-selector-parser: 6.1.2 resolve: 1.22.10 @@ -9165,6 +10314,24 @@ snapshots: transitivePeerDependencies: - ts-node + tar-fs@3.0.6: + dependencies: + pump: 3.0.2 + tar-stream: 3.1.7 + optionalDependencies: + bare-fs: 2.3.5 + bare-path: 2.1.3 + + tar-stream@3.1.7: + dependencies: + b4a: 1.6.7 + fast-fifo: 1.3.2 + streamx: 2.21.1 + + text-decoder@1.2.3: + dependencies: + b4a: 1.6.7 + thenify-all@1.6.0: dependencies: thenify: 3.3.1 @@ -9177,6 +10344,8 @@ snapshots: throttleit@2.1.0: {} + through@2.3.8: {} + tiny-invariant@1.3.3: {} tldts-core@6.1.70: {} @@ -9205,6 +10374,17 @@ snapshots: ts-interface-checker@0.1.13: {} + ts-node@9.1.1(typescript@5.6.3): + dependencies: + arg: 4.1.3 + create-require: 1.1.1 + diff: 4.0.2 + make-error: 1.3.6 + source-map-support: 0.5.21 + typescript: 5.6.3 + yn: 3.1.1 + optional: true + tsconfck@3.1.4(typescript@5.6.3): optionalDependencies: typescript: 5.6.3 @@ -9233,6 +10413,8 @@ snapshots: type-fest@2.19.0: {} + type-fest@4.26.0: {} + typed-array-buffer@1.0.3: dependencies: call-bound: 1.0.3 @@ -9275,12 +10457,19 @@ snapshots: has-symbols: 1.1.0 which-boxed-primitive: 1.1.1 + unbzip2-stream@1.4.3: + dependencies: + buffer: 5.7.1 + through: 2.3.8 + undici-types@5.26.5: {} undici-types@6.19.8: {} undici-types@6.20.0: {} + undici@6.21.0: {} + universal-user-agent@7.0.2: {} update-browserslist-db@1.1.1(browserslist@4.24.3): @@ -9318,6 +10507,8 @@ snapshots: dependencies: react: 19.0.0-rc-7771d3a7-20240827 + userhome@1.0.1: {} + util-deprecate@1.0.2: {} validator@13.12.0: {} @@ -9368,8 +10559,69 @@ snapshots: dependencies: xml-name-validator: 5.0.0 + wait-port@1.1.0: + dependencies: + chalk: 4.1.2 + commander: 9.5.0 + debug: 4.4.0 + transitivePeerDependencies: + - supports-color + + web-streams-polyfill@3.3.3: {} + web-streams-polyfill@4.0.0-beta.3: {} + webdriver@9.5.0(bufferutil@4.0.9): + dependencies: + '@types/node': 20.17.10 + '@types/ws': 8.5.13 + '@wdio/config': 9.5.0 + '@wdio/logger': 9.4.4 + '@wdio/protocols': 9.4.4 + '@wdio/types': 9.5.0 + '@wdio/utils': 9.5.0 + deepmerge-ts: 7.1.3 + undici: 6.21.0 + ws: 8.18.0(bufferutil@4.0.9) + transitivePeerDependencies: + - bufferutil + - supports-color + - utf-8-validate + + webdriverio@9.5.0(bufferutil@4.0.9): + dependencies: + '@types/node': 20.17.10 + '@types/sinonjs__fake-timers': 8.1.5 + '@wdio/config': 9.5.0 + '@wdio/logger': 9.4.4 + '@wdio/protocols': 9.4.4 + '@wdio/repl': 9.4.4 + '@wdio/types': 9.5.0 + '@wdio/utils': 9.5.0 + archiver: 7.0.1 + aria-query: 5.3.2 + cheerio: 1.0.0 + css-shorthand-properties: 1.1.2 + css-value: 0.0.1 + grapheme-splitter: 1.0.4 + htmlfy: 0.5.0 + import-meta-resolve: 4.1.0 + is-plain-obj: 4.1.0 + jszip: 3.10.1 + lodash.clonedeep: 4.5.0 + lodash.zip: 4.2.0 + minimatch: 9.0.5 + query-selector-shadow-dom: 1.0.1 + resq: 1.11.0 + rgb2hex: 0.2.5 + serialize-error: 11.0.3 + urlpattern-polyfill: 10.0.0 + webdriver: 9.5.0(bufferutil@4.0.9) + transitivePeerDependencies: + - bufferutil + - supports-color + - utf-8-validate + webidl-conversions@3.0.1: {} webidl-conversions@7.0.0: {} @@ -9436,6 +10688,10 @@ snapshots: dependencies: isexe: 2.0.0 + which@5.0.0: + dependencies: + isexe: 3.1.1 + word-wrap@1.2.5: {} wrap-ansi@7.0.0: @@ -9450,6 +10706,8 @@ snapshots: string-width: 5.1.2 strip-ansi: 7.1.0 + wrappy@1.0.2: {} + ws@8.18.0(bufferutil@4.0.9): optionalDependencies: bufferutil: 4.0.9 @@ -9458,16 +10716,44 @@ snapshots: xmlchars@2.2.0: {} + y18n@5.0.8: {} + yallist@3.1.1: {} yaml@1.10.2: {} yaml@2.6.1: {} + yargs-parser@21.1.1: {} + + yargs@17.7.2: + dependencies: + cliui: 8.0.1 + escalade: 3.2.0 + get-caller-file: 2.0.5 + require-directory: 2.1.1 + string-width: 4.2.3 + y18n: 5.0.8 + yargs-parser: 21.1.1 + + yauzl@2.10.0: + dependencies: + buffer-crc32: 0.2.13 + fd-slicer: 1.1.0 + + yn@3.1.1: + optional: true + yocto-queue@0.1.0: {} zimmerframe@1.1.2: {} + zip-stream@6.0.1: + dependencies: + archiver-utils: 5.0.2 + compress-commons: 6.0.2 + readable-stream: 4.6.0 + zod-to-json-schema@3.24.1(zod@3.24.1): dependencies: zod: 3.24.1 From cd75b85ec5218465a98ce9773a22aef0a245358b Mon Sep 17 00:00:00 2001 From: Amine Saissi Hassani Date: Wed, 1 Jan 2025 21:42:37 +0100 Subject: [PATCH 2/2] add more functions for the driver --- packages/shortest/src/core/runner/index.ts | 4 +- packages/shortest/src/mobile/actions/index.ts | 51 ++++++++++++++++--- .../src/mobile/core/drivers/base-driver.ts | 5 ++ .../mobile/core/drivers/uiautomator-driver.ts | 10 +++- .../mobile/core/drivers/xcuitest-driver.ts | 10 +++- .../shortest/src/mobile/core/mobile-driver.ts | 9 ++++ .../shortest/src/mobile/core/mobile-tool.ts | 8 ++- 7 files changed, 85 insertions(+), 12 deletions(-) diff --git a/packages/shortest/src/core/runner/index.ts b/packages/shortest/src/core/runner/index.ts index 1e6b1e00..37c20a71 100644 --- a/packages/shortest/src/core/runner/index.ts +++ b/packages/shortest/src/core/runner/index.ts @@ -389,8 +389,8 @@ export class TestRunner { const result = await this.executeTest(test, context); this.logger.reportTest( test.name, - result.result === "pass" ? "passed" : "failed", - result.result === "fail" ? new Error(result.reason) : undefined, + result?.result === "pass" ? "passed" : "failed", + result?.result === "fail" ? new Error(result?.reason ?? 'Test failed') : undefined, ); // Execute afterEach hooks with shared context diff --git a/packages/shortest/src/mobile/actions/index.ts b/packages/shortest/src/mobile/actions/index.ts index aa4b3b4a..dff12de0 100644 --- a/packages/shortest/src/mobile/actions/index.ts +++ b/packages/shortest/src/mobile/actions/index.ts @@ -1,5 +1,4 @@ -import { MobileElement } from '../core' -import { MobileDriver } from '../core' +import { MobileElement, MobileDriver } from '../core' export async function tap(driver: MobileDriver, element: MobileElement): Promise { await driver.tap(element) @@ -20,9 +19,45 @@ export async function scroll( export async function swipe( driver: MobileDriver, direction: 'left' | 'right' | 'up' | 'down', - element?: MobileElement + startPercentage: number = 0.8, + endPercentage: number = 0.2 ): Promise { - // Implementation coming soon + const { width, height } = await driver.getWindowSize() + + let startX: number + let startY: number + let endX: number + let endY: number + + switch (direction) { + case 'left': + startX = width * startPercentage + endX = width * endPercentage + startY = endY = height / 2 + break + case 'right': + startX = width * endPercentage + endX = width * startPercentage + startY = endY = height / 2 + break + case 'up': + startY = height * startPercentage + endY = height * endPercentage + startX = endX = width / 2 + break + case 'down': + startY = height * endPercentage + endY = height * startPercentage + startX = endX = width / 2 + break + } + + await driver.performGesture([ + { action: 'press', x: startX, y: startY }, + { action: 'wait', ms: 100 }, + { action: 'moveTo', x: endX, y: endY }, + { action: 'release' } + ]) } export async function longPress( @@ -30,5 +65,9 @@ export async function longPress( element: MobileElement, duration: number = 1000 ): Promise { - // Implementation coming soon -} \ No newline at end of file + await driver.performGesture([ + { action: 'press', element: element.id }, + { action: 'wait', ms: duration }, + { action: 'release' } + ]) +} \ No newline at end of file diff --git a/packages/shortest/src/mobile/core/drivers/base-driver.ts b/packages/shortest/src/mobile/core/drivers/base-driver.ts index 691f5cb5..6c8c5389 100644 --- a/packages/shortest/src/mobile/core/drivers/base-driver.ts +++ b/packages/shortest/src/mobile/core/drivers/base-driver.ts @@ -1,5 +1,6 @@ import { MobileElement } from '../mobile-driver' import { MobileRunnerConfig } from '../../../types' +import type { TouchAction } from 'webdriverio' export interface BaseMobileDriver { init(): Promise @@ -7,6 +8,8 @@ export interface BaseMobileDriver { tap(element: MobileElement): Promise type(element: MobileElement, text: string): Promise scroll(direction: 'up' | 'down', amount: number): Promise + getWindowSize(): Promise<{ width: number; height: number }> + performGesture(gesture: TouchAction[]): Promise quit(): Promise } @@ -22,5 +25,7 @@ export abstract class AbstractMobileDriver implements BaseMobileDriver { abstract tap(element: MobileElement): Promise abstract type(element: MobileElement, text: string): Promise abstract scroll(direction: 'up' | 'down', amount: number): Promise + abstract getWindowSize(): Promise<{ width: number; height: number }> + abstract performGesture(gesture: TouchAction[]): Promise abstract quit(): Promise } \ No newline at end of file diff --git a/packages/shortest/src/mobile/core/drivers/uiautomator-driver.ts b/packages/shortest/src/mobile/core/drivers/uiautomator-driver.ts index aef0da71..86e29122 100644 --- a/packages/shortest/src/mobile/core/drivers/uiautomator-driver.ts +++ b/packages/shortest/src/mobile/core/drivers/uiautomator-driver.ts @@ -1,4 +1,4 @@ -import { remote, Browser } from 'webdriverio' +import { remote, Browser, TouchAction } from 'webdriverio' import { AbstractMobileDriver } from './base-driver' import { MobileElement } from '../mobile-driver' import { MobileRunnerConfig } from '../../../types' @@ -122,4 +122,12 @@ export class UIAutomatorDriver extends AbstractMobileDriver { this.driver = null } } + + async getWindowSize(): Promise<{ width: number; height: number }> { + return await this.driver!.getWindowSize() + } + + async performGesture(gesture: TouchAction[]): Promise { + await this.driver!.touchAction(gesture) + } } \ No newline at end of file diff --git a/packages/shortest/src/mobile/core/drivers/xcuitest-driver.ts b/packages/shortest/src/mobile/core/drivers/xcuitest-driver.ts index 384f1dc7..099b3e60 100644 --- a/packages/shortest/src/mobile/core/drivers/xcuitest-driver.ts +++ b/packages/shortest/src/mobile/core/drivers/xcuitest-driver.ts @@ -1,4 +1,4 @@ -import { remote, Browser } from 'webdriverio' +import { remote, Browser, TouchAction } from 'webdriverio' import { AbstractMobileDriver } from './base-driver' import { MobileElement } from '../mobile-driver' import { MobileRunnerConfig } from '../../../types' @@ -122,4 +122,12 @@ export class XCUITestDriver extends AbstractMobileDriver { this.driver = null } } + + async getWindowSize(): Promise<{ width: number; height: number }> { + return await this.driver!.getWindowSize() + } + + async performGesture(gesture: TouchAction[]): Promise { + await this.driver!.touchAction(gesture) + } } \ No newline at end of file diff --git a/packages/shortest/src/mobile/core/mobile-driver.ts b/packages/shortest/src/mobile/core/mobile-driver.ts index 05d58697..4df25249 100644 --- a/packages/shortest/src/mobile/core/mobile-driver.ts +++ b/packages/shortest/src/mobile/core/mobile-driver.ts @@ -2,6 +2,7 @@ import { MobileRunnerConfig } from '../../types' import { UIAutomatorDriver } from './drivers/uiautomator-driver' import { XCUITestDriver } from './drivers/xcuitest-driver' import { BaseMobileDriver } from './drivers/base-driver' +import type { TouchAction } from 'webdriverio' export interface MobileElement { id: string @@ -48,4 +49,12 @@ export class MobileDriver { async quit(): Promise { await this.driver.quit() } + + async getWindowSize(): Promise<{ width: number; height: number }> { + return await this.driver.getWindowSize() + } + + async performGesture(gesture: TouchAction[]): Promise { + await this.driver.performGesture(gesture) + } } \ No newline at end of file diff --git a/packages/shortest/src/mobile/core/mobile-tool.ts b/packages/shortest/src/mobile/core/mobile-tool.ts index 4b694a65..d5a487d1 100644 --- a/packages/shortest/src/mobile/core/mobile-tool.ts +++ b/packages/shortest/src/mobile/core/mobile-tool.ts @@ -28,8 +28,12 @@ export class MobileTool { await actions.scroll(this.driver, direction, amount) } - async swipe(direction: 'left' | 'right' | 'up' | 'down', element?: MobileElement): Promise { - await actions.swipe(this.driver, direction, element) + async swipe( + direction: 'left' | 'right' | 'up' | 'down', + startPercentage: number = 0.8, + endPercentage: number = 0.2 + ): Promise { + await actions.swipe(this.driver, direction, startPercentage, endPercentage) } async longPress(element: MobileElement, duration?: number): Promise {