From 01af89e8fccf5cc5805e28b19bdbb9821256f867 Mon Sep 17 00:00:00 2001 From: Ben Houston Date: Tue, 11 Feb 2025 14:13:56 -0500 Subject: [PATCH 1/3] handle timeout correct in shellStart --- src/tools/system/shellStart.ts | 17 +++++++++++------ 1 file changed, 11 insertions(+), 6 deletions(-) diff --git a/src/tools/system/shellStart.ts b/src/tools/system/shellStart.ts index 7685610..0d626b1 100644 --- a/src/tools/system/shellStart.ts +++ b/src/tools/system/shellStart.ts @@ -42,7 +42,7 @@ const returnSchema = z.union([ error: z.string().optional(), }) .describe( - "Synchronous execution results when command completes within timeout", + "Synchronous execution results when command completes within timeout" ), z .object({ @@ -58,6 +58,8 @@ const returnSchema = z.union([ type Parameters = z.infer; type ReturnType = z.infer; +const DEFAULT_TIMEOUT = 100; + export const shellStartTool: Tool = { name: "shellStart", description: @@ -66,8 +68,8 @@ export const shellStartTool: Tool = { returns: zodToJsonSchema(returnSchema), execute: async ( - { command, timeout = 100 }, - { logger }, + { command, timeout = DEFAULT_TIMEOUT }, + { logger } ): Promise => { logger.verbose(`Starting shell command: ${command}`); @@ -122,7 +124,7 @@ export const shellStartTool: Tool = { process.on("exit", (code, signal) => { logger.verbose( - `[${instanceId}] Process exited with code ${code} and signal ${signal}`, + `[${instanceId}] Process exited with code ${code} and signal ${signal}` ); processState.state.completed = true; @@ -170,9 +172,12 @@ export const shellStartTool: Tool = { }); }, - logParameters: (input, { logger }) => { + logParameters: ( + { command, description, timeout = DEFAULT_TIMEOUT }, + { logger } + ) => { logger.info( - `Starting "${input.command}", ${input.description} (timeout: ${input.timeout}ms)`, + `Starting "${command}", ${description} (timeout: ${timeout}ms)` ); }, logReturns: (output, { logger }) => { From 729d3189a2bbb1c11ba6d60c088b7a24a516d03a Mon Sep 17 00:00:00 2001 From: Ben Houston Date: Tue, 11 Feb 2025 14:36:14 -0500 Subject: [PATCH 2/3] compiles --- BROWSER_AUTOMATION.md | 196 +++++ package.json | 3 + pnpm-lock.yaml | 1089 ++++++++++++++++++------ src/tools/browser/BrowserAutomation.ts | 39 + src/tools/browser/browseMessage.ts | 164 ++++ src/tools/browser/browseStart.ts | 104 +++ src/tools/browser/browser-manager.ts | 109 +++ src/tools/browser/page-controller.ts | 115 +++ src/tools/browser/screenshot.ts | 69 ++ src/tools/browser/types.ts | 77 ++ src/tools/getTools.ts | 5 +- src/tools/index.ts | 18 + src/types/browser.ts | 38 + tests/browser/browser-manager.test.ts | 74 ++ tsconfig.json | 4 +- 15 files changed, 1840 insertions(+), 264 deletions(-) create mode 100644 BROWSER_AUTOMATION.md create mode 100644 src/tools/browser/BrowserAutomation.ts create mode 100644 src/tools/browser/browseMessage.ts create mode 100644 src/tools/browser/browseStart.ts create mode 100644 src/tools/browser/browser-manager.ts create mode 100644 src/tools/browser/page-controller.ts create mode 100644 src/tools/browser/screenshot.ts create mode 100644 src/tools/browser/types.ts create mode 100644 src/tools/index.ts create mode 100644 src/types/browser.ts create mode 100644 tests/browser/browser-manager.test.ts diff --git a/BROWSER_AUTOMATION.md b/BROWSER_AUTOMATION.md new file mode 100644 index 0000000..a490ca3 --- /dev/null +++ b/BROWSER_AUTOMATION.md @@ -0,0 +1,196 @@ +# Browser Automation + +## Overview + +This document describes the browser automation capabilities implemented in the project, combining both the original planning and the current implementation status. + +## Key Features + +- Browser session management +- Page control and interaction +- Screenshot capture +- Resource cleanup and management +- Error handling +- Type-safe API + +## Architecture + +The browser automation system is implemented as a modular system with the following core components: + +### BrowserManager +Handles browser session lifecycle, including: +- Session creation and cleanup +- Context management +- Resource optimization + +### PageController +Manages page interactions: +- Navigation +- Element selection and interaction +- State management +- Event handling + +### ScreenshotManager +Provides screenshot capabilities: +- Full page captures +- Element-specific captures +- Screenshot storage and management + +## Installation & Setup + +```bash +npm install @mycoder/browser-automation +``` + +### Configuration + +Basic configuration example: +```typescript +import { BrowserAutomation } from '@mycoder/browser-automation'; + +const browser = new BrowserAutomation({ + headless: true, + defaultViewport: { width: 1920, height: 1080 } +}); +``` + +## Usage Examples + +### Basic Navigation +```typescript +const page = await browser.newPage(); +await page.navigate('https://example.com'); +await page.waitForSelector('.main-content'); +``` + +### Interacting with Elements +```typescript +await page.click('#submit-button'); +await page.type('#search-input', 'search term'); +``` + +### Taking Screenshots +```typescript +await page.screenshot({ + path: './screenshot.png', + fullPage: true +}); +``` + +## Error Handling + +The system implements comprehensive error handling: + +- Browser-specific errors are wrapped in custom error types +- Automatic retry mechanisms for flaky operations +- Resource cleanup on failure +- Detailed error messages and stack traces + +## Resource Management + +Resources are managed automatically: + +- Browser sessions are cleaned up when no longer needed +- Memory usage is optimized +- Concurrent sessions are managed efficiently +- Automatic page context cleanup + +## Testing & Debugging + +### Running Tests +```bash +npm test +``` + +### Debugging + +Debug logs can be enabled via environment variables: +```bash +DEBUG=browser-automation:* npm test +``` + +## API Reference + +### BrowserAutomation +Main class providing browser automation capabilities. + +#### Methods +- `newPage()`: Creates a new page session +- `close()`: Closes all browser sessions +- `screenshot()`: Captures screenshots +- `evaluate()`: Evaluates JavaScript in the page context + +### PageController +Handles page-specific operations. + +#### Methods +- `navigate(url: string)`: Navigates to URL +- `click(selector: string)`: Clicks element +- `type(selector: string, text: string)`: Types text +- `waitForSelector(selector: string)`: Waits for element + +### ScreenshotManager +Manages screenshot operations. + +#### Methods +- `capture(options: ScreenshotOptions)`: Takes screenshot +- `saveToFile(path: string)`: Saves screenshot to file + +## Future Enhancements + +The following features are planned for future releases: + +- Network monitoring capabilities +- Video recording support +- Trace viewer integration +- Extended cross-browser support +- Enhanced selector handling module + +## Migration Guide + +When upgrading from previous versions: + +1. Update import paths to use new structure +2. Replace deprecated methods with new alternatives +3. Update configuration objects to match new schema +4. Test thoroughly after migration + +## Best Practices + +1. Always clean up resources: +```typescript +try { + const browser = new BrowserAutomation(); + // ... operations +} finally { + await browser.close(); +} +``` + +2. Use typed selectors: +```typescript +const selector: SelectorOptions = { + type: 'css', + value: '.main-content' +}; +``` + +3. Implement proper error handling: +```typescript +try { + await page.click('#button'); +} catch (error) { + if (error instanceof ElementNotFoundError) { + // Handle missing element + } + throw error; +} +``` + +## Contributing + +Please see CONTRIBUTING.md for guidelines on contributing to this project. + +## License + +This project is licensed under the MIT License - see the LICENSE file for details. \ No newline at end of file diff --git a/package.json b/package.json index 99f4bab..41cfca7 100644 --- a/package.json +++ b/package.json @@ -49,8 +49,11 @@ "license": "MIT", "dependencies": { "@anthropic-ai/sdk": "^0.36", + "@playwright/test": "^1.50.1", "chalk": "^5", "dotenv": "^16", + "playwright": "^1.50.1", + "source-map-support": "^0.5", "uuid": "^11", "yargs": "^17", diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 69865bf..4aeafab 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -11,12 +11,21 @@ importers: '@anthropic-ai/sdk': specifier: ^0.36 version: 0.36.3 + '@playwright/test': + specifier: ^1.50.1 + version: 1.50.1 chalk: specifier: ^5 version: 5.4.1 dotenv: specifier: ^16 version: 16.4.7 + playwright: + specifier: ^1.50.1 + version: 1.50.1 + puppeteer: + specifier: ^24.2.0 + version: 24.2.0(typescript@5.7.3) source-map-support: specifier: ^0.5 version: 0.5.21 @@ -53,25 +62,25 @@ importers: version: 17.0.33 '@typescript-eslint/eslint-plugin': specifier: ^8 - version: 8.23.0(@typescript-eslint/parser@8.23.0(eslint@9.20.0)(typescript@5.7.3))(eslint@9.20.0)(typescript@5.7.3) + version: 8.24.0(@typescript-eslint/parser@8.24.0(eslint@9.20.1)(typescript@5.7.3))(eslint@9.20.1)(typescript@5.7.3) '@typescript-eslint/parser': specifier: ^8 - version: 8.23.0(eslint@9.20.0)(typescript@5.7.3) + version: 8.24.0(eslint@9.20.1)(typescript@5.7.3) eslint: specifier: ^9 - version: 9.20.0 + version: 9.20.1 eslint-config-prettier: specifier: ^9 - version: 9.1.0(eslint@9.20.0) + version: 9.1.0(eslint@9.20.1) eslint-plugin-import: specifier: ^2 - version: 2.31.0(@typescript-eslint/parser@8.23.0(eslint@9.20.0)(typescript@5.7.3))(eslint@9.20.0) + version: 2.31.0(@typescript-eslint/parser@8.24.0(eslint@9.20.1)(typescript@5.7.3))(eslint@9.20.1) eslint-plugin-prettier: specifier: ^5 - version: 5.2.3(eslint-config-prettier@9.1.0(eslint@9.20.0))(eslint@9.20.0)(prettier@3.5.0) + version: 5.2.3(eslint-config-prettier@9.1.0(eslint@9.20.1))(eslint@9.20.1)(prettier@3.5.0) eslint-plugin-unused-imports: specifier: ^4 - version: 4.1.4(@typescript-eslint/eslint-plugin@8.23.0(@typescript-eslint/parser@8.23.0(eslint@9.20.0)(typescript@5.7.3))(eslint@9.20.0)(typescript@5.7.3))(eslint@9.20.0) + version: 4.1.4(@typescript-eslint/eslint-plugin@8.24.0(@typescript-eslint/parser@8.24.0(eslint@9.20.1)(typescript@5.7.3))(eslint@9.20.1)(typescript@5.7.3))(eslint@9.20.1) prettier: specifier: ^3 version: 3.5.0 @@ -86,7 +95,7 @@ importers: version: 5.7.3 typescript-eslint: specifier: ^8 - version: 8.23.0(eslint@9.20.0)(typescript@5.7.3) + version: 8.24.0(eslint@9.20.1)(typescript@5.7.3) vitest: specifier: ^3 version: 3.0.5(@types/node@18.19.75) @@ -96,6 +105,14 @@ packages: '@anthropic-ai/sdk@0.36.3': resolution: {integrity: sha512-+c0mMLxL/17yFZ4P5+U6bTWiCSFZUKJddrv01ud2aFBWnTPLdRncYV76D3q1tqfnL7aCnhRtykFnoCFzvr4U3Q==} + '@babel/code-frame@7.26.2': + resolution: {integrity: sha512-RJlIHRueQgwWitWgF8OdFYGZX328Ax5BCemNGlqHfplnRT9ESi8JkFlvaVYbS+UubVY6dpv87Fs2u5M29iNFVQ==} + engines: {node: '>=6.9.0'} + + '@babel/helper-validator-identifier@7.25.9': + resolution: {integrity: sha512-Ed61U6XJc3CVRfkERJWDz4dJwKe7iLmmJsbOGu9wSloNSFttHV0I8g6UAgb7qnK5ly5bGLPd4oXZlxCdANBOWQ==} + engines: {node: '>=6.9.0'} + '@babel/runtime@7.26.7': resolution: {integrity: sha512-AOPI3D+a8dXnja+iwsUqGRjr1BbZIe771sXdapOtYI531gSqpi92vXivKcq2asu/DFpdl1ceFAKZyRzK2PCVcQ==} engines: {node: '>=6.9.0'} @@ -155,153 +172,141 @@ packages: '@changesets/write@0.3.2': resolution: {integrity: sha512-kDxDrPNpUgsjDbWBvUo27PzKX4gqeKOlhibaOXDJA6kuBisGqNHv/HwGJrAu8U/dSf8ZEFIeHIPtvSlZI1kULw==} - '@esbuild/aix-ppc64@0.24.2': - resolution: {integrity: sha512-thpVCb/rhxE/BnMLQ7GReQLLN8q9qbHmI55F4489/ByVg2aQaQ6kbcLb6FHkocZzQhxc4gx0sCk0tJkKBFzDhA==} - engines: {node: '>=18'} + '@esbuild/aix-ppc64@0.21.5': + resolution: {integrity: sha512-1SDgH6ZSPTlggy1yI6+Dbkiz8xzpHJEVAlF/AM1tHPLsf5STom9rwtjE4hKAF20FfXXNTFqEYXyJNWh1GiZedQ==} + engines: {node: '>=12'} cpu: [ppc64] os: [aix] - '@esbuild/android-arm64@0.24.2': - resolution: {integrity: sha512-cNLgeqCqV8WxfcTIOeL4OAtSmL8JjcN6m09XIgro1Wi7cF4t/THaWEa7eL5CMoMBdjoHOTh/vwTO/o2TRXIyzg==} - engines: {node: '>=18'} + '@esbuild/android-arm64@0.21.5': + resolution: {integrity: sha512-c0uX9VAUBQ7dTDCjq+wdyGLowMdtR/GoC2U5IYk/7D1H1JYC0qseD7+11iMP2mRLN9RcCMRcjC4YMclCzGwS/A==} + engines: {node: '>=12'} cpu: [arm64] os: [android] - '@esbuild/android-arm@0.24.2': - resolution: {integrity: sha512-tmwl4hJkCfNHwFB3nBa8z1Uy3ypZpxqxfTQOcHX+xRByyYgunVbZ9MzUUfb0RxaHIMnbHagwAxuTL+tnNM+1/Q==} - engines: {node: '>=18'} + '@esbuild/android-arm@0.21.5': + resolution: {integrity: sha512-vCPvzSjpPHEi1siZdlvAlsPxXl7WbOVUBBAowWug4rJHb68Ox8KualB+1ocNvT5fjv6wpkX6o/iEpbDrf68zcg==} + engines: {node: '>=12'} cpu: [arm] os: [android] - '@esbuild/android-x64@0.24.2': - resolution: {integrity: sha512-B6Q0YQDqMx9D7rvIcsXfmJfvUYLoP722bgfBlO5cGvNVb5V/+Y7nhBE3mHV9OpxBf4eAS2S68KZztiPaWq4XYw==} - engines: {node: '>=18'} + '@esbuild/android-x64@0.21.5': + resolution: {integrity: sha512-D7aPRUUNHRBwHxzxRvp856rjUHRFW1SdQATKXH2hqA0kAZb1hKmi02OpYRacl0TxIGz/ZmXWlbZgjwWYaCakTA==} + engines: {node: '>=12'} cpu: [x64] os: [android] - '@esbuild/darwin-arm64@0.24.2': - resolution: {integrity: sha512-kj3AnYWc+CekmZnS5IPu9D+HWtUI49hbnyqk0FLEJDbzCIQt7hg7ucF1SQAilhtYpIujfaHr6O0UHlzzSPdOeA==} - engines: {node: '>=18'} + '@esbuild/darwin-arm64@0.21.5': + resolution: {integrity: sha512-DwqXqZyuk5AiWWf3UfLiRDJ5EDd49zg6O9wclZ7kUMv2WRFr4HKjXp/5t8JZ11QbQfUS6/cRCKGwYhtNAY88kQ==} + engines: {node: '>=12'} cpu: [arm64] os: [darwin] - '@esbuild/darwin-x64@0.24.2': - resolution: {integrity: sha512-WeSrmwwHaPkNR5H3yYfowhZcbriGqooyu3zI/3GGpF8AyUdsrrP0X6KumITGA9WOyiJavnGZUwPGvxvwfWPHIA==} - engines: {node: '>=18'} + '@esbuild/darwin-x64@0.21.5': + resolution: {integrity: sha512-se/JjF8NlmKVG4kNIuyWMV/22ZaerB+qaSi5MdrXtd6R08kvs2qCN4C09miupktDitvh8jRFflwGFBQcxZRjbw==} + engines: {node: '>=12'} cpu: [x64] os: [darwin] - '@esbuild/freebsd-arm64@0.24.2': - resolution: {integrity: sha512-UN8HXjtJ0k/Mj6a9+5u6+2eZ2ERD7Edt1Q9IZiB5UZAIdPnVKDoG7mdTVGhHJIeEml60JteamR3qhsr1r8gXvg==} - engines: {node: '>=18'} + '@esbuild/freebsd-arm64@0.21.5': + resolution: {integrity: sha512-5JcRxxRDUJLX8JXp/wcBCy3pENnCgBR9bN6JsY4OmhfUtIHe3ZW0mawA7+RDAcMLrMIZaf03NlQiX9DGyB8h4g==} + engines: {node: '>=12'} cpu: [arm64] os: [freebsd] - '@esbuild/freebsd-x64@0.24.2': - resolution: {integrity: sha512-TvW7wE/89PYW+IevEJXZ5sF6gJRDY/14hyIGFXdIucxCsbRmLUcjseQu1SyTko+2idmCw94TgyaEZi9HUSOe3Q==} - engines: {node: '>=18'} + '@esbuild/freebsd-x64@0.21.5': + resolution: {integrity: sha512-J95kNBj1zkbMXtHVH29bBriQygMXqoVQOQYA+ISs0/2l3T9/kj42ow2mpqerRBxDJnmkUDCaQT/dfNXWX/ZZCQ==} + engines: {node: '>=12'} cpu: [x64] os: [freebsd] - '@esbuild/linux-arm64@0.24.2': - resolution: {integrity: sha512-7HnAD6074BW43YvvUmE/35Id9/NB7BeX5EoNkK9obndmZBUk8xmJJeU7DwmUeN7tkysslb2eSl6CTrYz6oEMQg==} - engines: {node: '>=18'} + '@esbuild/linux-arm64@0.21.5': + resolution: {integrity: sha512-ibKvmyYzKsBeX8d8I7MH/TMfWDXBF3db4qM6sy+7re0YXya+K1cem3on9XgdT2EQGMu4hQyZhan7TeQ8XkGp4Q==} + engines: {node: '>=12'} cpu: [arm64] os: [linux] - '@esbuild/linux-arm@0.24.2': - resolution: {integrity: sha512-n0WRM/gWIdU29J57hJyUdIsk0WarGd6To0s+Y+LwvlC55wt+GT/OgkwoXCXvIue1i1sSNWblHEig00GBWiJgfA==} - engines: {node: '>=18'} + '@esbuild/linux-arm@0.21.5': + resolution: {integrity: sha512-bPb5AHZtbeNGjCKVZ9UGqGwo8EUu4cLq68E95A53KlxAPRmUyYv2D6F0uUI65XisGOL1hBP5mTronbgo+0bFcA==} + engines: {node: '>=12'} cpu: [arm] os: [linux] - '@esbuild/linux-ia32@0.24.2': - resolution: {integrity: sha512-sfv0tGPQhcZOgTKO3oBE9xpHuUqguHvSo4jl+wjnKwFpapx+vUDcawbwPNuBIAYdRAvIDBfZVvXprIj3HA+Ugw==} - engines: {node: '>=18'} + '@esbuild/linux-ia32@0.21.5': + resolution: {integrity: sha512-YvjXDqLRqPDl2dvRODYmmhz4rPeVKYvppfGYKSNGdyZkA01046pLWyRKKI3ax8fbJoK5QbxblURkwK/MWY18Tg==} + engines: {node: '>=12'} cpu: [ia32] os: [linux] - '@esbuild/linux-loong64@0.24.2': - resolution: {integrity: sha512-CN9AZr8kEndGooS35ntToZLTQLHEjtVB5n7dl8ZcTZMonJ7CCfStrYhrzF97eAecqVbVJ7APOEe18RPI4KLhwQ==} - engines: {node: '>=18'} + '@esbuild/linux-loong64@0.21.5': + resolution: {integrity: sha512-uHf1BmMG8qEvzdrzAqg2SIG/02+4/DHB6a9Kbya0XDvwDEKCoC8ZRWI5JJvNdUjtciBGFQ5PuBlpEOXQj+JQSg==} + engines: {node: '>=12'} cpu: [loong64] os: [linux] - '@esbuild/linux-mips64el@0.24.2': - resolution: {integrity: sha512-iMkk7qr/wl3exJATwkISxI7kTcmHKE+BlymIAbHO8xanq/TjHaaVThFF6ipWzPHryoFsesNQJPE/3wFJw4+huw==} - engines: {node: '>=18'} + '@esbuild/linux-mips64el@0.21.5': + resolution: {integrity: sha512-IajOmO+KJK23bj52dFSNCMsz1QP1DqM6cwLUv3W1QwyxkyIWecfafnI555fvSGqEKwjMXVLokcV5ygHW5b3Jbg==} + engines: {node: '>=12'} cpu: [mips64el] os: [linux] - '@esbuild/linux-ppc64@0.24.2': - resolution: {integrity: sha512-shsVrgCZ57Vr2L8mm39kO5PPIb+843FStGt7sGGoqiiWYconSxwTiuswC1VJZLCjNiMLAMh34jg4VSEQb+iEbw==} - engines: {node: '>=18'} + '@esbuild/linux-ppc64@0.21.5': + resolution: {integrity: sha512-1hHV/Z4OEfMwpLO8rp7CvlhBDnjsC3CttJXIhBi+5Aj5r+MBvy4egg7wCbe//hSsT+RvDAG7s81tAvpL2XAE4w==} + engines: {node: '>=12'} cpu: [ppc64] os: [linux] - '@esbuild/linux-riscv64@0.24.2': - resolution: {integrity: sha512-4eSFWnU9Hhd68fW16GD0TINewo1L6dRrB+oLNNbYyMUAeOD2yCK5KXGK1GH4qD/kT+bTEXjsyTCiJGHPZ3eM9Q==} - engines: {node: '>=18'} + '@esbuild/linux-riscv64@0.21.5': + resolution: {integrity: sha512-2HdXDMd9GMgTGrPWnJzP2ALSokE/0O5HhTUvWIbD3YdjME8JwvSCnNGBnTThKGEB91OZhzrJ4qIIxk/SBmyDDA==} + engines: {node: '>=12'} cpu: [riscv64] os: [linux] - '@esbuild/linux-s390x@0.24.2': - resolution: {integrity: sha512-S0Bh0A53b0YHL2XEXC20bHLuGMOhFDO6GN4b3YjRLK//Ep3ql3erpNcPlEFed93hsQAjAQDNsvcK+hV90FubSw==} - engines: {node: '>=18'} + '@esbuild/linux-s390x@0.21.5': + resolution: {integrity: sha512-zus5sxzqBJD3eXxwvjN1yQkRepANgxE9lgOW2qLnmr8ikMTphkjgXu1HR01K4FJg8h1kEEDAqDcZQtbrRnB41A==} + engines: {node: '>=12'} cpu: [s390x] os: [linux] - '@esbuild/linux-x64@0.24.2': - resolution: {integrity: sha512-8Qi4nQcCTbLnK9WoMjdC9NiTG6/E38RNICU6sUNqK0QFxCYgoARqVqxdFmWkdonVsvGqWhmm7MO0jyTqLqwj0Q==} - engines: {node: '>=18'} + '@esbuild/linux-x64@0.21.5': + resolution: {integrity: sha512-1rYdTpyv03iycF1+BhzrzQJCdOuAOtaqHTWJZCWvijKD2N5Xu0TtVC8/+1faWqcP9iBCWOmjmhoH94dH82BxPQ==} + engines: {node: '>=12'} cpu: [x64] os: [linux] - '@esbuild/netbsd-arm64@0.24.2': - resolution: {integrity: sha512-wuLK/VztRRpMt9zyHSazyCVdCXlpHkKm34WUyinD2lzK07FAHTq0KQvZZlXikNWkDGoT6x3TD51jKQ7gMVpopw==} - engines: {node: '>=18'} - cpu: [arm64] - os: [netbsd] - - '@esbuild/netbsd-x64@0.24.2': - resolution: {integrity: sha512-VefFaQUc4FMmJuAxmIHgUmfNiLXY438XrL4GDNV1Y1H/RW3qow68xTwjZKfj/+Plp9NANmzbH5R40Meudu8mmw==} - engines: {node: '>=18'} + '@esbuild/netbsd-x64@0.21.5': + resolution: {integrity: sha512-Woi2MXzXjMULccIwMnLciyZH4nCIMpWQAs049KEeMvOcNADVxo0UBIQPfSmxB3CWKedngg7sWZdLvLczpe0tLg==} + engines: {node: '>=12'} cpu: [x64] os: [netbsd] - '@esbuild/openbsd-arm64@0.24.2': - resolution: {integrity: sha512-YQbi46SBct6iKnszhSvdluqDmxCJA+Pu280Av9WICNwQmMxV7nLRHZfjQzwbPs3jeWnuAhE9Jy0NrnJ12Oz+0A==} - engines: {node: '>=18'} - cpu: [arm64] - os: [openbsd] - - '@esbuild/openbsd-x64@0.24.2': - resolution: {integrity: sha512-+iDS6zpNM6EnJyWv0bMGLWSWeXGN/HTaF/LXHXHwejGsVi+ooqDfMCCTerNFxEkM3wYVcExkeGXNqshc9iMaOA==} - engines: {node: '>=18'} + '@esbuild/openbsd-x64@0.21.5': + resolution: {integrity: sha512-HLNNw99xsvx12lFBUwoT8EVCsSvRNDVxNpjZ7bPn947b8gJPzeHWyNVhFsaerc0n3TsbOINvRP2byTZ5LKezow==} + engines: {node: '>=12'} cpu: [x64] os: [openbsd] - '@esbuild/sunos-x64@0.24.2': - resolution: {integrity: sha512-hTdsW27jcktEvpwNHJU4ZwWFGkz2zRJUz8pvddmXPtXDzVKTTINmlmga3ZzwcuMpUvLw7JkLy9QLKyGpD2Yxig==} - engines: {node: '>=18'} + '@esbuild/sunos-x64@0.21.5': + resolution: {integrity: sha512-6+gjmFpfy0BHU5Tpptkuh8+uw3mnrvgs+dSPQXQOv3ekbordwnzTVEb4qnIvQcYXq6gzkyTnoZ9dZG+D4garKg==} + engines: {node: '>=12'} cpu: [x64] os: [sunos] - '@esbuild/win32-arm64@0.24.2': - resolution: {integrity: sha512-LihEQ2BBKVFLOC9ZItT9iFprsE9tqjDjnbulhHoFxYQtQfai7qfluVODIYxt1PgdoyQkz23+01rzwNwYfutxUQ==} - engines: {node: '>=18'} + '@esbuild/win32-arm64@0.21.5': + resolution: {integrity: sha512-Z0gOTd75VvXqyq7nsl93zwahcTROgqvuAcYDUr+vOv8uHhNSKROyU961kgtCD1e95IqPKSQKH7tBTslnS3tA8A==} + engines: {node: '>=12'} cpu: [arm64] os: [win32] - '@esbuild/win32-ia32@0.24.2': - resolution: {integrity: sha512-q+iGUwfs8tncmFC9pcnD5IvRHAzmbwQ3GPS5/ceCyHdjXubwQWI12MKWSNSMYLJMq23/IUCvJMS76PDqXe1fxA==} - engines: {node: '>=18'} + '@esbuild/win32-ia32@0.21.5': + resolution: {integrity: sha512-SWXFF1CL2RVNMaVs+BBClwtfZSvDgtL//G/smwAc5oVK/UPu2Gu9tIaRgFmYFFKrmg3SyAjSrElf0TiJ1v8fYA==} + engines: {node: '>=12'} cpu: [ia32] os: [win32] - '@esbuild/win32-x64@0.24.2': - resolution: {integrity: sha512-7VTgWzgMGvup6aSqDPLiW5zHaxYJGTO4OokMjIlrCtf+VpEL+cXKtCvg723iguPYI5oaUNdS+/V7OU2gvXVWEg==} - engines: {node: '>=18'} + '@esbuild/win32-x64@0.21.5': + resolution: {integrity: sha512-tQd/1efJuzPC6rCFwEvLtci/xNFcTZknmXs98FYDfGE4wP9ClFV98nyKrzJKVPMhdDnjzLhdUyMX4PsQAPjwIw==} + engines: {node: '>=12'} cpu: [x64] os: [win32] @@ -396,6 +401,16 @@ packages: resolution: {integrity: sha512-cq8o4cWH0ibXh9VGi5P20Tu9XF/0fFXl9EUinr9QfTM7a7p0oTA4iJRCQWppXR1Pg8dSM0UCItCkPwsk9qWWYA==} engines: {node: ^12.20.0 || ^14.18.0 || >=16.0.0} + '@playwright/test@1.50.1': + resolution: {integrity: sha512-Jii3aBg+CEDpgnuDxEp/h7BimHcUTDlpEtce89xEumlJ5ef2hqepZ+PWp1DDpYC/VO9fmWVI1IlEaoI5fK9FXQ==} + engines: {node: '>=18'} + hasBin: true + + '@puppeteer/browsers@2.7.1': + resolution: {integrity: sha512-MK7rtm8JjaxPN7Mf1JdZIZKPD2Z+W7osvrC1vjpvfOX1K0awDIHYbNi89f7eotp7eMUn2shWnt03HwVbriXtKQ==} + engines: {node: '>=18'} + hasBin: true + '@rollup/rollup-android-arm-eabi@4.34.6': resolution: {integrity: sha512-+GcCXtOQoWuC7hhX1P00LqjjIiS/iOouHXhMdiDSnq/1DGTox4SpUvO52Xm+div6+106r+TcvOeo/cxvyEyTgg==} cpu: [arm] @@ -494,6 +509,9 @@ packages: '@rtsao/scc@1.1.0': resolution: {integrity: sha512-zt6OdqaDoOnJ1ZYsCYGt9YmWzDXl4vQdKTyJev62gFhRGKdx7mcT54V9KIjg+d2wi9EXsPvAPKe7i7WjfVWB8g==} + '@tootallnate/quickjs-emscripten@0.23.0': + resolution: {integrity: sha512-C5Mc6rdnsaJDjO3UpGW/CQTHtCKaYlScZTly4JIu97Jxo/odCiH0ITnDXSJPTOrEKk/ycSZ0AOgTmkDtkOsvIA==} + '@types/estree@1.0.6': resolution: {integrity: sha512-AYnb1nQyY49te+VRAVgmzfcgjYS91mY5P0TKUDCLEM+gNnA+3T6rWITXRLYCpahpqSQbN5cE+gHpnPyXjHWxcw==} @@ -521,51 +539,54 @@ packages: '@types/yargs@17.0.33': resolution: {integrity: sha512-WpxBCKWPLr4xSsHgz511rFJAM+wS28w2zEO1QDNY5zM/S8ok70NNfztH0xwhqKyaK0OHCbN98LDAZuy1ctxDkA==} - '@typescript-eslint/eslint-plugin@8.23.0': - resolution: {integrity: sha512-vBz65tJgRrA1Q5gWlRfvoH+w943dq9K1p1yDBY2pc+a1nbBLZp7fB9+Hk8DaALUbzjqlMfgaqlVPT1REJdkt/w==} + '@types/yauzl@2.10.3': + resolution: {integrity: sha512-oJoftv0LSuaDZE3Le4DbKX+KS9G36NzOeSap90UIK0yMA/NhKJhqlSGtNDORNRaIbQfzjXDrQa0ytJ6mNRGz/Q==} + + '@typescript-eslint/eslint-plugin@8.24.0': + resolution: {integrity: sha512-aFcXEJJCI4gUdXgoo/j9udUYIHgF23MFkg09LFz2dzEmU0+1Plk4rQWv/IYKvPHAtlkkGoB3m5e6oUp+JPsNaQ==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} peerDependencies: '@typescript-eslint/parser': ^8.0.0 || ^8.0.0-alpha.0 eslint: ^8.57.0 || ^9.0.0 typescript: '>=4.8.4 <5.8.0' - '@typescript-eslint/parser@8.23.0': - resolution: {integrity: sha512-h2lUByouOXFAlMec2mILeELUbME5SZRN/7R9Cw2RD2lRQQY08MWMM+PmVVKKJNK1aIwqTo9t/0CvOxwPbRIE2Q==} + '@typescript-eslint/parser@8.24.0': + resolution: {integrity: sha512-MFDaO9CYiard9j9VepMNa9MTcqVvSny2N4hkY6roquzj8pdCBRENhErrteaQuu7Yjn1ppk0v1/ZF9CG3KIlrTA==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} peerDependencies: eslint: ^8.57.0 || ^9.0.0 typescript: '>=4.8.4 <5.8.0' - '@typescript-eslint/scope-manager@8.23.0': - resolution: {integrity: sha512-OGqo7+dXHqI7Hfm+WqkZjKjsiRtFUQHPdGMXzk5mYXhJUedO7e/Y7i8AK3MyLMgZR93TX4bIzYrfyVjLC+0VSw==} + '@typescript-eslint/scope-manager@8.24.0': + resolution: {integrity: sha512-HZIX0UByphEtdVBKaQBgTDdn9z16l4aTUz8e8zPQnyxwHBtf5vtl1L+OhH+m1FGV9DrRmoDuYKqzVrvWDcDozw==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} - '@typescript-eslint/type-utils@8.23.0': - resolution: {integrity: sha512-iIuLdYpQWZKbiH+RkCGc6iu+VwscP5rCtQ1lyQ7TYuKLrcZoeJVpcLiG8DliXVkUxirW/PWlmS+d6yD51L9jvA==} + '@typescript-eslint/type-utils@8.24.0': + resolution: {integrity: sha512-8fitJudrnY8aq0F1wMiPM1UUgiXQRJ5i8tFjq9kGfRajU+dbPyOuHbl0qRopLEidy0MwqgTHDt6CnSeXanNIwA==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} peerDependencies: eslint: ^8.57.0 || ^9.0.0 typescript: '>=4.8.4 <5.8.0' - '@typescript-eslint/types@8.23.0': - resolution: {integrity: sha512-1sK4ILJbCmZOTt9k4vkoulT6/y5CHJ1qUYxqpF1K/DBAd8+ZUL4LlSCxOssuH5m4rUaaN0uS0HlVPvd45zjduQ==} + '@typescript-eslint/types@8.24.0': + resolution: {integrity: sha512-VacJCBTyje7HGAw7xp11q439A+zeGG0p0/p2zsZwpnMzjPB5WteaWqt4g2iysgGFafrqvyLWqq6ZPZAOCoefCw==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} - '@typescript-eslint/typescript-estree@8.23.0': - resolution: {integrity: sha512-LcqzfipsB8RTvH8FX24W4UUFk1bl+0yTOf9ZA08XngFwMg4Kj8A+9hwz8Cr/ZS4KwHrmo9PJiLZkOt49vPnuvQ==} + '@typescript-eslint/typescript-estree@8.24.0': + resolution: {integrity: sha512-ITjYcP0+8kbsvT9bysygfIfb+hBj6koDsu37JZG7xrCiy3fPJyNmfVtaGsgTUSEuTzcvME5YI5uyL5LD1EV5ZQ==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} peerDependencies: typescript: '>=4.8.4 <5.8.0' - '@typescript-eslint/utils@8.23.0': - resolution: {integrity: sha512-uB/+PSo6Exu02b5ZEiVtmY6RVYO7YU5xqgzTIVZwTHvvK3HsL8tZZHFaTLFtRG3CsV4A5mhOv+NZx5BlhXPyIA==} + '@typescript-eslint/utils@8.24.0': + resolution: {integrity: sha512-07rLuUBElvvEb1ICnafYWr4hk8/U7X9RDCOqd9JcAMtjh/9oRmcfN4yGzbPVirgMR0+HLVHehmu19CWeh7fsmQ==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} peerDependencies: eslint: ^8.57.0 || ^9.0.0 typescript: '>=4.8.4 <5.8.0' - '@typescript-eslint/visitor-keys@8.23.0': - resolution: {integrity: sha512-oWWhcWDLwDfu++BGTZcmXWqpwtkwb5o7fxUIGksMQQDSdPW9prsSnfIOZMlsj4vBOSrcnjIUZMiIjODgGosFhQ==} + '@typescript-eslint/visitor-keys@8.24.0': + resolution: {integrity: sha512-kArLq83QxGLbuHrTMoOEWO+l2MwsNS2TGISEdx8xgqpkbytB07XmlQyQdNDrCc1ecSqx0cnmhGvpX+VBwqqSkg==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} '@vitest/expect@3.0.5': @@ -611,6 +632,10 @@ packages: engines: {node: '>=0.4.0'} hasBin: true + agent-base@7.1.3: + resolution: {integrity: sha512-jRR5wdylq8CkOe6hei19GGZnxM6rBGwFl3Bg0YItGDimvjGtAvdZk4Pu6Cl4u4Igsws4a1fd1Vq3ezrhn4KmFw==} + engines: {node: '>= 14'} + agentkeepalive@4.6.0: resolution: {integrity: sha512-kja8j7PjmncONqaTsB8fQ+wE2mSU2DJ9D4XKoJ5PFWIdRMa6SLSN1ff4mOr4jCbfRSsxR4keIiySJU0N9T5hIQ==} engines: {node: '>= 8.0.0'} @@ -676,6 +701,10 @@ packages: resolution: {integrity: sha512-Izi8RQcffqCeNVgFigKli1ssklIbpHnCYc6AknXGYoB6grJqyeby7jv12JUQgmTAnIDnbck1uxksT4dzN3PWBA==} engines: {node: '>=12'} + ast-types@0.13.4: + resolution: {integrity: sha512-x1FCFnFifvYDDzTaLII71vG5uvDwgtmDTEVWAxrgeiR8VjMONcCXJx7E+USjDtHlwFmt9MysbqgF9b9Vjr6w+w==} + engines: {node: '>=4'} + async-function@1.0.0: resolution: {integrity: sha512-hsU18Ae8CDTR6Kgu9DYf0EbCr/a5iGL0rytQDobUcdpYOKokk8LEjVphnXkDkgpi0wYVsqrXuP0bZxJaTqdgoA==} engines: {node: '>= 0.4'} @@ -687,9 +716,41 @@ packages: resolution: {integrity: sha512-wvUjBtSGN7+7SjNpq/9M2Tg350UZD3q62IFZLbRAR1bSMlCo1ZaeW+BJ+D090e4hIIZLBcTDWe4Mh4jvUDajzQ==} engines: {node: '>= 0.4'} + b4a@1.6.7: + resolution: {integrity: sha512-OnAYlL5b7LEkALw87fUVafQw5rVR9RjwGd4KUwNQ6DrrNmaVaUCgLipfVlzrPQ4tWOR9P0IXGNOx50jYCCdSJg==} + balanced-match@1.0.2: resolution: {integrity: sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==} + bare-events@2.5.4: + resolution: {integrity: sha512-+gFfDkR8pj4/TrWCGUGWmJIkBwuxPS5F+a5yWjOHQt2hHvNZd5YLzadjmDUtFmMM4y429bnKLa8bYBMHcYdnQA==} + + bare-fs@4.0.1: + resolution: {integrity: sha512-ilQs4fm/l9eMfWY2dY0WCIUplSUp7U0CT1vrqMg1MUdeZl4fypu5UP0XcDBK5WBQPJAKP1b7XEodISmekH/CEg==} + engines: {bare: '>=1.7.0'} + + bare-os@3.4.0: + resolution: {integrity: sha512-9Ous7UlnKbe3fMi7Y+qh0DwAup6A1JkYgPnjvMDNOlmnxNRQvQ/7Nst+OnUQKzk0iAT0m9BisbDVp9gCv8+ETA==} + engines: {bare: '>=1.6.0'} + + bare-path@3.0.0: + resolution: {integrity: sha512-tyfW2cQcB5NN8Saijrhqn0Zh7AnFNsnczRcuWODH0eYAXBsJ5gVxAUuNr7tsHSC6IZ77cA0SitzT+s47kot8Mw==} + + bare-stream@2.6.5: + resolution: {integrity: sha512-jSmxKJNJmHySi6hC42zlZnq00rga4jjxcgNZjY9N5WlOe/iOoGRtdwGsHzQv2RlH2KOYMwGUXhf2zXd32BA9RA==} + peerDependencies: + bare-buffer: '*' + bare-events: '*' + peerDependenciesMeta: + bare-buffer: + optional: true + bare-events: + optional: true + + basic-ftp@5.0.5: + resolution: {integrity: sha512-4Bcg1P8xhUuqcii/S0Z9wiHIrQVPMermM1any+MX5GeGD7faD3/msQUDGLol9wOcz4/jbg/WJnGqoJF6LiBdtg==} + engines: {node: '>=10.0.0'} + better-path-resolve@1.0.0: resolution: {integrity: sha512-pbnl5XzGBdrFU/wT4jqmJVPn2B6UHPBOhzMQkY/SPUPB6QtUXtmBHBIwCbXJol93mOpGMnQyP/+BB19q04xj7g==} engines: {node: '>=4'} @@ -704,6 +765,9 @@ packages: resolution: {integrity: sha512-yQbXgO/OSZVD2IsiLlro+7Hf6Q18EJrKSEsdoMzKePKXct3gvD8oLcOQdIzGupr5Fj+EDe8gO/lxc1BzfMpxvA==} engines: {node: '>=8'} + buffer-crc32@0.2.13: + resolution: {integrity: sha512-VO9Ht/+p3SN7SKWqcrgEzjGbRSJYTx+Q1pTQC0wrWqHx0vpJraQ6GtHx8tvcg1rlK1byhU5gccxgOgj7B0TDkQ==} + buffer-from@1.1.2: resolution: {integrity: sha512-E+XQCRwSbaaiChtv6k6Dwgc+bx+Bs6vuKJHHl5kox/BaKbhiXzqQOwK4cO22yElGp2OCmjwVhT3HmxgyPGnJfQ==} @@ -746,6 +810,11 @@ packages: resolution: {integrity: sha512-OAlb+T7V4Op9OwdkjmguYRqncdlx5JiofwOAUkmTF+jNdHwzTaTs4sRAGpzLF3oOz5xAyDGrPgeIDFQmDOTiJw==} engines: {node: '>= 16'} + chromium-bidi@1.2.0: + resolution: {integrity: sha512-XtdJ1GSN6S3l7tO7F77GhNsw0K367p0IsLYf2yZawCVAKKC3lUvDhPdMVrB2FNhmhfW43QGYbEX3Wg6q0maGwQ==} + peerDependencies: + devtools-protocol: '*' + ci-info@3.9.0: resolution: {integrity: sha512-NIxF55hv4nSqQswkAeiOi1r83xy8JldOFDTWiug55KBu9Jnblncd2U6ViHmYgHf01TPZS77NJBhBMKdWj9HQMQ==} engines: {node: '>=8'} @@ -768,10 +837,23 @@ packages: concat-map@0.0.1: resolution: {integrity: sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==} + cosmiconfig@9.0.0: + resolution: {integrity: sha512-itvL5h8RETACmOTFc4UfIyB2RfEHi71Ax6E/PivVxq9NseKbOWpeyHEOIbmAw1rs8Ak0VursQNww7lf7YtUwzg==} + engines: {node: '>=14'} + peerDependencies: + typescript: '>=4.9.5' + peerDependenciesMeta: + typescript: + optional: true + cross-spawn@7.0.6: resolution: {integrity: sha512-uV2QOWP2nWzsy2aMp8aRibhi9dlzF5Hgh5SHaB9OiTGEyDTiJJyx0uy51QXdyWbtAHNua4XJzUKca3OzKUd3vA==} engines: {node: '>= 8'} + data-uri-to-buffer@6.0.2: + resolution: {integrity: sha512-7hvf7/GW8e86rW0ptuwS3OcBGDjIi6SZva7hCyWC0yYry2cOPmLIjXAUHI6DK2HsnwJd9ifmt57i8eV2n4YNpw==} + engines: {node: '>= 14'} + data-view-buffer@1.0.2: resolution: {integrity: sha512-EmKO5V3OLXh1rtK2wgXRansaK1/mtVdTUEiEI0W8RkvgT05kfxaH29PliLnpLP73yYO6142Q72QNa8Wx/A5CqQ==} engines: {node: '>= 0.4'} @@ -816,6 +898,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'} @@ -824,6 +910,9 @@ packages: resolution: {integrity: sha512-reYkTUJAZb9gUuZ2RvVCNhVHdg62RHnJ7WJl8ftMi4diZ6NWlciOzQN88pUhSELEwflJht4oQDv0F0BMlwaYtA==} engines: {node: '>=8'} + devtools-protocol@0.0.1402036: + resolution: {integrity: sha512-JwAYQgEvm3yD45CHB+RmF5kMbWtXBaOGwuxa87sZogHcLCv8c/IqnThaoQ1y60d7pXWjSKWQphPEc+1rAScVdg==} + dir-glob@3.0.1: resolution: {integrity: sha512-WkrWp9GR4KXfKGYzOLmTuGVi1UWFfws377n9cc55/tb6DuqyF6pcQ5AbiHEshaDpY9v6oaSr2XCDidGmMwdzIA==} engines: {node: '>=8'} @@ -849,10 +938,20 @@ packages: emoji-regex@9.2.2: resolution: {integrity: sha512-L18DaJsXSUk2+42pv8mLs5jJT2hqFkFE4j21wOmgbUqsZ2hL72NsUU785g9RXgo3s0ZNgVl42TiHp3ZtOv/Vyg==} + end-of-stream@1.4.4: + resolution: {integrity: sha512-+uw1inIHVPQoaVuHzRyXd21icM+cnt4CzD5rW+NC1wjOUSTOs+Te7FOv7AhN7vS9x/oIyhLP5PR1H+phQAHu5Q==} + enquirer@2.4.1: resolution: {integrity: sha512-rRqJg/6gd538VHvR3PSrdRBb/1Vy2YfzHqzvbhGIQpDRKIa4FgV/54b5Q1xYSxOOwKvjXweS26E0Q+nAMwp2pQ==} engines: {node: '>=8.6'} + env-paths@2.2.1: + resolution: {integrity: sha512-+h1lkLKhZMTYjog1VEpJNG7NZJWcuc2DDk/qsqSTRRCOXiLjeQ1d1/udrUGhqMxUgAlwKNZ0cf2uqan5GLuS2A==} + engines: {node: '>=6'} + + error-ex@1.3.2: + resolution: {integrity: sha512-7dFHNmqeFSEt2ZBsCriorKnn3Z2pj+fd9kmI6QoWw4//DL+icEBfc0U7qJCisqrTsKTjw4fNFy2pW9OqStD84g==} + es-abstract@1.23.9: resolution: {integrity: sha512-py07lI0wjxAC/DcfK1S6G7iANonniZwTISvdPzk9hzeH0IZIshbuuFxLIU96OyF89Yb9hiqWn8M/bY83KY5vzA==} engines: {node: '>= 0.4'} @@ -883,9 +982,9 @@ packages: resolution: {integrity: sha512-w+5mJ3GuFL+NjVtJlvydShqE1eN3h3PbI7/5LAsYJP/2qtuMXjfL2LpHSRqo4b4eSF5K/DH1JXKUAHSB2UW50g==} engines: {node: '>= 0.4'} - esbuild@0.24.2: - resolution: {integrity: sha512-+9egpBW8I3CD5XPe0n6BfT5fxLzxrlDzqydF3aviG+9ni1lDC/OvMHcxqEFV0+LANZG5R1bFMWfUrjVsdwxJvA==} - engines: {node: '>=18'} + esbuild@0.21.5: + resolution: {integrity: sha512-mg3OPMV4hXywwpoDxu3Qda5xCKQi+vCTZq8S9J/EpkhB2HzKXq4SNFZE3+NK93JYxc8VMSep+lOUSC/RVKaBqw==} + engines: {node: '>=12'} hasBin: true escalade@3.2.0: @@ -896,6 +995,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 @@ -971,8 +1075,8 @@ packages: resolution: {integrity: sha512-UyLnSehNt62FFhSwjZlHmeokpRK59rcz29j+F1/aDgbkbRTk7wIc9XzdoasMUbRNKDM0qQt/+BJ4BrpFeABemw==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} - eslint@9.20.0: - resolution: {integrity: sha512-aL4F8167Hg4IvsW89ejnpTwx+B/UQRzJPGgbIOl+4XqffWsahVVsLEWoZvnrVuwpWmnRd7XeXmQI1zlKcFDteA==} + eslint@9.20.1: + resolution: {integrity: sha512-m1mM33o6dBUjxl2qb6wv6nGNwCAsns1eKtaQ4l/NPHeTvhiUPbtdfMyktxN4B3fgHIgsYh1VT3V9txblpQHq+g==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} hasBin: true peerDependencies: @@ -1024,12 +1128,20 @@ packages: resolution: {integrity: sha512-hMQ4CX1p1izmuLYyZqLMO/qGNw10wSv9QDCPfzXfyFrOaCSSoRfqE1Kf1s5an66J5JZC62NewG+mK49jOCtQew==} engines: {node: '>=4'} + extract-zip@2.0.1: + resolution: {integrity: sha512-GDhU9ntwuKyGXdZBUgTIe+vXnWj0fppUEtMDL0+idd5Sta8TGpHssn/eusA9mrPr9qNDym6SxAYZjNvCn/9RBg==} + engines: {node: '>= 10.17.0'} + hasBin: true + 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.3: resolution: {integrity: sha512-7MptL8U0cqcFdzIzwOTHoilX9x5BrNqye7Z/LuC7kCMRio1EMSyqRK3BEAUD7sXRq4iT4AzTVuZdhgQ2TCvYLg==} engines: {node: '>=8.6.0'} @@ -1043,6 +1155,9 @@ packages: fastq@1.19.0: resolution: {integrity: sha512-7SFSRCNjBQIZH/xZR3iy5iQYR8aGBE0h3VG6/cwlbrpdciNYBMotQav8c1XI3HjHH+NikUpP53nPdlZSdWmFzA==} + fd-slicer@1.1.0: + resolution: {integrity: sha512-cE1qsB/VwyQozZ+q1dGxR8LBYNZeofhEdUNGSMbQD3Gw2lAzX9Zb3uIU6Ebc/Fmyjo9AWWfnn0AUCHqtevs/8g==} + file-entry-cache@8.0.0: resolution: {integrity: sha512-XXTUwCvisa5oacNGRP9SfNtYBNAMi+RPwBFmblZEF7N7swHYQS6/Zfk7SRwx4D5j3CH211YNRco1DEMNVfZCnQ==} engines: {node: '>=16.0.0'} @@ -1066,8 +1181,8 @@ packages: flatted@3.3.2: resolution: {integrity: sha512-AiwGJM8YcNOaobumgtng+6NHuOqC3A7MixFeDafM3X9cIUM+xUXoS5Vfgf+OihAYe20fxqNM9yPBXJzRtZ/4eA==} - for-each@0.3.4: - resolution: {integrity: sha512-kKaIINnFpzW6ffJNDjjyjrk21BkDx38c0xa/klsT8VzLCaMEefv4ZTacrcVR4DmgTeBra++jMDAfS/tS799YDw==} + for-each@0.3.5: + resolution: {integrity: sha512-dKx12eRCVIzqCxFGplyFKJMPvLEWgmNtUrpTiJIR5u97zEhRG8ySrtboPHZXx7daLxQVrl643cTzbab2tkQjxg==} engines: {node: '>= 0.4'} foreground-child@3.3.0: @@ -1093,6 +1208,11 @@ packages: resolution: {integrity: sha512-yhlQgA6mnOJUKOsRUFsgJdQCvkKhcz8tlZG5HBQfReYZy46OwLcY+Zia0mtdHsOo9y/hP+CxMN0TU9QxoOtG4g==} engines: {node: '>=6 <7 || >=8'} + fsevents@2.3.2: + resolution: {integrity: sha512-xiqMQR4xAeHTuB9uWm+fFRcIOgKBMiOBP+eXiyT7jsgVCq1bkVygt00oASowB7EdtpOHaaPgKt812P9ab+DDKA==} + engines: {node: ^8.16.0 || ^10.6.0 || >=11.0.0} + os: [darwin] + fsevents@2.3.3: resolution: {integrity: sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==} engines: {node: ^8.16.0 || ^10.6.0 || >=11.0.0} @@ -1120,10 +1240,18 @@ packages: resolution: {integrity: sha512-sTSfBjoXBp89JvIKIefqw7U2CCebsc74kiY6awiGogKtoSGbgjYE/G/+l9sF3MWFPNc9IcoOC4ODfKHfxFmp0g==} engines: {node: '>= 0.4'} + 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'} + 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'} @@ -1185,6 +1313,14 @@ packages: resolution: {integrity: sha512-0hJU9SCPvmMzIBdZFqNPXWa6dqh7WdH0cII9y+CyS8rG3nL48Bclra9HmKhVVUHyPWNH5Y7xDwAB7bfgSjkUMQ==} engines: {node: '>= 0.4'} + http-proxy-agent@7.0.2: + resolution: {integrity: sha512-T1gkAiYYDWYx3V5Bmyu7HcfcvL7mUrTWiM6yOfa3PIphViJ/gFPbvidQ+veqSOHci/PxBcDabeUNCzpOODJZig==} + engines: {node: '>= 14'} + + https-proxy-agent@7.0.6: + resolution: {integrity: sha512-vK9P5/iUfdl95AI+JVyUuIcVtd4ofvtrOr3HNtM2yxC9bnMbEdp3x01OhQNnjb8IJYi38VlTE3mBXwcfvywuSw==} + engines: {node: '>= 14'} + human-id@1.0.2: resolution: {integrity: sha512-UNopramDEhHJD+VR+ehk8rOslwSfByxPIZyJRfV739NDhN5LF1fa1MqnzKm2lGTQRjNrjK19Q5fhkgIfjlVUKw==} @@ -1211,10 +1347,17 @@ packages: 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'} + is-arrayish@0.2.1: + resolution: {integrity: sha512-zz06S8t0ozoDXMG+ube26zeCTNXcKIPJZJi8hBrF4idCLms4CG9QtK7qBl1boi5ODzFpjswb5JPmHCbMpjaYzg==} + is-async-function@2.1.1: resolution: {integrity: sha512-9dgM/cZBnNvjzaMYHVoxxfPj2QXt22Ev7SuuPrs+xav0ukGB0S6d4ydZdEiM48kLx5kDV+QBPrpVnFyefL8kkQ==} engines: {node: '>= 0.4'} @@ -1328,6 +1471,9 @@ packages: jackspeak@3.4.3: resolution: {integrity: sha512-OGlZQpz2yfahA/Rd1Y8Cd9SIEsqvXkLVoSw/cgwhnhFMDbsQFeZYoJJ7bIZBS9BcamUW96asq/npPWugM+RQBw==} + js-tokens@4.0.0: + resolution: {integrity: sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==} + js-yaml@3.14.1: resolution: {integrity: sha512-okMH7OXXJ7YrN9Ok3/SXrnu4iX9yOk+25nqX4imS2npuvTYDmo/QEZoqwZkYaIDk3jVvBOTOIEgEhaLOynBS9g==} hasBin: true @@ -1336,9 +1482,15 @@ packages: resolution: {integrity: sha512-wpxZs9NoxZaJESJGIZTyDEaYpl0FKSA+FB9aJiyemKhMwkxQg63h4T1KJgUGHpTqPDNRcmmYLugrRjJlBtWvRA==} hasBin: true + jsbn@1.1.0: + resolution: {integrity: sha512-4bYVV3aAMtDTTu4+xsDYa6sy9GyJ69/amsu9sYF2zqjiEoZA5xJi3BrfX3uY+/IekIu7MwdObdbDWpoZdBv3/A==} + json-buffer@3.0.1: resolution: {integrity: sha512-4bV5BfR2mqfQTJm+V5tPPdf+ZpuhiIvTuAB5g8kcrXOZpTT/QwwVRWBywX1ozr6lEuPdbHxwaJlm9G6mI2sfSQ==} + json-parse-even-better-errors@2.3.1: + resolution: {integrity: sha512-xyFwyhro/JEof6Ghe2iz2NcXoj2sloNsWr/XsERDK/oiPCfaNhl5ONfp+jQdAZRQQ0IJWNzH9zIZF7li91kh2w==} + json-schema-traverse@0.4.1: resolution: {integrity: sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==} @@ -1359,6 +1511,9 @@ packages: resolution: {integrity: sha512-+bT2uH4E5LGE7h/n3evcS/sQlJXCpIp6ym8OWJ5eV6+67Dsql/LaaT7qJBAt2rzfoa/5QBGBhxDix1dMt2kQKQ==} engines: {node: '>= 0.8.0'} + lines-and-columns@1.2.4: + resolution: {integrity: sha512-7ylylesZQ/PV29jhEDl3Ufjo6ZX7gCqJr5F7PKrqc93v7fzSymt1BpwEU8nAUXs8qzzvqhbjhK5QZg6Mt/HkBg==} + locate-path@5.0.0: resolution: {integrity: sha512-t7hw9pI+WvuwNJXwk5zVHpyhIqzg2qTlklJOf0mVxGSbe3Fp2VieZcduNYjaLDoy6p9uGpQEGWG87WpMKlNq8g==} engines: {node: '>=8'} @@ -1379,6 +1534,10 @@ packages: lru-cache@10.4.3: resolution: {integrity: sha512-JNAzZcXrCt42VGLuYz0zfAzDfAvJWW6AfYlDBQyDV5DClI2m5sAmK+OIO7s59XfsRsWHp02jAJrRadPRGTt6SQ==} + lru-cache@7.18.3: + resolution: {integrity: sha512-jumlc0BIUrS3qJGgIkWZsyfAM7NCWiBcCDhnd+3NNM5KbBmLTgHVfWBcg6W+rLUsIpzpERPsvwUP7CckAQSOoA==} + engines: {node: '>=12'} + magic-string@0.30.17: resolution: {integrity: sha512-sNPKHvyjVf7gyjwS4xGTaW/mCnF8wnjtifKBEhxfZ7E/S8tQ0rssrwGNn6q8JH/ohItJfSQp9mBtQYuTlH5QnA==} @@ -1416,6 +1575,9 @@ packages: resolution: {integrity: sha512-qOOzS1cBTWYF4BH8fVePDBOO9iptMnGUEZwNc/cMWnTV2nVLZ7VoNWEPHkYczZA0pdoA7dl6e7FL659nX9S2aw==} engines: {node: '>=16 || 14 >=14.17'} + mitt@3.0.1: + resolution: {integrity: sha512-vKivATfr97l2/QBCYAkXYDbrIWPM2IIKEl7YPhjCvKlG3kE2gm+uBo6nEXK3M5/Ffh/FLpKExzOQ3JJoJGFKBw==} + mri@1.2.0: resolution: {integrity: sha512-tzzskb3bG8LvYGFF/mDTpq3jpI6Q9wc3LEmBaghu+DdCssd1FakN7Bc0hVNmEyGq1bq3RgfkCb3cmQLpNPOroA==} engines: {node: '>=4'} @@ -1431,6 +1593,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'} + node-domexception@1.0.0: resolution: {integrity: sha512-/jKZoMpw0F8GRwl4/eLROPA3cfcXtLApP0QzLmUT/HuPCZWyB7IY9ZrMeKw2O/nFIqPQB3PVM9aYm0F312AXDQ==} engines: {node: '>=10.5.0'} @@ -1468,6 +1634,9 @@ packages: resolution: {integrity: sha512-gXah6aZrcUxjWg2zR2MwouP2eHlCBzdV4pygudehaKXSGW4v2AsRQUK+lwwXhii6KFZcunEnmSUoYp5CXibxtA==} engines: {node: '>= 0.4'} + 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'} @@ -1511,6 +1680,14 @@ packages: resolution: {integrity: sha512-R4nPAVTAU0B9D35/Gk3uJf/7XYbQcyohSKdvAxIRSNghFl4e71hVoGnBNQz9cWaXxO2I10KTC+3jMdvvoKw6dQ==} engines: {node: '>=6'} + 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==} @@ -1521,6 +1698,10 @@ packages: resolution: {integrity: sha512-GQ2EWRpQV8/o+Aw8YqtfZZPfNRWZYkbidE9k5rpl/hC3vtHHBfGm2Ifi6qWV+coDGkrUKZAxE3Lot5kcsRlh+g==} engines: {node: '>=6'} + parse-json@5.2.0: + resolution: {integrity: sha512-ayCKvm/phCGxOkYRSCM82iDwct8/EonSEgCSxWxD7ve6jHggsFl4fZVQBPRNgQoKiuV/odhFrGzQXZwbifC8Rg==} + engines: {node: '>=8'} + path-exists@4.0.0: resolution: {integrity: sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w==} engines: {node: '>=8'} @@ -1547,6 +1728,9 @@ packages: resolution: {integrity: sha512-vE7JKRyES09KiunauX7nd2Q9/L7lhok4smP9RZTDeD4MVs72Dp2qNFVz39Nz5a0FVEW0BJR6C0DYrq6unoziZA==} engines: {node: '>= 14.16'} + pend@1.2.0: + resolution: {integrity: sha512-F3asv42UuXchdzt+xXqfW1OGlVBe+mxa2mqI0pg5yAHZPvFmY3Y6drSf/GQ1A86WgWEN9Kzh/WrgKa6iGcHXLg==} + picocolors@1.1.1: resolution: {integrity: sha512-xceH2snhtb5M9liqDsmEw56le376mTZkEX/jEb/RxNFyegNul7eNslCXP9FDj/Lcu0X8KEyMceP2ntpaHrDEVA==} @@ -1558,12 +1742,22 @@ packages: resolution: {integrity: sha512-uB80kBFb/tfd68bVleG9T5GGsGPjJrLAUpR5PZIrhBnIaRTQRjqdJSsIKkOP6OAIFbj7GOrcudc5pNjZ+geV2g==} engines: {node: '>=6'} + playwright-core@1.50.1: + resolution: {integrity: sha512-ra9fsNWayuYumt+NiM069M6OkcRb1FZSK8bgi66AtpFoWkg2+y0bJSNmkFrWhMbEBbVKC/EruAHH3g0zmtwGmQ==} + engines: {node: '>=18'} + hasBin: true + + playwright@1.50.1: + resolution: {integrity: sha512-G8rwsOQJ63XG6BbKj2w5rHeavFjy5zynBA9zsJMMtBoe/Uf757oG12NXz6e6OirF7RCrTVAKFXbLmn1RbL7Qaw==} + engines: {node: '>=18'} + hasBin: true + possible-typed-array-names@1.1.0: resolution: {integrity: sha512-/+5VFTchJDoVj3bhoqi6UeymcD00DAwb1nJwamzPvHEszJ4FpF6SNNbUbOS8yI56qHzdV8eK0qEfOSiodkTdxg==} engines: {node: '>= 0.4'} - postcss@8.5.1: - resolution: {integrity: sha512-6oz2beyjc5VMn/KV1pPw8fliQkhBXrVn1Z3TVyqZxU8kZpzEKhBdmCFqI6ZbmGtamQvQGuU1sgPTk8ZrXDD7jQ==} + postcss@8.5.2: + resolution: {integrity: sha512-MjOadfU3Ys9KYoX0AdkBlFEF1Vx37uCCeN4ZHnmwm9FfpbsGWMZeBLMmmpY+6Ocqod7mkdZ0DT31OlbsFrLlkA==} engines: {node: ^10 || ^12 || >=14} prelude-ls@1.2.1: @@ -1584,10 +1778,33 @@ packages: engines: {node: '>=14'} hasBin: true + progress@2.0.3: + resolution: {integrity: sha512-7PiHtLll5LdnKIMw100I+8xJXR5gW2QwWYkT6iJva0bXitZKa/XMrSbdmg3r2Xnaidz9Qumd0VPaMrZlF9V9sA==} + engines: {node: '>=0.4.0'} + + 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'} + puppeteer-core@24.2.0: + resolution: {integrity: sha512-e4A4/xqWdd4kcE6QVHYhJ+Qlx/+XpgjP4d8OwBx0DJoY/nkIRhSgYmKQnv7+XSs1ofBstalt+XPGrkaz4FoXOQ==} + engines: {node: '>=18'} + + puppeteer@24.2.0: + resolution: {integrity: sha512-z8vv7zPEgrilIbOo3WNvM+2mXMnyM9f4z6zdrB88Fzeuo43Oupmjrzk3EpuvuCtyK0A7Lsllfx7Z+4BvEEGJcQ==} + engines: {node: '>=18'} + hasBin: true + queue-microtask@1.2.3: resolution: {integrity: sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A==} @@ -1710,6 +1927,18 @@ 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'} + + socks-proxy-agent@8.0.5: + resolution: {integrity: sha512-HehCEsotFqbPW9sJ8WVYB6UbmIMv7kUUORIF2Nncq4VQvBfNBLibW9YZR5dlYCSUhwcD628pRllm7n+E+YTzJw==} + engines: {node: '>= 14'} + + socks@2.8.4: + resolution: {integrity: sha512-D3YaD0aRxR3mEcqnidIs7ReYJFVzWdd6fXJYUM8ixcQcJRGTka/b3saV0KflYhyVJXKhb947GndU35SxYNResQ==} + 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'} @@ -1727,12 +1956,18 @@ packages: sprintf-js@1.0.3: resolution: {integrity: sha512-D9cPgkvLlV3t3IzL0D0YLvGA9Ahk4PcvVwUbN0dSGr1aP0Nrt4AEnTUbuGvquEC0mA64Gqt1fzirlRs5ibXx8g==} + sprintf-js@1.1.3: + resolution: {integrity: sha512-Oo+0REFV59/rz3gfJNKQiBlwfHaSESl1pcGyABQsnnIfWOFt6JNj5gCog2U6MLZ//IGYD+nA8nI+mTShREReaA==} + stackback@0.0.2: resolution: {integrity: sha512-1XMJE5fQo1jGH6Y/7ebnwPOBEkIEnT4QF32d5R1+VXdXveM0IBMJt8zfaxX1P3QhVwrYe+576+jkANtSS2mBbw==} std-env@3.8.0: resolution: {integrity: sha512-Bc3YwwCB+OzldMxOXJIIvC6cPRWr/LxOp48CdQTOkPyk/t4JWWJbrilwBd7RJzKV8QW7tJkcgAmeuLLJugl5/w==} + streamx@2.22.0: + resolution: {integrity: sha512-sLh1evHOzBy/iWRiR6d1zRcLao4gGZr3C1kzNz4fopCOKJb6xD9ub8Mpi9Mr1R6id5o43S+d93fI48UC5uM9aw==} + string-width@4.2.3: resolution: {integrity: sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==} engines: {node: '>=8'} @@ -1781,10 +2016,19 @@ packages: resolution: {integrity: sha512-vrozgXDQwYO72vHjUb/HnFbQx1exDjoKzqx23aXEg2a9VIg2TSFZ8FmeZpTjUCFMYw7mpX4BE2SFu8wI7asYsw==} engines: {node: ^14.18.0 || >=16.0.0} + tar-fs@3.0.8: + resolution: {integrity: sha512-ZoROL70jptorGAlgAYiLoBLItEKw/fUxg9BSYK/dF/GAGYFJOJJJMvjPAKDJraCXFwadD456FCuvLWgfhMsPwg==} + + tar-stream@3.1.7: + resolution: {integrity: sha512-qJj60CXt7IU1Ffyc3NJMjh6EkuCFej46zUqJ4J7pqYlThyd9bO0XBTmcOIhSzZJVWfsLks0+nle/j538YAW9RQ==} + term-size@2.2.1: resolution: {integrity: sha512-wK0Ri4fOGjv/XPy8SBHZChl8CM7uMc5VML7SqiQ0zG7+J5Vr+RMQDoHa2CNT6KHUnTGIXH34UDMkPzAUyapBZg==} engines: {node: '>=8'} + text-decoder@1.2.3: + resolution: {integrity: sha512-3/o9z3X0X0fTupwsYvR03pJ/DjWuqqrfwBgTQzdWDiQSm9KitAyz/9WqsT2JQW7KV2m+bC2ol/zqpW37NHxLaA==} + tinybench@2.9.0: resolution: {integrity: sha512-0+DUvqWMValLmha6lr4kD8iAMK1HzV0/aKnCtWb9v9641TnP/MFb7Pc2bxoxQjTXAErryXVgUOfv2YqNllqGeg==} @@ -1850,8 +2094,11 @@ packages: resolution: {integrity: sha512-3KS2b+kL7fsuk/eJZ7EQdnEmQoaho/r6KUef7hxvltNA5DR8NAUM+8wJMbJyZ4G9/7i3v5zPBIMN5aybAh2/Jg==} engines: {node: '>= 0.4'} - typescript-eslint@8.23.0: - resolution: {integrity: sha512-/LBRo3HrXr5LxmrdYSOCvoAMm7p2jNizNfbIpCgvG4HMsnoprRUOce/+8VJ9BDYWW68rqIENE/haVLWPeFZBVQ==} + typed-query-selector@2.12.0: + resolution: {integrity: sha512-SbklCd1F0EiZOyPiW192rrHZzZ5sBijB6xM+cpmrwDqObvdtunOHHIk9fCGsoK5JVIYXoyEp4iEdE3upFH3PAg==} + + typescript-eslint@8.24.0: + resolution: {integrity: sha512-/lmv4366en/qbB32Vz5+kCNZEMf6xYHwh1z48suBwZvAtnXKbP+YhGe8OLE2BqC67LMqKkCNLtjejdwsdW6uOQ==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} peerDependencies: eslint: ^8.57.0 || ^9.0.0 @@ -1885,27 +2132,22 @@ packages: engines: {node: ^18.0.0 || ^20.0.0 || >=22.0.0} hasBin: true - vite@6.1.0: - resolution: {integrity: sha512-RjjMipCKVoR4hVfPY6GQTgveinjNuyLw+qruksLDvA5ktI1150VmcMBKmQaEWJhg/j6Uaf6dNCNA0AfdzUb/hQ==} - engines: {node: ^18.0.0 || ^20.0.0 || >=22.0.0} + vite@5.4.14: + resolution: {integrity: sha512-EK5cY7Q1D8JNhSaPKVK4pwBFvaTmZxEnoKXLG/U9gmdDcihQGNzFlgIvaxezFR4glP1LsuiedwMBqCXH3wZccA==} + engines: {node: ^18.0.0 || >=20.0.0} hasBin: true peerDependencies: - '@types/node': ^18.0.0 || ^20.0.0 || >=22.0.0 - jiti: '>=1.21.0' + '@types/node': ^18.0.0 || >=20.0.0 less: '*' lightningcss: ^1.21.0 sass: '*' sass-embedded: '*' stylus: '*' sugarss: '*' - terser: ^5.16.0 - tsx: ^4.8.1 - yaml: ^2.4.2 + terser: ^5.4.0 peerDependenciesMeta: '@types/node': optional: true - jiti: - optional: true less: optional: true lightningcss: @@ -1920,10 +2162,6 @@ packages: optional: true terser: optional: true - tsx: - optional: true - yaml: - optional: true vitest@3.0.5: resolution: {integrity: sha512-4dof+HvqONw9bvsYxtkfUp2uHsTN9bV2CZIi1pWgoFpL1Lld8LA1ka9q/ONSsoScAKG7NVGf2stJTI7XRkXb2Q==} @@ -2001,6 +2239,21 @@ 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'} + peerDependencies: + bufferutil: ^4.0.1 + utf-8-validate: '>=5.0.2' + peerDependenciesMeta: + bufferutil: + optional: true + utf-8-validate: + optional: true + y18n@5.0.8: resolution: {integrity: sha512-0pfFzegeDWJHJIAmTLRP2DwHjdF5s7jo9tuztdQxAhINCdvS+3nGINqPd00AphqJR/0LhANUS6/+7SCb98YOfA==} engines: {node: '>=10'} @@ -2019,6 +2272,9 @@ packages: resolution: {integrity: sha512-7dSzzRQ++CKnNI/krKnYRV7JKKPUXMEh61soaHKg9mrWEhzFWhFnxPxGl+69cD1Ou63C13NUPCnmIcrvqCuM6w==} engines: {node: '>=12'} + yauzl@2.10.0: + resolution: {integrity: sha512-p4a9I6X6nu6IhoGmBqAcbJy1mlC4j27vEPZX9F4L4/vZT3Lyq1VkFHw/V/PUcB9Buo+DG3iHkT0x3Qya58zc3g==} + yocto-queue@0.1.0: resolution: {integrity: sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q==} engines: {node: '>=10'} @@ -2045,6 +2301,14 @@ snapshots: transitivePeerDependencies: - encoding + '@babel/code-frame@7.26.2': + dependencies: + '@babel/helper-validator-identifier': 7.25.9 + js-tokens: 4.0.0 + picocolors: 1.1.1 + + '@babel/helper-validator-identifier@7.25.9': {} + '@babel/runtime@7.26.7': dependencies: regenerator-runtime: 0.14.1 @@ -2191,84 +2455,78 @@ snapshots: human-id: 1.0.2 prettier: 2.8.8 - '@esbuild/aix-ppc64@0.24.2': - optional: true - - '@esbuild/android-arm64@0.24.2': - optional: true - - '@esbuild/android-arm@0.24.2': + '@esbuild/aix-ppc64@0.21.5': optional: true - '@esbuild/android-x64@0.24.2': + '@esbuild/android-arm64@0.21.5': optional: true - '@esbuild/darwin-arm64@0.24.2': + '@esbuild/android-arm@0.21.5': optional: true - '@esbuild/darwin-x64@0.24.2': + '@esbuild/android-x64@0.21.5': optional: true - '@esbuild/freebsd-arm64@0.24.2': + '@esbuild/darwin-arm64@0.21.5': optional: true - '@esbuild/freebsd-x64@0.24.2': + '@esbuild/darwin-x64@0.21.5': optional: true - '@esbuild/linux-arm64@0.24.2': + '@esbuild/freebsd-arm64@0.21.5': optional: true - '@esbuild/linux-arm@0.24.2': + '@esbuild/freebsd-x64@0.21.5': optional: true - '@esbuild/linux-ia32@0.24.2': + '@esbuild/linux-arm64@0.21.5': optional: true - '@esbuild/linux-loong64@0.24.2': + '@esbuild/linux-arm@0.21.5': optional: true - '@esbuild/linux-mips64el@0.24.2': + '@esbuild/linux-ia32@0.21.5': optional: true - '@esbuild/linux-ppc64@0.24.2': + '@esbuild/linux-loong64@0.21.5': optional: true - '@esbuild/linux-riscv64@0.24.2': + '@esbuild/linux-mips64el@0.21.5': optional: true - '@esbuild/linux-s390x@0.24.2': + '@esbuild/linux-ppc64@0.21.5': optional: true - '@esbuild/linux-x64@0.24.2': + '@esbuild/linux-riscv64@0.21.5': optional: true - '@esbuild/netbsd-arm64@0.24.2': + '@esbuild/linux-s390x@0.21.5': optional: true - '@esbuild/netbsd-x64@0.24.2': + '@esbuild/linux-x64@0.21.5': optional: true - '@esbuild/openbsd-arm64@0.24.2': + '@esbuild/netbsd-x64@0.21.5': optional: true - '@esbuild/openbsd-x64@0.24.2': + '@esbuild/openbsd-x64@0.21.5': optional: true - '@esbuild/sunos-x64@0.24.2': + '@esbuild/sunos-x64@0.21.5': optional: true - '@esbuild/win32-arm64@0.24.2': + '@esbuild/win32-arm64@0.21.5': optional: true - '@esbuild/win32-ia32@0.24.2': + '@esbuild/win32-ia32@0.21.5': optional: true - '@esbuild/win32-x64@0.24.2': + '@esbuild/win32-x64@0.21.5': optional: true - '@eslint-community/eslint-utils@4.4.1(eslint@9.20.0)': + '@eslint-community/eslint-utils@4.4.1(eslint@9.20.1)': dependencies: - eslint: 9.20.0 + eslint: 9.20.1 eslint-visitor-keys: 3.4.3 '@eslint-community/regexpp@4.12.1': {} @@ -2369,6 +2627,23 @@ snapshots: '@pkgr/core@0.1.1': {} + '@playwright/test@1.50.1': + dependencies: + playwright: 1.50.1 + + '@puppeteer/browsers@2.7.1': + dependencies: + debug: 4.4.0 + extract-zip: 2.0.1 + progress: 2.0.3 + proxy-agent: 6.5.0 + semver: 7.7.1 + tar-fs: 3.0.8 + yargs: 17.7.2 + transitivePeerDependencies: + - bare-buffer + - supports-color + '@rollup/rollup-android-arm-eabi@4.34.6': optional: true @@ -2428,6 +2703,8 @@ snapshots: '@rtsao/scc@1.1.0': {} + '@tootallnate/quickjs-emscripten@0.23.0': {} + '@types/estree@1.0.6': {} '@types/json-schema@7.0.15': {} @@ -2453,15 +2730,20 @@ snapshots: dependencies: '@types/yargs-parser': 21.0.3 - '@typescript-eslint/eslint-plugin@8.23.0(@typescript-eslint/parser@8.23.0(eslint@9.20.0)(typescript@5.7.3))(eslint@9.20.0)(typescript@5.7.3)': + '@types/yauzl@2.10.3': + dependencies: + '@types/node': 18.19.75 + optional: true + + '@typescript-eslint/eslint-plugin@8.24.0(@typescript-eslint/parser@8.24.0(eslint@9.20.1)(typescript@5.7.3))(eslint@9.20.1)(typescript@5.7.3)': dependencies: '@eslint-community/regexpp': 4.12.1 - '@typescript-eslint/parser': 8.23.0(eslint@9.20.0)(typescript@5.7.3) - '@typescript-eslint/scope-manager': 8.23.0 - '@typescript-eslint/type-utils': 8.23.0(eslint@9.20.0)(typescript@5.7.3) - '@typescript-eslint/utils': 8.23.0(eslint@9.20.0)(typescript@5.7.3) - '@typescript-eslint/visitor-keys': 8.23.0 - eslint: 9.20.0 + '@typescript-eslint/parser': 8.24.0(eslint@9.20.1)(typescript@5.7.3) + '@typescript-eslint/scope-manager': 8.24.0 + '@typescript-eslint/type-utils': 8.24.0(eslint@9.20.1)(typescript@5.7.3) + '@typescript-eslint/utils': 8.24.0(eslint@9.20.1)(typescript@5.7.3) + '@typescript-eslint/visitor-keys': 8.24.0 + eslint: 9.20.1 graphemer: 1.4.0 ignore: 5.3.2 natural-compare: 1.4.0 @@ -2470,40 +2752,40 @@ snapshots: transitivePeerDependencies: - supports-color - '@typescript-eslint/parser@8.23.0(eslint@9.20.0)(typescript@5.7.3)': + '@typescript-eslint/parser@8.24.0(eslint@9.20.1)(typescript@5.7.3)': dependencies: - '@typescript-eslint/scope-manager': 8.23.0 - '@typescript-eslint/types': 8.23.0 - '@typescript-eslint/typescript-estree': 8.23.0(typescript@5.7.3) - '@typescript-eslint/visitor-keys': 8.23.0 + '@typescript-eslint/scope-manager': 8.24.0 + '@typescript-eslint/types': 8.24.0 + '@typescript-eslint/typescript-estree': 8.24.0(typescript@5.7.3) + '@typescript-eslint/visitor-keys': 8.24.0 debug: 4.4.0 - eslint: 9.20.0 + eslint: 9.20.1 typescript: 5.7.3 transitivePeerDependencies: - supports-color - '@typescript-eslint/scope-manager@8.23.0': + '@typescript-eslint/scope-manager@8.24.0': dependencies: - '@typescript-eslint/types': 8.23.0 - '@typescript-eslint/visitor-keys': 8.23.0 + '@typescript-eslint/types': 8.24.0 + '@typescript-eslint/visitor-keys': 8.24.0 - '@typescript-eslint/type-utils@8.23.0(eslint@9.20.0)(typescript@5.7.3)': + '@typescript-eslint/type-utils@8.24.0(eslint@9.20.1)(typescript@5.7.3)': dependencies: - '@typescript-eslint/typescript-estree': 8.23.0(typescript@5.7.3) - '@typescript-eslint/utils': 8.23.0(eslint@9.20.0)(typescript@5.7.3) + '@typescript-eslint/typescript-estree': 8.24.0(typescript@5.7.3) + '@typescript-eslint/utils': 8.24.0(eslint@9.20.1)(typescript@5.7.3) debug: 4.4.0 - eslint: 9.20.0 + eslint: 9.20.1 ts-api-utils: 2.0.1(typescript@5.7.3) typescript: 5.7.3 transitivePeerDependencies: - supports-color - '@typescript-eslint/types@8.23.0': {} + '@typescript-eslint/types@8.24.0': {} - '@typescript-eslint/typescript-estree@8.23.0(typescript@5.7.3)': + '@typescript-eslint/typescript-estree@8.24.0(typescript@5.7.3)': dependencies: - '@typescript-eslint/types': 8.23.0 - '@typescript-eslint/visitor-keys': 8.23.0 + '@typescript-eslint/types': 8.24.0 + '@typescript-eslint/visitor-keys': 8.24.0 debug: 4.4.0 fast-glob: 3.3.3 is-glob: 4.0.3 @@ -2514,20 +2796,20 @@ snapshots: transitivePeerDependencies: - supports-color - '@typescript-eslint/utils@8.23.0(eslint@9.20.0)(typescript@5.7.3)': + '@typescript-eslint/utils@8.24.0(eslint@9.20.1)(typescript@5.7.3)': dependencies: - '@eslint-community/eslint-utils': 4.4.1(eslint@9.20.0) - '@typescript-eslint/scope-manager': 8.23.0 - '@typescript-eslint/types': 8.23.0 - '@typescript-eslint/typescript-estree': 8.23.0(typescript@5.7.3) - eslint: 9.20.0 + '@eslint-community/eslint-utils': 4.4.1(eslint@9.20.1) + '@typescript-eslint/scope-manager': 8.24.0 + '@typescript-eslint/types': 8.24.0 + '@typescript-eslint/typescript-estree': 8.24.0(typescript@5.7.3) + eslint: 9.20.1 typescript: 5.7.3 transitivePeerDependencies: - supports-color - '@typescript-eslint/visitor-keys@8.23.0': + '@typescript-eslint/visitor-keys@8.24.0': dependencies: - '@typescript-eslint/types': 8.23.0 + '@typescript-eslint/types': 8.24.0 eslint-visitor-keys: 4.2.0 '@vitest/expect@3.0.5': @@ -2537,13 +2819,13 @@ snapshots: chai: 5.1.2 tinyrainbow: 2.0.0 - '@vitest/mocker@3.0.5(vite@6.1.0(@types/node@18.19.75))': + '@vitest/mocker@3.0.5(vite@5.4.14(@types/node@18.19.75))': dependencies: '@vitest/spy': 3.0.5 estree-walker: 3.0.3 magic-string: 0.30.17 optionalDependencies: - vite: 6.1.0(@types/node@18.19.75) + vite: 5.4.14(@types/node@18.19.75) '@vitest/pretty-format@3.0.5': dependencies: @@ -2580,6 +2862,8 @@ snapshots: acorn@8.14.0: {} + agent-base@7.1.3: {} + agentkeepalive@4.6.0: dependencies: humanize-ms: 1.2.1 @@ -2660,6 +2944,10 @@ snapshots: assertion-error@2.0.1: {} + ast-types@0.13.4: + dependencies: + tslib: 2.8.1 + async-function@1.0.0: {} asynckit@0.4.0: {} @@ -2668,8 +2956,39 @@ snapshots: dependencies: possible-typed-array-names: 1.1.0 + b4a@1.6.7: {} + balanced-match@1.0.2: {} + bare-events@2.5.4: + optional: true + + bare-fs@4.0.1: + dependencies: + bare-events: 2.5.4 + bare-path: 3.0.0 + bare-stream: 2.6.5(bare-events@2.5.4) + transitivePeerDependencies: + - bare-buffer + optional: true + + bare-os@3.4.0: + optional: true + + bare-path@3.0.0: + dependencies: + bare-os: 3.4.0 + optional: true + + bare-stream@2.6.5(bare-events@2.5.4): + dependencies: + streamx: 2.22.0 + optionalDependencies: + bare-events: 2.5.4 + optional: true + + basic-ftp@5.0.5: {} + better-path-resolve@1.0.0: dependencies: is-windows: 1.0.2 @@ -2687,6 +3006,8 @@ snapshots: dependencies: fill-range: 7.1.1 + buffer-crc32@0.2.13: {} + buffer-from@1.1.2: {} cac@6.7.14: {} @@ -2729,6 +3050,12 @@ snapshots: check-error@2.1.1: {} + chromium-bidi@1.2.0(devtools-protocol@0.0.1402036): + dependencies: + devtools-protocol: 0.0.1402036 + mitt: 3.0.1 + zod: 3.24.1 + ci-info@3.9.0: {} cliui@8.0.1: @@ -2749,12 +3076,23 @@ snapshots: concat-map@0.0.1: {} + cosmiconfig@9.0.0(typescript@5.7.3): + dependencies: + env-paths: 2.2.1 + import-fresh: 3.3.1 + js-yaml: 4.1.0 + parse-json: 5.2.0 + optionalDependencies: + typescript: 5.7.3 + cross-spawn@7.0.6: dependencies: path-key: 3.1.1 shebang-command: 2.0.0 which: 2.0.2 + data-uri-to-buffer@6.0.2: {} + data-view-buffer@1.0.2: dependencies: call-bound: 1.0.3 @@ -2797,10 +3135,18 @@ 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: {} detect-indent@6.1.0: {} + devtools-protocol@0.0.1402036: {} + dir-glob@3.0.1: dependencies: path-type: 4.0.0 @@ -2823,11 +3169,21 @@ snapshots: emoji-regex@9.2.2: {} + end-of-stream@1.4.4: + dependencies: + once: 1.4.0 + enquirer@2.4.1: dependencies: ansi-colors: 4.1.3 strip-ansi: 6.0.1 + env-paths@2.2.1: {} + + error-ex@1.3.2: + dependencies: + is-arrayish: 0.2.1 + es-abstract@1.23.9: dependencies: array-buffer-byte-length: 1.0.2 @@ -2909,41 +3265,47 @@ snapshots: is-date-object: 1.1.0 is-symbol: 1.1.1 - esbuild@0.24.2: + esbuild@0.21.5: optionalDependencies: - '@esbuild/aix-ppc64': 0.24.2 - '@esbuild/android-arm': 0.24.2 - '@esbuild/android-arm64': 0.24.2 - '@esbuild/android-x64': 0.24.2 - '@esbuild/darwin-arm64': 0.24.2 - '@esbuild/darwin-x64': 0.24.2 - '@esbuild/freebsd-arm64': 0.24.2 - '@esbuild/freebsd-x64': 0.24.2 - '@esbuild/linux-arm': 0.24.2 - '@esbuild/linux-arm64': 0.24.2 - '@esbuild/linux-ia32': 0.24.2 - '@esbuild/linux-loong64': 0.24.2 - '@esbuild/linux-mips64el': 0.24.2 - '@esbuild/linux-ppc64': 0.24.2 - '@esbuild/linux-riscv64': 0.24.2 - '@esbuild/linux-s390x': 0.24.2 - '@esbuild/linux-x64': 0.24.2 - '@esbuild/netbsd-arm64': 0.24.2 - '@esbuild/netbsd-x64': 0.24.2 - '@esbuild/openbsd-arm64': 0.24.2 - '@esbuild/openbsd-x64': 0.24.2 - '@esbuild/sunos-x64': 0.24.2 - '@esbuild/win32-arm64': 0.24.2 - '@esbuild/win32-ia32': 0.24.2 - '@esbuild/win32-x64': 0.24.2 + '@esbuild/aix-ppc64': 0.21.5 + '@esbuild/android-arm': 0.21.5 + '@esbuild/android-arm64': 0.21.5 + '@esbuild/android-x64': 0.21.5 + '@esbuild/darwin-arm64': 0.21.5 + '@esbuild/darwin-x64': 0.21.5 + '@esbuild/freebsd-arm64': 0.21.5 + '@esbuild/freebsd-x64': 0.21.5 + '@esbuild/linux-arm': 0.21.5 + '@esbuild/linux-arm64': 0.21.5 + '@esbuild/linux-ia32': 0.21.5 + '@esbuild/linux-loong64': 0.21.5 + '@esbuild/linux-mips64el': 0.21.5 + '@esbuild/linux-ppc64': 0.21.5 + '@esbuild/linux-riscv64': 0.21.5 + '@esbuild/linux-s390x': 0.21.5 + '@esbuild/linux-x64': 0.21.5 + '@esbuild/netbsd-x64': 0.21.5 + '@esbuild/openbsd-x64': 0.21.5 + '@esbuild/sunos-x64': 0.21.5 + '@esbuild/win32-arm64': 0.21.5 + '@esbuild/win32-ia32': 0.21.5 + '@esbuild/win32-x64': 0.21.5 escalade@3.2.0: {} escape-string-regexp@4.0.0: {} - eslint-config-prettier@9.1.0(eslint@9.20.0): + escodegen@2.1.0: dependencies: - eslint: 9.20.0 + 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.20.1): + dependencies: + eslint: 9.20.1 eslint-import-resolver-node@0.3.9: dependencies: @@ -2953,17 +3315,17 @@ snapshots: transitivePeerDependencies: - supports-color - eslint-module-utils@2.12.0(@typescript-eslint/parser@8.23.0(eslint@9.20.0)(typescript@5.7.3))(eslint-import-resolver-node@0.3.9)(eslint@9.20.0): + eslint-module-utils@2.12.0(@typescript-eslint/parser@8.24.0(eslint@9.20.1)(typescript@5.7.3))(eslint-import-resolver-node@0.3.9)(eslint@9.20.1): dependencies: debug: 3.2.7 optionalDependencies: - '@typescript-eslint/parser': 8.23.0(eslint@9.20.0)(typescript@5.7.3) - eslint: 9.20.0 + '@typescript-eslint/parser': 8.24.0(eslint@9.20.1)(typescript@5.7.3) + eslint: 9.20.1 eslint-import-resolver-node: 0.3.9 transitivePeerDependencies: - supports-color - eslint-plugin-import@2.31.0(@typescript-eslint/parser@8.23.0(eslint@9.20.0)(typescript@5.7.3))(eslint@9.20.0): + eslint-plugin-import@2.31.0(@typescript-eslint/parser@8.24.0(eslint@9.20.1)(typescript@5.7.3))(eslint@9.20.1): dependencies: '@rtsao/scc': 1.1.0 array-includes: 3.1.8 @@ -2972,9 +3334,9 @@ snapshots: array.prototype.flatmap: 1.3.3 debug: 3.2.7 doctrine: 2.1.0 - eslint: 9.20.0 + eslint: 9.20.1 eslint-import-resolver-node: 0.3.9 - eslint-module-utils: 2.12.0(@typescript-eslint/parser@8.23.0(eslint@9.20.0)(typescript@5.7.3))(eslint-import-resolver-node@0.3.9)(eslint@9.20.0) + eslint-module-utils: 2.12.0(@typescript-eslint/parser@8.24.0(eslint@9.20.1)(typescript@5.7.3))(eslint-import-resolver-node@0.3.9)(eslint@9.20.1) hasown: 2.0.2 is-core-module: 2.16.1 is-glob: 4.0.3 @@ -2986,26 +3348,26 @@ snapshots: string.prototype.trimend: 1.0.9 tsconfig-paths: 3.15.0 optionalDependencies: - '@typescript-eslint/parser': 8.23.0(eslint@9.20.0)(typescript@5.7.3) + '@typescript-eslint/parser': 8.24.0(eslint@9.20.1)(typescript@5.7.3) transitivePeerDependencies: - eslint-import-resolver-typescript - eslint-import-resolver-webpack - supports-color - eslint-plugin-prettier@5.2.3(eslint-config-prettier@9.1.0(eslint@9.20.0))(eslint@9.20.0)(prettier@3.5.0): + eslint-plugin-prettier@5.2.3(eslint-config-prettier@9.1.0(eslint@9.20.1))(eslint@9.20.1)(prettier@3.5.0): dependencies: - eslint: 9.20.0 + eslint: 9.20.1 prettier: 3.5.0 prettier-linter-helpers: 1.0.0 synckit: 0.9.2 optionalDependencies: - eslint-config-prettier: 9.1.0(eslint@9.20.0) + eslint-config-prettier: 9.1.0(eslint@9.20.1) - eslint-plugin-unused-imports@4.1.4(@typescript-eslint/eslint-plugin@8.23.0(@typescript-eslint/parser@8.23.0(eslint@9.20.0)(typescript@5.7.3))(eslint@9.20.0)(typescript@5.7.3))(eslint@9.20.0): + eslint-plugin-unused-imports@4.1.4(@typescript-eslint/eslint-plugin@8.24.0(@typescript-eslint/parser@8.24.0(eslint@9.20.1)(typescript@5.7.3))(eslint@9.20.1)(typescript@5.7.3))(eslint@9.20.1): dependencies: - eslint: 9.20.0 + eslint: 9.20.1 optionalDependencies: - '@typescript-eslint/eslint-plugin': 8.23.0(@typescript-eslint/parser@8.23.0(eslint@9.20.0)(typescript@5.7.3))(eslint@9.20.0)(typescript@5.7.3) + '@typescript-eslint/eslint-plugin': 8.24.0(@typescript-eslint/parser@8.24.0(eslint@9.20.1)(typescript@5.7.3))(eslint@9.20.1)(typescript@5.7.3) eslint-scope@8.2.0: dependencies: @@ -3016,9 +3378,9 @@ snapshots: eslint-visitor-keys@4.2.0: {} - eslint@9.20.0: + eslint@9.20.1: dependencies: - '@eslint-community/eslint-utils': 4.4.1(eslint@9.20.0) + '@eslint-community/eslint-utils': 4.4.1(eslint@9.20.1) '@eslint-community/regexpp': 4.12.1 '@eslint/config-array': 0.19.2 '@eslint/core': 0.11.0 @@ -3091,10 +3453,22 @@ snapshots: iconv-lite: 0.4.24 tmp: 0.0.33 + 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@3.1.3: {} fast-diff@1.3.0: {} + fast-fifo@1.3.2: {} + fast-glob@3.3.3: dependencies: '@nodelib/fs.stat': 2.0.5 @@ -3111,6 +3485,10 @@ snapshots: dependencies: reusify: 1.0.4 + fd-slicer@1.1.0: + dependencies: + pend: 1.2.0 + file-entry-cache@8.0.0: dependencies: flat-cache: 4.0.1 @@ -3136,7 +3514,7 @@ snapshots: flatted@3.3.2: {} - for-each@0.3.4: + for-each@0.3.5: dependencies: is-callable: 1.2.7 @@ -3170,6 +3548,9 @@ snapshots: jsonfile: 4.0.0 universalify: 0.1.2 + fsevents@2.3.2: + optional: true + fsevents@2.3.3: optional: true @@ -3206,12 +3587,24 @@ snapshots: dunder-proto: 1.0.1 es-object-atoms: 1.1.1 + get-stream@5.2.0: + dependencies: + pump: 3.0.2 + get-symbol-description@1.1.0: dependencies: call-bound: 1.0.3 es-errors: 1.3.0 get-intrinsic: 1.2.7 + 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 @@ -3273,6 +3666,20 @@ snapshots: dependencies: function-bind: 1.1.2 + http-proxy-agent@7.0.2: + dependencies: + agent-base: 7.1.3 + debug: 4.4.0 + transitivePeerDependencies: + - supports-color + + https-proxy-agent@7.0.6: + dependencies: + agent-base: 7.1.3 + debug: 4.4.0 + transitivePeerDependencies: + - supports-color + human-id@1.0.2: {} humanize-ms@1.2.1: @@ -3298,12 +3705,19 @@ snapshots: 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 call-bound: 1.0.3 get-intrinsic: 1.2.7 + is-arrayish@0.2.1: {} + is-async-function@2.1.1: dependencies: async-function: 1.0.0 @@ -3421,6 +3835,8 @@ snapshots: optionalDependencies: '@pkgjs/parseargs': 0.11.0 + js-tokens@4.0.0: {} + js-yaml@3.14.1: dependencies: argparse: 1.0.10 @@ -3430,8 +3846,12 @@ snapshots: dependencies: argparse: 2.0.1 + jsbn@1.1.0: {} + json-buffer@3.0.1: {} + json-parse-even-better-errors@2.3.1: {} + json-schema-traverse@0.4.1: {} json-stable-stringify-without-jsonify@1.0.1: {} @@ -3453,6 +3873,8 @@ snapshots: prelude-ls: 1.2.1 type-check: 0.4.0 + lines-and-columns@1.2.4: {} + locate-path@5.0.0: dependencies: p-locate: 4.1.0 @@ -3469,6 +3891,8 @@ snapshots: lru-cache@10.4.3: {} + lru-cache@7.18.3: {} + magic-string@0.30.17: dependencies: '@jridgewell/sourcemap-codec': 1.5.0 @@ -3500,6 +3924,8 @@ snapshots: minipass@7.1.2: {} + mitt@3.0.1: {} + mri@1.2.0: {} ms@2.1.3: {} @@ -3508,6 +3934,8 @@ snapshots: natural-compare@1.4.0: {} + netmask@2.0.2: {} + node-domexception@1.0.0: {} node-fetch@2.7.0: @@ -3547,6 +3975,10 @@ snapshots: define-properties: 1.2.1 es-object-atoms: 1.1.1 + once@1.4.0: + dependencies: + wrappy: 1.0.2 + optionator@0.9.4: dependencies: deep-is: 0.1.4 @@ -3590,6 +4022,24 @@ snapshots: p-try@2.2.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.9: {} @@ -3598,6 +4048,13 @@ snapshots: dependencies: callsites: 3.1.0 + parse-json@5.2.0: + dependencies: + '@babel/code-frame': 7.26.2 + error-ex: 1.3.2 + json-parse-even-better-errors: 2.3.1 + lines-and-columns: 1.2.4 + path-exists@4.0.0: {} path-key@3.1.1: {} @@ -3615,15 +4072,25 @@ snapshots: pathval@2.0.0: {} + pend@1.2.0: {} + picocolors@1.1.1: {} picomatch@2.3.1: {} pify@4.0.1: {} + playwright-core@1.50.1: {} + + playwright@1.50.1: + dependencies: + playwright-core: 1.50.1 + optionalDependencies: + fsevents: 2.3.2 + possible-typed-array-names@1.1.0: {} - postcss@8.5.1: + postcss@8.5.2: dependencies: nanoid: 3.3.8 picocolors: 1.1.1 @@ -3639,8 +4106,59 @@ snapshots: prettier@3.5.0: {} + progress@2.0.3: {} + + 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: {} + puppeteer-core@24.2.0: + dependencies: + '@puppeteer/browsers': 2.7.1 + chromium-bidi: 1.2.0(devtools-protocol@0.0.1402036) + debug: 4.4.0 + devtools-protocol: 0.0.1402036 + typed-query-selector: 2.12.0 + ws: 8.18.0 + transitivePeerDependencies: + - bare-buffer + - bufferutil + - supports-color + - utf-8-validate + + puppeteer@24.2.0(typescript@5.7.3): + dependencies: + '@puppeteer/browsers': 2.7.1 + chromium-bidi: 1.2.0(devtools-protocol@0.0.1402036) + cosmiconfig: 9.0.0(typescript@5.7.3) + devtools-protocol: 0.0.1402036 + puppeteer-core: 24.2.0 + typed-query-selector: 2.12.0 + transitivePeerDependencies: + - bare-buffer + - bufferutil + - supports-color + - typescript + - utf-8-validate + queue-microtask@1.2.3: {} read-yaml-file@1.1.0: @@ -3806,6 +4324,21 @@ snapshots: slash@3.0.0: {} + smart-buffer@4.2.0: {} + + socks-proxy-agent@8.0.5: + dependencies: + agent-base: 7.1.3 + debug: 4.4.0 + socks: 2.8.4 + transitivePeerDependencies: + - supports-color + + socks@2.8.4: + dependencies: + ip-address: 9.0.5 + smart-buffer: 4.2.0 + source-map-js@1.2.1: {} source-map-support@0.5.21: @@ -3822,10 +4355,19 @@ snapshots: sprintf-js@1.0.3: {} + sprintf-js@1.1.3: {} + stackback@0.0.2: {} std-env@3.8.0: {} + streamx@2.22.0: + dependencies: + fast-fifo: 1.3.2 + text-decoder: 1.2.3 + optionalDependencies: + bare-events: 2.5.4 + string-width@4.2.3: dependencies: emoji-regex: 8.0.0 @@ -3884,8 +4426,28 @@ snapshots: '@pkgr/core': 0.1.1 tslib: 2.8.1 + tar-fs@3.0.8: + dependencies: + pump: 3.0.2 + tar-stream: 3.1.7 + optionalDependencies: + bare-fs: 4.0.1 + bare-path: 3.0.0 + transitivePeerDependencies: + - bare-buffer + + tar-stream@3.1.7: + dependencies: + b4a: 1.6.7 + fast-fifo: 1.3.2 + streamx: 2.22.0 + term-size@2.2.1: {} + text-decoder@1.2.3: + dependencies: + b4a: 1.6.7 + tinybench@2.9.0: {} tinyexec@0.3.2: {} @@ -3934,7 +4496,7 @@ snapshots: typed-array-byte-length@1.0.3: dependencies: call-bind: 1.0.8 - for-each: 0.3.4 + for-each: 0.3.5 gopd: 1.2.0 has-proto: 1.2.0 is-typed-array: 1.1.15 @@ -3943,7 +4505,7 @@ snapshots: dependencies: available-typed-arrays: 1.0.7 call-bind: 1.0.8 - for-each: 0.3.4 + for-each: 0.3.5 gopd: 1.2.0 has-proto: 1.2.0 is-typed-array: 1.1.15 @@ -3952,18 +4514,20 @@ snapshots: typed-array-length@1.0.7: dependencies: call-bind: 1.0.8 - for-each: 0.3.4 + for-each: 0.3.5 gopd: 1.2.0 is-typed-array: 1.1.15 possible-typed-array-names: 1.1.0 reflect.getprototypeof: 1.0.10 - typescript-eslint@8.23.0(eslint@9.20.0)(typescript@5.7.3): + typed-query-selector@2.12.0: {} + + typescript-eslint@8.24.0(eslint@9.20.1)(typescript@5.7.3): dependencies: - '@typescript-eslint/eslint-plugin': 8.23.0(@typescript-eslint/parser@8.23.0(eslint@9.20.0)(typescript@5.7.3))(eslint@9.20.0)(typescript@5.7.3) - '@typescript-eslint/parser': 8.23.0(eslint@9.20.0)(typescript@5.7.3) - '@typescript-eslint/utils': 8.23.0(eslint@9.20.0)(typescript@5.7.3) - eslint: 9.20.0 + '@typescript-eslint/eslint-plugin': 8.24.0(@typescript-eslint/parser@8.24.0(eslint@9.20.1)(typescript@5.7.3))(eslint@9.20.1)(typescript@5.7.3) + '@typescript-eslint/parser': 8.24.0(eslint@9.20.1)(typescript@5.7.3) + '@typescript-eslint/utils': 8.24.0(eslint@9.20.1)(typescript@5.7.3) + eslint: 9.20.1 typescript: 5.7.3 transitivePeerDependencies: - supports-color @@ -3993,10 +4557,9 @@ snapshots: debug: 4.4.0 es-module-lexer: 1.6.0 pathe: 2.0.2 - vite: 6.1.0(@types/node@18.19.75) + vite: 5.4.14(@types/node@18.19.75) transitivePeerDependencies: - '@types/node' - - jiti - less - lightningcss - sass @@ -4005,13 +4568,11 @@ snapshots: - sugarss - supports-color - terser - - tsx - - yaml - vite@6.1.0(@types/node@18.19.75): + vite@5.4.14(@types/node@18.19.75): dependencies: - esbuild: 0.24.2 - postcss: 8.5.1 + esbuild: 0.21.5 + postcss: 8.5.2 rollup: 4.34.6 optionalDependencies: '@types/node': 18.19.75 @@ -4020,7 +4581,7 @@ snapshots: vitest@3.0.5(@types/node@18.19.75): dependencies: '@vitest/expect': 3.0.5 - '@vitest/mocker': 3.0.5(vite@6.1.0(@types/node@18.19.75)) + '@vitest/mocker': 3.0.5(vite@5.4.14(@types/node@18.19.75)) '@vitest/pretty-format': 3.0.5 '@vitest/runner': 3.0.5 '@vitest/snapshot': 3.0.5 @@ -4036,13 +4597,12 @@ snapshots: tinyexec: 0.3.2 tinypool: 1.0.2 tinyrainbow: 2.0.0 - vite: 6.1.0(@types/node@18.19.75) + vite: 5.4.14(@types/node@18.19.75) vite-node: 3.0.5(@types/node@18.19.75) why-is-node-running: 2.3.0 optionalDependencies: '@types/node': 18.19.75 transitivePeerDependencies: - - jiti - less - lightningcss - msw @@ -4052,8 +4612,6 @@ snapshots: - sugarss - supports-color - terser - - tsx - - yaml web-streams-polyfill@4.0.0-beta.3: {} @@ -4100,7 +4658,7 @@ snapshots: available-typed-arrays: 1.0.7 call-bind: 1.0.8 call-bound: 1.0.3 - for-each: 0.3.4 + for-each: 0.3.5 gopd: 1.2.0 has-tostringtag: 1.0.2 @@ -4127,6 +4685,10 @@ snapshots: string-width: 5.1.2 strip-ansi: 7.1.0 + wrappy@1.0.2: {} + + ws@8.18.0: {} + y18n@5.0.8: {} yargs-file-commands@0.0.17(yargs@17.7.2): @@ -4145,6 +4707,11 @@ snapshots: y18n: 5.0.8 yargs-parser: 21.1.1 + yauzl@2.10.0: + dependencies: + buffer-crc32: 0.2.13 + fd-slicer: 1.1.0 + yocto-queue@0.1.0: {} zod-to-json-schema@3.24.1(zod@3.24.1): diff --git a/src/tools/browser/BrowserAutomation.ts b/src/tools/browser/BrowserAutomation.ts new file mode 100644 index 0000000..5c19c72 --- /dev/null +++ b/src/tools/browser/BrowserAutomation.ts @@ -0,0 +1,39 @@ +import { BrowserManager } from "./browser-manager.js"; +import { PageController } from "./page-controller.js"; +import { ScreenshotController } from "./screenshot.js"; + +export class BrowserAutomation { + private static instance: BrowserAutomation; + private browserManager: BrowserManager; + + private constructor() { + this.browserManager = new BrowserManager(); + } + + static getInstance(): BrowserAutomation { + if (!BrowserAutomation.instance) { + BrowserAutomation.instance = new BrowserAutomation(); + } + return BrowserAutomation.instance; + } + + async createSession(headless: boolean = false) { + const session = await this.browserManager.createSession({ headless }); + const pageController = new PageController(session.page); + const screenshotManager = new ScreenshotController(session.page); + + return { + sessionId: session.id, + pageController, + screenshotManager, + close: () => this.browserManager.closeSession(session.id), + }; + } + + async cleanup() { + await this.browserManager.closeAllSessions(); + } +} + +// Export singleton instance +export const browserAutomation = BrowserAutomation.getInstance(); diff --git a/src/tools/browser/browseMessage.ts b/src/tools/browser/browseMessage.ts new file mode 100644 index 0000000..34ad279 --- /dev/null +++ b/src/tools/browser/browseMessage.ts @@ -0,0 +1,164 @@ +import { Tool } from '../../core/types.js'; +import { z } from 'zod'; +import { zodToJsonSchema } from 'zod-to-json-schema'; +import { browserSessions, type BrowserAction, SelectorType, type ScreenshotOptions } from './types.js'; + +// Schema for browser action options +const screenshotOptionsSchema = z.object({ + path: z.string().optional(), + fullPage: z.boolean().optional(), + type: z.enum(['png', 'jpeg']).optional(), + quality: z.number().min(0).max(100).optional(), +}).optional(); + +// Schema for browser action +const browserActionSchema = z.object({ + type: z.enum(['goto', 'click', 'type', 'wait', 'screenshot', 'content', 'close']), + url: z.string().url().optional(), + selector: z.string().optional(), + selectorType: z.nativeEnum(SelectorType).optional(), + text: z.string().optional(), + options: screenshotOptionsSchema, +}).describe('Browser action to perform'); + +// Main parameter schema +const parameterSchema = z.object({ + instanceId: z.string().describe('The ID returned by browseStart'), + action: browserActionSchema, + description: z.string().max(80).describe('The reason for this browser action (max 80 chars)'), +}); + +// Return schema +const returnSchema = z.object({ + status: z.string(), + content: z.string().optional(), + screenshot: z.string().optional(), + error: z.string().optional(), +}); + +type Parameters = z.infer; +type ReturnType = z.infer; + +// Helper function to handle selectors +const getSelector = (selector: string, type?: SelectorType): string => { + switch (type) { + case SelectorType.XPATH: + return `xpath=${selector}`; + case SelectorType.TEXT: + return `text=${selector}`; + default: + return selector; // CSS selector is default + } +}; + +export const browseMessageTool: Tool = { + name: 'browseMessage', + description: 'Performs actions in an active browser session', + parameters: zodToJsonSchema(parameterSchema), + returns: zodToJsonSchema(returnSchema), + + execute: async ({ instanceId, action }, { logger }): Promise => { + logger.verbose(`Executing browser action: ${action.type}`); + + try { + const session = browserSessions.get(instanceId); + if (!session) { + throw new Error(`No browser session found with ID ${instanceId}`); + } + + const { page } = session; + + switch (action.type) { + case 'goto': { + if (!action.url) { + throw new Error('URL required for goto action'); + } + await page.goto(action.url, { waitUntil: 'networkidle' }); + const content = await page.content(); + logger.verbose('Navigation completed successfully'); + return { status: 'success', content }; + } + + case 'click': { + if (!action.selector) { + throw new Error('Selector required for click action'); + } + const clickSelector = getSelector(action.selector, action.selectorType); + await page.click(clickSelector); + const content = await page.content(); + logger.verbose(`Click action completed on selector: ${clickSelector}`); + return { status: 'success', content }; + } + + case 'type': { + if (!action.selector || !action.text) { + throw new Error('Selector and text required for type action'); + } + const typeSelector = getSelector(action.selector, action.selectorType); + await page.fill(typeSelector, action.text); + logger.verbose(`Type action completed on selector: ${typeSelector}`); + return { status: 'success' }; + } + + case 'wait': { + if (!action.selector) { + throw new Error('Selector required for wait action'); + } + const waitSelector = getSelector(action.selector, action.selectorType); + await page.waitForSelector(waitSelector); + logger.verbose(`Wait action completed for selector: ${waitSelector}`); + return { status: 'success' }; + } + + case 'screenshot': { + const screenshotBuffer = await page.screenshot({ + ...action.options, + type: 'png', + }); + const screenshotBase64 = screenshotBuffer.toString('base64'); + logger.verbose('Screenshot captured successfully'); + return { status: 'success', screenshot: screenshotBase64 }; + } + + case 'content': { + const content = await page.content(); + logger.verbose('Page content retrieved successfully'); + return { status: 'success', content }; + } + + case 'close': { + await session.page.context().close(); + await session.browser.close(); + browserSessions.delete(instanceId); + logger.verbose('Browser session closed successfully'); + return { status: 'closed' }; + } + + default: { + throw new Error(`Unsupported action type: ${(action as BrowserAction).type}`); + } + } + + } catch (error) { + logger.error('Browser action failed:', { error }); + return { + status: 'error', + error: error instanceof Error ? error.message : String(error), + }; + } + }, + + logParameters: ({ action, description }, { logger }) => { + logger.info( + `Performing browser action: ${action.type}, ${description}`, + ); + }, + + logReturns: (output, { logger }) => { + if (output.error) { + logger.error(`Browser action failed: ${output.error}`); + } else { + logger.info(`Browser action completed with status: ${output.status}`); + } + }, +}; diff --git a/src/tools/browser/browseStart.ts b/src/tools/browser/browseStart.ts new file mode 100644 index 0000000..24b12e0 --- /dev/null +++ b/src/tools/browser/browseStart.ts @@ -0,0 +1,104 @@ +import { Tool } from '../../core/types.js'; +import { z } from 'zod'; +import { zodToJsonSchema } from 'zod-to-json-schema'; +import { v4 as uuidv4 } from 'uuid'; +import { chromium } from '@playwright/test'; +import { browserSessions, type BrowserError, BrowserErrorCode } from './types.js'; + +const parameterSchema = z.object({ + url: z.string().url().optional().describe('Initial URL to navigate to'), + headless: z.boolean().optional().describe('Run browser in headless mode (default: true)'), + timeout: z.number().optional().describe('Default timeout in milliseconds (default: 30000)'), + description: z.string().max(80).describe('The reason for starting this browser session (max 80 chars)'), +}); + +const returnSchema = z.object({ + instanceId: z.string(), + status: z.string(), + content: z.string().optional(), + error: z.string().optional(), +}); + +type Parameters = z.infer; +type ReturnType = z.infer; + +export const browseStartTool: Tool = { + name: 'browseStart', + description: 'Starts a new browser session with optional initial URL', + parameters: zodToJsonSchema(parameterSchema), + returns: zodToJsonSchema(returnSchema), + + execute: async ({ url, headless = true, timeout = 30000 }, { logger }): Promise => { + logger.verbose(`Starting browser session${url ? ` at ${url}` : ''}`); + + try { + const instanceId = uuidv4(); + + // Launch browser + const browser = await chromium.launch({ + headless + }); + + // Create new context with default settings + const context = await browser.newContext({ + viewport: null, + userAgent: 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/91.0.4472.124 Safari/537.36' + }); + + // Create new page + const page = await context.newPage(); + page.setDefaultTimeout(timeout); + + // Initialize browser session + const session = { + browser, + page, + id: instanceId, + }; + + browserSessions.set(instanceId, session); + + // Setup cleanup handlers + browser.on('disconnected', () => { + browserSessions.delete(instanceId); + }); + + // Navigate to URL if provided + let content = ''; + if (url) { + await page.goto(url, { waitUntil: 'networkidle' }); + content = await page.content(); + } + + logger.verbose('Browser session started successfully'); + + return { + instanceId, + status: 'initialized', + content: content || undefined, + }; + + } catch (error) { + logger.error(`Failed to start browser: ${error}`); + return { + instanceId: '', + status: 'error', + error: error instanceof Error ? error.message : String(error), + }; + } + }, + + logParameters: ({ url, description }, { logger }) => { + logger.info( + `Starting browser session${url ? ` at ${url}` : ''}, ${description}`, + ); + }, + + logReturns: (output, { logger }) => { + if (output.error) { + logger.error(`Browser start failed: ${output.error}`); + } else { + logger.info(`Browser session started with ID: ${output.instanceId}`); + } + }, +}; diff --git a/src/tools/browser/browser-manager.ts b/src/tools/browser/browser-manager.ts new file mode 100644 index 0000000..105083e --- /dev/null +++ b/src/tools/browser/browser-manager.ts @@ -0,0 +1,109 @@ +import { chromium } from '@playwright/test'; +import { v4 as uuidv4 } from 'uuid'; +import { + BrowserConfig, + BrowserSession, + BrowserError, + BrowserErrorCode, +} from './types.js'; + +export class BrowserManager { + private sessions: Map = new Map(); + private readonly defaultConfig: BrowserConfig = { + headless: false, + defaultTimeout: 30000, + }; + + async createSession(config?: BrowserConfig): Promise { + try { + const sessionConfig = { ...this.defaultConfig, ...config }; + const browser = await chromium.launch({ + headless: sessionConfig.headless, + }); + + // Create a new context (equivalent to Puppeteer's incognito context) + const context = await browser.newContext({ + viewport: null, + userAgent: 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/91.0.4472.124 Safari/537.36' + }); + + const page = await context.newPage(); + page.setDefaultTimeout(sessionConfig.defaultTimeout ?? 1000); + + const session: BrowserSession = { + browser, + page, + id: uuidv4(), + }; + + this.sessions.set(session.id, session); + this.setupCleanup(session); + + return session; + } catch (error) { + throw new BrowserError( + 'Failed to create browser session', + BrowserErrorCode.LAUNCH_FAILED, + error + ); + } + } + + async closeSession(sessionId: string): Promise { + const session = this.sessions.get(sessionId); + if (!session) { + throw new BrowserError( + 'Session not found', + BrowserErrorCode.SESSION_ERROR + ); + } + + try { + // In Playwright, we should close the context which will automatically close its pages + await session.page.context().close(); + await session.browser.close(); + this.sessions.delete(sessionId); + } catch (error) { + throw new BrowserError( + 'Failed to close session', + BrowserErrorCode.SESSION_ERROR, + error + ); + } + } + + private setupCleanup(session: BrowserSession): void { + // Handle browser disconnection + session.browser.on('disconnected', () => { + this.sessions.delete(session.id); + }); + + // Handle process exit + process.on('exit', () => { + this.closeSession(session.id).catch(() => {}); + }); + + // Handle unexpected errors + process.on('uncaughtException', () => { + this.closeSession(session.id).catch(() => {}); + }); + } + + async closeAllSessions(): Promise { + const closePromises = Array.from(this.sessions.keys()).map((sessionId) => + this.closeSession(sessionId).catch(() => {}) + ); + await Promise.all(closePromises); + } + + getSession(sessionId: string): BrowserSession { + const session = this.sessions.get(sessionId); + if (!session) { + throw new BrowserError( + 'Session not found', + BrowserErrorCode.SESSION_ERROR + ); + } + return session; + } +} \ No newline at end of file diff --git a/src/tools/browser/page-controller.ts b/src/tools/browser/page-controller.ts new file mode 100644 index 0000000..21a0d11 --- /dev/null +++ b/src/tools/browser/page-controller.ts @@ -0,0 +1,115 @@ +import { Page } from '@playwright/test'; +import { + SelectorType, + SelectorOptions, + BrowserError, + BrowserErrorCode, +} from './types.js'; + +export class PageController { + constructor(private page: Page) {} + + private getSelector(selector: string, type: SelectorType = SelectorType.CSS): string { + switch (type) { + case SelectorType.XPATH: + return `xpath=${selector}`; + case SelectorType.TEXT: + return `text=${selector}`; + case SelectorType.ROLE: + return `role=${selector}`; + case SelectorType.TESTID: + return `[data-testid="${selector}"]`; + default: + return selector; + } + } + + private validateSelector(selector: string, type: SelectorType): void { + if (!selector) { + throw new BrowserError( + 'Invalid selector: empty string', + BrowserErrorCode.SELECTOR_INVALID + ); + } + } + + async waitForSelector( + selector: string, + options: SelectorOptions = {} + ): Promise { + this.validateSelector(selector, options.type || SelectorType.CSS); + try { + const locator = this.page.locator( + this.getSelector(selector, options.type) + ); + await locator.waitFor({ + state: options.visible ? 'visible' : 'attached', + timeout: options.timeout, + }); + } catch (error) { + throw new BrowserError( + `Failed to find element: ${error}`, + BrowserErrorCode.ELEMENT_NOT_FOUND, + error + ); + } + } + + async click( + selector: string, + options: SelectorOptions = {} + ): Promise { + this.validateSelector(selector, options.type || SelectorType.CSS); + try { + const locator = this.page.locator( + this.getSelector(selector, options.type) + ); + await locator.click({ timeout: options.timeout }); + } catch (error) { + throw new BrowserError( + `Failed to click element: ${error}`, + BrowserErrorCode.SELECTOR_ERROR, + error + ); + } + } + + async type( + selector: string, + text: string, + options: SelectorOptions = {} + ): Promise { + this.validateSelector(selector, options.type || SelectorType.CSS); + try { + const locator = this.page.locator( + this.getSelector(selector, options.type) + ); + await locator.fill(text, { timeout: options.timeout }); + } catch (error) { + throw new BrowserError( + `Failed to type text: ${error}`, + BrowserErrorCode.SELECTOR_ERROR, + error + ); + } + } + + async getText( + selector: string, + options: SelectorOptions = {} + ): Promise { + this.validateSelector(selector, options.type || SelectorType.CSS); + try { + const locator = this.page.locator( + this.getSelector(selector, options.type) + ); + return await locator.textContent() || ''; + } catch (error) { + throw new BrowserError( + `Failed to get text: ${error}`, + BrowserErrorCode.SELECTOR_ERROR, + error + ); + } + } +} diff --git a/src/tools/browser/screenshot.ts b/src/tools/browser/screenshot.ts new file mode 100644 index 0000000..13275f3 --- /dev/null +++ b/src/tools/browser/screenshot.ts @@ -0,0 +1,69 @@ +import { Page } from '@playwright/test'; +import { + SelectorType, + ScreenshotOptions, + BrowserError, + BrowserErrorCode, +} from './types.js'; + +export class ScreenshotController { + constructor(private page: Page) {} + + async takeFullPageScreenshot( + options: ScreenshotOptions = {} + ): Promise { + try { + return await this.page.screenshot({ + fullPage: true, + type: options.type || 'png', + quality: options.type === 'jpeg' ? options.quality : undefined, + path: options.path, + }); + } catch (error) { + throw new BrowserError( + `Failed to take full page screenshot: ${error}`, + BrowserErrorCode.SCREENSHOT_FAILED, + error + ); + } + } + + async takeElementScreenshot( + selector: string, + options: ScreenshotOptions = {} + ): Promise { + try { + const element = this.page.locator(selector); + return await element.screenshot({ + type: options.type || 'png', + quality: options.type === 'jpeg' ? options.quality : undefined, + path: options.path, + }); + } catch (error) { + throw new BrowserError( + `Failed to take element screenshot: ${error}`, + BrowserErrorCode.SCREENSHOT_FAILED, + error + ); + } + } + + async takeViewportScreenshot( + options: ScreenshotOptions = {} + ): Promise { + try { + return await this.page.screenshot({ + fullPage: false, + type: options.type || 'png', + quality: options.type === 'jpeg' ? options.quality : undefined, + path: options.path, + }); + } catch (error) { + throw new BrowserError( + `Failed to take viewport screenshot: ${error}`, + BrowserErrorCode.SCREENSHOT_FAILED, + error + ); + } + } +} diff --git a/src/tools/browser/types.ts b/src/tools/browser/types.ts new file mode 100644 index 0000000..4ca2e8f --- /dev/null +++ b/src/tools/browser/types.ts @@ -0,0 +1,77 @@ +import type { Browser, Page, BrowserContext } from '@playwright/test'; + +// Browser configuration +export interface BrowserConfig { + headless?: boolean; + defaultTimeout?: number; +} + +// Browser session +export interface BrowserSession { + browser: Browser; + page: Page; + id: string; +} + +// Browser error codes +export enum BrowserErrorCode { + LAUNCH_FAILED = 'LAUNCH_FAILED', + NAVIGATION_FAILED = 'NAVIGATION_FAILED', + SESSION_ERROR = 'SESSION_ERROR', + SELECTOR_ERROR = 'SELECTOR_ERROR', + TIMEOUT = 'TIMEOUT', + UNKNOWN = 'UNKNOWN', + SELECTOR_INVALID = 'SELECTOR_INVALID', + ELEMENT_NOT_FOUND = 'ELEMENT_NOT_FOUND', + SCREENSHOT_FAILED = 'SCREENSHOT_FAILED' +} + +// Browser error class +export class BrowserError extends Error { + constructor( + message: string, + public code: BrowserErrorCode, + public cause?: unknown + ) { + super(message); + this.name = 'BrowserError'; + } +} + +// Selector types for element interaction +export enum SelectorType { + CSS = 'css', + XPATH = 'xpath', + TEXT = 'text', + ROLE = 'role', + TESTID = 'testid' +} + +// Selector options +export interface SelectorOptions { + type?: SelectorType; + timeout?: number; + visible?: boolean; +} + +// Screenshot options +export interface ScreenshotOptions { + path?: string; + fullPage?: boolean; + type?: 'png' | 'jpeg'; + quality?: number; + scale?: number; +} + +// Global map to store browser sessions +export const browserSessions: Map = new Map(); + +// Browser action types +export type BrowserAction = + | { type: 'goto'; url: string } + | { type: 'click'; selector: string; selectorType?: SelectorType } + | { type: 'type'; selector: string; text: string; selectorType?: SelectorType } + | { type: 'wait'; selector: string; selectorType?: SelectorType } + | { type: 'screenshot'; options?: ScreenshotOptions } + | { type: 'content' } + | { type: 'close' }; diff --git a/src/tools/getTools.ts b/src/tools/getTools.ts index 32133b7..f881862 100644 --- a/src/tools/getTools.ts +++ b/src/tools/getTools.ts @@ -7,17 +7,20 @@ import { Tool } from "../core/types.js"; import { updateFileTool } from "./io/updateFile.js"; import { shellStartTool } from "./system/shellStart.js"; import { shellMessageTool } from "./system/shellMessage.js"; +import { browseStartTool } from "./browser/browseStart.js"; +import { browseMessageTool } from "./browser/browseMessage.js"; export async function getTools(): Promise { return [ subAgentTool, readFileTool, updateFileTool, - //shellExecuteTool, - remove for now. userPromptTool, sequenceCompleteTool, fetchTool, shellStartTool, shellMessageTool, + browseStartTool, + browseMessageTool, ] as Tool[]; } diff --git a/src/tools/index.ts b/src/tools/index.ts new file mode 100644 index 0000000..c997287 --- /dev/null +++ b/src/tools/index.ts @@ -0,0 +1,18 @@ +// Browser tools +export { browseStartTool } from './browser/browseStart.js'; +export { browseMessageTool } from './browser/browseMessage.js'; + +// Shell tools +export { shellStartTool } from './system/shellStart.js'; +export { shellMessageTool } from './system/shellMessage.js'; + +// IO tools +export { readFileTool } from './io/readFile.js'; +export { updateFileTool } from './io/updateFile.js'; +export { fetchTool } from './io/fetch.js'; + +// System tools +export { sequenceCompleteTool } from './system/sequenceComplete.js'; + +// Interaction tools +export { subAgentTool } from './interaction/subAgent.js'; diff --git a/src/types/browser.ts b/src/types/browser.ts new file mode 100644 index 0000000..99f6d62 --- /dev/null +++ b/src/types/browser.ts @@ -0,0 +1,38 @@ +import { z } from 'zod'; + +export const BrowseStartSchema = z.object({ + headless: z.boolean().optional().default(true), + description: z.string().max(80), +}); + +export type BrowseStartParams = z.infer; + +export const SelectorTypeSchema = z.enum(['css', 'xpath']); + +export const BrowseActionSchema = z.discriminatedUnion('action', [ + z.object({ + action: z.literal('navigate'), + url: z.string().url(), + }), + z.object({ + action: z.literal('click'), + selector: z.string(), + selectorType: SelectorTypeSchema, + }), + z.object({ + action: z.literal('type'), + selector: z.string(), + selectorType: SelectorTypeSchema, + text: z.string(), + }), +]); + +export const BrowseMessageSchema = z.object({ + instanceId: z.string(), + description: z.string().max(80), + action: BrowseActionSchema.optional(), + takeScreenshot: z.boolean().optional().default(false), + endSession: z.boolean().optional().default(false), +}); + +export type BrowseMessageParams = z.infer; diff --git a/tests/browser/browser-manager.test.ts b/tests/browser/browser-manager.test.ts new file mode 100644 index 0000000..9bda81b --- /dev/null +++ b/tests/browser/browser-manager.test.ts @@ -0,0 +1,74 @@ +import { BrowserManager } from '../../src/tools/browser/browser-manager'; +import { BrowserError, BrowserErrorCode } from '../../src/tools/browser/types'; + +describe('BrowserManager', () => { + let browserManager: BrowserManager; + + beforeEach(() => { + browserManager = new BrowserManager(); + }); + + afterEach(async () => { + await browserManager.closeAllSessions(); + }); + + describe('createSession', () => { + it('should create a new browser session', async () => { + const session = await browserManager.createSession(); + expect(session.id).toBeDefined(); + expect(session.browser).toBeDefined(); + expect(session.page).toBeDefined(); + }); + + it('should create a headless session when specified', async () => { + const session = await browserManager.createSession({ headless: true }); + expect(session.id).toBeDefined(); + // Additional headless mode checks could be added here + }); + + it('should apply custom timeout when specified', async () => { + const customTimeout = 50000; + const session = await browserManager.createSession({ + defaultTimeout: customTimeout + }); + expect(session.page.getDefaultTimeout()).toBe(customTimeout); + }); + }); + + describe('closeSession', () => { + it('should close an existing session', async () => { + const session = await browserManager.createSession(); + await browserManager.closeSession(session.id); + + expect(() => { + browserManager.getSession(session.id); + }).toThrow(BrowserError); + }); + + it('should throw error when closing non-existent session', async () => { + await expect(browserManager.closeSession('invalid-id')) + .rejects + .toThrow(new BrowserError( + 'Session not found', + BrowserErrorCode.SESSION_ERROR + )); + }); + }); + + describe('getSession', () => { + it('should return existing session', async () => { + const session = await browserManager.createSession(); + const retrieved = browserManager.getSession(session.id); + expect(retrieved).toBe(session); + }); + + it('should throw error for non-existent session', () => { + expect(() => { + browserManager.getSession('invalid-id'); + }).toThrow(new BrowserError( + 'Session not found', + BrowserErrorCode.SESSION_ERROR + )); + }); + }); +}); \ No newline at end of file diff --git a/tsconfig.json b/tsconfig.json index 2014b8f..6dced66 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -3,7 +3,7 @@ "target": "ES2022", "module": "ES2022", "moduleResolution": "node", - "lib": ["ES2022"], + "lib": ["ES2022", "DOM", "DOM.Iterable"], "typeRoots": ["./node_modules/@types"], "outDir": "./dist", @@ -24,7 +24,7 @@ "noUncheckedIndexedAccess": true, // Module Resolution - "esModuleInterop": false, + "esModuleInterop": true, "resolveJsonModule": true, // Source Map Support From ab30fb8080dd03753a0351a560fa117d9cb4a390 Mon Sep 17 00:00:00 2001 From: Ben Houston Date: Tue, 11 Feb 2025 21:59:18 -0500 Subject: [PATCH 3/3] Fix the linux cli and add a test to ensure it doesn't break again in the future. --- CHANGELOG.md | 6 ++++++ bin/cli.js | 4 ++-- package.json | 3 +-- tests/cli.test.ts | 10 ++++++++++ vitest.config.ts | 2 +- 5 files changed, 20 insertions(+), 5 deletions(-) create mode 100644 tests/cli.test.ts diff --git a/CHANGELOG.md b/CHANGELOG.md index 843cc02..5093313 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,11 @@ # mycoder +## 0.0.17 + +### Patch Changes + +- Fix the linux cli and add a test to ensure it doesn't break again. + ## 0.0.16 ### Patch Changes diff --git a/bin/cli.js b/bin/cli.js index 4723cb7..de77d7f 100755 --- a/bin/cli.js +++ b/bin/cli.js @@ -1,2 +1,2 @@ -#!/usr/bin/env node --no-deprecation -import "../dist/index.js"; +#!/usr/bin/env node +import "../dist/index.js"; \ No newline at end of file diff --git a/package.json b/package.json index 41cfca7..b45c677 100644 --- a/package.json +++ b/package.json @@ -1,7 +1,7 @@ { "name": "mycoder", "description": "A command line tool using agent that can do arbitrary tasks, including coding tasks", - "version": "0.0.16", + "version": "0.0.17", "type": "module", "bin": "./bin/cli.js", "main": "./dist/index.js", @@ -53,7 +53,6 @@ "chalk": "^5", "dotenv": "^16", "playwright": "^1.50.1", - "source-map-support": "^0.5", "uuid": "^11", "yargs": "^17", diff --git a/tests/cli.test.ts b/tests/cli.test.ts new file mode 100644 index 0000000..94a2fe9 --- /dev/null +++ b/tests/cli.test.ts @@ -0,0 +1,10 @@ +import { expect, test, describe } from 'vitest' +import { execSync } from 'child_process' +import { version } from '../package.json' + +describe('CLI', () => { + test('version command outputs correct version', () => { + const output = execSync('node ./bin/cli.js --version').toString() + expect(output.trim()).toContain(version) + }) +}) \ No newline at end of file diff --git a/vitest.config.ts b/vitest.config.ts index 2c53493..6692410 100644 --- a/vitest.config.ts +++ b/vitest.config.ts @@ -2,7 +2,7 @@ import { defineConfig } from "vitest/config"; export default defineConfig({ test: { - include: ["src/**/*.test.ts"], + include: ["src/**/*.test.ts", "tests/**/*.test.ts"], environment: "node", globals: true, },