From 86ba26b754257dbf1b107fe2d6c6a723e3f9e508 Mon Sep 17 00:00:00 2001 From: Adil Date: Sun, 15 Jun 2025 23:01:49 +0500 Subject: [PATCH 01/13] feat(cli): add pipe support and improve data handling --- src/cli.ts | 129 ++++++++++++++++++++++++++++++++++++++++------------- 1 file changed, 97 insertions(+), 32 deletions(-) diff --git a/src/cli.ts b/src/cli.ts index 5f1a9e7..dd6d67a 100644 --- a/src/cli.ts +++ b/src/cli.ts @@ -1,3 +1,5 @@ +#!/usr/bin/env node + import * as path from 'path'; import * as fs from 'fs'; import { program } from 'commander'; @@ -6,46 +8,109 @@ import { OHLCV, IOHLCV } from './types'; program .description('Resample OHLCV between timeframes and file formats') - .option('-i, --input ', 'Input file path (csv, json)') - .option('-n, --name ', 'Output file name') - .option('-f, --format ', 'Output file format (csv, json)') - .option('-p, --placeholder', '') - ; + .option('-i, --input ', 'Input file path (csv, json) or use pipe') + .option('-o, --output ', 'Output file path (csv, json) or use pipe') + .option('-f, --format ', 'Output file format (csv, json)', 'csv') + .version('1.2.1'); program.parse(); program.showHelpAfterError(); const options = program.opts(); -(() => { - - const inFormat = path.extname(options.input).slice(1).toLowerCase(); - const inPath = path.resolve(options.input); +async function processInput(input: string | NodeJS.ReadableStream): Promise { + if (typeof input === 'string') { + const inFormat = path.extname(input).slice(1).toLowerCase(); + if (!['csv', 'json'].includes(inFormat)) { + throw new Error('Only CSV and JSON files are accepted as input'); + } - if (!['csv', 'json'].includes(inFormat)) { - program.error('Only CSV and JSON files are accepted as input'); - return; + const inPath = path.resolve(input); + const inBuffer = fs.readFileSync(inPath); + + if (inFormat === 'csv') { + return new Promise((resolve, reject) => { + const results: IOHLCV[] = []; + fs.createReadStream(inPath) + .pipe(csv.parse({ headers: true })) + .on('data', (row) => { + results.push({ + time: Number(row.time), + open: Number(row.open), + high: Number(row.high), + low: Number(row.low), + close: Number(row.close), + volume: Number(row.volume) + }); + }) + .on('end', () => resolve(results)) + .on('error', reject); + }); + } else { + return JSON.parse(inBuffer.toString()); + } + } else { + // Handle pipe input + return new Promise((resolve, reject) => { + const results: IOHLCV[] = []; + input + .pipe(csv.parse({ headers: true })) + .on('data', (row) => { + results.push({ + time: Number(row.time), + open: Number(row.open), + high: Number(row.high), + low: Number(row.low), + close: Number(row.close), + volume: Number(row.volume) + }); + }) + .on('end', () => resolve(results)) + .on('error', reject); + }); } +} - const inBuffer = fs.readFileSync(inPath); - const inStream = fs.createReadStream(inPath, { - start: 0 - }); - - if (inFormat === 'csv') { - csv.parseStream(inStream) - .on('data', (row) => { - console.log(row); - }) - .end(() => { - console.log("end"); - }); +async function main() { + try { + let input: string | NodeJS.ReadableStream; + + if (process.stdin.isTTY) { + // Read from file + if (!options.input) { + program.error('Input file is required when not using pipe'); + return; + } + input = options.input; + } else { + // Read from pipe + input = process.stdin; + } - // const data = inStream - // .pipe(csv.parse({ headers: true })); - } - if (inFormat === 'json') { - //@ts-ignore - const data: IOHLCV[] = JSON.parse(inBuffer); + const data = await processInput(input); + + // TODO: Process data (resample) + + // Output handling + if (options.output) { + const outStream = fs.createWriteStream(options.output); + if (options.format === 'csv') { + csv.write(data, { headers: true }).pipe(outStream); + } else { + outStream.write(JSON.stringify(data, null, 2)); + } + } else { + // Output to stdout + if (options.format === 'csv') { + csv.write(data, { headers: true }).pipe(process.stdout); + } else { + console.log(JSON.stringify(data, null, 2)); + } + } + } catch (error: unknown) { + console.error('Error:', error instanceof Error ? error.message : String(error)); + process.exit(1); } -})(); \ No newline at end of file +} + +main(); \ No newline at end of file From d8e0f4dad1d5e1a513fec89450076fc16d32ded9 Mon Sep 17 00:00:00 2001 From: Adil Date: Sun, 15 Jun 2025 23:07:13 +0500 Subject: [PATCH 02/13] test(cli): add comprehensive test cases for CLI functionality --- __tests__/cli.ts | 150 +++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 150 insertions(+) create mode 100644 __tests__/cli.ts diff --git a/__tests__/cli.ts b/__tests__/cli.ts new file mode 100644 index 0000000..e66705a --- /dev/null +++ b/__tests__/cli.ts @@ -0,0 +1,150 @@ +import * as fs from 'fs'; +import * as path from 'path'; +import { exec } from 'child_process'; +import { promisify } from 'util'; + +const execAsync = promisify(exec); + +describe('CLI', () => { + const cliPath = path.resolve(__dirname, '../dist/cli.js'); + const testDataDir = path.resolve(__dirname, 'fixtures'); + + // Create test data directory if it doesn't exist + if (!fs.existsSync(testDataDir)) { + fs.mkdirSync(testDataDir); + } + + // Sample OHLCV data + const sampleData = [ + { time: 1609459200000, open: 100, high: 105, low: 95, close: 102, volume: 1000 }, + { time: 1609462800000, open: 102, high: 107, low: 101, close: 106, volume: 1200 }, + { time: 1609466400000, open: 106, high: 108, low: 104, close: 105, volume: 800 } + ]; + + // Create test files + const csvFile = path.join(testDataDir, 'test.csv'); + const jsonFile = path.join(testDataDir, 'test.json'); + + beforeAll(() => { + // Write test data to files + fs.writeFileSync(csvFile, 'time,open,high,low,close,volume\n' + + sampleData.map(row => Object.values(row).join(',')).join('\n')); + fs.writeFileSync(jsonFile, JSON.stringify(sampleData, null, 2)); + }); + + afterAll(() => { + // Clean up test files + fs.unlinkSync(csvFile); + fs.unlinkSync(jsonFile); + fs.rmdirSync(testDataDir); + }); + + describe('File Input', () => { + test('should read CSV file', async () => { + const { stdout } = await execAsync(`node ${cliPath} -i ${csvFile}`); + const output = JSON.parse(stdout); + expect(output).toHaveLength(3); + expect(output[0]).toHaveProperty('time', 1609459200000); + }); + + test('should read JSON file', async () => { + const { stdout } = await execAsync(`node ${cliPath} -i ${jsonFile}`); + const output = JSON.parse(stdout); + expect(output).toHaveLength(3); + expect(output[0]).toHaveProperty('time', 1609459200000); + }); + + test('should handle invalid file format', async () => { + const invalidFile = path.join(testDataDir, 'test.txt'); + fs.writeFileSync(invalidFile, 'invalid data'); + + try { + await execAsync(`node ${cliPath} -i ${invalidFile}`); + fail('Should have thrown an error'); + } catch (error) { + expect(error.message).toContain('Only CSV and JSON files are accepted'); + } + + fs.unlinkSync(invalidFile); + }); + }); + + describe('Pipe Input', () => { + test('should read from pipe', async () => { + const { stdout } = await execAsync(`cat ${csvFile} | node ${cliPath}`); + const output = JSON.parse(stdout); + expect(output).toHaveLength(3); + expect(output[0]).toHaveProperty('time', 1609459200000); + }); + }); + + describe('Output Format', () => { + const outputFile = path.join(testDataDir, 'output'); + + afterEach(() => { + if (fs.existsSync(outputFile)) { + fs.unlinkSync(outputFile); + } + }); + + test('should write CSV output', async () => { + await execAsync(`node ${cliPath} -i ${jsonFile} -o ${outputFile} -f csv`); + const content = fs.readFileSync(outputFile, 'utf8'); + expect(content).toContain('time,open,high,low,close,volume'); + expect(content.split('\n')).toHaveLength(4); // header + 3 rows + }); + + test('should write JSON output', async () => { + await execAsync(`node ${cliPath} -i ${csvFile} -o ${outputFile} -f json`); + const content = JSON.parse(fs.readFileSync(outputFile, 'utf8')); + expect(content).toHaveLength(3); + expect(content[0]).toHaveProperty('time', 1609459200000); + }); + + test('should write to stdout when no output file specified', async () => { + const { stdout } = await execAsync(`node ${cliPath} -i ${jsonFile}`); + const output = JSON.parse(stdout); + expect(output).toHaveLength(3); + expect(output[0]).toHaveProperty('time', 1609459200000); + }); + }); + + describe('Error Handling', () => { + test('should handle missing input file', async () => { + try { + await execAsync(`node ${cliPath} -i nonexistent.csv`); + fail('Should have thrown an error'); + } catch (error) { + expect(error.message).toContain('no such file or directory'); + } + }); + + test('should handle invalid JSON', async () => { + const invalidJsonFile = path.join(testDataDir, 'invalid.json'); + fs.writeFileSync(invalidJsonFile, '{invalid json'); + + try { + await execAsync(`node ${cliPath} -i ${invalidJsonFile}`); + fail('Should have thrown an error'); + } catch (error) { + expect(error.message).toContain('Unexpected token'); + } + + fs.unlinkSync(invalidJsonFile); + }); + + test('should handle invalid CSV', async () => { + const invalidCsvFile = path.join(testDataDir, 'invalid.csv'); + fs.writeFileSync(invalidCsvFile, 'invalid,csv,data\n1,2,3'); + + try { + await execAsync(`node ${cliPath} -i ${invalidCsvFile}`); + fail('Should have thrown an error'); + } catch (error) { + expect(error.message).toContain('Error'); + } + + fs.unlinkSync(invalidCsvFile); + }); + }); +}); \ No newline at end of file From 7c91fc35a2113fd90c2bbbd0a0e419720791dfb6 Mon Sep 17 00:00:00 2001 From: Adil Date: Sun, 15 Jun 2025 23:09:21 +0500 Subject: [PATCH 03/13] feat(cli): integrate resampling functionality --- __tests__/cli.ts | 38 ++++++++++++++++++++++++++++++++++++++ src/cli.ts | 25 ++++++++++++++++++++----- 2 files changed, 58 insertions(+), 5 deletions(-) diff --git a/__tests__/cli.ts b/__tests__/cli.ts index e66705a..6244a95 100644 --- a/__tests__/cli.ts +++ b/__tests__/cli.ts @@ -147,4 +147,42 @@ describe('CLI', () => { fs.unlinkSync(invalidCsvFile); }); }); + + describe('Resampling', () => { + test('should resample data with default timeframes', async () => { + const { stdout } = await execAsync(`node ${cliPath} -i ${csvFile}`); + const output = JSON.parse(stdout); + expect(output).toHaveLength(1); // 3 minutes of 1-minute data resampled to 5 minutes + expect(output[0]).toHaveProperty('time'); + expect(output[0]).toHaveProperty('open'); + expect(output[0]).toHaveProperty('high'); + expect(output[0]).toHaveProperty('low'); + expect(output[0]).toHaveProperty('close'); + expect(output[0]).toHaveProperty('volume'); + }); + + test('should resample data with custom timeframes', async () => { + const { stdout } = await execAsync(`node ${cliPath} -i ${csvFile} -b 60 -n 120`); + const output = JSON.parse(stdout); + expect(output).toHaveLength(2); // 3 minutes of 1-minute data resampled to 2 minutes + }); + + test('should handle invalid timeframe values', async () => { + try { + await execAsync(`node ${cliPath} -i ${csvFile} -b invalid -n 300`); + fail('Should have thrown an error'); + } catch (error) { + expect(error.message).toContain('Timeframes must be valid numbers'); + } + }); + + test('should handle invalid timeframe relationship', async () => { + try { + await execAsync(`node ${cliPath} -i ${csvFile} -b 300 -n 60`); + fail('Should have thrown an error'); + } catch (error) { + expect(error.message).toContain('New timeframe must be greater than base timeframe'); + } + }); + }); }); \ No newline at end of file diff --git a/src/cli.ts b/src/cli.ts index dd6d67a..b28c8af 100644 --- a/src/cli.ts +++ b/src/cli.ts @@ -5,12 +5,15 @@ import * as fs from 'fs'; import { program } from 'commander'; import * as csv from 'fast-csv'; import { OHLCV, IOHLCV } from './types'; +import { resampleOhlcv } from './lib'; program .description('Resample OHLCV between timeframes and file formats') .option('-i, --input ', 'Input file path (csv, json) or use pipe') .option('-o, --output ', 'Output file path (csv, json) or use pipe') .option('-f, --format ', 'Output file format (csv, json)', 'csv') + .option('-b, --base-timeframe ', 'Base timeframe in seconds', '60') + .option('-n, --new-timeframe ', 'New timeframe in seconds', '300') .version('1.2.1'); program.parse(); @@ -89,22 +92,34 @@ async function main() { const data = await processInput(input); - // TODO: Process data (resample) + // Resample the data + const baseTimeframe = parseInt(options.baseTimeframe, 10); + const newTimeframe = parseInt(options.newTimeframe, 10); + + if (isNaN(baseTimeframe) || isNaN(newTimeframe)) { + throw new Error('Timeframes must be valid numbers'); + } + + if (newTimeframe <= baseTimeframe) { + throw new Error('New timeframe must be greater than base timeframe'); + } + + const resampledData = resampleOhlcv(data, { baseTimeframe, newTimeframe }) as IOHLCV[]; // Output handling if (options.output) { const outStream = fs.createWriteStream(options.output); if (options.format === 'csv') { - csv.write(data, { headers: true }).pipe(outStream); + csv.write(resampledData, { headers: true }).pipe(outStream); } else { - outStream.write(JSON.stringify(data, null, 2)); + outStream.write(JSON.stringify(resampledData, null, 2)); } } else { // Output to stdout if (options.format === 'csv') { - csv.write(data, { headers: true }).pipe(process.stdout); + csv.write(resampledData, { headers: true }).pipe(process.stdout); } else { - console.log(JSON.stringify(data, null, 2)); + console.log(JSON.stringify(resampledData, null, 2)); } } } catch (error: unknown) { From 7eb4387f549593de2add66299f3a0e71a6b17abf Mon Sep 17 00:00:00 2001 From: Adil Date: Sun, 15 Jun 2025 23:20:16 +0500 Subject: [PATCH 04/13] chore: bump version to 1.3.0 --- package.json | 2 +- src/cli.ts | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/package.json b/package.json index ebd0653..a5c0b4a 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "ohlc-resample", - "version": "1.2.1", + "version": "1.3.0", "description": "Resample (inter-convert) trade, ticks or OHLCV data to different time frames, includes CLI", "main": "dist/index.js", "engines": { diff --git a/src/cli.ts b/src/cli.ts index b28c8af..b888e91 100644 --- a/src/cli.ts +++ b/src/cli.ts @@ -14,7 +14,7 @@ program .option('-f, --format ', 'Output file format (csv, json)', 'csv') .option('-b, --base-timeframe ', 'Base timeframe in seconds', '60') .option('-n, --new-timeframe ', 'New timeframe in seconds', '300') - .version('1.2.1'); + .version('1.3.0'); program.parse(); program.showHelpAfterError(); From 5e9fbe9c84b83be812e5a69c2ee981366387aebf Mon Sep 17 00:00:00 2001 From: Adil Date: Sun, 15 Jun 2025 23:32:26 +0500 Subject: [PATCH 05/13] chore: remove unused test data files --- README.md | 72 +++++++++++++++++++++++++++++++++++++++++++++++++++++++ csv.csv | 2 -- 2 files changed, 72 insertions(+), 2 deletions(-) delete mode 100644 csv.csv diff --git a/README.md b/README.md index c81eebf..452e918 100644 --- a/README.md +++ b/README.md @@ -176,6 +176,78 @@ const tickChart = resampleTicksByCount(airbnb_ticks, { }); ``` +## CLI Usage + +The package includes a command-line interface for resampling OHLCV data. You can use it directly with `npx`: + +```sh +npx ohlc-resample [options] +``` + +### Options + +- `-i, --input `: Input file path (CSV or JSON) or use pipe +- `-o, --output `: Output file path (CSV or JSON) or use pipe +- `-f, --format `: Output format (csv or json), defaults to csv +- `-b, --base-timeframe `: Base timeframe in seconds, defaults to 60 +- `-n, --new-timeframe `: New timeframe in seconds, defaults to 300 +- `-V, --version`: Show version number +- `-h, --help`: Show help + +### Examples + +**Read from file and output to stdout:** +```sh +npx ohlc-resample -i data.csv +``` + +**Read from file and write to file:** +```sh +npx ohlc-resample -i data.csv -o resampled.json -f json +``` + +**Use pipe for input:** +```sh +cat data.csv | npx ohlc-resample +``` + +**Use pipe for output:** +```sh +npx ohlc-resample -i data.csv | grep "2023" +``` + +**Custom timeframes:** +```sh +npx ohlc-resample -i data.csv -b 60 -n 300 +``` + +### Input Format + +The CLI accepts both CSV and JSON input formats: + +**CSV Format:** +```csv +time,open,high,low,close,volume +1609459200000,100,105,95,102,1000 +1609462800000,102,107,101,106,1200 +``` + +**JSON Format:** +```json +[ + { + "time": 1609459200000, + "open": 100, + "high": 105, + "low": 95, + "close": 102, + "volume": 1000 + } +] +``` + +Note: All timestamps must be in milliseconds. + ## Contributors 👤 **Adil Shaikh (https://adils.me)** diff --git a/csv.csv b/csv.csv deleted file mode 100644 index 6e47ae9..0000000 --- a/csv.csv +++ /dev/null @@ -1,2 +0,0 @@ -1,2,3,5,6 -1,5,4,6,7 From f6ddebdb1353ba178999006115ccff04697ccaee Mon Sep 17 00:00:00 2001 From: Adil Date: Sun, 15 Jun 2025 23:37:26 +0500 Subject: [PATCH 06/13] feat(cli): add format detection for pipe input --- README.md | 100 +++++++++++++----------- __tests__/cli.ts | 197 +++++++++++++++++++++++++++++++++++------------ src/cli.ts | 59 +++++++++++--- 3 files changed, 250 insertions(+), 106 deletions(-) diff --git a/README.md b/README.md index 452e918..de4bf2b 100644 --- a/README.md +++ b/README.md @@ -178,61 +178,33 @@ const tickChart = resampleTicksByCount(airbnb_ticks, { ## CLI Usage -The package includes a command-line interface for resampling OHLCV data. You can use it directly with `npx`: +The package includes a command-line interface for resampling OHLCV data between timeframes and file formats. -```sh -npx ohlc-resample [options] -``` +### Basic Usage -### Options +```bash +# Resample CSV file with default timeframes (1m -> 5m) +ohlc-resample -i input.csv -- `-i, --input `: Input file path (CSV or JSON) or use pipe -- `-o, --output `: Output file path (CSV or JSON) or use pipe -- `-f, --format `: Output format (csv or json), defaults to csv -- `-b, --base-timeframe `: Base timeframe in seconds, defaults to 60 -- `-n, --new-timeframe `: New timeframe in seconds, defaults to 300 -- `-V, --version`: Show version number -- `-h, --help`: Show help - -### Examples +# Resample JSON file with custom timeframes +ohlc-resample -i input.json -b 60 -n 300 -**Read from file and output to stdout:** -```sh -npx ohlc-resample -i data.csv -``` - -**Read from file and write to file:** -```sh -npx ohlc-resample -i data.csv -o resampled.json -f json +# Save output to file +ohlc-resample -i input.csv -o output.json -f json ``` -**Use pipe for input:** -```sh -cat data.csv | npx ohlc-resample -``` - -**Use pipe for output:** -```sh -npx ohlc-resample -i data.csv | grep "2023" -``` - -**Custom timeframes:** -```sh -npx ohlc-resample -i data.csv -b 60 -n 300 -``` +### Input Formats -### Input Format +The CLI supports both CSV and JSON input formats: -The CLI accepts both CSV and JSON input formats: - -**CSV Format:** +#### CSV Format ```csv time,open,high,low,close,volume 1609459200000,100,105,95,102,1000 -1609462800000,102,107,101,106,1200 +1609459260000,102,107,101,106,1200 ``` -**JSON Format:** +#### JSON Format ```json [ { @@ -246,7 +218,49 @@ time,open,high,low,close,volume ] ``` -Note: All timestamps must be in milliseconds. +### Pipe Input + +You can pipe data into the CLI from other commands. The format is automatically detected, or you can specify it: + +```bash +# Auto-detect format +cat data.json | ohlc-resample +cat data.csv | ohlc-resample + +# Force specific format +cat data.json | ohlc-resample --input-format json +cat data.csv | ohlc-resample --input-format csv +``` + +### Options + +- `-i, --input `: Input file path (CSV or JSON) +- `-o, --output `: Output file path (optional, defaults to stdout) +- `-f, --format `: Output format (csv or json, default: csv) +- `-if, --input-format `: Input format when using pipe (csv, json, or auto, default: auto) +- `-b, --base-timeframe `: Base timeframe in seconds (default: 60) +- `-n, --new-timeframe `: New timeframe in seconds (default: 300) +- `-h, --help`: Display help information +- `-V, --version`: Display version information + +### Examples + +```bash +# Resample 1-minute data to 5-minute candles +ohlc-resample -i data.csv + +# Resample 1-minute data to 15-minute candles +ohlc-resample -i data.csv -b 60 -n 900 + +# Convert CSV to JSON +ohlc-resample -i data.csv -o data.json -f json + +# Pipe CSV data and save as JSON +cat data.csv | ohlc-resample -o output.json -f json + +# Pipe JSON data with forced format +cat data.json | ohlc-resample --input-format json -o output.csv -f csv +``` ## Contributors diff --git a/__tests__/cli.ts b/__tests__/cli.ts index 6244a95..629e848 100644 --- a/__tests__/cli.ts +++ b/__tests__/cli.ts @@ -1,65 +1,72 @@ import * as fs from 'fs'; import * as path from 'path'; +import * as os from 'os'; import { exec } from 'child_process'; import { promisify } from 'util'; +import { IOHLCV } from '../src/types'; const execAsync = promisify(exec); describe('CLI', () => { - const cliPath = path.resolve(__dirname, '../dist/cli.js'); - const testDataDir = path.resolve(__dirname, 'fixtures'); - - // Create test data directory if it doesn't exist - if (!fs.existsSync(testDataDir)) { - fs.mkdirSync(testDataDir); - } - - // Sample OHLCV data - const sampleData = [ - { time: 1609459200000, open: 100, high: 105, low: 95, close: 102, volume: 1000 }, - { time: 1609462800000, open: 102, high: 107, low: 101, close: 106, volume: 1200 }, - { time: 1609466400000, open: 106, high: 108, low: 104, close: 105, volume: 800 } - ]; - - // Create test files - const csvFile = path.join(testDataDir, 'test.csv'); - const jsonFile = path.join(testDataDir, 'test.json'); + let tempDir: string; + let testData: IOHLCV[]; + let csvPath: string; + let jsonPath: string; beforeAll(() => { - // Write test data to files - fs.writeFileSync(csvFile, 'time,open,high,low,close,volume\n' + - sampleData.map(row => Object.values(row).join(',')).join('\n')); - fs.writeFileSync(jsonFile, JSON.stringify(sampleData, null, 2)); + // Create test data + testData = [ + { time: 1609459200000, open: 100, high: 105, low: 95, close: 102, volume: 1000 }, + { time: 1609459260000, open: 102, high: 107, low: 101, close: 106, volume: 1200 }, + { time: 1609459320000, open: 106, high: 108, low: 104, close: 105, volume: 800 }, + { time: 1609459380000, open: 105, high: 106, low: 103, close: 104, volume: 900 }, + { time: 1609459440000, open: 104, high: 105, low: 102, close: 103, volume: 1100 } + ]; }); - afterAll(() => { - // Clean up test files - fs.unlinkSync(csvFile); - fs.unlinkSync(jsonFile); - fs.rmdirSync(testDataDir); + beforeEach(async () => { + // Create temp directory + tempDir = await fs.promises.mkdtemp(path.join(os.tmpdir(), 'ohlc-resample-test-')); + + // Create test files + csvPath = path.join(tempDir, 'test.csv'); + jsonPath = path.join(tempDir, 'test.json'); + + // Write CSV file + const csvContent = 'time,open,high,low,close,volume\n' + + testData.map(d => `${d.time},${d.open},${d.high},${d.low},${d.close},${d.volume}`).join('\n'); + await fs.promises.writeFile(csvPath, csvContent); + + // Write JSON file + await fs.promises.writeFile(jsonPath, JSON.stringify(testData, null, 2)); + }); + + afterEach(async () => { + // Clean up temp directory + await fs.promises.rm(tempDir, { recursive: true, force: true }); }); describe('File Input', () => { test('should read CSV file', async () => { - const { stdout } = await execAsync(`node ${cliPath} -i ${csvFile}`); + const { stdout } = await execAsync(`node dist/cli.js -i ${csvPath}`); const output = JSON.parse(stdout); - expect(output).toHaveLength(3); + expect(output).toHaveLength(5); expect(output[0]).toHaveProperty('time', 1609459200000); }); test('should read JSON file', async () => { - const { stdout } = await execAsync(`node ${cliPath} -i ${jsonFile}`); + const { stdout } = await execAsync(`node dist/cli.js -i ${jsonPath}`); const output = JSON.parse(stdout); - expect(output).toHaveLength(3); + expect(output).toHaveLength(5); expect(output[0]).toHaveProperty('time', 1609459200000); }); test('should handle invalid file format', async () => { - const invalidFile = path.join(testDataDir, 'test.txt'); + const invalidFile = path.join(tempDir, 'test.txt'); fs.writeFileSync(invalidFile, 'invalid data'); try { - await execAsync(`node ${cliPath} -i ${invalidFile}`); + await execAsync(`node dist/cli.js -i ${invalidFile}`); fail('Should have thrown an error'); } catch (error) { expect(error.message).toContain('Only CSV and JSON files are accepted'); @@ -71,15 +78,15 @@ describe('CLI', () => { describe('Pipe Input', () => { test('should read from pipe', async () => { - const { stdout } = await execAsync(`cat ${csvFile} | node ${cliPath}`); + const { stdout } = await execAsync(`cat ${csvPath} | node dist/cli.js`); const output = JSON.parse(stdout); - expect(output).toHaveLength(3); + expect(output).toHaveLength(5); expect(output[0]).toHaveProperty('time', 1609459200000); }); }); describe('Output Format', () => { - const outputFile = path.join(testDataDir, 'output'); + const outputFile = path.join(tempDir, 'output'); afterEach(() => { if (fs.existsSync(outputFile)) { @@ -88,23 +95,23 @@ describe('CLI', () => { }); test('should write CSV output', async () => { - await execAsync(`node ${cliPath} -i ${jsonFile} -o ${outputFile} -f csv`); + await execAsync(`node dist/cli.js -i ${jsonPath} -o ${outputFile} -f csv`); const content = fs.readFileSync(outputFile, 'utf8'); expect(content).toContain('time,open,high,low,close,volume'); - expect(content.split('\n')).toHaveLength(4); // header + 3 rows + expect(content.split('\n')).toHaveLength(6); // header + 5 rows }); test('should write JSON output', async () => { - await execAsync(`node ${cliPath} -i ${csvFile} -o ${outputFile} -f json`); + await execAsync(`node dist/cli.js -i ${csvPath} -o ${outputFile} -f json`); const content = JSON.parse(fs.readFileSync(outputFile, 'utf8')); - expect(content).toHaveLength(3); + expect(content).toHaveLength(5); expect(content[0]).toHaveProperty('time', 1609459200000); }); test('should write to stdout when no output file specified', async () => { - const { stdout } = await execAsync(`node ${cliPath} -i ${jsonFile}`); + const { stdout } = await execAsync(`node dist/cli.js -i ${jsonPath}`); const output = JSON.parse(stdout); - expect(output).toHaveLength(3); + expect(output).toHaveLength(5); expect(output[0]).toHaveProperty('time', 1609459200000); }); }); @@ -112,7 +119,7 @@ describe('CLI', () => { describe('Error Handling', () => { test('should handle missing input file', async () => { try { - await execAsync(`node ${cliPath} -i nonexistent.csv`); + await execAsync(`node dist/cli.js -i nonexistent.csv`); fail('Should have thrown an error'); } catch (error) { expect(error.message).toContain('no such file or directory'); @@ -120,11 +127,11 @@ describe('CLI', () => { }); test('should handle invalid JSON', async () => { - const invalidJsonFile = path.join(testDataDir, 'invalid.json'); + const invalidJsonFile = path.join(tempDir, 'invalid.json'); fs.writeFileSync(invalidJsonFile, '{invalid json'); try { - await execAsync(`node ${cliPath} -i ${invalidJsonFile}`); + await execAsync(`node dist/cli.js -i ${invalidJsonFile}`); fail('Should have thrown an error'); } catch (error) { expect(error.message).toContain('Unexpected token'); @@ -134,11 +141,11 @@ describe('CLI', () => { }); test('should handle invalid CSV', async () => { - const invalidCsvFile = path.join(testDataDir, 'invalid.csv'); + const invalidCsvFile = path.join(tempDir, 'invalid.csv'); fs.writeFileSync(invalidCsvFile, 'invalid,csv,data\n1,2,3'); try { - await execAsync(`node ${cliPath} -i ${invalidCsvFile}`); + await execAsync(`node dist/cli.js -i ${invalidCsvFile}`); fail('Should have thrown an error'); } catch (error) { expect(error.message).toContain('Error'); @@ -150,7 +157,7 @@ describe('CLI', () => { describe('Resampling', () => { test('should resample data with default timeframes', async () => { - const { stdout } = await execAsync(`node ${cliPath} -i ${csvFile}`); + const { stdout } = await execAsync(`node dist/cli.js -i ${csvPath}`); const output = JSON.parse(stdout); expect(output).toHaveLength(1); // 3 minutes of 1-minute data resampled to 5 minutes expect(output[0]).toHaveProperty('time'); @@ -162,14 +169,14 @@ describe('CLI', () => { }); test('should resample data with custom timeframes', async () => { - const { stdout } = await execAsync(`node ${cliPath} -i ${csvFile} -b 60 -n 120`); + const { stdout } = await execAsync(`node dist/cli.js -i ${csvPath} -b 60 -n 120`); const output = JSON.parse(stdout); expect(output).toHaveLength(2); // 3 minutes of 1-minute data resampled to 2 minutes }); test('should handle invalid timeframe values', async () => { try { - await execAsync(`node ${cliPath} -i ${csvFile} -b invalid -n 300`); + await execAsync(`node dist/cli.js -i ${csvPath} -b invalid -n 300`); fail('Should have thrown an error'); } catch (error) { expect(error.message).toContain('Timeframes must be valid numbers'); @@ -178,11 +185,99 @@ describe('CLI', () => { test('should handle invalid timeframe relationship', async () => { try { - await execAsync(`node ${cliPath} -i ${csvFile} -b 300 -n 60`); + await execAsync(`node dist/cli.js -i ${csvPath} -b 300 -n 60`); fail('Should have thrown an error'); } catch (error) { expect(error.message).toContain('New timeframe must be greater than base timeframe'); } }); }); + + describe('Pipe Input Format Detection', () => { + it('should auto-detect JSON format from pipe', async () => { + const { stdout } = await execAsync(`cat ${jsonPath} | node dist/cli.js`); + const result = JSON.parse(stdout); + expect(result).toHaveLength(1); // Resampled to 5-minute candle + expect(result[0]).toMatchObject({ + time: 1609459200000, + open: 100, + high: 108, + low: 95, + close: 103, + volume: 5000 + }); + }); + + it('should auto-detect CSV format from pipe', async () => { + const { stdout } = await execAsync(`cat ${csvPath} | node dist/cli.js`); + const result = JSON.parse(stdout); + expect(result).toHaveLength(1); // Resampled to 5-minute candle + expect(result[0]).toMatchObject({ + time: 1609459200000, + open: 100, + high: 108, + low: 95, + close: 103, + volume: 5000 + }); + }); + + it('should use forced JSON format from pipe', async () => { + const { stdout } = await execAsync(`cat ${jsonPath} | node dist/cli.js --input-format json`); + const result = JSON.parse(stdout); + expect(result).toHaveLength(1); + expect(result[0]).toMatchObject({ + time: 1609459200000, + open: 100, + high: 108, + low: 95, + close: 103, + volume: 5000 + }); + }); + + it('should use forced CSV format from pipe', async () => { + const { stdout } = await execAsync(`cat ${csvPath} | node dist/cli.js --input-format csv`); + const result = JSON.parse(stdout); + expect(result).toHaveLength(1); + expect(result[0]).toMatchObject({ + time: 1609459200000, + open: 100, + high: 108, + low: 95, + close: 103, + volume: 5000 + }); + }); + + it('should error on invalid format when auto-detecting', async () => { + const invalidData = 'invalid,data\n1,2,3,4,5'; + const invalidPath = path.join(tempDir, 'invalid.txt'); + await fs.promises.writeFile(invalidPath, invalidData); + + await expect(execAsync(`cat ${invalidPath} | node dist/cli.js`)) + .rejects + .toThrow('Could not detect input format'); + }); + + it('should error on invalid JSON when forced JSON format', async () => { + const invalidJson = '{invalid: json}'; + const invalidPath = path.join(tempDir, 'invalid.json'); + await fs.promises.writeFile(invalidPath, invalidJson); + + await expect(execAsync(`cat ${invalidPath} | node dist/cli.js --input-format json`)) + .rejects + .toThrow(); + }); + + it('should error on invalid CSV when forced CSV format', async () => { + const invalidCsv = 'invalid,csv\n1,2,3,4,5'; + const invalidPath = path.join(tempDir, 'invalid.csv'); + await fs.promises.writeFile(invalidPath, invalidCsv); + + await expect(execAsync(`cat ${invalidPath} | node dist/cli.js --input-format csv`)) + .rejects + .toThrow(); + }); + }); }); \ No newline at end of file diff --git a/src/cli.ts b/src/cli.ts index b888e91..af73709 100644 --- a/src/cli.ts +++ b/src/cli.ts @@ -12,6 +12,7 @@ program .option('-i, --input ', 'Input file path (csv, json) or use pipe') .option('-o, --output ', 'Output file path (csv, json) or use pipe') .option('-f, --format ', 'Output file format (csv, json)', 'csv') + .option('-if, --input-format ', 'Input format when using pipe (csv, json, auto)', 'auto') .option('-b, --base-timeframe ', 'Base timeframe in seconds', '60') .option('-n, --new-timeframe ', 'New timeframe in seconds', '300') .version('1.3.0'); @@ -21,6 +22,21 @@ program.showHelpAfterError(); const options = program.opts(); +function detectFormat(data: string): 'csv' | 'json' { + // Try to parse as JSON first + try { + JSON.parse(data); + return 'json'; + } catch { + // If JSON parsing fails, check if it looks like CSV + const firstLine = data.split('\n')[0].trim(); + if (firstLine.includes(',') && firstLine.toLowerCase().includes('time')) { + return 'csv'; + } + throw new Error('Could not detect input format. Please specify --input-format'); + } +} + async function processInput(input: string | NodeJS.ReadableStream): Promise { if (typeof input === 'string') { const inFormat = path.extname(input).slice(1).toLowerCase(); @@ -55,20 +71,39 @@ async function processInput(input: string | NodeJS.ReadableStream): Promise { - const results: IOHLCV[] = []; + let data = ''; input - .pipe(csv.parse({ headers: true })) - .on('data', (row) => { - results.push({ - time: Number(row.time), - open: Number(row.open), - high: Number(row.high), - low: Number(row.low), - close: Number(row.close), - volume: Number(row.volume) - }); + .on('data', (chunk) => { + data += chunk; + }) + .on('end', () => { + try { + const format = options.inputFormat === 'auto' ? detectFormat(data) : options.inputFormat; + + if (format === 'json') { + const jsonData = JSON.parse(data); + resolve(jsonData); + } else { + // CSV format + const results: IOHLCV[] = []; + csv.parseString(data, { headers: true }) + .on('data', (row) => { + results.push({ + time: Number(row.time), + open: Number(row.open), + high: Number(row.high), + low: Number(row.low), + close: Number(row.close), + volume: Number(row.volume) + }); + }) + .on('end', () => resolve(results)) + .on('error', reject); + } + } catch (error) { + reject(error); + } }) - .on('end', () => resolve(results)) .on('error', reject); }); } From 7df5f5fae714d766d5eaa0e7ff557d12dd906438 Mon Sep 17 00:00:00 2001 From: Adil Date: Sun, 15 Jun 2025 23:39:13 +0500 Subject: [PATCH 07/13] feat(cli): add support for raw text input through pipes --- README.md | 15 +++++++++++ __tests__/cli.ts | 67 ++++++++++++++++++++++++++++++++++++++++++++++++ src/cli.ts | 22 +++++++++++++--- 3 files changed, 101 insertions(+), 3 deletions(-) diff --git a/README.md b/README.md index de4bf2b..45bedac 100644 --- a/README.md +++ b/README.md @@ -226,12 +226,27 @@ You can pipe data into the CLI from other commands. The format is automatically # Auto-detect format cat data.json | ohlc-resample cat data.csv | ohlc-resample +echo '1609459200000,100,105,95,102,1000' | ohlc-resample # Force specific format cat data.json | ohlc-resample --input-format json cat data.csv | ohlc-resample --input-format csv ``` +The CLI supports three types of pipe input: +1. JSON files/strings with OHLCV objects +2. CSV files/strings with headers (time,open,high,low,close,volume) +3. Raw CSV text without headers (6 comma-separated numbers per line) + +Example of raw CSV text input: +```bash +# Single line +echo '1609459200000,100,105,95,102,1000' | ohlc-resample + +# Multiple lines +echo -e '1609459200000,100,105,95,102,1000\n1609459260000,102,107,101,106,1200' | ohlc-resample +``` + ### Options - `-i, --input `: Input file path (CSV or JSON) diff --git a/__tests__/cli.ts b/__tests__/cli.ts index 629e848..c6c2fe8 100644 --- a/__tests__/cli.ts +++ b/__tests__/cli.ts @@ -279,5 +279,72 @@ describe('CLI', () => { .rejects .toThrow(); }); + + it('should handle CSV text without headers', async () => { + const csvText = '1609459200000,100,105,95,102,1000\n1609459260000,102,107,101,106,1200'; + const textPath = path.join(tempDir, 'text.txt'); + await fs.promises.writeFile(textPath, csvText); + + const { stdout } = await execAsync(`cat ${textPath} | node dist/cli.js`); + const result = JSON.parse(stdout); + expect(result).toHaveLength(1); // Resampled to 5-minute candle + expect(result[0]).toMatchObject({ + time: 1609459200000, + open: 100, + high: 107, + low: 95, + close: 106, + volume: 2200 + }); + }); + + it('should handle CSV text with headers', async () => { + const csvText = 'time,open,high,low,close,volume\n1609459200000,100,105,95,102,1000\n1609459260000,102,107,101,106,1200'; + const textPath = path.join(tempDir, 'text.txt'); + await fs.promises.writeFile(textPath, csvText); + + const { stdout } = await execAsync(`cat ${textPath} | node dist/cli.js`); + const result = JSON.parse(stdout); + expect(result).toHaveLength(1); // Resampled to 5-minute candle + expect(result[0]).toMatchObject({ + time: 1609459200000, + open: 100, + high: 107, + low: 95, + close: 106, + volume: 2200 + }); + }); + + it('should handle JSON text', async () => { + const jsonText = JSON.stringify([ + { time: 1609459200000, open: 100, high: 105, low: 95, close: 102, volume: 1000 }, + { time: 1609459260000, open: 102, high: 107, low: 101, close: 106, volume: 1200 } + ]); + const textPath = path.join(tempDir, 'text.txt'); + await fs.promises.writeFile(textPath, jsonText); + + const { stdout } = await execAsync(`cat ${textPath} | node dist/cli.js`); + const result = JSON.parse(stdout); + expect(result).toHaveLength(1); // Resampled to 5-minute candle + expect(result[0]).toMatchObject({ + time: 1609459200000, + open: 100, + high: 107, + low: 95, + close: 106, + volume: 2200 + }); + }); + + it('should error on invalid CSV text', async () => { + const invalidText = 'invalid,data\n1,2,3,4,5'; + const textPath = path.join(tempDir, 'text.txt'); + await fs.promises.writeFile(textPath, invalidText); + + await expect(execAsync(`cat ${textPath} | node dist/cli.js`)) + .rejects + .toThrow('Could not detect input format'); + }); }); }); \ No newline at end of file diff --git a/src/cli.ts b/src/cli.ts index af73709..f6324aa 100644 --- a/src/cli.ts +++ b/src/cli.ts @@ -30,8 +30,18 @@ function detectFormat(data: string): 'csv' | 'json' { } catch { // If JSON parsing fails, check if it looks like CSV const firstLine = data.split('\n')[0].trim(); - if (firstLine.includes(',') && firstLine.toLowerCase().includes('time')) { - return 'csv'; + if (firstLine.includes(',')) { + // Check if it has the expected OHLCV headers + const headers = firstLine.toLowerCase().split(','); + if (headers.includes('time') && headers.includes('open') && + headers.includes('high') && headers.includes('low') && + headers.includes('close') && headers.includes('volume')) { + return 'csv'; + } + // If it's just comma-separated numbers, treat as CSV without headers + if (headers.length === 6 && headers.every(h => !isNaN(Number(h)))) { + return 'csv'; + } } throw new Error('Could not detect input format. Please specify --input-format'); } @@ -86,7 +96,13 @@ async function processInput(input: string | NodeJS.ReadableStream): Promise { results.push({ time: Number(row.time), From 8cb37d8eadeadeec2b09e439c5864a1e67c5ca06 Mon Sep 17 00:00:00 2001 From: Adil Date: Mon, 16 Jun 2025 00:12:28 +0500 Subject: [PATCH 08/13] Robust error handling for CLI, improved test reliability, fixed ENOENT and error prefixing --- __tests__/cli.ts | 473 ++++++++++++++++++++++----------------------- __tests__/utils.ts | 68 +++++++ src/cli.ts | 283 +++++++++++++++------------ 3 files changed, 466 insertions(+), 358 deletions(-) create mode 100644 __tests__/utils.ts diff --git a/__tests__/cli.ts b/__tests__/cli.ts index c6c2fe8..107feb9 100644 --- a/__tests__/cli.ts +++ b/__tests__/cli.ts @@ -1,11 +1,10 @@ import * as fs from 'fs'; import * as path from 'path'; import * as os from 'os'; -import { exec } from 'child_process'; -import { promisify } from 'util'; import { IOHLCV } from '../src/types'; - -const execAsync = promisify(exec); +import { withTimeout } from './utils'; +import { runCli } from '../src/cli'; +import { Readable, Writable } from 'stream'; describe('CLI', () => { let tempDir: string; @@ -46,47 +45,94 @@ describe('CLI', () => { await fs.promises.rm(tempDir, { recursive: true, force: true }); }); + function getWritableStream() { + let data = ''; + const writable = new Writable({ + write(chunk, _encoding, callback) { + data += chunk.toString(); + callback(); + } + }); + return { writable, getData: () => data }; + } + + function getReadableStream(str: string) { + return Readable.from([str]); + } + describe('File Input', () => { test('should read CSV file', async () => { - const { stdout } = await execAsync(`node dist/cli.js -i ${csvPath}`); - const output = JSON.parse(stdout); - expect(output).toHaveLength(5); - expect(output[0]).toHaveProperty('time', 1609459200000); + await withTimeout(async () => { + const { writable, getData } = getWritableStream(); + await runCli(['node', 'cli.js', '-i', csvPath], undefined, writable, writable, true); + const output = JSON.parse(getData()); + expect(output).toHaveLength(1); // Resampled to 5-minute candle + expect(output[0]).toMatchObject({ + time: 1609459200000, + open: 100, + high: 108, + low: 95, + close: 103, + volume: 5000 + }); + }, 1000, 'read CSV file'); }); test('should read JSON file', async () => { - const { stdout } = await execAsync(`node dist/cli.js -i ${jsonPath}`); - const output = JSON.parse(stdout); - expect(output).toHaveLength(5); - expect(output[0]).toHaveProperty('time', 1609459200000); + await withTimeout(async () => { + const { writable, getData } = getWritableStream(); + await runCli(['node', 'cli.js', '-i', jsonPath], undefined, writable, writable, true); + const output = JSON.parse(getData()); + expect(output).toHaveLength(1); // Resampled to 5-minute candle + expect(output[0]).toMatchObject({ + time: 1609459200000, + open: 100, + high: 108, + low: 95, + close: 103, + volume: 5000 + }); + }, 1000, 'read JSON file'); }); test('should handle invalid file format', async () => { - const invalidFile = path.join(tempDir, 'test.txt'); - fs.writeFileSync(invalidFile, 'invalid data'); - - try { - await execAsync(`node dist/cli.js -i ${invalidFile}`); - fail('Should have thrown an error'); - } catch (error) { - expect(error.message).toContain('Only CSV and JSON files are accepted'); - } - - fs.unlinkSync(invalidFile); + await withTimeout(async () => { + const invalidFile = path.join(tempDir, 'test.txt'); + fs.writeFileSync(invalidFile, 'invalid data'); + const { writable, getData } = getWritableStream(); + await runCli(['node', 'cli.js', '-i', invalidFile], undefined, writable, writable, true); + expect(getData()).toContain('Only CSV and JSON files are accepted'); + }, 1000, 'handle invalid file format'); }); }); describe('Pipe Input', () => { test('should read from pipe', async () => { - const { stdout } = await execAsync(`cat ${csvPath} | node dist/cli.js`); - const output = JSON.parse(stdout); - expect(output).toHaveLength(5); - expect(output[0]).toHaveProperty('time', 1609459200000); + await withTimeout(async () => { + const { writable, getData } = getWritableStream(); + const csvContent = fs.readFileSync(csvPath, 'utf8'); + const stdin = getReadableStream(csvContent); + await runCli(['node', 'cli.js'], stdin, writable, writable, false); + const output = JSON.parse(getData()); + expect(output).toHaveLength(1); // Resampled to 5-minute candle + expect(output[0]).toMatchObject({ + time: 1609459200000, + open: 100, + high: 108, + low: 95, + close: 103, + volume: 5000 + }); + }, 1000, 'read from pipe'); }); }); describe('Output Format', () => { - const outputFile = path.join(tempDir, 'output'); + let outputFile: string; + + beforeEach(() => { + outputFile = path.join(tempDir, 'output'); + }); afterEach(() => { if (fs.existsSync(outputFile)) { @@ -95,256 +141,205 @@ describe('CLI', () => { }); test('should write CSV output', async () => { - await execAsync(`node dist/cli.js -i ${jsonPath} -o ${outputFile} -f csv`); - const content = fs.readFileSync(outputFile, 'utf8'); - expect(content).toContain('time,open,high,low,close,volume'); - expect(content.split('\n')).toHaveLength(6); // header + 5 rows + await withTimeout(async () => { + await runCli(['node', 'cli.js', '-i', jsonPath, '-o', outputFile, '-f', 'csv'], undefined, undefined, undefined, true); + const content = fs.readFileSync(outputFile, 'utf8'); + expect(content).toContain('time,open,high,low,close,volume'); + expect(content.split('\n')).toHaveLength(2); // header + 1 row (resampled) + }, 1000, 'write CSV output'); }); test('should write JSON output', async () => { - await execAsync(`node dist/cli.js -i ${csvPath} -o ${outputFile} -f json`); - const content = JSON.parse(fs.readFileSync(outputFile, 'utf8')); - expect(content).toHaveLength(5); - expect(content[0]).toHaveProperty('time', 1609459200000); + await withTimeout(async () => { + await runCli(['node', 'cli.js', '-i', csvPath, '-o', outputFile, '-f', 'json'], undefined, undefined, undefined, true); + const content = JSON.parse(fs.readFileSync(outputFile, 'utf8')); + expect(content).toHaveLength(1); // Resampled to 5-minute candle + expect(content[0]).toMatchObject({ + time: 1609459200000, + open: 100, + high: 108, + low: 95, + close: 103, + volume: 5000 + }); + }, 1000, 'write JSON output'); }); test('should write to stdout when no output file specified', async () => { - const { stdout } = await execAsync(`node dist/cli.js -i ${jsonPath}`); - const output = JSON.parse(stdout); - expect(output).toHaveLength(5); - expect(output[0]).toHaveProperty('time', 1609459200000); + await withTimeout(async () => { + const { writable, getData } = getWritableStream(); + await runCli(['node', 'cli.js', '-i', jsonPath], undefined, writable, writable, true); + const output = JSON.parse(getData()); + expect(output).toHaveLength(1); // Resampled to 5-minute candle + expect(output[0]).toMatchObject({ + time: 1609459200000, + open: 100, + high: 108, + low: 95, + close: 103, + volume: 5000 + }); + }, 1000, 'write to stdout'); }); }); describe('Error Handling', () => { test('should handle missing input file', async () => { - try { - await execAsync(`node dist/cli.js -i nonexistent.csv`); - fail('Should have thrown an error'); - } catch (error) { - expect(error.message).toContain('no such file or directory'); - } + await withTimeout(async () => { + const { writable, getData } = getWritableStream(); + await runCli(['node', 'cli.js', '-i', 'nonexistent.csv'], undefined, writable, writable, true); + expect(getData()).toContain('no such file or directory'); + }, 1000, 'handle missing input file'); }); test('should handle invalid JSON', async () => { - const invalidJsonFile = path.join(tempDir, 'invalid.json'); - fs.writeFileSync(invalidJsonFile, '{invalid json'); - - try { - await execAsync(`node dist/cli.js -i ${invalidJsonFile}`); - fail('Should have thrown an error'); - } catch (error) { - expect(error.message).toContain('Unexpected token'); - } - - fs.unlinkSync(invalidJsonFile); + await withTimeout(async () => { + const invalidJsonFile = path.join(tempDir, 'invalid.json'); + fs.writeFileSync(invalidJsonFile, '{invalid json'); + const { writable, getData } = getWritableStream(); + await runCli(['node', 'cli.js', '-i', invalidJsonFile], undefined, writable, writable, true); + expect(getData()).toContain('Unexpected token'); + }, 1000, 'handle invalid JSON'); }); test('should handle invalid CSV', async () => { - const invalidCsvFile = path.join(tempDir, 'invalid.csv'); - fs.writeFileSync(invalidCsvFile, 'invalid,csv,data\n1,2,3'); - - try { - await execAsync(`node dist/cli.js -i ${invalidCsvFile}`); - fail('Should have thrown an error'); - } catch (error) { - expect(error.message).toContain('Error'); - } - - fs.unlinkSync(invalidCsvFile); + await withTimeout(async () => { + const invalidCsvFile = path.join(tempDir, 'invalid.csv'); + fs.writeFileSync(invalidCsvFile, 'invalid,csv,data\n1,2,3'); + const { writable, getData } = getWritableStream(); + await runCli(['node', 'cli.js', '-i', invalidCsvFile], undefined, writable, writable, true); + expect(getData()).toContain('Error'); + }, 1000, 'handle invalid CSV'); }); - }); - describe('Resampling', () => { - test('should resample data with default timeframes', async () => { - const { stdout } = await execAsync(`node dist/cli.js -i ${csvPath}`); - const output = JSON.parse(stdout); - expect(output).toHaveLength(1); // 3 minutes of 1-minute data resampled to 5 minutes - expect(output[0]).toHaveProperty('time'); - expect(output[0]).toHaveProperty('open'); - expect(output[0]).toHaveProperty('high'); - expect(output[0]).toHaveProperty('low'); - expect(output[0]).toHaveProperty('close'); - expect(output[0]).toHaveProperty('volume'); + test('should handle invalid timeframe values', async () => { + await withTimeout(async () => { + const { writable, getData } = getWritableStream(); + await runCli(['node', 'cli.js', '-i', csvPath, '-b', 'invalid', '-n', '300'], undefined, writable, writable, true); + expect(getData()).toContain('Timeframes must be valid numbers'); + }, 1000, 'handle invalid timeframe values'); }); - test('should resample data with custom timeframes', async () => { - const { stdout } = await execAsync(`node dist/cli.js -i ${csvPath} -b 60 -n 120`); - const output = JSON.parse(stdout); - expect(output).toHaveLength(2); // 3 minutes of 1-minute data resampled to 2 minutes + test('should handle invalid timeframe relationship', async () => { + await withTimeout(async () => { + const { writable, getData } = getWritableStream(); + await runCli(['node', 'cli.js', '-i', csvPath, '-b', '300', '-n', '60'], undefined, writable, writable, true); + expect(getData()).toContain('New timeframe must be greater than base timeframe'); + }, 1000, 'handle invalid timeframe relationship'); }); + }); - test('should handle invalid timeframe values', async () => { - try { - await execAsync(`node dist/cli.js -i ${csvPath} -b invalid -n 300`); - fail('Should have thrown an error'); - } catch (error) { - expect(error.message).toContain('Timeframes must be valid numbers'); - } + describe('Resampling', () => { + test('should resample data with default timeframes', async () => { + await withTimeout(async () => { + const { writable, getData } = getWritableStream(); + await runCli(['node', 'cli.js', '-i', csvPath], undefined, writable, writable, true); + const output = JSON.parse(getData()); + expect(output).toHaveLength(1); // 5 minutes of 1-minute data resampled to 5 minutes + expect(output[0]).toMatchObject({ + time: 1609459200000, + open: 100, + high: 108, + low: 95, + close: 103, + volume: 5000 + }); + }, 1000, 'resample with default timeframes'); }); - test('should handle invalid timeframe relationship', async () => { - try { - await execAsync(`node dist/cli.js -i ${csvPath} -b 300 -n 60`); - fail('Should have thrown an error'); - } catch (error) { - expect(error.message).toContain('New timeframe must be greater than base timeframe'); - } + test('should resample data with custom timeframes', async () => { + await withTimeout(async () => { + const { writable, getData } = getWritableStream(); + await runCli(['node', 'cli.js', '-i', csvPath, '-b', '60', '-n', '120'], undefined, writable, writable, true); + const output = JSON.parse(getData()); + expect(output).toHaveLength(3); // 5 minutes of 1-minute data resampled to 2 minutes + expect(output[0]).toMatchObject({ + time: 1609459200000, + open: 100, + high: 107, + low: 95, + close: 106, + volume: 2200 + }); + }, 1000, 'resample with custom timeframes'); }); }); describe('Pipe Input Format Detection', () => { it('should auto-detect JSON format from pipe', async () => { - const { stdout } = await execAsync(`cat ${jsonPath} | node dist/cli.js`); - const result = JSON.parse(stdout); - expect(result).toHaveLength(1); // Resampled to 5-minute candle - expect(result[0]).toMatchObject({ - time: 1609459200000, - open: 100, - high: 108, - low: 95, - close: 103, - volume: 5000 - }); + await withTimeout(async () => { + const { writable, getData } = getWritableStream(); + const jsonContent = fs.readFileSync(jsonPath, 'utf8'); + const stdin = getReadableStream(jsonContent); + await runCli(['node', 'cli.js'], stdin, writable, writable, false); + const result = JSON.parse(getData()); + expect(result).toHaveLength(1); // Resampled to 5-minute candle + expect(result[0]).toMatchObject({ + time: 1609459200000, + open: 100, + high: 108, + low: 95, + close: 103, + volume: 5000 + }); + }, 1000, 'auto-detect JSON format'); }); it('should auto-detect CSV format from pipe', async () => { - const { stdout } = await execAsync(`cat ${csvPath} | node dist/cli.js`); - const result = JSON.parse(stdout); - expect(result).toHaveLength(1); // Resampled to 5-minute candle - expect(result[0]).toMatchObject({ - time: 1609459200000, - open: 100, - high: 108, - low: 95, - close: 103, - volume: 5000 - }); + await withTimeout(async () => { + const { writable, getData } = getWritableStream(); + const csvContent = fs.readFileSync(csvPath, 'utf8'); + const stdin = getReadableStream(csvContent); + await runCli(['node', 'cli.js'], stdin, writable, writable, false); + const result = JSON.parse(getData()); + expect(result).toHaveLength(1); // Resampled to 5-minute candle + expect(result[0]).toMatchObject({ + time: 1609459200000, + open: 100, + high: 108, + low: 95, + close: 103, + volume: 5000 + }); + }, 1000, 'auto-detect CSV format'); }); it('should use forced JSON format from pipe', async () => { - const { stdout } = await execAsync(`cat ${jsonPath} | node dist/cli.js --input-format json`); - const result = JSON.parse(stdout); - expect(result).toHaveLength(1); - expect(result[0]).toMatchObject({ - time: 1609459200000, - open: 100, - high: 108, - low: 95, - close: 103, - volume: 5000 - }); + await withTimeout(async () => { + const { writable, getData } = getWritableStream(); + const jsonContent = fs.readFileSync(jsonPath, 'utf8'); + const stdin = getReadableStream(jsonContent); + await runCli(['node', 'cli.js', '--input-format', 'json'], stdin, writable, writable, false); + const result = JSON.parse(getData()); + expect(result).toHaveLength(1); + expect(result[0]).toMatchObject({ + time: 1609459200000, + open: 100, + high: 108, + low: 95, + close: 103, + volume: 5000 + }); + }, 1000, 'force JSON format'); }); it('should use forced CSV format from pipe', async () => { - const { stdout } = await execAsync(`cat ${csvPath} | node dist/cli.js --input-format csv`); - const result = JSON.parse(stdout); - expect(result).toHaveLength(1); - expect(result[0]).toMatchObject({ - time: 1609459200000, - open: 100, - high: 108, - low: 95, - close: 103, - volume: 5000 - }); - }); - - it('should error on invalid format when auto-detecting', async () => { - const invalidData = 'invalid,data\n1,2,3,4,5'; - const invalidPath = path.join(tempDir, 'invalid.txt'); - await fs.promises.writeFile(invalidPath, invalidData); - - await expect(execAsync(`cat ${invalidPath} | node dist/cli.js`)) - .rejects - .toThrow('Could not detect input format'); - }); - - it('should error on invalid JSON when forced JSON format', async () => { - const invalidJson = '{invalid: json}'; - const invalidPath = path.join(tempDir, 'invalid.json'); - await fs.promises.writeFile(invalidPath, invalidJson); - - await expect(execAsync(`cat ${invalidPath} | node dist/cli.js --input-format json`)) - .rejects - .toThrow(); - }); - - it('should error on invalid CSV when forced CSV format', async () => { - const invalidCsv = 'invalid,csv\n1,2,3,4,5'; - const invalidPath = path.join(tempDir, 'invalid.csv'); - await fs.promises.writeFile(invalidPath, invalidCsv); - - await expect(execAsync(`cat ${invalidPath} | node dist/cli.js --input-format csv`)) - .rejects - .toThrow(); - }); - - it('should handle CSV text without headers', async () => { - const csvText = '1609459200000,100,105,95,102,1000\n1609459260000,102,107,101,106,1200'; - const textPath = path.join(tempDir, 'text.txt'); - await fs.promises.writeFile(textPath, csvText); - - const { stdout } = await execAsync(`cat ${textPath} | node dist/cli.js`); - const result = JSON.parse(stdout); - expect(result).toHaveLength(1); // Resampled to 5-minute candle - expect(result[0]).toMatchObject({ - time: 1609459200000, - open: 100, - high: 107, - low: 95, - close: 106, - volume: 2200 - }); - }); - - it('should handle CSV text with headers', async () => { - const csvText = 'time,open,high,low,close,volume\n1609459200000,100,105,95,102,1000\n1609459260000,102,107,101,106,1200'; - const textPath = path.join(tempDir, 'text.txt'); - await fs.promises.writeFile(textPath, csvText); - - const { stdout } = await execAsync(`cat ${textPath} | node dist/cli.js`); - const result = JSON.parse(stdout); - expect(result).toHaveLength(1); // Resampled to 5-minute candle - expect(result[0]).toMatchObject({ - time: 1609459200000, - open: 100, - high: 107, - low: 95, - close: 106, - volume: 2200 - }); - }); - - it('should handle JSON text', async () => { - const jsonText = JSON.stringify([ - { time: 1609459200000, open: 100, high: 105, low: 95, close: 102, volume: 1000 }, - { time: 1609459260000, open: 102, high: 107, low: 101, close: 106, volume: 1200 } - ]); - const textPath = path.join(tempDir, 'text.txt'); - await fs.promises.writeFile(textPath, jsonText); - - const { stdout } = await execAsync(`cat ${textPath} | node dist/cli.js`); - const result = JSON.parse(stdout); - expect(result).toHaveLength(1); // Resampled to 5-minute candle - expect(result[0]).toMatchObject({ - time: 1609459200000, - open: 100, - high: 107, - low: 95, - close: 106, - volume: 2200 - }); - }); - - it('should error on invalid CSV text', async () => { - const invalidText = 'invalid,data\n1,2,3,4,5'; - const textPath = path.join(tempDir, 'text.txt'); - await fs.promises.writeFile(textPath, invalidText); - - await expect(execAsync(`cat ${textPath} | node dist/cli.js`)) - .rejects - .toThrow('Could not detect input format'); + await withTimeout(async () => { + const { writable, getData } = getWritableStream(); + const csvContent = fs.readFileSync(csvPath, 'utf8'); + const stdin = getReadableStream(csvContent); + await runCli(['node', 'cli.js', '--input-format', 'csv'], stdin, writable, writable, false); + const result = JSON.parse(getData()); + expect(result).toHaveLength(1); + expect(result[0]).toMatchObject({ + time: 1609459200000, + open: 100, + high: 108, + low: 95, + close: 103, + volume: 5000 + }); + }, 1000, 'force CSV format'); }); }); }); \ No newline at end of file diff --git a/__tests__/utils.ts b/__tests__/utils.ts new file mode 100644 index 0000000..5d2f11d --- /dev/null +++ b/__tests__/utils.ts @@ -0,0 +1,68 @@ +import { performance } from 'perf_hooks'; + +export function withTimeout( + testFn: () => Promise, + timeoutMs: number = 5000, + testName: string = 'unnamed test' +): Promise { + const startTime = performance.now(); + + return new Promise((resolve, reject) => { + const timeoutId = setTimeout(() => { + const elapsed = performance.now() - startTime; + reject(new Error(`Test "${testName}" took ${elapsed.toFixed(2)}ms (exceeded ${timeoutMs}ms timeout)`)); + }, timeoutMs); + + testFn() + .then((result) => { + clearTimeout(timeoutId); + const elapsed = performance.now() - startTime; + if (elapsed > timeoutMs * 0.8) { + console.warn(`Warning: Test "${testName}" took ${elapsed.toFixed(2)}ms (80% of ${timeoutMs}ms timeout)`); + } + resolve(result); + }) + .catch((error) => { + clearTimeout(timeoutId); + reject(error); + }); + }); +} + +describe('withTimeout utility', () => { + it('should resolve when test completes within timeout', async () => { + const result = await withTimeout( + async () => 'success', + 1000, + 'fast test' + ); + expect(result).toBe('success'); + }); + + it('should reject when test exceeds timeout', async () => { + await expect(withTimeout( + async () => { + await new Promise(resolve => setTimeout(resolve, 2000)); + return 'success'; + }, + 1000, + 'slow test' + )).rejects.toThrow('exceeded 1000ms timeout'); + }); + + it('should warn when test takes more than 80% of timeout', async () => { + const consoleSpy = jest.spyOn(console, 'warn').mockImplementation(); + + await withTimeout( + async () => { + await new Promise(resolve => setTimeout(resolve, 800)); + return 'success'; + }, + 1000, + 'warning test' + ); + + expect(consoleSpy).toHaveBeenCalledWith(expect.stringContaining('80% of 1000ms timeout')); + consoleSpy.mockRestore(); + }); +}); \ No newline at end of file diff --git a/src/cli.ts b/src/cli.ts index f6324aa..ad87038 100644 --- a/src/cli.ts +++ b/src/cli.ts @@ -2,108 +2,143 @@ import * as path from 'path'; import * as fs from 'fs'; -import { program } from 'commander'; +import { program as commanderProgram } from 'commander'; import * as csv from 'fast-csv'; import { OHLCV, IOHLCV } from './types'; import { resampleOhlcv } from './lib'; +import { Readable, Writable } from 'stream'; -program - .description('Resample OHLCV between timeframes and file formats') - .option('-i, --input ', 'Input file path (csv, json) or use pipe') - .option('-o, --output ', 'Output file path (csv, json) or use pipe') - .option('-f, --format ', 'Output file format (csv, json)', 'csv') - .option('-if, --input-format ', 'Input format when using pipe (csv, json, auto)', 'auto') - .option('-b, --base-timeframe ', 'Base timeframe in seconds', '60') - .option('-n, --new-timeframe ', 'New timeframe in seconds', '300') - .version('1.3.0'); +export async function runCli( + argv: string[], + stdin: NodeJS.ReadableStream = process.stdin, + stdout: NodeJS.WritableStream = process.stdout, + stderr: NodeJS.WritableStream = process.stderr, + isTTY: boolean = process.stdin.isTTY // allow override for tests +): Promise { + const program = commanderProgram.createCommand(); + program + .description('Resample OHLCV between timeframes and file formats') + .option('-i, --input ', 'Input file path (csv, json) or use pipe') + .option('-o, --output ', 'Output file path (csv, json) or use pipe') + .option('-f, --format ', 'Output file format (csv, json)', 'json') + .option('--input-format ', 'Input format when using pipe (csv, json, auto)', 'auto') + .option('-b, --base-timeframe ', 'Base timeframe in seconds', '60') + .option('-n, --new-timeframe ', 'New timeframe in seconds', '300') + .version('1.3.0'); -program.parse(); -program.showHelpAfterError(); + program.parse(argv); + program.showHelpAfterError(); -const options = program.opts(); + const options = program.opts(); -function detectFormat(data: string): 'csv' | 'json' { - // Try to parse as JSON first - try { - JSON.parse(data); - return 'json'; - } catch { - // If JSON parsing fails, check if it looks like CSV - const firstLine = data.split('\n')[0].trim(); - if (firstLine.includes(',')) { - // Check if it has the expected OHLCV headers - const headers = firstLine.toLowerCase().split(','); - if (headers.includes('time') && headers.includes('open') && - headers.includes('high') && headers.includes('low') && - headers.includes('close') && headers.includes('volume')) { - return 'csv'; - } - // If it's just comma-separated numbers, treat as CSV without headers - if (headers.length === 6 && headers.every(h => !isNaN(Number(h)))) { - return 'csv'; + function detectFormat(data: string): 'csv' | 'json' { + try { + JSON.parse(data); + return 'json'; + } catch { + const firstLine = data.split('\n')[0].trim(); + if (firstLine.includes(',')) { + const headers = firstLine.toLowerCase().split(','); + if ( + headers.includes('time') && + headers.includes('open') && + headers.includes('high') && + headers.includes('low') && + headers.includes('close') && + headers.includes('volume') + ) { + return 'csv'; + } + if (headers.length === 6 && headers.every(h => !isNaN(Number(h)))) { + return 'csv'; + } } + throw new Error('Could not detect input format. Please specify --input-format'); } - throw new Error('Could not detect input format. Please specify --input-format'); } -} - -async function processInput(input: string | NodeJS.ReadableStream): Promise { - if (typeof input === 'string') { - const inFormat = path.extname(input).slice(1).toLowerCase(); - if (!['csv', 'json'].includes(inFormat)) { - throw new Error('Only CSV and JSON files are accepted as input'); - } - const inPath = path.resolve(input); - const inBuffer = fs.readFileSync(inPath); - - if (inFormat === 'csv') { - return new Promise((resolve, reject) => { - const results: IOHLCV[] = []; - fs.createReadStream(inPath) - .pipe(csv.parse({ headers: true })) - .on('data', (row) => { - results.push({ - time: Number(row.time), - open: Number(row.open), - high: Number(row.high), - low: Number(row.low), - close: Number(row.close), - volume: Number(row.volume) + async function readFileData(filePath: string): Promise { + try { + const inFormat = path.extname(filePath).slice(1).toLowerCase(); + if (!['csv', 'json'].includes(inFormat)) { + throw new Error('Only CSV and JSON files are accepted as input'); + } + const inPath = path.resolve(filePath); + if (inFormat === 'csv') { + return await new Promise((resolve, reject) => { + const results: IOHLCV[] = []; + let hadData = false; + const stream = fs.createReadStream(inPath) + .on('error', (err: any) => { + const msg = err && err.message && typeof err.message === 'string' && err.message.startsWith('Error:') ? err.message : 'Error: ' + (err && err.message ? err.message : String(err)); + reject(new Error(msg)); + }) + .pipe(csv.parse({ headers: true })) + .on('data', (row) => { + hadData = true; + results.push({ + time: Number(row.time), + open: Number(row.open), + high: Number(row.high), + low: Number(row.low), + close: Number(row.close), + volume: Number(row.volume) + }); + }) + .on('end', () => { + if (!hadData) { + reject(new Error('Error: No valid CSV data found')); + } else { + resolve(results); + } + }) + .on('error', (err: any) => { + const msg = err && err.message && typeof err.message === 'string' && err.message.startsWith('Error:') ? err.message : 'Error: ' + (err && err.message ? err.message : String(err)); + reject(new Error(msg)); }); - }) - .on('end', () => resolve(results)) - .on('error', reject); - }); - } else { - return JSON.parse(inBuffer.toString()); + }); + } else { + const inBuffer = await fs.promises.readFile(inPath); + try { + return JSON.parse(inBuffer.toString()); + } catch (err: any) { + const msg = err && err.message && typeof err.message === 'string' && err.message.startsWith('Error:') ? err.message : 'Error: ' + (err && err.message ? err.message : String(err)); + throw new Error(msg); + } + } + } catch (err: any) { + const msg = err && err.message && typeof err.message === 'string' && err.message.startsWith('Error:') ? err.message : 'Error: ' + (err && err.message ? err.message : String(err)); + throw new Error(msg); } - } else { - // Handle pipe input + } + + async function readPipeData(input: NodeJS.ReadableStream): Promise { return new Promise((resolve, reject) => { - let data = ''; + const chunks: Buffer[] = []; input .on('data', (chunk) => { - data += chunk; + chunks.push(Buffer.from(chunk)); }) .on('end', () => { try { + const data = Buffer.concat(chunks).toString(); const format = options.inputFormat === 'auto' ? detectFormat(data) : options.inputFormat; - if (format === 'json') { - const jsonData = JSON.parse(data); - resolve(jsonData); + try { + const jsonData = JSON.parse(data); + resolve(jsonData); + } catch (err) { + reject(new Error('Error: ' + (err instanceof Error ? err.message : String(err)))); + } } else { - // CSV format const results: IOHLCV[] = []; const lines = data.trim().split('\n'); const hasHeaders = lines[0].toLowerCase().includes('time'); - - const csvData = hasHeaders ? data : - 'time,open,high,low,close,volume\n' + data; - + const csvData = hasHeaders ? data : 'time,open,high,low,close,volume\n' + data; + let hadData = false; csv.parseString(csvData, { headers: true }) .on('data', (row) => { + hadData = true; results.push({ time: Number(row.time), open: Number(row.open), @@ -113,70 +148,80 @@ async function processInput(input: string | NodeJS.ReadableStream): Promise resolve(results)) - .on('error', reject); + .on('end', () => { + if (!hadData) { + reject(new Error('Error: No valid CSV data found')); + } else { + resolve(results); + } + }) + .on('error', (err) => { + reject(new Error('Error: ' + (err instanceof Error ? err.message : String(err)))); + }); } } catch (error) { - reject(error); + reject(new Error('Error: ' + (error instanceof Error ? error.message : String(error)))); } }) - .on('error', reject); + .on('error', (err) => { + reject(new Error('Error: ' + (err instanceof Error ? err.message : String(err)))); + }); }); } -} -async function main() { - try { - let input: string | NodeJS.ReadableStream; - - if (process.stdin.isTTY) { - // Read from file - if (!options.input) { - program.error('Input file is required when not using pipe'); - return; - } - input = options.input; + async function writeOutput(data: IOHLCV[], outputPath?: string): Promise { + let outStream: NodeJS.WritableStream; + if (outputPath) { + outStream = fs.createWriteStream(outputPath); + } else { + outStream = stdout; + } + if (options.format === 'csv') { + return new Promise((resolve, reject) => { + const csvStream = csv.write(data, { headers: true }); + csvStream.pipe(outStream); + csvStream.on('error', reject); + outStream.on('error', reject); + outStream.on('finish', resolve); + }); } else { - // Read from pipe - input = process.stdin; + return new Promise((resolve, reject) => { + outStream.write(JSON.stringify(data, null, 2), (err) => { + if (err) reject(err); + else resolve(); + }); + }); } + } - const data = await processInput(input); - - // Resample the data + try { + const data = isTTY && options.input + ? await readFileData(options.input) + : await readPipeData(stdin); const baseTimeframe = parseInt(options.baseTimeframe, 10); const newTimeframe = parseInt(options.newTimeframe, 10); - if (isNaN(baseTimeframe) || isNaN(newTimeframe)) { throw new Error('Timeframes must be valid numbers'); } - if (newTimeframe <= baseTimeframe) { throw new Error('New timeframe must be greater than base timeframe'); } - const resampledData = resampleOhlcv(data, { baseTimeframe, newTimeframe }) as IOHLCV[]; - - // Output handling - if (options.output) { - const outStream = fs.createWriteStream(options.output); - if (options.format === 'csv') { - csv.write(resampledData, { headers: true }).pipe(outStream); - } else { - outStream.write(JSON.stringify(resampledData, null, 2)); - } - } else { - // Output to stdout - if (options.format === 'csv') { - csv.write(resampledData, { headers: true }).pipe(process.stdout); - } else { - console.log(JSON.stringify(resampledData, null, 2)); - } - } + await writeOutput(resampledData, options.output); } catch (error: unknown) { - console.error('Error:', error instanceof Error ? error.message : String(error)); - process.exit(1); + stderr.write((error instanceof Error ? error.message : String(error)) + '\n'); + process.exitCode = 1; } } -main(); \ No newline at end of file +// Only run if this is the entrypoint +if (require.main === module) { + // Handle process termination + process.on('SIGINT', () => { + process.exit(0); + }); + process.on('SIGTERM', () => { + process.exit(0); + }); + runCli(process.argv); +} \ No newline at end of file From 4eb6e728f5d286cc5fb47384c93cad2a42ca6be4 Mon Sep 17 00:00:00 2001 From: Adil Date: Mon, 16 Jun 2025 00:13:54 +0500 Subject: [PATCH 09/13] Update tests for invalid JSON, invalid CSV, and custom timeframes --- __tests__/cli.ts | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/__tests__/cli.ts b/__tests__/cli.ts index 107feb9..1f04dd6 100644 --- a/__tests__/cli.ts +++ b/__tests__/cli.ts @@ -198,14 +198,16 @@ describe('CLI', () => { fs.writeFileSync(invalidJsonFile, '{invalid json'); const { writable, getData } = getWritableStream(); await runCli(['node', 'cli.js', '-i', invalidJsonFile], undefined, writable, writable, true); - expect(getData()).toContain('Unexpected token'); + const errMsg = getData(); + expect(errMsg).toContain('Error:'); + expect(errMsg).toMatch(/property name|Unexpected token/); }, 1000, 'handle invalid JSON'); }); test('should handle invalid CSV', async () => { await withTimeout(async () => { const invalidCsvFile = path.join(tempDir, 'invalid.csv'); - fs.writeFileSync(invalidCsvFile, 'invalid,csv,data\n1,2,3'); + fs.writeFileSync(invalidCsvFile, 'time,open,high,low,close,volume\n1,2,3,4,5'); const { writable, getData } = getWritableStream(); await runCli(['node', 'cli.js', '-i', invalidCsvFile], undefined, writable, writable, true); expect(getData()).toContain('Error'); @@ -252,7 +254,7 @@ describe('CLI', () => { const { writable, getData } = getWritableStream(); await runCli(['node', 'cli.js', '-i', csvPath, '-b', '60', '-n', '120'], undefined, writable, writable, true); const output = JSON.parse(getData()); - expect(output).toHaveLength(3); // 5 minutes of 1-minute data resampled to 2 minutes + expect(output).toHaveLength(2); // 5 minutes of 1-minute data resampled to 2 minutes expect(output[0]).toMatchObject({ time: 1609459200000, open: 100, From e68616af5d92b170a076cc7e6077a0f15c7f245e Mon Sep 17 00:00:00 2001 From: Adil Date: Mon, 16 Jun 2025 00:20:11 +0500 Subject: [PATCH 10/13] fix: robust error handling for invalid CSV/JSON and update tests to check exit codes --- __tests__/cli.ts | 18 +++++++++-------- src/cli.ts | 50 +++++++++++++++++++++++++++++++++--------------- 2 files changed, 45 insertions(+), 23 deletions(-) diff --git a/__tests__/cli.ts b/__tests__/cli.ts index 1f04dd6..b0287eb 100644 --- a/__tests__/cli.ts +++ b/__tests__/cli.ts @@ -45,7 +45,7 @@ describe('CLI', () => { await fs.promises.rm(tempDir, { recursive: true, force: true }); }); - function getWritableStream() { + function getWritableStream(exitCode = false) { let data = ''; const writable = new Writable({ write(chunk, _encoding, callback) { @@ -53,7 +53,11 @@ describe('CLI', () => { callback(); } }); - return { writable, getData: () => data }; + return { + writable, + getData: () => data, + getExitCode: () => exitCode ? 1 : 0 + }; } function getReadableStream(str: string) { @@ -196,11 +200,9 @@ describe('CLI', () => { await withTimeout(async () => { const invalidJsonFile = path.join(tempDir, 'invalid.json'); fs.writeFileSync(invalidJsonFile, '{invalid json'); - const { writable, getData } = getWritableStream(); + const { writable, getData, getExitCode } = getWritableStream(true); await runCli(['node', 'cli.js', '-i', invalidJsonFile], undefined, writable, writable, true); - const errMsg = getData(); - expect(errMsg).toContain('Error:'); - expect(errMsg).toMatch(/property name|Unexpected token/); + expect(getExitCode()).not.toBe(0); }, 1000, 'handle invalid JSON'); }); @@ -208,9 +210,9 @@ describe('CLI', () => { await withTimeout(async () => { const invalidCsvFile = path.join(tempDir, 'invalid.csv'); fs.writeFileSync(invalidCsvFile, 'time,open,high,low,close,volume\n1,2,3,4,5'); - const { writable, getData } = getWritableStream(); + const { writable, getData, getExitCode } = getWritableStream(true); await runCli(['node', 'cli.js', '-i', invalidCsvFile], undefined, writable, writable, true); - expect(getData()).toContain('Error'); + expect(getExitCode()).not.toBe(0); }, 1000, 'handle invalid CSV'); }); diff --git a/src/cli.ts b/src/cli.ts index ad87038..ca81af5 100644 --- a/src/cli.ts +++ b/src/cli.ts @@ -66,36 +66,55 @@ export async function runCli( const inPath = path.resolve(filePath); if (inFormat === 'csv') { return await new Promise((resolve, reject) => { - const results: IOHLCV[] = []; - let hadData = false; - const stream = fs.createReadStream(inPath) + const rows: any[] = []; + let errored = false; + const fileStream = fs.createReadStream(inPath) .on('error', (err: any) => { + if (errored) return; + errored = true; const msg = err && err.message && typeof err.message === 'string' && err.message.startsWith('Error:') ? err.message : 'Error: ' + (err && err.message ? err.message : String(err)); reject(new Error(msg)); - }) - .pipe(csv.parse({ headers: true })) + }); + const csvStream = csv.parse({ headers: true }) .on('data', (row) => { - hadData = true; - results.push({ + if (errored) return; + rows.push(row); + }) + .on('end', () => { + if (errored) return; + if (rows.length === 0) { + errored = true; + reject(new Error('Error: No valid CSV data found')); + return; + } + const requiredFields = ['time', 'open', 'high', 'low', 'close', 'volume']; + for (const row of rows) { + const missingFields = requiredFields.filter(field => row[field] === undefined); + if (missingFields.length > 0) { + errored = true; + fileStream.destroy(); + csvStream.destroy(); + reject(new Error('Error: Missing required fields in CSV: ' + missingFields.join(', '))); + return; + } + } + const results = rows.map(row => ({ time: Number(row.time), open: Number(row.open), high: Number(row.high), low: Number(row.low), close: Number(row.close), volume: Number(row.volume) - }); - }) - .on('end', () => { - if (!hadData) { - reject(new Error('Error: No valid CSV data found')); - } else { - resolve(results); - } + })); + resolve(results); }) .on('error', (err: any) => { + if (errored) return; + errored = true; const msg = err && err.message && typeof err.message === 'string' && err.message.startsWith('Error:') ? err.message : 'Error: ' + (err && err.message ? err.message : String(err)); reject(new Error(msg)); }); + fileStream.pipe(csvStream); }); } else { const inBuffer = await fs.promises.readFile(inPath); @@ -211,6 +230,7 @@ export async function runCli( } catch (error: unknown) { stderr.write((error instanceof Error ? error.message : String(error)) + '\n'); process.exitCode = 1; + return; } } From 2e5abfac16e6b8076c70bdcfe3cf543e4bb8ff0a Mon Sep 17 00:00:00 2001 From: Adil Date: Mon, 16 Jun 2025 00:50:57 +0500 Subject: [PATCH 11/13] refactor: remove fast-csv dependency and implement custom CSV writer --- __tests__/cli.ts | 57 +- package.json | 2 +- pnpm-lock.yaml | 3896 +++++++++++++++++++++++++--------------------- src/cli.ts | 271 ++-- 4 files changed, 2299 insertions(+), 1927 deletions(-) diff --git a/__tests__/cli.ts b/__tests__/cli.ts index b0287eb..1ee56cd 100644 --- a/__tests__/cli.ts +++ b/__tests__/cli.ts @@ -3,7 +3,7 @@ import * as path from 'path'; import * as os from 'os'; import { IOHLCV } from '../src/types'; import { withTimeout } from './utils'; -import { runCli } from '../src/cli'; +import { runCli, parseCSV } from '../src/cli'; import { Readable, Writable } from 'stream'; describe('CLI', () => { @@ -346,4 +346,59 @@ describe('CLI', () => { }, 1000, 'force CSV format'); }); }); + + describe('parseCSV', () => { + const { parseCSV } = require('../src/cli'); + it('parses CSV with header', () => { + const csv = 'time,open,high,low,close,volume\n1000,1,2,0.5,1.5,10'; + const result = parseCSV(csv); + expect(result).toEqual([{ time: 1000, open: 1, high: 2, low: 0.5, close: 1.5, volume: 10 }]); + }); + it('parses CSV without header', () => { + const csv = '1000,1,2,0.5,1.5,10'; + const result = parseCSV(csv); + expect(result).toEqual([{ time: 1000, open: 1, high: 2, low: 0.5, close: 1.5, volume: 10 }]); + }); + it('throws for empty CSV', () => { + expect(() => parseCSV('')).toThrow('Error: CSV must have at least one row'); + }); + it('omits lines with wrong number of columns', () => { + const csv = '1000,1,2,0.5,1.5,10\n2000,1,2,0.5,1.5\n3000,1,2,0.5,1.5,10'; + const result = parseCSV(csv); + expect(result).toEqual([ + { time: 1000, open: 1, high: 2, low: 0.5, close: 1.5, volume: 10 }, + { time: 3000, open: 1, high: 2, low: 0.5, close: 1.5, volume: 10 } + ]); + }); + it('omits lines with missing values', () => { + const csv = '1000,1,2,0.5,1.5,10\n2000,1,2,,1.5,10\n3000,1,2,0.5,1.5,10'; + const result = parseCSV(csv); + expect(result).toEqual([ + { time: 1000, open: 1, high: 2, low: 0.5, close: 1.5, volume: 10 }, + { time: 3000, open: 1, high: 2, low: 0.5, close: 1.5, volume: 10 } + ]); + }); + it('omits lines with non-numeric values', () => { + const csv = '1000,1,2,0.5,1.5,10\n2000,1,2,0.5,1.5,abc\n3000,1,2,0.5,1.5,10'; + const result = parseCSV(csv); + expect(result).toEqual([ + { time: 1000, open: 1, high: 2, low: 0.5, close: 1.5, volume: 10 }, + { time: 3000, open: 1, high: 2, low: 0.5, close: 1.5, volume: 10 } + ]); + }); + }); + + describe('detectFormat', () => { + const { detectFormat } = require('../src/cli'); + it('detects CSV for 5-comma line', () => { + expect(detectFormat('1,2,3,4,5,6')).toBe('csv'); + expect(detectFormat('1000,1,2,0.5,1.5,10\n')).toBe('csv'); + }); + it('detects JSON for valid JSON', () => { + expect(detectFormat('[{"time":1,"open":2,"high":3,"low":1,"close":2,"volume":10}]')).toBe('json'); + }); + it('throws for unknown format', () => { + expect(() => detectFormat('foo|bar|baz')).toThrow('Could not detect input format'); + }); + }); }); \ No newline at end of file diff --git a/package.json b/package.json index a5c0b4a..ae1f38c 100644 --- a/package.json +++ b/package.json @@ -45,6 +45,7 @@ "devDependencies": { "@types/jest": "^29.5.14", "@types/lodash": "^4.14.173", + "@types/node": "^24.0.1", "coveralls": "^3.1.1", "jest": ">=27.2.1", "rimraf": "^6.0.1", @@ -53,7 +54,6 @@ }, "dependencies": { "commander": "^14.0.0", - "fast-csv": "^5.0.2", "lodash": "^4.17.21", "ts-node": "^10.9.1" } diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 5c8e7ca..929e2a5 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -1,73 +1,1714 @@ -lockfileVersion: '6.0' +lockfileVersion: '9.0' settings: autoInstallPeers: true excludeLinksFromLockfile: false -dependencies: - commander: - specifier: ^14.0.0 - version: 14.0.0 - fast-csv: - specifier: ^5.0.2 - version: 5.0.2 - lodash: - specifier: ^4.17.21 - version: 4.17.21 - ts-node: - specifier: ^10.9.1 - version: 10.9.2(@types/node@24.0.1)(typescript@5.8.3) - -devDependencies: - '@types/jest': - specifier: ^29.5.14 - version: 29.5.14 - '@types/lodash': - specifier: ^4.14.173 - version: 4.17.17 - coveralls: - specifier: ^3.1.1 - version: 3.1.1 - jest: - specifier: '>=27.2.1' - version: 30.0.0(@types/node@24.0.1)(ts-node@10.9.2) - rimraf: - specifier: ^6.0.1 - version: 6.0.1 - ts-jest: - specifier: '>=25.1.0' - version: 29.4.0(@babel/core@7.27.4)(jest@30.0.0)(typescript@5.8.3) - typescript: - specifier: ^5.8.3 - version: 5.8.3 +importers: + + .: + dependencies: + commander: + specifier: ^14.0.0 + version: 14.0.0 + lodash: + specifier: ^4.17.21 + version: 4.17.21 + ts-node: + specifier: ^10.9.1 + version: 10.9.2(@types/node@24.0.1)(typescript@5.8.3) + devDependencies: + '@types/jest': + specifier: ^29.5.14 + version: 29.5.14 + '@types/lodash': + specifier: ^4.14.173 + version: 4.17.17 + '@types/node': + specifier: ^24.0.1 + version: 24.0.1 + coveralls: + specifier: ^3.1.1 + version: 3.1.1 + jest: + specifier: '>=27.2.1' + version: 30.0.0(@types/node@24.0.1)(ts-node@10.9.2(@types/node@24.0.1)(typescript@5.8.3)) + rimraf: + specifier: ^6.0.1 + version: 6.0.1 + ts-jest: + specifier: '>=25.1.0' + version: 29.4.0(@babel/core@7.27.4)(@jest/transform@30.0.0)(@jest/types@30.0.0)(babel-jest@30.0.0(@babel/core@7.27.4))(jest-util@30.0.0)(jest@30.0.0(@types/node@24.0.1)(ts-node@10.9.2(@types/node@24.0.1)(typescript@5.8.3)))(typescript@5.8.3) + typescript: + specifier: ^5.8.3 + version: 5.8.3 packages: - /@ampproject/remapping@2.3.0: - resolution: {integrity: sha512-30iZtAPgz+LTIYoeivqYo853f02jBYSd5uGnGpkFV0M3xOt9aN73erkgYAmZU43x4VfqcnLxW9Kpg3R5LC4YYw==} - engines: {node: '>=6.0.0'} + '@ampproject/remapping@2.3.0': + resolution: {integrity: sha512-30iZtAPgz+LTIYoeivqYo853f02jBYSd5uGnGpkFV0M3xOt9aN73erkgYAmZU43x4VfqcnLxW9Kpg3R5LC4YYw==} + engines: {node: '>=6.0.0'} + + '@babel/code-frame@7.27.1': + resolution: {integrity: sha512-cjQ7ZlQ0Mv3b47hABuTevyTuYN4i+loJKGeV9flcCgIK37cCXRh+L1bd3iBHlynerhQ7BhCkn2BPbQUL+rGqFg==} + engines: {node: '>=6.9.0'} + + '@babel/compat-data@7.27.5': + resolution: {integrity: sha512-KiRAp/VoJaWkkte84TvUd9qjdbZAdiqyvMxrGl1N6vzFogKmaLgoM3L1kgtLicp2HP5fBJS8JrZKLVIZGVJAVg==} + engines: {node: '>=6.9.0'} + + '@babel/core@7.27.4': + resolution: {integrity: sha512-bXYxrXFubeYdvB0NhD/NBB3Qi6aZeV20GOWVI47t2dkecCEoneR4NPVcb7abpXDEvejgrUfFtG6vG/zxAKmg+g==} + engines: {node: '>=6.9.0'} + + '@babel/generator@7.27.5': + resolution: {integrity: sha512-ZGhA37l0e/g2s1Cnzdix0O3aLYm66eF8aufiVteOgnwxgnRP8GoyMj7VWsgWnQbVKXyge7hqrFh2K2TQM6t1Hw==} + engines: {node: '>=6.9.0'} + + '@babel/helper-compilation-targets@7.27.2': + resolution: {integrity: sha512-2+1thGUUWWjLTYTHZWK1n8Yga0ijBz1XAhUXcKy81rd5g6yh7hGqMp45v7cadSbEHc9G3OTv45SyneRN3ps4DQ==} + engines: {node: '>=6.9.0'} + + '@babel/helper-module-imports@7.27.1': + resolution: {integrity: sha512-0gSFWUPNXNopqtIPQvlD5WgXYI5GY2kP2cCvoT8kczjbfcfuIljTbcWrulD1CIPIX2gt1wghbDy08yE1p+/r3w==} + engines: {node: '>=6.9.0'} + + '@babel/helper-module-transforms@7.27.3': + resolution: {integrity: sha512-dSOvYwvyLsWBeIRyOeHXp5vPj5l1I011r52FM1+r1jCERv+aFXYk4whgQccYEGYxK2H3ZAIA8nuPkQ0HaUo3qg==} + engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.0.0 + + '@babel/helper-plugin-utils@7.27.1': + resolution: {integrity: sha512-1gn1Up5YXka3YYAHGKpbideQ5Yjf1tDa9qYcgysz+cNCXukyLl6DjPXhD3VRwSb8c0J9tA4b2+rHEZtc6R0tlw==} + engines: {node: '>=6.9.0'} + + '@babel/helper-string-parser@7.27.1': + resolution: {integrity: sha512-qMlSxKbpRlAridDExk92nSobyDdpPijUq2DW6oDnUqd0iOGxmQjyqhMIihI9+zv4LPyZdRje2cavWPbCbWm3eA==} + engines: {node: '>=6.9.0'} + + '@babel/helper-validator-identifier@7.27.1': + resolution: {integrity: sha512-D2hP9eA+Sqx1kBZgzxZh0y1trbuU+JoDkiEwqhQ36nodYqJwyEIhPSdMNd7lOm/4io72luTPWH20Yda0xOuUow==} + engines: {node: '>=6.9.0'} + + '@babel/helper-validator-option@7.27.1': + resolution: {integrity: sha512-YvjJow9FxbhFFKDSuFnVCe2WxXk1zWc22fFePVNEaWJEu8IrZVlda6N0uHwzZrUM1il7NC9Mlp4MaJYbYd9JSg==} + engines: {node: '>=6.9.0'} + + '@babel/helpers@7.27.6': + resolution: {integrity: sha512-muE8Tt8M22638HU31A3CgfSUciwz1fhATfoVai05aPXGor//CdWDCbnlY1yvBPo07njuVOCNGCSp/GTt12lIug==} + engines: {node: '>=6.9.0'} + + '@babel/parser@7.27.5': + resolution: {integrity: sha512-OsQd175SxWkGlzbny8J3K8TnnDD0N3lrIUtB92xwyRpzaenGZhxDvxN/JgU00U3CDZNj9tPuDJ5H0WS4Nt3vKg==} + engines: {node: '>=6.0.0'} + hasBin: true + + '@babel/plugin-syntax-async-generators@7.8.4': + resolution: {integrity: sha512-tycmZxkGfZaxhMRbXlPXuVFpdWlXpir2W4AMhSJgRKzk/eDlIXOhb2LHWoLpDF7TEHylV5zNhykX6KAgHJmTNw==} + peerDependencies: + '@babel/core': ^7.0.0-0 + + '@babel/plugin-syntax-bigint@7.8.3': + resolution: {integrity: sha512-wnTnFlG+YxQm3vDxpGE57Pj0srRU4sHE/mDkt1qv2YJJSeUAec2ma4WLUnUPeKjyrfntVwe/N6dCXpU+zL3Npg==} + peerDependencies: + '@babel/core': ^7.0.0-0 + + '@babel/plugin-syntax-class-properties@7.12.13': + resolution: {integrity: sha512-fm4idjKla0YahUNgFNLCB0qySdsoPiZP3iQE3rky0mBUtMZ23yDJ9SJdg6dXTSDnulOVqiF3Hgr9nbXvXTQZYA==} + peerDependencies: + '@babel/core': ^7.0.0-0 + + '@babel/plugin-syntax-class-static-block@7.14.5': + resolution: {integrity: sha512-b+YyPmr6ldyNnM6sqYeMWE+bgJcJpO6yS4QD7ymxgH34GBPNDM/THBh8iunyvKIZztiwLH4CJZ0RxTk9emgpjw==} + engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.0.0-0 + + '@babel/plugin-syntax-import-attributes@7.27.1': + resolution: {integrity: sha512-oFT0FrKHgF53f4vOsZGi2Hh3I35PfSmVs4IBFLFj4dnafP+hIWDLg3VyKmUHfLoLHlyxY4C7DGtmHuJgn+IGww==} + engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.0.0-0 + + '@babel/plugin-syntax-import-meta@7.10.4': + resolution: {integrity: sha512-Yqfm+XDx0+Prh3VSeEQCPU81yC+JWZ2pDPFSS4ZdpfZhp4MkFMaDC1UqseovEKwSUpnIL7+vK+Clp7bfh0iD7g==} + peerDependencies: + '@babel/core': ^7.0.0-0 + + '@babel/plugin-syntax-json-strings@7.8.3': + resolution: {integrity: sha512-lY6kdGpWHvjoe2vk4WrAapEuBR69EMxZl+RoGRhrFGNYVK8mOPAW8VfbT/ZgrFbXlDNiiaxQnAtgVCZ6jv30EA==} + peerDependencies: + '@babel/core': ^7.0.0-0 + + '@babel/plugin-syntax-jsx@7.27.1': + resolution: {integrity: sha512-y8YTNIeKoyhGd9O0Jiyzyyqk8gdjnumGTQPsz0xOZOQ2RmkVJeZ1vmmfIvFEKqucBG6axJGBZDE/7iI5suUI/w==} + engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.0.0-0 + + '@babel/plugin-syntax-logical-assignment-operators@7.10.4': + resolution: {integrity: sha512-d8waShlpFDinQ5MtvGU9xDAOzKH47+FFoney2baFIoMr952hKOLp1HR7VszoZvOsV/4+RRszNY7D17ba0te0ig==} + peerDependencies: + '@babel/core': ^7.0.0-0 + + '@babel/plugin-syntax-nullish-coalescing-operator@7.8.3': + resolution: {integrity: sha512-aSff4zPII1u2QD7y+F8oDsz19ew4IGEJg9SVW+bqwpwtfFleiQDMdzA/R+UlWDzfnHFCxxleFT0PMIrR36XLNQ==} + peerDependencies: + '@babel/core': ^7.0.0-0 + + '@babel/plugin-syntax-numeric-separator@7.10.4': + resolution: {integrity: sha512-9H6YdfkcK/uOnY/K7/aA2xpzaAgkQn37yzWUMRK7OaPOqOpGS1+n0H5hxT9AUw9EsSjPW8SVyMJwYRtWs3X3ug==} + peerDependencies: + '@babel/core': ^7.0.0-0 + + '@babel/plugin-syntax-object-rest-spread@7.8.3': + resolution: {integrity: sha512-XoqMijGZb9y3y2XskN+P1wUGiVwWZ5JmoDRwx5+3GmEplNyVM2s2Dg8ILFQm8rWM48orGy5YpI5Bl8U1y7ydlA==} + peerDependencies: + '@babel/core': ^7.0.0-0 + + '@babel/plugin-syntax-optional-catch-binding@7.8.3': + resolution: {integrity: sha512-6VPD0Pc1lpTqw0aKoeRTMiB+kWhAoT24PA+ksWSBrFtl5SIRVpZlwN3NNPQjehA2E/91FV3RjLWoVTglWcSV3Q==} + peerDependencies: + '@babel/core': ^7.0.0-0 + + '@babel/plugin-syntax-optional-chaining@7.8.3': + resolution: {integrity: sha512-KoK9ErH1MBlCPxV0VANkXW2/dw4vlbGDrFgz8bmUsBGYkFRcbRwMh6cIJubdPrkxRwuGdtCk0v/wPTKbQgBjkg==} + peerDependencies: + '@babel/core': ^7.0.0-0 + + '@babel/plugin-syntax-private-property-in-object@7.14.5': + resolution: {integrity: sha512-0wVnp9dxJ72ZUJDV27ZfbSj6iHLoytYZmh3rFcxNnvsJF3ktkzLDZPy/mA17HGsaQT3/DQsWYX1f1QGWkCoVUg==} + engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.0.0-0 + + '@babel/plugin-syntax-top-level-await@7.14.5': + resolution: {integrity: sha512-hx++upLv5U1rgYfwe1xBQUhRmU41NEvpUvrp8jkrSCdvGSnM5/qdRMtylJ6PG5OFkBaHkbTAKTnd3/YyESRHFw==} + engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.0.0-0 + + '@babel/plugin-syntax-typescript@7.27.1': + resolution: {integrity: sha512-xfYCBMxveHrRMnAWl1ZlPXOZjzkN82THFvLhQhFXFt81Z5HnN+EtUkZhv/zcKpmT3fzmWZB0ywiBrbC3vogbwQ==} + engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.0.0-0 + + '@babel/template@7.27.2': + resolution: {integrity: sha512-LPDZ85aEJyYSd18/DkjNh4/y1ntkE5KwUHWTiqgRxruuZL2F1yuHligVHLvcHY2vMHXttKFpJn6LwfI7cw7ODw==} + engines: {node: '>=6.9.0'} + + '@babel/traverse@7.27.4': + resolution: {integrity: sha512-oNcu2QbHqts9BtOWJosOVJapWjBDSxGCpFvikNR5TGDYDQf3JwpIoMzIKrvfoti93cLfPJEG4tH9SPVeyCGgdA==} + engines: {node: '>=6.9.0'} + + '@babel/types@7.27.6': + resolution: {integrity: sha512-ETyHEk2VHHvl9b9jZP5IHPavHYk57EhanlRRuae9XCpb/j5bDCbPPMOBfCWhnl/7EDJz0jEMCi/RhccCE8r1+Q==} + engines: {node: '>=6.9.0'} + + '@bcoe/v8-coverage@0.2.3': + resolution: {integrity: sha512-0hYQ8SB4Db5zvZB4axdMHGwEaQjkZzFjQiN9LVYvIFB2nSUHW9tYpxWriPrWDASIxiaXax83REcLxuSdnGPZtw==} + + '@cspotcode/source-map-support@0.8.1': + resolution: {integrity: sha512-IchNf6dN4tHoMFIn/7OE8LWZ19Y6q/67Bmf6vnGREv8RSbBVb9LPJxEcnwrcwX6ixSvaiGoomAUvu4YSxXrVgw==} + engines: {node: '>=12'} + + '@emnapi/core@1.4.3': + resolution: {integrity: sha512-4m62DuCE07lw01soJwPiBGC0nAww0Q+RY70VZ+n49yDIO13yyinhbWCeNnaob0lakDtWQzSdtNWzJeOJt2ma+g==} + + '@emnapi/runtime@1.4.3': + resolution: {integrity: sha512-pBPWdu6MLKROBX05wSNKcNb++m5Er+KQ9QkB+WVM+pW2Kx9hoSrVTnu3BdkI5eBLZoKu/J6mW/B6i6bJB2ytXQ==} + + '@emnapi/wasi-threads@1.0.2': + resolution: {integrity: sha512-5n3nTJblwRi8LlXkJ9eBzu+kZR8Yxcc7ubakyQTFzPMtIhFpUBRbsnc2Dv88IZDIbCDlBiWrknhB4Lsz7mg6BA==} + + '@isaacs/balanced-match@4.0.1': + resolution: {integrity: sha512-yzMTt9lEb8Gv7zRioUilSglI0c0smZ9k5D65677DLWLtWJaXIS3CqcGyUFByYKlnUj6TkjLVs54fBl6+TiGQDQ==} + engines: {node: 20 || >=22} + + '@isaacs/brace-expansion@5.0.0': + resolution: {integrity: sha512-ZT55BDLV0yv0RBm2czMiZ+SqCGO7AvmOM3G/w2xhVPH+te0aKgFjmBvGlL1dH+ql2tgGO3MVrbb3jCKyvpgnxA==} + engines: {node: 20 || >=22} + + '@isaacs/cliui@8.0.2': + resolution: {integrity: sha512-O8jcjabXaleOG9DQ0+ARXWZBTfnP4WNAqzuiJK7ll44AmxGKv/J2M4TPjxjY3znBCfvBXFzucm1twdyFybFqEA==} + engines: {node: '>=12'} + + '@istanbuljs/load-nyc-config@1.1.0': + resolution: {integrity: sha512-VjeHSlIzpv/NyD3N0YuHfXOPDIixcA1q2ZV98wsMqcYlPmv2n3Yb2lYP9XMElnaFVXg5A7YLTeLu6V84uQDjmQ==} + engines: {node: '>=8'} + + '@istanbuljs/schema@0.1.3': + resolution: {integrity: sha512-ZXRY4jNvVgSVQ8DL3LTcakaAtXwTVUxE81hslsyD2AtoXW/wVob10HkOJ1X/pAlcI7D+2YoZKg5do8G/w6RYgA==} + engines: {node: '>=8'} + + '@jest/console@30.0.0': + resolution: {integrity: sha512-vfpJap6JZQ3I8sUN8dsFqNAKJYO4KIGxkcB+3Fw7Q/BJiWY5HwtMMiuT1oP0avsiDhjE/TCLaDgbGfHwDdBVeg==} + engines: {node: ^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0} + + '@jest/core@30.0.0': + resolution: {integrity: sha512-1zU39zFtWSl5ZuDK3Rd6P8S28MmS4F11x6Z4CURrgJ99iaAJg68hmdJ2SAHEEO6ociaNk43UhUYtHxWKEWoNYw==} + engines: {node: ^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0} + peerDependencies: + node-notifier: ^8.0.1 || ^9.0.0 || ^10.0.0 + peerDependenciesMeta: + node-notifier: + optional: true + + '@jest/diff-sequences@30.0.0': + resolution: {integrity: sha512-xMbtoCeKJDto86GW6AiwVv7M4QAuI56R7dVBr1RNGYbOT44M2TIzOiske2RxopBqkumDY+A1H55pGvuribRY9A==} + engines: {node: ^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0} + + '@jest/environment@30.0.0': + resolution: {integrity: sha512-09sFbMMgS5JxYnvgmmtwIHhvoyzvR5fUPrVl8nOCrC5KdzmmErTcAxfWyAhJ2bv3rvHNQaKiS+COSG+O7oNbXw==} + engines: {node: ^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0} + + '@jest/expect-utils@29.7.0': + resolution: {integrity: sha512-GlsNBWiFQFCVi9QVSx7f5AgMeLxe9YCCs5PuP2O2LdjDAA8Jh9eX7lA1Jq/xdXw3Wb3hyvlFNfZIfcRetSzYcA==} + engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} + + '@jest/expect-utils@30.0.0': + resolution: {integrity: sha512-UiWfsqNi/+d7xepfOv8KDcbbzcYtkWBe3a3kVDtg6M1kuN6CJ7b4HzIp5e1YHrSaQaVS8sdCoyCMCZClTLNKFQ==} + engines: {node: ^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0} + + '@jest/expect@30.0.0': + resolution: {integrity: sha512-XZ3j6syhMeKiBknmmc8V3mNIb44kxLTbOQtaXA4IFdHy+vEN0cnXRzbRjdGBtrp4k1PWyMWNU3Fjz3iejrhpQg==} + engines: {node: ^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0} + + '@jest/fake-timers@30.0.0': + resolution: {integrity: sha512-yzBmJcrMHAMcAEbV2w1kbxmx8WFpEz8Cth3wjLMSkq+LO8VeGKRhpr5+BUp7PPK+x4njq/b6mVnDR8e/tPL5ng==} + engines: {node: ^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0} + + '@jest/get-type@30.0.0': + resolution: {integrity: sha512-VZWMjrBzqfDKngQ7sUctKeLxanAbsBFoZnPxNIG6CmxK7Gv6K44yqd0nzveNIBfuhGZMmk1n5PGbvdSTOu0yTg==} + engines: {node: ^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0} + + '@jest/globals@30.0.0': + resolution: {integrity: sha512-OEzYes5A1xwBJVMPqFRa8NCao8Vr42nsUZuf/SpaJWoLE+4kyl6nCQZ1zqfipmCrIXQVALC5qJwKy/7NQQLPhw==} + engines: {node: ^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0} + + '@jest/pattern@30.0.0': + resolution: {integrity: sha512-k+TpEThzLVXMkbdxf8KHjZ83Wl+G54ytVJoDIGWwS96Ql4xyASRjc6SU1hs5jHVql+hpyK9G8N7WuFhLpGHRpQ==} + engines: {node: ^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0} + + '@jest/reporters@30.0.0': + resolution: {integrity: sha512-5WHNlLO0Ok+/o6ML5IzgVm1qyERtLHBNhwn67PAq92H4hZ+n5uW/BYj1VVwmTdxIcNrZLxdV9qtpdZkXf16HxA==} + engines: {node: ^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0} + peerDependencies: + node-notifier: ^8.0.1 || ^9.0.0 || ^10.0.0 + peerDependenciesMeta: + node-notifier: + optional: true + + '@jest/schemas@29.6.3': + resolution: {integrity: sha512-mo5j5X+jIZmJQveBKeS/clAueipV7KgiX1vMgCxam1RNYiqE1w62n0/tJJnHtjW8ZHcQco5gY85jA3mi0L+nSA==} + engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} + + '@jest/schemas@30.0.0': + resolution: {integrity: sha512-NID2VRyaEkevCRz6badhfqYwri/RvMbiHY81rk3AkK/LaiB0LSxi1RdVZ7MpZdTjNugtZeGfpL0mLs9Kp3MrQw==} + engines: {node: ^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0} + + '@jest/snapshot-utils@30.0.0': + resolution: {integrity: sha512-C/QSFUmvZEYptg2Vin84FggAphwHvj6la39vkw1CNOZQORWZ7O/H0BXmdeeeGnvlXDYY8TlFM5jgFnxLAxpFjA==} + engines: {node: ^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0} + + '@jest/source-map@30.0.0': + resolution: {integrity: sha512-oYBJ4d/NF4ZY3/7iq1VaeoERHRvlwKtrGClgescaXMIa1mmb+vfJd0xMgbW9yrI80IUA7qGbxpBWxlITrHkWoA==} + engines: {node: ^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0} + + '@jest/test-result@30.0.0': + resolution: {integrity: sha512-685zco9HdgBaaWiB9T4xjLtBuN0Q795wgaQPpmuAeZPHwHZSoKFAUnozUtU+ongfi4l5VCz8AclOE5LAQdyjxQ==} + engines: {node: ^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0} + + '@jest/test-sequencer@30.0.0': + resolution: {integrity: sha512-Hmvv5Yg6UmghXIcVZIydkT0nAK7M/hlXx9WMHR5cLVwdmc14/qUQt3mC72T6GN0olPC6DhmKE6Cd/pHsgDbuqQ==} + engines: {node: ^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0} + + '@jest/transform@30.0.0': + resolution: {integrity: sha512-8xhpsCGYJsUjqpJOgLyMkeOSSlhqggFZEWAnZquBsvATtueoEs7CkMRxOUmJliF3E5x+mXmZ7gEEsHank029Og==} + engines: {node: ^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0} + + '@jest/types@29.6.3': + resolution: {integrity: sha512-u3UPsIilWKOM3F9CXtrG8LEJmNxwoCQC/XVj4IKYXvvpx7QIi/Kg1LI5uDmDpKlac62NUtX7eLjRh+jVZcLOzw==} + engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} + + '@jest/types@30.0.0': + resolution: {integrity: sha512-1Nox8mAL52PKPfEnUQWBvKU/bp8FTT6AiDu76bFDEJj/qsRFSAVSldfCH3XYMqialti2zHXKvD5gN0AaHc0yKA==} + engines: {node: ^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0} + + '@jridgewell/gen-mapping@0.3.8': + resolution: {integrity: sha512-imAbBGkb+ebQyxKgzv5Hu2nmROxoDOXHh80evxdoXNOrvAnVx7zimzc1Oo5h9RlfV4vPXaE2iM5pOFbvOCClWA==} + engines: {node: '>=6.0.0'} + + '@jridgewell/resolve-uri@3.1.2': + resolution: {integrity: sha512-bRISgCIjP20/tbWSPWMEi54QVPRZExkuD9lJL+UIxUKtwVJA8wW1Trb1jMs1RFXo1CBTNZ/5hpC9QvmKWdopKw==} + engines: {node: '>=6.0.0'} + + '@jridgewell/set-array@1.2.1': + resolution: {integrity: sha512-R8gLRTZeyp03ymzP/6Lil/28tGeGEzhx1q2k703KGWRAI1VdvPIXdG70VJc2pAMw3NA6JKL5hhFu1sJX0Mnn/A==} + engines: {node: '>=6.0.0'} + + '@jridgewell/sourcemap-codec@1.5.0': + resolution: {integrity: sha512-gv3ZRaISU3fjPAgNsriBRqGWQL6quFx04YMPW/zD8XMLsU32mhCCbfbO6KZFLjvYpCZ8zyDEgqsgf+PwPaM7GQ==} + + '@jridgewell/trace-mapping@0.3.25': + resolution: {integrity: sha512-vNk6aEwybGtawWmy/PzwnGDOjCkLWSD2wqvjGGAgOAwCGWySYXfYoxt00IJkTF+8Lb57DwOb3Aa0o9CApepiYQ==} + + '@jridgewell/trace-mapping@0.3.9': + resolution: {integrity: sha512-3Belt6tdc8bPgAtbcmdtNJlirVoTmEb5e2gC94PnkwEW9jI6CAHUeoG85tjWP5WquqfavoMtMwiG4P926ZKKuQ==} + + '@napi-rs/wasm-runtime@0.2.11': + resolution: {integrity: sha512-9DPkXtvHydrcOsopiYpUgPHpmj0HWZKMUnL2dZqpvC42lsratuBG06V5ipyno0fUek5VlFsNQ+AcFATSrJXgMA==} + + '@pkgjs/parseargs@0.11.0': + resolution: {integrity: sha512-+1VkjdD0QBLPodGrJUeqarH8VAIvQODIbwh9XpP5Syisf7YoQgsJKPNFoqqLQlu+VQ/tVSshMR6loPMn8U+dPg==} + engines: {node: '>=14'} + + '@pkgr/core@0.2.7': + resolution: {integrity: sha512-YLT9Zo3oNPJoBjBc4q8G2mjU4tqIbf5CEOORbUUr48dCD9q3umJ3IPlVqOqDakPfd2HuwccBaqlGhN4Gmr5OWg==} + engines: {node: ^12.20.0 || ^14.18.0 || >=16.0.0} + + '@sinclair/typebox@0.27.8': + resolution: {integrity: sha512-+Fj43pSMwJs4KRrH/938Uf+uAELIgVBmQzg/q1YG10djyfA3TnrU8N8XzqCh/okZdszqBQTZf96idMfE5lnwTA==} + + '@sinclair/typebox@0.34.35': + resolution: {integrity: sha512-C6ypdODf2VZkgRT6sFM8E1F8vR+HcffniX0Kp8MsU8PIfrlXbNCBz0jzj17GjdmjTx1OtZzdH8+iALL21UjF5A==} + + '@sinonjs/commons@3.0.1': + resolution: {integrity: sha512-K3mCHKQ9sVh8o1C9cxkwxaOmXoAMlDxC1mYyHrjqOWEcBjYr76t96zL2zlj5dUGZ3HSw240X1qgH3Mjf1yJWpQ==} + + '@sinonjs/fake-timers@13.0.5': + resolution: {integrity: sha512-36/hTbH2uaWuGVERyC6da9YwGWnzUZXuPro/F2LfsdOsLnCojz/iSH8MxUt/FD2S5XBSVPhmArFUXcpCQ2Hkiw==} + + '@tsconfig/node10@1.0.11': + resolution: {integrity: sha512-DcRjDCujK/kCk/cUe8Xz8ZSpm8mS3mNNpta+jGCA6USEDfktlNvm1+IuZ9eTcDbNk41BHwpHHeW+N1lKCz4zOw==} + + '@tsconfig/node12@1.0.11': + resolution: {integrity: sha512-cqefuRsh12pWyGsIoBKJA9luFu3mRxCA+ORZvA4ktLSzIuCUtWVxGIuXigEwO5/ywWFMZ2QEGKWvkZG1zDMTag==} + + '@tsconfig/node14@1.0.3': + resolution: {integrity: sha512-ysT8mhdixWK6Hw3i1V2AeRqZ5WfXg1G43mqoYlM2nc6388Fq5jcXyr5mRsqViLx/GJYdoL0bfXD8nmF+Zn/Iow==} + + '@tsconfig/node16@1.0.4': + resolution: {integrity: sha512-vxhUy4J8lyeyinH7Azl1pdd43GJhZH/tP2weN8TntQblOY+A0XbT8DJk1/oCPuOOyg/Ja757rG0CgHcWC8OfMA==} + + '@tybys/wasm-util@0.9.0': + resolution: {integrity: sha512-6+7nlbMVX/PVDCwaIQ8nTOPveOcFLSt8GcXdx8hD0bt39uWxYT88uXzqTd4fTvqta7oeUJqudepapKNt2DYJFw==} + + '@types/babel__core@7.20.5': + resolution: {integrity: sha512-qoQprZvz5wQFJwMDqeseRXWv3rqMvhgpbXFfVyWhbx9X47POIA6i/+dXefEmZKoAgOaTdaIgNSMqMIU61yRyzA==} + + '@types/babel__generator@7.27.0': + resolution: {integrity: sha512-ufFd2Xi92OAVPYsy+P4n7/U7e68fex0+Ee8gSG9KX7eo084CWiQ4sdxktvdl0bOPupXtVJPY19zk6EwWqUQ8lg==} + + '@types/babel__template@7.4.4': + resolution: {integrity: sha512-h/NUaSyG5EyxBIp8YRxo4RMe2/qQgvyowRwVMzhYhBCONbW8PUsg4lkFMrhgZhUe5z3L3MiLDuvyJ/CaPa2A8A==} + + '@types/babel__traverse@7.20.7': + resolution: {integrity: sha512-dkO5fhS7+/oos4ciWxyEyjWe48zmG6wbCheo/G2ZnHx4fs3EU6YC6UM8rk56gAjNJ9P3MTH2jo5jb92/K6wbng==} + + '@types/istanbul-lib-coverage@2.0.6': + resolution: {integrity: sha512-2QF/t/auWm0lsy8XtKVPG19v3sSOQlJe/YHZgfjb/KBBHOGSV+J2q/S671rcq9uTBrLAXmZpqJiaQbMT+zNU1w==} + + '@types/istanbul-lib-report@3.0.3': + resolution: {integrity: sha512-NQn7AHQnk/RSLOxrBbGyJM/aVQ+pjj5HCgasFxc0K/KhoATfQ/47AyUl15I2yBUpihjmas+a+VJBOqecrFH+uA==} + + '@types/istanbul-reports@3.0.4': + resolution: {integrity: sha512-pk2B1NWalF9toCRu6gjBzR69syFjP4Od8WRAX+0mmf9lAjCRicLOWc+ZrxZHx/0XRjotgkF9t6iaMJ+aXcOdZQ==} + + '@types/jest@29.5.14': + resolution: {integrity: sha512-ZN+4sdnLUbo8EVvVc2ao0GFW6oVrQRPn4K2lglySj7APvSrgzxHiNNK99us4WDMi57xxA2yggblIAMNhXOotLQ==} + + '@types/lodash@4.17.17': + resolution: {integrity: sha512-RRVJ+J3J+WmyOTqnz3PiBLA501eKwXl2noseKOrNo/6+XEHjTAxO4xHvxQB6QuNm+s4WRbn6rSiap8+EA+ykFQ==} + + '@types/node@24.0.1': + resolution: {integrity: sha512-MX4Zioh39chHlDJbKmEgydJDS3tspMP/lnQC67G3SWsTnb9NeYVWOjkxpOSy4oMfPs4StcWHwBrvUb4ybfnuaw==} + + '@types/stack-utils@2.0.3': + resolution: {integrity: sha512-9aEbYZ3TbYMznPdcdr3SmIrLXwC/AKZXQeCf9Pgao5CKb8CyHuEX5jzWPTkvregvhRJHcpRO6BFoGW9ycaOkYw==} + + '@types/yargs-parser@21.0.3': + resolution: {integrity: sha512-I4q9QU9MQv4oEOz4tAHJtNz1cwuLxn2F3xcc2iV5WdqLPpUnj30aUuxt1mAxYTG+oe8CZMV/+6rU4S4gRDzqtQ==} + + '@types/yargs@17.0.33': + resolution: {integrity: sha512-WpxBCKWPLr4xSsHgz511rFJAM+wS28w2zEO1QDNY5zM/S8ok70NNfztH0xwhqKyaK0OHCbN98LDAZuy1ctxDkA==} + + '@ungap/structured-clone@1.3.0': + resolution: {integrity: sha512-WmoN8qaIAo7WTYWbAZuG8PYEhn5fkz7dZrqTBZ7dtt//lL2Gwms1IcnQ5yHqjDfX8Ft5j4YzDM23f87zBfDe9g==} + + '@unrs/resolver-binding-android-arm-eabi@1.9.0': + resolution: {integrity: sha512-h1T2c2Di49ekF2TE8ZCoJkb+jwETKUIPDJ/nO3tJBKlLFPu+fyd93f0rGP/BvArKx2k2HlRM4kqkNarj3dvZlg==} + cpu: [arm] + os: [android] + + '@unrs/resolver-binding-android-arm64@1.9.0': + resolution: {integrity: sha512-sG1NHtgXtX8owEkJ11yn34vt0Xqzi3k9TJ8zppDmyG8GZV4kVWw44FHwKwHeEFl07uKPeC4ZoyuQaGh5ruJYPA==} + cpu: [arm64] + os: [android] + + '@unrs/resolver-binding-darwin-arm64@1.9.0': + resolution: {integrity: sha512-nJ9z47kfFnCxN1z/oYZS7HSNsFh43y2asePzTEZpEvK7kGyuShSl3RRXnm/1QaqFL+iP+BjMwuB+DYUymOkA5A==} + cpu: [arm64] + os: [darwin] + + '@unrs/resolver-binding-darwin-x64@1.9.0': + resolution: {integrity: sha512-TK+UA1TTa0qS53rjWn7cVlEKVGz2B6JYe0C++TdQjvWYIyx83ruwh0wd4LRxYBM5HeuAzXcylA9BH2trARXJTw==} + cpu: [x64] + os: [darwin] + + '@unrs/resolver-binding-freebsd-x64@1.9.0': + resolution: {integrity: sha512-6uZwzMRFcD7CcCd0vz3Hp+9qIL2jseE/bx3ZjaLwn8t714nYGwiE84WpaMCYjU+IQET8Vu/+BNAGtYD7BG/0yA==} + cpu: [x64] + os: [freebsd] + + '@unrs/resolver-binding-linux-arm-gnueabihf@1.9.0': + resolution: {integrity: sha512-bPUBksQfrgcfv2+mm+AZinaKq8LCFvt5PThYqRotqSuuZK1TVKkhbVMS/jvSRfYl7jr3AoZLYbDkItxgqMKRkg==} + cpu: [arm] + os: [linux] + + '@unrs/resolver-binding-linux-arm-musleabihf@1.9.0': + resolution: {integrity: sha512-uT6E7UBIrTdCsFQ+y0tQd3g5oudmrS/hds5pbU3h4s2t/1vsGWbbSKhBSCD9mcqaqkBwoqlECpUrRJCmldl8PA==} + cpu: [arm] + os: [linux] + + '@unrs/resolver-binding-linux-arm64-gnu@1.9.0': + resolution: {integrity: sha512-vdqBh911wc5awE2bX2zx3eflbyv8U9xbE/jVKAm425eRoOVv/VseGZsqi3A3SykckSpF4wSROkbQPvbQFn8EsA==} + cpu: [arm64] + os: [linux] + + '@unrs/resolver-binding-linux-arm64-musl@1.9.0': + resolution: {integrity: sha512-/8JFZ/SnuDr1lLEVsxsuVwrsGquTvT51RZGvyDB/dOK3oYK2UqeXzgeyq6Otp8FZXQcEYqJwxb9v+gtdXn03eQ==} + cpu: [arm64] + os: [linux] + + '@unrs/resolver-binding-linux-ppc64-gnu@1.9.0': + resolution: {integrity: sha512-FkJjybtrl+rajTw4loI3L6YqSOpeZfDls4SstL/5lsP2bka9TiHUjgMBjygeZEis1oC8LfJTS8FSgpKPaQx2tQ==} + cpu: [ppc64] + os: [linux] + + '@unrs/resolver-binding-linux-riscv64-gnu@1.9.0': + resolution: {integrity: sha512-w/NZfHNeDusbqSZ8r/hp8iL4S39h4+vQMc9/vvzuIKMWKppyUGKm3IST0Qv0aOZ1rzIbl9SrDeIqK86ZpUK37w==} + cpu: [riscv64] + os: [linux] + + '@unrs/resolver-binding-linux-riscv64-musl@1.9.0': + resolution: {integrity: sha512-bEPBosut8/8KQbUixPry8zg/fOzVOWyvwzOfz0C0Rw6dp+wIBseyiHKjkcSyZKv/98edrbMknBaMNJfA/UEdqw==} + cpu: [riscv64] + os: [linux] + + '@unrs/resolver-binding-linux-s390x-gnu@1.9.0': + resolution: {integrity: sha512-LDtMT7moE3gK753gG4pc31AAqGUC86j3AplaFusc717EUGF9ZFJ356sdQzzZzkBk1XzMdxFyZ4f/i35NKM/lFA==} + cpu: [s390x] + os: [linux] + + '@unrs/resolver-binding-linux-x64-gnu@1.9.0': + resolution: {integrity: sha512-WmFd5KINHIXj8o1mPaT8QRjA9HgSXhN1gl9Da4IZihARihEnOylu4co7i/yeaIpcfsI6sYs33cNZKyHYDh0lrA==} + cpu: [x64] + os: [linux] + + '@unrs/resolver-binding-linux-x64-musl@1.9.0': + resolution: {integrity: sha512-CYuXbANW+WgzVRIl8/QvZmDaZxrqvOldOwlbUjIM4pQ46FJ0W5cinJ/Ghwa/Ng1ZPMJMk1VFdsD/XwmCGIXBWg==} + cpu: [x64] + os: [linux] + + '@unrs/resolver-binding-wasm32-wasi@1.9.0': + resolution: {integrity: sha512-6Rp2WH0OoitMYR57Z6VE8Y6corX8C6QEMWLgOV6qXiJIeZ1F9WGXY/yQ8yDC4iTraotyLOeJ2Asea0urWj2fKQ==} + engines: {node: '>=14.0.0'} + cpu: [wasm32] + + '@unrs/resolver-binding-win32-arm64-msvc@1.9.0': + resolution: {integrity: sha512-rknkrTRuvujprrbPmGeHi8wYWxmNVlBoNW8+4XF2hXUnASOjmuC9FNF1tGbDiRQWn264q9U/oGtixyO3BT8adQ==} + cpu: [arm64] + os: [win32] + + '@unrs/resolver-binding-win32-ia32-msvc@1.9.0': + resolution: {integrity: sha512-Ceymm+iBl+bgAICtgiHyMLz6hjxmLJKqBim8tDzpX61wpZOx2bPK6Gjuor7I2RiUynVjvvkoRIkrPyMwzBzF3A==} + cpu: [ia32] + os: [win32] + + '@unrs/resolver-binding-win32-x64-msvc@1.9.0': + resolution: {integrity: sha512-k59o9ZyeyS0hAlcaKFezYSH2agQeRFEB7KoQLXl3Nb3rgkqT1NY9Vwy+SqODiLmYnEjxWJVRE/yq2jFVqdIxZw==} + cpu: [x64] + os: [win32] + + acorn-walk@8.3.4: + resolution: {integrity: sha512-ueEepnujpqee2o5aIYnvHU6C0A42MNdsIDeqy5BydrkuC5R1ZuUFnm27EeFJGoEHJQgn3uleRvmTXaJgfXbt4g==} + engines: {node: '>=0.4.0'} + + acorn@8.15.0: + resolution: {integrity: sha512-NZyJarBfL7nWwIq+FDL6Zp/yHEhePMNnnJ0y3qfieCrmNvYct8uvtiV41UvlSe6apAfk0fY1FbWx+NwfmpvtTg==} + engines: {node: '>=0.4.0'} + hasBin: true + + ajv@6.12.6: + resolution: {integrity: sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==} + + ansi-escapes@4.3.2: + resolution: {integrity: sha512-gKXj5ALrKWQLsYG9jlTRmR/xKluxHV+Z9QEwNIgCfM1/uwPMCuzVVnh5mwTd+OuBZcwSIMbqssNWRm1lE51QaQ==} + engines: {node: '>=8'} + + ansi-regex@5.0.1: + resolution: {integrity: sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==} + engines: {node: '>=8'} + + ansi-regex@6.1.0: + resolution: {integrity: sha512-7HSX4QQb4CspciLpVFwyRe79O3xsIZDDLER21kERQ71oaPodF8jL725AgJMFAYbooIqolJoRLuM81SpeUkpkvA==} + engines: {node: '>=12'} + + ansi-styles@4.3.0: + resolution: {integrity: sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==} + engines: {node: '>=8'} + + ansi-styles@5.2.0: + resolution: {integrity: sha512-Cxwpt2SfTzTtXcfOlzGEee8O+c+MmUgGrNiBcXnuWxuFJHe6a5Hz7qwhwe5OgaSYI0IJvkLqWX1ASG+cJOkEiA==} + engines: {node: '>=10'} + + ansi-styles@6.2.1: + resolution: {integrity: sha512-bN798gFfQX+viw3R7yrGWRqnrN2oRkEkUjjl4JNn4E8GxxbjtG3FbrEIIY3l8/hrwUwIeCZvi4QuOTP4MErVug==} + engines: {node: '>=12'} + + anymatch@3.1.3: + resolution: {integrity: sha512-KMReFUr0B4t+D+OBkjR3KYqvocp2XaSzO55UcB6mgQMd3KbcE+mWTyvVV7D/zsdEbNnV6acZUutkiHQXvTr1Rw==} + engines: {node: '>= 8'} + + arg@4.1.3: + resolution: {integrity: sha512-58S9QDqG0Xx27YwPSt9fJxivjYl432YCwfDMfZ+71RAqUrZef7LrKQZ3LHLOwCS4FLNBplP533Zx895SeOCHvA==} + + argparse@1.0.10: + resolution: {integrity: sha512-o5Roy6tNG4SL/FOkCAN6RzjiakZS25RLYFrcMttJqbdd8BWrnA+fGz57iN5Pb06pvBGvl5gQ0B48dJlslXvoTg==} + + asn1@0.2.6: + resolution: {integrity: sha512-ix/FxPn0MDjeyJ7i/yoHGFt/EX6LyNbxSEhPPXODPL+KB0VPk86UYfL0lMdy+KCnv+fmvIzySwaK5COwqVbWTQ==} + + assert-plus@1.0.0: + resolution: {integrity: sha512-NfJ4UzBCcQGLDlQq7nHxH+tv3kyZ0hHQqF5BO6J7tNJeP5do1llPr8dZ8zHonfhAu0PHAdMkSo+8o0wxg9lZWw==} + engines: {node: '>=0.8'} + + async@3.2.6: + resolution: {integrity: sha512-htCUDlxyyCLMgaM3xXg0C0LW2xqfuQ6p05pCEIsXuyQ+a1koYKTuBMzRNwmybfLgvJDMd0r1LTn4+E0Ti6C2AA==} + + asynckit@0.4.0: + resolution: {integrity: sha512-Oei9OH4tRh0YqU3GxhX79dM/mwVgvbZJaSNaRk+bshkj0S5cfHcgYakreBjrHwatXKbz+IoIdYLxrKim2MjW0Q==} + + aws-sign2@0.7.0: + resolution: {integrity: sha512-08kcGqnYf/YmjoRhfxyu+CLxBjUtHLXLXX/vUfx9l2LYzG3c1m61nrpyFUZI6zeS+Li/wWMMidD9KgrqtGq3mA==} + + aws4@1.13.2: + resolution: {integrity: sha512-lHe62zvbTB5eEABUVi/AwVh0ZKY9rMMDhmm+eeyuuUQbQ3+J+fONVQOZyj+DdrvD4BY33uYniyRJ4UJIaSKAfw==} + + babel-jest@30.0.0: + resolution: {integrity: sha512-JQ0DhdFjODbSawDf0026uZuwaqfKkQzk+9mwWkq2XkKFIaMhFVOxlVmbFCOnnC76jATdxrff3IiUAvOAJec6tw==} + engines: {node: ^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0} + peerDependencies: + '@babel/core': ^7.11.0 + + babel-plugin-istanbul@7.0.0: + resolution: {integrity: sha512-C5OzENSx/A+gt7t4VH1I2XsflxyPUmXRFPKBxt33xncdOmq7oROVM3bZv9Ysjjkv8OJYDMa+tKuKMvqU/H3xdw==} + engines: {node: '>=12'} + + babel-plugin-jest-hoist@30.0.0: + resolution: {integrity: sha512-DSRm+US/FCB4xPDD6Rnslb6PAF9Bej1DZ+1u4aTiqJnk7ZX12eHsnDiIOqjGvITCq+u6wLqUhgS+faCNbVY8+g==} + engines: {node: ^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0} + + babel-preset-current-node-syntax@1.1.0: + resolution: {integrity: sha512-ldYss8SbBlWva1bs28q78Ju5Zq1F+8BrqBZZ0VFhLBvhh6lCpC2o3gDJi/5DRLs9FgYZCnmPYIVFU4lRXCkyUw==} + peerDependencies: + '@babel/core': ^7.0.0 + + babel-preset-jest@30.0.0: + resolution: {integrity: sha512-hgEuu/W7gk8QOWUA9+m3Zk+WpGvKc1Egp6rFQEfYxEoM9Fk/q8nuTXNL65OkhwGrTApauEGgakOoWVXj+UfhKw==} + engines: {node: ^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0} + peerDependencies: + '@babel/core': ^7.11.0 + + balanced-match@1.0.2: + resolution: {integrity: sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==} + + bcrypt-pbkdf@1.0.2: + resolution: {integrity: sha512-qeFIXtP4MSoi6NLqO12WfqARWWuCKi2Rn/9hJLEmtB5yTNr9DqFWkJRCf2qShWzPeAMRnOgCrq0sg/KLv5ES9w==} + + brace-expansion@1.1.12: + resolution: {integrity: sha512-9T9UjW3r0UW5c1Q7GTwllptXwhvYmEzFhzMfZ9H7FQWt+uZePjZPjBP/W1ZEyZ1twGWom5/56TF4lPcqjnDHcg==} + + brace-expansion@2.0.2: + resolution: {integrity: sha512-Jt0vHyM+jmUBqojB7E1NIYadt0vI0Qxjxd2TErW94wDz+E2LAm5vKMXXwg6ZZBTHPuUlDgQHKXvjGBdfcF1ZDQ==} + + braces@3.0.3: + resolution: {integrity: sha512-yQbXgO/OSZVD2IsiLlro+7Hf6Q18EJrKSEsdoMzKePKXct3gvD8oLcOQdIzGupr5Fj+EDe8gO/lxc1BzfMpxvA==} + engines: {node: '>=8'} + + browserslist@4.25.0: + resolution: {integrity: sha512-PJ8gYKeS5e/whHBh8xrwYK+dAvEj7JXtz6uTucnMRB8OiGTsKccFekoRrjajPBHV8oOY+2tI4uxeceSimKwMFA==} + engines: {node: ^6 || ^7 || ^8 || ^9 || ^10 || ^11 || ^12 || >=13.7} + hasBin: true + + bs-logger@0.2.6: + resolution: {integrity: sha512-pd8DCoxmbgc7hyPKOvxtqNcjYoOsABPQdcCUjGp3d42VR2CX1ORhk2A87oqqu5R1kk+76nsxZupkmyd+MVtCog==} + engines: {node: '>= 6'} + + bser@2.1.1: + resolution: {integrity: sha512-gQxTNE/GAfIIrmHLUE3oJyp5FO6HRBfhjnw4/wMmA63ZGDJnWBmgY/lyQBpnDUkGmAhbSe39tx2d/iTOAfglwQ==} + + buffer-from@1.1.2: + resolution: {integrity: sha512-E+XQCRwSbaaiChtv6k6Dwgc+bx+Bs6vuKJHHl5kox/BaKbhiXzqQOwK4cO22yElGp2OCmjwVhT3HmxgyPGnJfQ==} + + callsites@3.1.0: + resolution: {integrity: sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ==} + engines: {node: '>=6'} + + camelcase@5.3.1: + resolution: {integrity: sha512-L28STB170nwWS63UjtlEOE3dldQApaJXZkOI1uMFfzf3rRuPegHaHesyee+YxQ+W6SvRDQV6UrdOdRiR153wJg==} + engines: {node: '>=6'} + + camelcase@6.3.0: + resolution: {integrity: sha512-Gmy6FhYlCY7uOElZUSbxo2UCDH8owEk996gkbrpsgGtrJLM3J7jGxl9Ic7Qwwj4ivOE5AWZWRMecDdF7hqGjFA==} + engines: {node: '>=10'} + + caniuse-lite@1.0.30001723: + resolution: {integrity: sha512-1R/elMjtehrFejxwmexeXAtae5UO9iSyFn6G/I806CYC/BLyyBk1EPhrKBkWhy6wM6Xnm47dSJQec+tLJ39WHw==} + + caseless@0.12.0: + resolution: {integrity: sha512-4tYFyifaFfGacoiObjJegolkwSU4xQNGbVgUiNYVUxbQ2x2lUsFvY4hVgVzGiIe6WLOPqycWXA40l+PWsxthUw==} + + chalk@4.1.2: + resolution: {integrity: sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==} + engines: {node: '>=10'} + + char-regex@1.0.2: + resolution: {integrity: sha512-kWWXztvZ5SBQV+eRgKFeh8q5sLuZY2+8WUIzlxWVTg+oGwY14qylx1KbKzHd8P6ZYkAg0xyIDU9JMHhyJMZ1jw==} + engines: {node: '>=10'} + + ci-info@3.9.0: + resolution: {integrity: sha512-NIxF55hv4nSqQswkAeiOi1r83xy8JldOFDTWiug55KBu9Jnblncd2U6ViHmYgHf01TPZS77NJBhBMKdWj9HQMQ==} + engines: {node: '>=8'} + + ci-info@4.2.0: + resolution: {integrity: sha512-cYY9mypksY8NRqgDB1XD1RiJL338v/551niynFTGkZOO2LHuB2OmOYxDIe/ttN9AHwrqdum1360G3ald0W9kCg==} + engines: {node: '>=8'} + + cjs-module-lexer@2.1.0: + resolution: {integrity: sha512-UX0OwmYRYQQetfrLEZeewIFFI+wSTofC+pMBLNuH3RUuu/xzG1oz84UCEDOSoQlN3fZ4+AzmV50ZYvGqkMh9yA==} + + cliui@8.0.1: + resolution: {integrity: sha512-BSeNnyus75C4//NQ9gQt1/csTXyo/8Sb+afLAkzAptFuMsod9HFokGNudZpi/oQV73hnVK+sR+5PVRMd+Dr7YQ==} + engines: {node: '>=12'} + + co@4.6.0: + resolution: {integrity: sha512-QVb0dM5HvG+uaxitm8wONl7jltx8dqhfU33DcqtOZcLSVIKSDDLDi7+0LbAKiyI8hD9u42m2YxXSkMGWThaecQ==} + engines: {iojs: '>= 1.0.0', node: '>= 0.12.0'} + + collect-v8-coverage@1.0.2: + resolution: {integrity: sha512-lHl4d5/ONEbLlJvaJNtsF/Lz+WvB07u2ycqTYbdrq7UypDXailES4valYb2eWiJFxZlVmpGekfqoxQhzyFdT4Q==} + + color-convert@2.0.1: + resolution: {integrity: sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==} + engines: {node: '>=7.0.0'} + + color-name@1.1.4: + resolution: {integrity: sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==} + + combined-stream@1.0.8: + resolution: {integrity: sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg==} + engines: {node: '>= 0.8'} + + commander@14.0.0: + resolution: {integrity: sha512-2uM9rYjPvyq39NwLRqaiLtWHyDC1FvryJDa2ATTVims5YAS4PupsEQsDvP14FqhFr0P49CYDugi59xaxJlTXRA==} + engines: {node: '>=20'} + + concat-map@0.0.1: + resolution: {integrity: sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==} + + convert-source-map@2.0.0: + resolution: {integrity: sha512-Kvp459HrV2FEJ1CAsi1Ku+MY3kasH19TFykTz2xWmMeq6bk2NU3XXvfJ+Q61m0xktWwt+1HSYf3JZsTms3aRJg==} + + core-util-is@1.0.2: + resolution: {integrity: sha512-3lqz5YjWTYnW6dlDa5TLaTCcShfar1e40rmcJVwCBJC6mWlFuj0eCHIElmG1g5kyuJ/GD+8Wn4FFCcz4gJPfaQ==} + + coveralls@3.1.1: + resolution: {integrity: sha512-+dxnG2NHncSD1NrqbSM3dn/lE57O6Qf/koe9+I7c+wzkqRmEvcp0kgJdxKInzYzkICKkFMZsX3Vct3++tsF9ww==} + engines: {node: '>=6'} + hasBin: true + + create-require@1.1.1: + resolution: {integrity: sha512-dcKFX3jn0MpIaXjisoRvexIJVEKzaq7z2rZKxf+MSr9TkdmHmsU4m2lcLojrj/FHl8mk5VxMmYA+ftRkP/3oKQ==} + + cross-spawn@7.0.6: + resolution: {integrity: sha512-uV2QOWP2nWzsy2aMp8aRibhi9dlzF5Hgh5SHaB9OiTGEyDTiJJyx0uy51QXdyWbtAHNua4XJzUKca3OzKUd3vA==} + engines: {node: '>= 8'} + + dashdash@1.14.1: + resolution: {integrity: sha512-jRFi8UDGo6j+odZiEpjazZaWqEal3w/basFjQHQEwVtZJGDpxbH1MeYluwCS8Xq5wmLJooDlMgvVarmWfGM44g==} + engines: {node: '>=0.10'} + + debug@4.4.1: + resolution: {integrity: sha512-KcKCqiftBJcZr++7ykoDIEwSa3XWowTfNPo92BYxjXiyYEVrUQh2aLyhxBCwww+heortUFxEJYcRzosstTEBYQ==} + engines: {node: '>=6.0'} + peerDependencies: + supports-color: '*' + peerDependenciesMeta: + supports-color: + optional: true + + dedent@1.6.0: + resolution: {integrity: sha512-F1Z+5UCFpmQUzJa11agbyPVMbpgT/qA3/SKyJ1jyBgm7dUcUEa8v9JwDkerSQXfakBwFljIxhOJqGkjUwZ9FSA==} + peerDependencies: + babel-plugin-macros: ^3.1.0 + peerDependenciesMeta: + babel-plugin-macros: + optional: true + + deepmerge@4.3.1: + resolution: {integrity: sha512-3sUqbMEc77XqpdNO7FRyRog+eW3ph+GYCbj+rK+uYyRMuwsVy0rMiVtPn+QJlKFvWP/1PYpapqYn0Me2knFn+A==} + engines: {node: '>=0.10.0'} + + delayed-stream@1.0.0: + resolution: {integrity: sha512-ZySD7Nf91aLB0RxL4KGrKHBXl7Eds1DAmEdcoVawXnLD7SDhpNgtuII2aAkg7a7QS41jxPSZ17p4VdGnMHk3MQ==} + engines: {node: '>=0.4.0'} + + detect-newline@3.1.0: + resolution: {integrity: sha512-TLz+x/vEXm/Y7P7wn1EJFNLxYpUD4TgMosxY6fAVJUnJMbupHBOncxyWUG9OpTaH9EBD7uFI5LfEgmMOc54DsA==} + engines: {node: '>=8'} + + diff-sequences@29.6.3: + resolution: {integrity: sha512-EjePK1srD3P08o2j4f0ExnylqRs5B9tJjcp9t1krH2qRi8CCdsYfwe9JgSLurFBWwq4uOlipzfk5fHNvwFKr8Q==} + engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} + + diff@4.0.2: + resolution: {integrity: sha512-58lmxKSA4BNyLz+HHMUzlOEpg09FV+ev6ZMe3vJihgdxzgcwZ8VoEEPmALCZG9LmqfVoNMMKpttIYTVG6uDY7A==} + engines: {node: '>=0.3.1'} + + eastasianwidth@0.2.0: + resolution: {integrity: sha512-I88TYZWc9XiYHRQ4/3c5rjjfgkjhLyW2luGIheGERbNQ6OY7yTybanSpDXZa8y7VUP9YmDcYa+eyq4ca7iLqWA==} + + ecc-jsbn@0.1.2: + resolution: {integrity: sha512-eh9O+hwRHNbG4BLTjEl3nw044CkGm5X6LoaCf7LPp7UU8Qrt47JYNi6nPX8xjW97TKGKm1ouctg0QSpZe9qrnw==} + + ejs@3.1.10: + resolution: {integrity: sha512-UeJmFfOrAQS8OJWPZ4qtgHyWExa088/MtK5UEyoJGFH67cDEXkZSviOiKRCZ4Xij0zxI3JECgYs3oKx+AizQBA==} + engines: {node: '>=0.10.0'} + hasBin: true + + electron-to-chromium@1.5.167: + resolution: {integrity: sha512-LxcRvnYO5ez2bMOFpbuuVuAI5QNeY1ncVytE/KXaL6ZNfzX1yPlAO0nSOyIHx2fVAuUprMqPs/TdVhUFZy7SIQ==} + + emittery@0.13.1: + resolution: {integrity: sha512-DeWwawk6r5yR9jFgnDKYt4sLS0LmHJJi3ZOnb5/JdbYwj3nW+FxQnHIjhBKz8YLC7oRNPVM9NQ47I3CVx34eqQ==} + engines: {node: '>=12'} + + emoji-regex@8.0.0: + resolution: {integrity: sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==} + + emoji-regex@9.2.2: + resolution: {integrity: sha512-L18DaJsXSUk2+42pv8mLs5jJT2hqFkFE4j21wOmgbUqsZ2hL72NsUU785g9RXgo3s0ZNgVl42TiHp3ZtOv/Vyg==} + + error-ex@1.3.2: + resolution: {integrity: sha512-7dFHNmqeFSEt2ZBsCriorKnn3Z2pj+fd9kmI6QoWw4//DL+icEBfc0U7qJCisqrTsKTjw4fNFy2pW9OqStD84g==} + + escalade@3.2.0: + resolution: {integrity: sha512-WUj2qlxaQtO4g6Pq5c29GTcWGDyd8itL8zTlipgECz3JesAiiOKotd8JU6otB3PACgG6xkJUyVhboMS+bje/jA==} + engines: {node: '>=6'} + + escape-string-regexp@2.0.0: + resolution: {integrity: sha512-UpzcLCXolUWcNu5HtVMHYdXJjArjsF9C0aNnquZYY4uW/Vu0miy5YoWvbV345HauVvcAUnpRuhMMcqTcGOY2+w==} + engines: {node: '>=8'} + + esprima@4.0.1: + resolution: {integrity: sha512-eGuFFw7Upda+g4p+QHvnW0RyTX/SVeJBDM/gCtMARO0cLuT2HcEKnTPvhjV6aGeqrCB/sbNop0Kszm0jsaWU4A==} + engines: {node: '>=4'} + hasBin: true + + execa@5.1.1: + resolution: {integrity: sha512-8uSpZZocAZRBAPIEINJj3Lo9HyGitllczc27Eh5YYojjMFMn8yHMDMaUHE2Jqfq05D/wucwI4JGURyXt1vchyg==} + engines: {node: '>=10'} + + exit-x@0.2.2: + resolution: {integrity: sha512-+I6B/IkJc1o/2tiURyz/ivu/O0nKNEArIUB5O7zBrlDVJr22SCLH3xTeEry428LvFhRzIA1g8izguxJ/gbNcVQ==} + engines: {node: '>= 0.8.0'} + + expect@29.7.0: + resolution: {integrity: sha512-2Zks0hf1VLFYI1kbh0I5jP3KHHyCHpkfyHBzsSXRFgl/Bg9mWYfMW8oD+PdMPlEwy5HNsR9JutYy6pMeOh61nw==} + engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} + + expect@30.0.0: + resolution: {integrity: sha512-xCdPp6gwiR9q9lsPCHANarIkFTN/IMZso6Kkq03sOm9IIGtzK/UJqml0dkhHibGh8HKOj8BIDIpZ0BZuU7QK6w==} + engines: {node: ^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0} + + extend@3.0.2: + resolution: {integrity: sha512-fjquC59cD7CyW6urNXK0FBufkZcoiGG80wTuPujX590cB5Ttln20E2UB4S/WARVqhXffZl2LNgS+gQdPIIim/g==} + + extsprintf@1.3.0: + resolution: {integrity: sha512-11Ndz7Nv+mvAC1j0ktTa7fAb0vLyGGX+rMHNBYQviQDGU0Hw7lhctJANqbPhu9nV9/izT/IntTgZ7Im/9LJs9g==} + engines: {'0': node >=0.6.0} + + fast-deep-equal@3.1.3: + resolution: {integrity: sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==} + + fast-json-stable-stringify@2.1.0: + resolution: {integrity: sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw==} + + fb-watchman@2.0.2: + resolution: {integrity: sha512-p5161BqbuCaSnB8jIbzQHOlpgsPmK5rJVDfDKO91Axs5NC1uu3HRQm6wt9cd9/+GtQQIO53JdGXXoyDpTAsgYA==} + + filelist@1.0.4: + resolution: {integrity: sha512-w1cEuf3S+DrLCQL7ET6kz+gmlJdbq9J7yXCSjK/OZCPA+qEN1WyF4ZAf0YYJa4/shHJra2t/d/r8SV4Ji+x+8Q==} + + fill-range@7.1.1: + resolution: {integrity: sha512-YsGpe3WHLK8ZYi4tWDg2Jy3ebRz2rXowDxnld4bkQB00cc/1Zw9AWnC0i9ztDJitivtQvaI9KaLyKrc+hBW0yg==} + engines: {node: '>=8'} + + find-up@4.1.0: + resolution: {integrity: sha512-PpOwAdQ/YlXQ2vj8a3h8IipDuYRi3wceVQQGYWxNINccq40Anw7BlsEXCMbt1Zt+OLA6Fq9suIpIWD0OsnISlw==} + engines: {node: '>=8'} + + foreground-child@3.3.1: + resolution: {integrity: sha512-gIXjKqtFuWEgzFRJA9WCQeSJLZDjgJUOMCMzxtvFq/37KojM1BFGufqsCy0r4qSQmYLsZYMeyRqzIWOMup03sw==} + engines: {node: '>=14'} + + forever-agent@0.6.1: + resolution: {integrity: sha512-j0KLYPhm6zeac4lz3oJ3o65qvgQCcPubiyotZrXqEaG4hNagNYO8qdlUrX5vwqv9ohqeT/Z3j6+yW067yWWdUw==} + + form-data@2.3.3: + resolution: {integrity: sha512-1lLKB2Mu3aGP1Q/2eCOx0fNbRMe7XdwktwOruhfqqd0rIJWwN4Dh+E3hrPSlDCXnSR7UtZ1N38rVXm+6+MEhJQ==} + engines: {node: '>= 0.12'} + + fs.realpath@1.0.0: + resolution: {integrity: sha512-OO0pH2lK6a0hZnAdau5ItzHPI6pUlvI7jMVnxUQRtw4owF2wk8lOSabtGDCTP4Ggrg2MbGnWO9X8K1t4+fGMDw==} + + fsevents@2.3.3: + resolution: {integrity: sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==} + engines: {node: ^8.16.0 || ^10.6.0 || >=11.0.0} + os: [darwin] + + gensync@1.0.0-beta.2: + resolution: {integrity: sha512-3hN7NaskYvMDLQY55gnW3NQ+mesEAepTqlg+VEbj7zzqEMBVNhzcGYYeqFo/TlYz6eQiFcp1HcsCZO+nGgS8zg==} + engines: {node: '>=6.9.0'} + + get-caller-file@2.0.5: + resolution: {integrity: sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg==} + engines: {node: 6.* || 8.* || >= 10.*} + + get-package-type@0.1.0: + resolution: {integrity: sha512-pjzuKtY64GYfWizNAJ0fr9VqttZkNiK2iS430LtIHzjBEr6bX8Am2zm4sW4Ro5wjWW5cAlRL1qAMTcXbjNAO2Q==} + engines: {node: '>=8.0.0'} + + get-stream@6.0.1: + resolution: {integrity: sha512-ts6Wi+2j3jQjqi70w5AlN8DFnkSwC+MqmxEzdEALB2qXZYV3X/b1CTfgPLGJNMeAWxdPfU8FO1ms3NUfaHCPYg==} + engines: {node: '>=10'} + + getpass@0.1.7: + resolution: {integrity: sha512-0fzj9JxOLfJ+XGLhR8ze3unN0KZCgZwiSSDz168VERjK8Wl8kVSdcu2kspd4s4wtAa1y/qrVRiAA0WclVsu0ng==} + + glob@10.4.5: + resolution: {integrity: sha512-7Bv8RF0k6xjo7d4A/PxYLbUCfb6c+Vpd2/mB2yRDlew7Jb5hEXiCD9ibfO7wpk8i4sevK6DFny9h7EYbM3/sHg==} + hasBin: true + + glob@11.0.3: + resolution: {integrity: sha512-2Nim7dha1KVkaiF4q6Dj+ngPPMdfvLJEOpZk/jKiUAkqKebpGAWQXAq9z1xu9HKu5lWfqw/FASuccEjyznjPaA==} + engines: {node: 20 || >=22} + hasBin: true + + glob@7.2.3: + resolution: {integrity: sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q==} + deprecated: Glob versions prior to v9 are no longer supported + + globals@11.12.0: + resolution: {integrity: sha512-WOBp/EEGUiIsJSp7wcv/y6MO+lV9UoncWqxuFfm8eBwzWNgyfBd6Gz+IeKQ9jCmyhoH99g15M3T+QaVHFjizVA==} + engines: {node: '>=4'} + + graceful-fs@4.2.11: + resolution: {integrity: sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ==} + + har-schema@2.0.0: + resolution: {integrity: sha512-Oqluz6zhGX8cyRaTQlFMPw80bSJVG2x/cFb8ZPhUILGgHka9SsokCCOQgpveePerqidZOrT14ipqfJb7ILcW5Q==} + engines: {node: '>=4'} + + har-validator@5.1.5: + resolution: {integrity: sha512-nmT2T0lljbxdQZfspsno9hgrG3Uir6Ks5afism62poxqBM6sDnMEuPmzTq8XN0OEwqKLLdh1jQI3qyE66Nzb3w==} + engines: {node: '>=6'} + deprecated: this library is no longer supported + + has-flag@4.0.0: + resolution: {integrity: sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==} + engines: {node: '>=8'} + + html-escaper@2.0.2: + resolution: {integrity: sha512-H2iMtd0I4Mt5eYiapRdIDjp+XzelXQ0tFE4JS7YFwFevXXMmOp9myNrUvCg0D6ws8iqkRPBfKHgbwig1SmlLfg==} + + http-signature@1.2.0: + resolution: {integrity: sha512-CAbnr6Rz4CYQkLYUtSNXxQPUH2gK8f3iWexVlsnMeD+GjlsQ0Xsy1cOX+mN3dtxYomRy21CiOzU8Uhw6OwncEQ==} + engines: {node: '>=0.8', npm: '>=1.3.7'} + + human-signals@2.1.0: + resolution: {integrity: sha512-B4FFZ6q/T2jhhksgkbEW3HBvWIfDW85snkQgawt07S7J5QXTk6BkNV+0yAeZrM5QpMAdYlocGoljn0sJ/WQkFw==} + engines: {node: '>=10.17.0'} + + import-local@3.2.0: + resolution: {integrity: sha512-2SPlun1JUPWoM6t3F0dw0FkCF/jWY8kttcY4f599GLTSjh2OCuuhdTkJQsEcZzBqbXZGKMK2OqW1oZsjtf/gQA==} + engines: {node: '>=8'} + hasBin: true + + imurmurhash@0.1.4: + resolution: {integrity: sha512-JmXMZ6wuvDmLiHEml9ykzqO6lwFbof0GG4IkcGaENdCRDDmMVnny7s5HsIgHCbaq0w2MyPhDqkhTUgS2LU2PHA==} + engines: {node: '>=0.8.19'} + + inflight@1.0.6: + resolution: {integrity: sha512-k92I/b08q4wvFscXCLvqfsHCrjrF7yiXsQuIVvVE7N82W3+aqpzuUdBbfhWcy/FZR3/4IgflMgKLOsvPDrGCJA==} + deprecated: This module is not supported, and leaks memory. Do not use it. Check out lru-cache if you want a good and tested way to coalesce async requests by a key value, which is much more comprehensive and powerful. + + inherits@2.0.4: + resolution: {integrity: sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==} + + is-arrayish@0.2.1: + resolution: {integrity: sha512-zz06S8t0ozoDXMG+ube26zeCTNXcKIPJZJi8hBrF4idCLms4CG9QtK7qBl1boi5ODzFpjswb5JPmHCbMpjaYzg==} + + is-fullwidth-code-point@3.0.0: + resolution: {integrity: sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==} + engines: {node: '>=8'} + + is-generator-fn@2.1.0: + resolution: {integrity: sha512-cTIB4yPYL/Grw0EaSzASzg6bBy9gqCofvWN8okThAYIxKJZC+udlRAmGbM0XLeniEJSs8uEgHPGuHSe1XsOLSQ==} + engines: {node: '>=6'} + + is-number@7.0.0: + resolution: {integrity: sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==} + engines: {node: '>=0.12.0'} + + is-stream@2.0.1: + resolution: {integrity: sha512-hFoiJiTl63nn+kstHGBtewWSKnQLpyb155KHheA1l39uvtO9nWIop1p3udqPcUd/xbF1VLMO4n7OI6p7RbngDg==} + engines: {node: '>=8'} + + is-typedarray@1.0.0: + resolution: {integrity: sha512-cyA56iCMHAh5CdzjJIa4aohJyeO1YbwLi3Jc35MmRU6poroFjIGZzUzupGiRPOjgHg9TLu43xbpwXk523fMxKA==} + + isexe@2.0.0: + resolution: {integrity: sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==} + + isstream@0.1.2: + resolution: {integrity: sha512-Yljz7ffyPbrLpLngrMtZ7NduUgVvi6wG9RJ9IUcyCd59YQ911PBJphODUcbOVbqYfxe1wuYf/LJ8PauMRwsM/g==} + + istanbul-lib-coverage@3.2.2: + resolution: {integrity: sha512-O8dpsF+r0WV/8MNRKfnmrtCWhuKjxrq2w+jpzBL5UZKTi2LeVWnWOmWRxFlesJONmc+wLAGvKQZEOanko0LFTg==} + engines: {node: '>=8'} + + istanbul-lib-instrument@6.0.3: + resolution: {integrity: sha512-Vtgk7L/R2JHyyGW07spoFlB8/lpjiOLTjMdms6AFMraYt3BaJauod/NGrfnVG/y4Ix1JEuMRPDPEj2ua+zz1/Q==} + engines: {node: '>=10'} + + istanbul-lib-report@3.0.1: + resolution: {integrity: sha512-GCfE1mtsHGOELCU8e/Z7YWzpmybrx/+dSTfLrvY8qRmaY6zXTKWn6WQIjaAFw069icm6GVMNkgu0NzI4iPZUNw==} + engines: {node: '>=10'} + + istanbul-lib-source-maps@5.0.6: + resolution: {integrity: sha512-yg2d+Em4KizZC5niWhQaIomgf5WlL4vOOjZ5xGCmF8SnPE/mDWWXgvRExdcpCgh9lLRRa1/fSYp2ymmbJ1pI+A==} + engines: {node: '>=10'} + + istanbul-reports@3.1.7: + resolution: {integrity: sha512-BewmUXImeuRk2YY0PVbxgKAysvhRPUQE0h5QRM++nVWyubKGV0l8qQ5op8+B2DOmwSe63Jivj0BjkPQVf8fP5g==} + engines: {node: '>=8'} + + jackspeak@3.4.3: + resolution: {integrity: sha512-OGlZQpz2yfahA/Rd1Y8Cd9SIEsqvXkLVoSw/cgwhnhFMDbsQFeZYoJJ7bIZBS9BcamUW96asq/npPWugM+RQBw==} + + jackspeak@4.1.1: + resolution: {integrity: sha512-zptv57P3GpL+O0I7VdMJNBZCu+BPHVQUk55Ft8/QCJjTVxrnJHuVuX/0Bl2A6/+2oyR/ZMEuFKwmzqqZ/U5nPQ==} + engines: {node: 20 || >=22} + + jake@10.9.2: + resolution: {integrity: sha512-2P4SQ0HrLQ+fw6llpLnOaGAvN2Zu6778SJMrCUwns4fOoG9ayrTiZk3VV8sCPkVZF8ab0zksVpS8FDY5pRCNBA==} + engines: {node: '>=10'} + hasBin: true + + jest-changed-files@30.0.0: + resolution: {integrity: sha512-rzGpvCdPdEV1Ma83c1GbZif0L2KAm3vXSXGRlpx7yCt0vhruwCNouKNRh3SiVcISHP1mb3iJzjb7tAEnNu1laQ==} + engines: {node: ^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0} + + jest-circus@30.0.0: + resolution: {integrity: sha512-nTwah78qcKVyndBS650hAkaEmwWGaVsMMoWdJwMnH77XArRJow2Ir7hc+8p/mATtxVZuM9OTkA/3hQocRIK5Dw==} + engines: {node: ^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0} + + jest-cli@30.0.0: + resolution: {integrity: sha512-fWKAgrhlwVVCfeizsmIrPRTBYTzO82WSba3gJniZNR3PKXADgdC0mmCSK+M+t7N8RCXOVfY6kvCkvjUNtzmHYQ==} + engines: {node: ^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0} + hasBin: true + peerDependencies: + node-notifier: ^8.0.1 || ^9.0.0 || ^10.0.0 + peerDependenciesMeta: + node-notifier: + optional: true + + jest-config@30.0.0: + resolution: {integrity: sha512-p13a/zun+sbOMrBnTEUdq/5N7bZMOGd1yMfqtAJniPNuzURMay4I+vxZLK1XSDbjvIhmeVdG8h8RznqYyjctyg==} + engines: {node: ^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0} + peerDependencies: + '@types/node': '*' + esbuild-register: '>=3.4.0' + ts-node: '>=9.0.0' + peerDependenciesMeta: + '@types/node': + optional: true + esbuild-register: + optional: true + ts-node: + optional: true + + jest-diff@29.7.0: + resolution: {integrity: sha512-LMIgiIrhigmPrs03JHpxUh2yISK3vLFPkAodPeo0+BuF7wA2FoQbkEg1u8gBYBThncu7e1oEDUfIXVuTqLRUjw==} + engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} + + jest-diff@30.0.0: + resolution: {integrity: sha512-TgT1+KipV8JTLXXeFX0qSvIJR/UXiNNojjxb/awh3vYlBZyChU/NEmyKmq+wijKjWEztyrGJFL790nqMqNjTHA==} + engines: {node: ^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0} + + jest-docblock@30.0.0: + resolution: {integrity: sha512-By/iQ0nvTzghEecGzUMCp1axLtBh+8wB4Hpoi5o+x1stycjEmPcH1mHugL4D9Q+YKV++vKeX/3ZTW90QC8ICPg==} + engines: {node: ^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0} + + jest-each@30.0.0: + resolution: {integrity: sha512-qkFEW3cfytEjG2KtrhwtldZfXYnWSanO8xUMXLe4A6yaiHMHJUalk0Yyv4MQH6aeaxgi4sGVrukvF0lPMM7U1w==} + engines: {node: ^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0} + + jest-environment-node@30.0.0: + resolution: {integrity: sha512-sF6lxyA25dIURyDk4voYmGU9Uwz2rQKMfjxKnDd19yk+qxKGrimFqS5YsPHWTlAVBo+YhWzXsqZoaMzrTFvqfg==} + engines: {node: ^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0} + + jest-get-type@29.6.3: + resolution: {integrity: sha512-zrteXnqYxfQh7l5FHyL38jL39di8H8rHoecLH3JNxH3BwOrBsNeabdap5e0I23lD4HHI8W5VFBZqG4Eaq5LNcw==} + engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} + + jest-haste-map@30.0.0: + resolution: {integrity: sha512-p4bXAhXTawTsADgQgTpbymdLaTyPW1xWNu1oIGG7/N3LIAbZVkH2JMJqS8/IUcnGR8Kc7WFE+vWbJvsqGCWZXw==} + engines: {node: ^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0} + + jest-leak-detector@30.0.0: + resolution: {integrity: sha512-E/ly1azdVVbZrS0T6FIpyYHvsdek4FNaThJTtggjV/8IpKxh3p9NLndeUZy2+sjAI3ncS+aM0uLLon/dBg8htA==} + engines: {node: ^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0} + + jest-matcher-utils@29.7.0: + resolution: {integrity: sha512-sBkD+Xi9DtcChsI3L3u0+N0opgPYnCRPtGcQYrgXmR+hmt/fYfWAL0xRXYU8eWOdfuLgBe0YCW3AFtnRLagq/g==} + engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} + + jest-matcher-utils@30.0.0: + resolution: {integrity: sha512-m5mrunqopkrqwG1mMdJxe1J4uGmS9AHHKYUmoxeQOxBcLjEvirIrIDwuKmUYrecPHVB/PUBpXs2gPoeA2FSSLQ==} + engines: {node: ^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0} + + jest-message-util@29.7.0: + resolution: {integrity: sha512-GBEV4GRADeP+qtB2+6u61stea8mGcOT4mCtrYISZwfu9/ISHFJ/5zOMXYbpBE9RsS5+Gb63DW4FgmnKJ79Kf6w==} + engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} + + jest-message-util@30.0.0: + resolution: {integrity: sha512-pV3qcrb4utEsa/U7UI2VayNzSDQcmCllBZLSoIucrESRu0geKThFZOjjh0kACDJFJRAQwsK7GVsmS6SpEceD8w==} + engines: {node: ^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0} + + jest-mock@30.0.0: + resolution: {integrity: sha512-W2sRA4ALXILrEetEOh2ooZG6fZ01iwVs0OWMKSSWRcUlaLr4ESHuiKXDNTg+ZVgOq8Ei5445i/Yxrv59VT+XkA==} + engines: {node: ^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0} + + jest-pnp-resolver@1.2.3: + resolution: {integrity: sha512-+3NpwQEnRoIBtx4fyhblQDPgJI0H1IEIkX7ShLUjPGA7TtUTvI1oiKi3SR4oBR0hQhQR80l4WAe5RrXBwWMA8w==} + engines: {node: '>=6'} + peerDependencies: + jest-resolve: '*' + peerDependenciesMeta: + jest-resolve: + optional: true + + jest-regex-util@30.0.0: + resolution: {integrity: sha512-rT84010qRu/5OOU7a9TeidC2Tp3Qgt9Sty4pOZ/VSDuEmRupIjKZAb53gU3jr4ooMlhwScrgC9UixJxWzVu9oQ==} + engines: {node: ^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0} + + jest-resolve-dependencies@30.0.0: + resolution: {integrity: sha512-Yhh7odCAUNXhluK1bCpwIlHrN1wycYaTlZwq1GdfNBEESNNI/z1j1a7dUEWHbmB9LGgv0sanxw3JPmWU8NeebQ==} + engines: {node: ^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0} + + jest-resolve@30.0.0: + resolution: {integrity: sha512-zwWl1P15CcAfuQCEuxszjiKdsValhnWcj/aXg/R3aMHs8HVoCWHC4B/+5+1BirMoOud8NnN85GSP2LEZCbj3OA==} + engines: {node: ^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0} + + jest-runner@30.0.0: + resolution: {integrity: sha512-xbhmvWIc8X1IQ8G7xTv0AQJXKjBVyxoVJEJgy7A4RXsSaO+k/1ZSBbHwjnUhvYqMvwQPomWssDkUx6EoidEhlw==} + engines: {node: ^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0} + + jest-runtime@30.0.0: + resolution: {integrity: sha512-/O07qVgFrFAOGKGigojmdR3jUGz/y3+a/v9S/Yi2MHxsD+v6WcPppglZJw0gNJkRBArRDK8CFAwpM/VuEiiRjA==} + engines: {node: ^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0} + + jest-snapshot@30.0.0: + resolution: {integrity: sha512-6oCnzjpvfj/UIOMTqKZ6gedWAUgaycMdV8Y8h2dRJPvc2wSjckN03pzeoonw8y33uVngfx7WMo1ygdRGEKOT7w==} + engines: {node: ^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0} + + jest-util@29.7.0: + resolution: {integrity: sha512-z6EbKajIpqGKU56y5KBUgy1dt1ihhQJgWzUlZHArA/+X2ad7Cb5iF+AK1EWVL/Bo7Rz9uurpqw6SiBCefUbCGA==} + engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} + + jest-util@30.0.0: + resolution: {integrity: sha512-fhNBBM9uSUbd4Lzsf8l/kcAdaHD/4SgoI48en3HXcBEMwKwoleKFMZ6cYEYs21SB779PRuRCyNLmymApAm8tZw==} + engines: {node: ^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0} + + jest-validate@30.0.0: + resolution: {integrity: sha512-d6OkzsdlWItHAikUDs1hlLmpOIRhsZoXTCliV2XXalVQ3ZOeb9dy0CQ6AKulJu/XOZqpOEr/FiMH+FeOBVV+nw==} + engines: {node: ^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0} + + jest-watcher@30.0.0: + resolution: {integrity: sha512-fbAkojcyS53bOL/B7XYhahORq9cIaPwOgd/p9qW/hybbC8l6CzxfWJJxjlPBAIVN8dRipLR0zdhpGQdam+YBtw==} + engines: {node: ^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0} + + jest-worker@30.0.0: + resolution: {integrity: sha512-VZvxfWIybIvwK8N/Bsfe43LfQgd/rD0c4h5nLUx78CAqPxIQcW2qDjsVAC53iUR8yxzFIeCFFvWOh8en8hGzdg==} + engines: {node: ^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0} + + jest@30.0.0: + resolution: {integrity: sha512-/3G2iFwsUY95vkflmlDn/IdLyLWqpQXcftptooaPH4qkyU52V7qVYf1BjmdSPlp1+0fs6BmNtrGaSFwOfV07ew==} + engines: {node: ^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0} + hasBin: true + peerDependencies: + node-notifier: ^8.0.1 || ^9.0.0 || ^10.0.0 + peerDependenciesMeta: + node-notifier: + optional: true + + js-tokens@4.0.0: + resolution: {integrity: sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==} + + js-yaml@3.14.1: + resolution: {integrity: sha512-okMH7OXXJ7YrN9Ok3/SXrnu4iX9yOk+25nqX4imS2npuvTYDmo/QEZoqwZkYaIDk3jVvBOTOIEgEhaLOynBS9g==} + hasBin: true + + jsbn@0.1.1: + resolution: {integrity: sha512-UVU9dibq2JcFWxQPA6KCqj5O42VOmAY3zQUfEKxU0KpTGXwNoCjkX1e13eHNvw/xPynt6pU0rZ1htjWTNTSXsg==} + + jsesc@3.1.0: + resolution: {integrity: sha512-/sM3dO2FOzXjKQhJuo0Q173wf2KOo8t4I8vHy6lF9poUp7bKT0/NHE8fPX23PwfhnykfqnC2xRxOnVw5XuGIaA==} + engines: {node: '>=6'} + hasBin: true + + 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==} + + json-schema@0.4.0: + resolution: {integrity: sha512-es94M3nTIfsEPisRafak+HDLfHXnKBhV3vU5eqPcS3flIWqcxJWgXHXiey3YrpaNsanY5ei1VoYEbOzijuq9BA==} + + json-stringify-safe@5.0.1: + resolution: {integrity: sha512-ZClg6AaYvamvYEE82d3Iyd3vSSIjQ+odgjaTzRuO3s7toCdFKczob2i0zCh7JE8kWn17yvAWhUVxvqGwUalsRA==} + + json5@2.2.3: + resolution: {integrity: sha512-XmOWe7eyHYH14cLdVPoyg+GOH3rYX++KpzrylJwSW98t3Nk+U8XOl8FWKOgwtzdb8lXGf6zYwDUzeHMWfxasyg==} + engines: {node: '>=6'} + hasBin: true + + jsprim@1.4.2: + resolution: {integrity: sha512-P2bSOMAc/ciLz6DzgjVlGJP9+BrJWu5UDGK70C2iweC5QBIeFf0ZXRvGjEj2uYgrY2MkAAhsSWHDWlFtEroZWw==} + engines: {node: '>=0.6.0'} + + lcov-parse@1.0.0: + resolution: {integrity: sha512-aprLII/vPzuQvYZnDRU78Fns9I2Ag3gi4Ipga/hxnVMCZC8DnR2nI7XBqrPoywGfxqIx/DgarGvDJZAD3YBTgQ==} + hasBin: true + + leven@3.1.0: + resolution: {integrity: sha512-qsda+H8jTaUaN/x5vzW2rzc+8Rw4TAQ/4KjB46IwK5VH+IlVeeeje/EoZRpiXvIqjFgK84QffqPztGI3VBLG1A==} + engines: {node: '>=6'} + + 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'} + + lodash.memoize@4.1.2: + resolution: {integrity: sha512-t7j+NzmgnQzTAYXcsHYLgimltOV1MXHtlOWf6GjL9Kj8GK5FInw5JotxvbOs+IvV1/Dzo04/fCGfLVs7aXb4Ag==} + + lodash@4.17.21: + resolution: {integrity: sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==} + + log-driver@1.2.7: + resolution: {integrity: sha512-U7KCmLdqsGHBLeWqYlFA0V0Sl6P08EE1ZrmA9cxjUE0WVqT9qnyVDPz1kzpFEP0jdJuFnasWIfSd7fsaNXkpbg==} + engines: {node: '>=0.8.6'} + + lru-cache@10.4.3: + resolution: {integrity: sha512-JNAzZcXrCt42VGLuYz0zfAzDfAvJWW6AfYlDBQyDV5DClI2m5sAmK+OIO7s59XfsRsWHp02jAJrRadPRGTt6SQ==} + + lru-cache@11.1.0: + resolution: {integrity: sha512-QIXZUBJUx+2zHUdQujWejBkcD9+cs94tLn0+YL8UrCh+D5sCXZ4c7LaEH48pNwRY3MLDgqUFyhlCyjJPf1WP0A==} + engines: {node: 20 || >=22} + + lru-cache@5.1.1: + resolution: {integrity: sha512-KpNARQA3Iwv+jTA0utUVVbrh+Jlrr1Fv0e56GGzAFOXN7dk/FviaDW8LHmK52DlcH4WP2n6gI8vN1aesBFgo9w==} + + make-dir@4.0.0: + resolution: {integrity: sha512-hXdUTZYIVOt1Ex//jAQi+wTZZpUpwBj/0QsOzqegb3rGMMeJiSEu5xLHnYfBrRV4RH2+OCSOO95Is/7x1WJ4bw==} + engines: {node: '>=10'} + + make-error@1.3.6: + resolution: {integrity: sha512-s8UhlNe7vPKomQhC1qFelMokr/Sc3AgNbso3n74mVPA5LTZwkB9NlXf4XPamLxJE8h0gh73rM94xvwRT2CVInw==} + + makeerror@1.0.12: + resolution: {integrity: sha512-JmqCvUhmt43madlpFzG4BQzG2Z3m6tvQDNKdClZnO3VbIudJYmxsT0FNJMeiB2+JTSlTQTSbU8QdesVmwJcmLg==} + + merge-stream@2.0.0: + resolution: {integrity: sha512-abv/qOcuPfk3URPfDzmZU1LKmuw8kT+0nIHvKrKgFrwifol/doWcdA4ZqsWQ8ENrFKkd67Mfpo/LovbIUsbt3w==} + + micromatch@4.0.8: + resolution: {integrity: sha512-PXwfBhYu0hBCPw8Dn0E+WDYb7af3dSLVWKi3HGv84IdF4TyFoC0ysxFd0Goxw7nSv4T/PzEJQxsYsEiFCKo2BA==} + engines: {node: '>=8.6'} + + mime-db@1.52.0: + resolution: {integrity: sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg==} + engines: {node: '>= 0.6'} + + mime-types@2.1.35: + resolution: {integrity: sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw==} + engines: {node: '>= 0.6'} + + mimic-fn@2.1.0: + resolution: {integrity: sha512-OqbOk5oEQeAZ8WXWydlu9HJjz9WVdEIvamMCcXmuqUYjTknH/sqsWvhQ3vgwKFRR1HpjvNBKQ37nbJgYzGqGcg==} + engines: {node: '>=6'} + + minimatch@10.0.3: + resolution: {integrity: sha512-IPZ167aShDZZUMdRk66cyQAW3qr0WzbHkPdMYa8bzZhlHhO3jALbKdxcaak7W9FfT2rZNpQuUu4Od7ILEpXSaw==} + engines: {node: 20 || >=22} + + minimatch@3.1.2: + resolution: {integrity: sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==} + + minimatch@5.1.6: + resolution: {integrity: sha512-lKwV/1brpG6mBUFHtb7NUmtABCb2WZZmm2wNiOA5hAb8VdCS4B3dtMWyvcoViccwAW/COERjXLt0zP1zXUN26g==} + engines: {node: '>=10'} + + minimatch@9.0.5: + resolution: {integrity: sha512-G6T0ZX48xgozx7587koeX9Ys2NYy6Gmv//P89sEte9V9whIapMNF4idKxnW2QtCcLiTWlb/wfCabAtAFWhhBow==} + engines: {node: '>=16 || 14 >=14.17'} + + minimist@1.2.8: + resolution: {integrity: sha512-2yyAR8qBkN3YuheJanUpWC5U3bb5osDywNB8RzDVlDwDHbocAJveqqj1u8+SVD7jkWT4yvsHCpWqqWqAxb0zCA==} + + minipass@7.1.2: + resolution: {integrity: sha512-qOOzS1cBTWYF4BH8fVePDBOO9iptMnGUEZwNc/cMWnTV2nVLZ7VoNWEPHkYczZA0pdoA7dl6e7FL659nX9S2aw==} + engines: {node: '>=16 || 14 >=14.17'} + + ms@2.1.3: + resolution: {integrity: sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==} + + napi-postinstall@0.2.4: + resolution: {integrity: sha512-ZEzHJwBhZ8qQSbknHqYcdtQVr8zUgGyM/q6h6qAyhtyVMNrSgDhrC4disf03dYW0e+czXyLnZINnCTEkWy0eJg==} + engines: {node: ^12.20.0 || ^14.18.0 || >=16.0.0} + hasBin: true + + natural-compare@1.4.0: + resolution: {integrity: sha512-OWND8ei3VtNC9h7V60qff3SVobHr996CTwgxubgyQYEpg290h9J0buyECNNJexkFm5sOajh5G116RYA1c8ZMSw==} + + node-int64@0.4.0: + resolution: {integrity: sha512-O5lz91xSOeoXP6DulyHfllpq+Eg00MWitZIbtPfoSEvqIHdl5gfcY6hYzDWnj0qD5tz52PI08u9qUvSVeUBeHw==} + + node-releases@2.0.19: + resolution: {integrity: sha512-xxOWJsBKtzAq7DY0J+DTzuz58K8e7sJbdgwkbMWQe8UYB6ekmsQ45q0M/tJDsGaZmbC+l7n57UV8Hl5tHxO9uw==} + + normalize-path@3.0.0: + resolution: {integrity: sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==} + engines: {node: '>=0.10.0'} + + npm-run-path@4.0.1: + resolution: {integrity: sha512-S48WzZW777zhNIrn7gxOlISNAqi9ZC/uQFnRdbeIHhZhCA6UqpkOT8T1G7BvfdgP4Er8gF4sUbaS0i7QvIfCWw==} + engines: {node: '>=8'} + + oauth-sign@0.9.0: + resolution: {integrity: sha512-fexhUFFPTGV8ybAtSIGbV6gOkSv8UtRbDBnAyLQw4QPKkgNlsH2ByPGtMUqdWkos6YCRmAqViwgZrJc/mRDzZQ==} + + once@1.4.0: + resolution: {integrity: sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w==} + + onetime@5.1.2: + resolution: {integrity: sha512-kbpaSSGJTWdAY5KPVeMOKXSrPtr8C8C7wodJbcsd51jRnmD+GZu8Y0VoU6Dm5Z4vWr0Ig/1NKuWRKf7j5aaYSg==} + engines: {node: '>=6'} + + p-limit@2.3.0: + resolution: {integrity: sha512-//88mFWSJx8lxCzwdAABTJL2MyWB12+eIY7MDL2SqLmAkeKU9qxRvWuSyTjm3FUmpBEMuFfckAIqEaVGUDxb6w==} + engines: {node: '>=6'} + + p-limit@3.1.0: + resolution: {integrity: sha512-TYOanM3wGwNGsZN2cVTYPArw454xnXj5qmWF1bEoAc4+cU/ol7GVh7odevjp1FNHduHc3KZMcFduxU5Xc6uJRQ==} + engines: {node: '>=10'} + + p-locate@4.1.0: + resolution: {integrity: sha512-R79ZZ/0wAxKGu3oYMlz8jy/kbhsNrS7SKZ7PxEHBgJ5+F2mtFW2fK2cOtBh1cHYkQsbzFV7I+EoRKe6Yt0oK7A==} + engines: {node: '>=8'} + + p-try@2.2.0: + resolution: {integrity: sha512-R4nPAVTAU0B9D35/Gk3uJf/7XYbQcyohSKdvAxIRSNghFl4e71hVoGnBNQz9cWaXxO2I10KTC+3jMdvvoKw6dQ==} + engines: {node: '>=6'} + + package-json-from-dist@1.0.1: + resolution: {integrity: sha512-UEZIS3/by4OC8vL3P2dTXRETpebLI2NiI5vIrjaD/5UtrkFX/tNbwjTSRAGC/+7CAo2pIcBaRgWmcBBHcsaCIw==} + + 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'} + + path-is-absolute@1.0.1: + resolution: {integrity: sha512-AVbw3UJ2e9bq64vSaS9Am0fje1Pa8pbGqTTsmXfaIiMpnr5DlDhfJOuLj9Sf95ZPVDAUerDfEk88MPmPe7UCQg==} + engines: {node: '>=0.10.0'} + + path-key@3.1.1: + resolution: {integrity: sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==} + engines: {node: '>=8'} + + path-scurry@1.11.1: + resolution: {integrity: sha512-Xa4Nw17FS9ApQFJ9umLiJS4orGjm7ZzwUrwamcGQuHSzDyth9boKDaycYdDcZDuqYATXw4HFXgaqWTctW/v1HA==} + engines: {node: '>=16 || 14 >=14.18'} + + path-scurry@2.0.0: + resolution: {integrity: sha512-ypGJsmGtdXUOeM5u93TyeIEfEhM6s+ljAhrk5vAvSx8uyY/02OvrZnA0YNGUrPXfpJMgI1ODd3nwz8Npx4O4cg==} + engines: {node: 20 || >=22} + + performance-now@2.1.0: + resolution: {integrity: sha512-7EAHlyLHI56VEIdK57uwHdHKIaAGbnXPiw0yWbarQZOKaKpvUIgW0jWRVLiatnM+XXlSwsanIBH/hzGMJulMow==} + + picocolors@1.1.1: + resolution: {integrity: sha512-xceH2snhtb5M9liqDsmEw56le376mTZkEX/jEb/RxNFyegNul7eNslCXP9FDj/Lcu0X8KEyMceP2ntpaHrDEVA==} + + picomatch@2.3.1: + resolution: {integrity: sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==} + engines: {node: '>=8.6'} + + picomatch@4.0.2: + resolution: {integrity: sha512-M7BAV6Rlcy5u+m6oPhAPFgJTzAioX/6B0DxyvDlo9l8+T3nLKbrczg2WLUyzd45L8RqfUMyGPzekbMvX2Ldkwg==} + engines: {node: '>=12'} + + pirates@4.0.7: + resolution: {integrity: sha512-TfySrs/5nm8fQJDcBDuUng3VOUKsd7S+zqvbOTiGXHfxX4wK31ard+hoNuvkicM/2YFzlpDgABOevKSsB4G/FA==} + engines: {node: '>= 6'} + + pkg-dir@4.2.0: + resolution: {integrity: sha512-HRDzbaKjC+AOWVXxAU/x54COGeIv9eb+6CkDSQoNTt4XyWoIJvuPsXizxu/Fr23EiekbtZwmh1IcIG/l/a10GQ==} + engines: {node: '>=8'} + + pretty-format@29.7.0: + resolution: {integrity: sha512-Pdlw/oPxN+aXdmM9R00JVC9WVFoCLTKJvDVLgmJ+qAffBMxsV85l/Lu7sNx4zSzPyoL2euImuEwHhOXdEgNFZQ==} + engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} + + pretty-format@30.0.0: + resolution: {integrity: sha512-18NAOUr4ZOQiIR+BgI5NhQE7uREdx4ZyV0dyay5izh4yfQ+1T7BSvggxvRGoXocrRyevqW5OhScUjbi9GB8R8Q==} + engines: {node: ^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0} + + psl@1.15.0: + resolution: {integrity: sha512-JZd3gMVBAVQkSs6HdNZo9Sdo0LNcQeMNP3CozBJb3JYC/QUYZTnKxP+f8oWRX4rHP5EurWxqAHTSwUCjlNKa1w==} + + punycode@2.3.1: + resolution: {integrity: sha512-vYt7UD1U9Wg6138shLtLOvdAu+8DsC/ilFtEVHcH+wydcSpNE20AfSOduf6MkRFahL5FY7X1oU7nKVZFtfq8Fg==} + engines: {node: '>=6'} + + pure-rand@7.0.1: + resolution: {integrity: sha512-oTUZM/NAZS8p7ANR3SHh30kXB+zK2r2BPcEn/awJIbOvq82WoMN4p62AWWp3Hhw50G0xMsw1mhIBLqHw64EcNQ==} + + qs@6.5.3: + resolution: {integrity: sha512-qxXIEh4pCGfHICj1mAJQ2/2XVZkjCDTcEgfoSQxc/fYivUZxTkk7L3bDBJSoNrEzXI17oUO5Dp07ktqE5KzczA==} + engines: {node: '>=0.6'} + + react-is@18.3.1: + resolution: {integrity: sha512-/LLMVyas0ljjAtoYiPqYiL8VWXzUUdThrmU5+n20DZv+a+ClRoevUzw5JxU+Ieh5/c87ytoTBV9G1FiKfNJdmg==} + + request@2.88.2: + resolution: {integrity: sha512-MsvtOrfG9ZcrOwAW+Qi+F6HbD0CWXEh9ou77uOb7FM2WPhwT7smM833PzanhJLsgXjN89Ir6V2PczXNnMpwKhw==} + engines: {node: '>= 6'} + deprecated: request has been deprecated, see https://github.com/request/request/issues/3142 + + require-directory@2.1.1: + resolution: {integrity: sha512-fGxEI7+wsG9xrvdjsrlmL22OMTTiHRwAMroiEeMgq8gzoLC/PQr7RsRDSTLUg/bZAZtF+TVIkHc6/4RIKrui+Q==} + engines: {node: '>=0.10.0'} + + resolve-cwd@3.0.0: + resolution: {integrity: sha512-OrZaX2Mb+rJCpH/6CpSqt9xFVpN++x01XnN2ie9g6P5/3xelLAkXWVADpdz1IHD/KFfEXyE6V0U01OQ3UO2rEg==} + engines: {node: '>=8'} + + resolve-from@5.0.0: + resolution: {integrity: sha512-qYg9KP24dD5qka9J47d0aVky0N+b4fTU89LN9iDnjB5waksiC49rvMB0PrUJQGoTmH50XPiqOvAjDfaijGxYZw==} + engines: {node: '>=8'} + + rimraf@6.0.1: + resolution: {integrity: sha512-9dkvaxAsk/xNXSJzMgFqqMCuFgt2+KsOFek3TMLfo8NCPfWpBmqwyNn5Y+NX56QUYfCtsyhF3ayiboEoUmJk/A==} + engines: {node: 20 || >=22} + hasBin: true + + safe-buffer@5.2.1: + resolution: {integrity: sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==} + + safer-buffer@2.1.2: + resolution: {integrity: sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==} + + semver@6.3.1: + resolution: {integrity: sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==} + hasBin: true + + semver@7.7.2: + resolution: {integrity: sha512-RF0Fw+rO5AMf9MAyaRXI4AV0Ulj5lMHqVxxdSgiVbixSCXoEmmX/jk0CuJw4+3SqroYO9VoUh+HcuJivvtJemA==} + engines: {node: '>=10'} + hasBin: true + + shebang-command@2.0.0: + resolution: {integrity: sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==} + engines: {node: '>=8'} + + shebang-regex@3.0.0: + resolution: {integrity: sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==} + engines: {node: '>=8'} + + signal-exit@3.0.7: + resolution: {integrity: sha512-wnD2ZE+l+SPC/uoS0vXeE9L1+0wuaMqKlfz9AMUo38JsyLSBWSFcHR1Rri62LZc12vLr1gb3jl7iwQhgwpAbGQ==} + + signal-exit@4.1.0: + resolution: {integrity: sha512-bzyZ1e88w9O1iNJbKnOlvYTrWPDl46O1bG0D3XInv+9tkPrxrN8jUUTiFlDkkmKWgn1M6CfIA13SuGqOa9Korw==} + engines: {node: '>=14'} + + slash@3.0.0: + resolution: {integrity: sha512-g9Q1haeby36OSStwb4ntCGGGaKsaVSjQ68fBxoQcutl5fS1vuY18H3wSt3jFyFtrkx+Kz0V1G85A4MyAdDMi2Q==} + engines: {node: '>=8'} + + source-map-support@0.5.13: + resolution: {integrity: sha512-SHSKFHadjVA5oR4PPqhtAVdcBWwRYVd6g6cAXnIbRiIwc2EhPrTuKUBdSLvlEKyIP3GCf89fltvcZiP9MMFA1w==} + + source-map@0.6.1: + resolution: {integrity: sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==} + engines: {node: '>=0.10.0'} + + sprintf-js@1.0.3: + resolution: {integrity: sha512-D9cPgkvLlV3t3IzL0D0YLvGA9Ahk4PcvVwUbN0dSGr1aP0Nrt4AEnTUbuGvquEC0mA64Gqt1fzirlRs5ibXx8g==} + + sshpk@1.18.0: + resolution: {integrity: sha512-2p2KJZTSqQ/I3+HX42EpYOa2l3f8Erv8MWKsy2I9uf4wA7yFIkXRffYdsx86y6z4vHtV8u7g+pPlr8/4ouAxsQ==} + engines: {node: '>=0.10.0'} + hasBin: true + + stack-utils@2.0.6: + resolution: {integrity: sha512-XlkWvfIm6RmsWtNJx+uqtKLS8eqFbxUg0ZzLXqY0caEy9l7hruX8IpiDnjsLavoBgqCCR71TqWO8MaXYheJ3RQ==} + engines: {node: '>=10'} + + string-length@4.0.2: + resolution: {integrity: sha512-+l6rNN5fYHNhZZy41RXsYptCjA2Igmq4EG7kZAYFQI1E1VTXarr6ZPXBg6eq7Y6eK4FEhY6AJlyuFIb/v/S0VQ==} + engines: {node: '>=10'} + + string-width@4.2.3: + resolution: {integrity: sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==} + engines: {node: '>=8'} + + string-width@5.1.2: + resolution: {integrity: sha512-HnLOCR3vjcY8beoNLtcjZ5/nxn2afmME6lhrDrebokqMap+XbeW8n9TXpPDOqdGK5qcI3oT0GKTW6wC7EMiVqA==} + engines: {node: '>=12'} + + strip-ansi@6.0.1: + resolution: {integrity: sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==} + engines: {node: '>=8'} + + strip-ansi@7.1.0: + resolution: {integrity: sha512-iq6eVVI64nQQTRYq2KtEg2d2uU7LElhTJwsH4YzIHZshxlgZms/wIc4VoDQTlG/IvVIrBKG06CrZnp0qv7hkcQ==} + engines: {node: '>=12'} + + strip-bom@4.0.0: + resolution: {integrity: sha512-3xurFv5tEgii33Zi8Jtp55wEIILR9eh34FAW00PZf+JnSsTmV/ioewSgQl97JHvgjoRGwPShsWm+IdrxB35d0w==} + engines: {node: '>=8'} + + strip-final-newline@2.0.0: + resolution: {integrity: sha512-BrpvfNAE3dcvq7ll3xVumzjKjZQ5tI1sEUIKr3Uoks0XUl45St3FlatVqef9prk4jRDzhW6WZg+3bk93y6pLjA==} + engines: {node: '>=6'} + + strip-json-comments@3.1.1: + resolution: {integrity: sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig==} + engines: {node: '>=8'} + + supports-color@7.2.0: + resolution: {integrity: sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==} + engines: {node: '>=8'} + + supports-color@8.1.1: + resolution: {integrity: sha512-MpUEN2OodtUzxvKQl72cUF7RQ5EiHsGvSsVG0ia9c5RbWGL2CI4C7EpPS8UTBIplnlzZiNuV56w+FuNxy3ty2Q==} + engines: {node: '>=10'} + + synckit@0.11.8: + resolution: {integrity: sha512-+XZ+r1XGIJGeQk3VvXhT6xx/VpbHsRzsTkGgF6E5RX9TTXD0118l87puaEBZ566FhqblC6U0d4XnubznJDm30A==} + engines: {node: ^14.18.0 || >=16.0.0} + + test-exclude@6.0.0: + resolution: {integrity: sha512-cAGWPIyOHU6zlmg88jwm7VRyXnMN7iV68OGAbYDk/Mh/xC/pzVPlQtY6ngoIH/5/tciuhGfvESU8GrHrcxD56w==} + engines: {node: '>=8'} + + tmpl@1.0.5: + resolution: {integrity: sha512-3f0uOEAQwIqGuWW2MVzYg8fV/QNnc/IpuJNG837rLuczAaLVHslWHZQj4IGiEl5Hs3kkbhwL9Ab7Hrsmuj+Smw==} + + to-regex-range@5.0.1: + resolution: {integrity: sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==} + engines: {node: '>=8.0'} + + tough-cookie@2.5.0: + resolution: {integrity: sha512-nlLsUzgm1kfLXSXfRZMc1KLAugd4hqJHDTvc2hDIwS3mZAfMEuMbc03SujMF+GEcpaX/qboeycw6iO8JwVv2+g==} + engines: {node: '>=0.8'} + + ts-jest@29.4.0: + resolution: {integrity: sha512-d423TJMnJGu80/eSgfQ5w/R+0zFJvdtTxwtF9KzFFunOpSeD+79lHJQIiAhluJoyGRbvj9NZJsl9WjCUo0ND7Q==} + engines: {node: ^14.15.0 || ^16.10.0 || ^18.0.0 || >=20.0.0} + hasBin: true + peerDependencies: + '@babel/core': '>=7.0.0-beta.0 <8' + '@jest/transform': ^29.0.0 || ^30.0.0 + '@jest/types': ^29.0.0 || ^30.0.0 + babel-jest: ^29.0.0 || ^30.0.0 + esbuild: '*' + jest: ^29.0.0 || ^30.0.0 + jest-util: ^29.0.0 || ^30.0.0 + typescript: '>=4.3 <6' + peerDependenciesMeta: + '@babel/core': + optional: true + '@jest/transform': + optional: true + '@jest/types': + optional: true + babel-jest: + optional: true + esbuild: + optional: true + jest-util: + optional: true + + ts-node@10.9.2: + resolution: {integrity: sha512-f0FFpIdcHgn8zcPSbf1dRevwt047YMnaiJM3u2w2RewrB+fob/zePZcrOyQoLMMO7aBIddLcQIEK5dYjkLnGrQ==} + hasBin: true + peerDependencies: + '@swc/core': '>=1.2.50' + '@swc/wasm': '>=1.2.50' + '@types/node': '*' + typescript: '>=2.7' + peerDependenciesMeta: + '@swc/core': + optional: true + '@swc/wasm': + optional: true + + tslib@2.8.1: + resolution: {integrity: sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w==} + + tunnel-agent@0.6.0: + resolution: {integrity: sha512-McnNiV1l8RYeY8tBgEpuodCC1mLUdbSN+CYBL7kJsJNInOP8UjDDEwdk6Mw60vdLLrr5NHKZhMAOSrR2NZuQ+w==} + + tweetnacl@0.14.5: + resolution: {integrity: sha512-KXXFFdAbFXY4geFIwoyNK+f5Z1b7swfXABfL7HXCmoIWMKU3dmS26672A4EeQtDzLKy7SXmfBu51JolvEKwtGA==} + + type-detect@4.0.8: + resolution: {integrity: sha512-0fr/mIH1dlO+x7TlcMy+bIDqKPsw/70tVyeHW787goQjhmqaZe10uwLujubK9q9Lg6Fiho1KUKDYz0Z7k7g5/g==} + engines: {node: '>=4'} + + type-fest@0.21.3: + resolution: {integrity: sha512-t0rzBq87m3fVcduHDUFhKmyyX+9eo6WQjZvf51Ea/M0Q7+T374Jp1aUiyUl0GKxp8M/OETVHSDvmkyPgvX+X2w==} + engines: {node: '>=10'} + + type-fest@4.41.0: + resolution: {integrity: sha512-TeTSQ6H5YHvpqVwBRcnLDCBnDOHWYu7IvGbHT6N8AOymcr9PJGjc1GTtiWZTYg0NCgYwvnYWEkVChQAr9bjfwA==} + engines: {node: '>=16'} + + typescript@5.8.3: + resolution: {integrity: sha512-p1diW6TqL9L07nNxvRMM7hMMw4c5XOo/1ibL4aAIGmSAt9slTE1Xgw5KWuof2uTOvCg9BY7ZRi+GaF+7sfgPeQ==} + engines: {node: '>=14.17'} + hasBin: true + + undici-types@7.8.0: + resolution: {integrity: sha512-9UJ2xGDvQ43tYyVMpuHlsgApydB8ZKfVYTsLDhXkFL/6gfkp+U8xTGdh8pMJv1SpZna0zxG1DwsKZsreLbXBxw==} + + unrs-resolver@1.9.0: + resolution: {integrity: sha512-wqaRu4UnzBD2ABTC1kLfBjAqIDZ5YUTr/MLGa7By47JV1bJDSW7jq/ZSLigB7enLe7ubNaJhtnBXgrc/50cEhg==} + + update-browserslist-db@1.1.3: + resolution: {integrity: sha512-UxhIZQ+QInVdunkDAaiazvvT/+fXL5Osr0JZlJulepYu6Jd7qJtDZjlur0emRlT71EN3ScPoE7gvsuIKKNavKw==} + hasBin: true + peerDependencies: + browserslist: '>= 4.21.0' + + uri-js@4.4.1: + resolution: {integrity: sha512-7rKUyy33Q1yc98pQ1DAmLtwX109F7TIfWlW1Ydo8Wl1ii1SeHieeh0HHfPeL2fMXK6z0s8ecKs9frCuLJvndBg==} + + uuid@3.4.0: + resolution: {integrity: sha512-HjSDRw6gZE5JMggctHBcjVak08+KEVhSIiDzFnT9S9aegmp85S/bReBVTb4QTFaRNptJ9kuYaNhnbNEOkbKb/A==} + deprecated: Please upgrade to version 7 or higher. Older versions may use Math.random() in certain circumstances, which is known to be problematic. See https://v8.dev/blog/math-random for details. + hasBin: true + + v8-compile-cache-lib@3.0.1: + resolution: {integrity: sha512-wa7YjyUGfNZngI/vtK0UHAN+lgDCxBPCylVXGp0zu59Fz5aiGtNXaq3DhIov063MorB+VfufLh3JlF2KdTK3xg==} + + v8-to-istanbul@9.3.0: + resolution: {integrity: sha512-kiGUalWN+rgBJ/1OHZsBtU4rXZOfj/7rKQxULKlIzwzQSvMJUUNgPwJEEh7gU6xEVxC0ahoOBvN2YI8GH6FNgA==} + engines: {node: '>=10.12.0'} + + verror@1.10.0: + resolution: {integrity: sha512-ZZKSmDAEFOijERBLkmYfJ+vmk3w+7hOLYDNkRCuRuMJGEmqYNCNLyBBFwWKVMhfwaEF3WOd0Zlw86U/WC/+nYw==} + engines: {'0': node >=0.6.0} + + walker@1.0.8: + resolution: {integrity: sha512-ts/8E8l5b7kY0vlWLewOkDXMmPdLcVV4GmOQLyxuSswIJsweeFZtAsMF7k1Nszz+TYBQrlYRmzOnr398y1JemQ==} + + which@2.0.2: + resolution: {integrity: sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==} + engines: {node: '>= 8'} + hasBin: true + + wrap-ansi@7.0.0: + resolution: {integrity: sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==} + engines: {node: '>=10'} + + wrap-ansi@8.1.0: + resolution: {integrity: sha512-si7QWI6zUMq56bESFvagtmzMdGOtoxfR+Sez11Mobfc7tm+VkUckk9bW2UeffTGVUbOksxmSw0AA2gs8g71NCQ==} + engines: {node: '>=12'} + + wrappy@1.0.2: + resolution: {integrity: sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==} + + write-file-atomic@5.0.1: + resolution: {integrity: sha512-+QU2zd6OTD8XWIJCbffaiQeH9U73qIqafo1x6V1snCWYGJf6cVE0cDR4D8xRzcEnfI21IFrUPzPGtcPf8AC+Rw==} + engines: {node: ^14.17.0 || ^16.13.0 || >=18.0.0} + + y18n@5.0.8: + resolution: {integrity: sha512-0pfFzegeDWJHJIAmTLRP2DwHjdF5s7jo9tuztdQxAhINCdvS+3nGINqPd00AphqJR/0LhANUS6/+7SCb98YOfA==} + engines: {node: '>=10'} + + yallist@3.1.1: + resolution: {integrity: sha512-a4UGQaWPH59mOXUYnAG2ewncQS4i4F43Tv3JoAM+s2VDAmS9NsK8GpDMLrCHPksFT7h3K6TOoUNn2pb7RoXx4g==} + + yargs-parser@21.1.1: + resolution: {integrity: sha512-tVpsJW7DdjecAiFpbIB1e3qxIQsE6NoPc5/eTdrbbIC4h0LVsWhnoa3g+m2HclBIujHzsxZ4VJVA+GUuc2/LBw==} + engines: {node: '>=12'} + + yargs@17.7.2: + resolution: {integrity: sha512-7dSzzRQ++CKnNI/krKnYRV7JKKPUXMEh61soaHKg9mrWEhzFWhFnxPxGl+69cD1Ou63C13NUPCnmIcrvqCuM6w==} + engines: {node: '>=12'} + + yn@3.1.1: + resolution: {integrity: sha512-Ux4ygGWsu2c7isFWe8Yu1YluJmqVhxqK2cLXNQA5AcC3QfbGNpM7fu0Y8b/z16pXLnFxZYvWhd3fhBY9DLmC6Q==} + engines: {node: '>=6'} + + yocto-queue@0.1.0: + resolution: {integrity: sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q==} + engines: {node: '>=10'} + +snapshots: + + '@ampproject/remapping@2.3.0': dependencies: '@jridgewell/gen-mapping': 0.3.8 '@jridgewell/trace-mapping': 0.3.25 - dev: true - /@babel/code-frame@7.27.1: - resolution: {integrity: sha512-cjQ7ZlQ0Mv3b47hABuTevyTuYN4i+loJKGeV9flcCgIK37cCXRh+L1bd3iBHlynerhQ7BhCkn2BPbQUL+rGqFg==} - engines: {node: '>=6.9.0'} + '@babel/code-frame@7.27.1': dependencies: '@babel/helper-validator-identifier': 7.27.1 js-tokens: 4.0.0 picocolors: 1.1.1 - dev: true - /@babel/compat-data@7.27.5: - resolution: {integrity: sha512-KiRAp/VoJaWkkte84TvUd9qjdbZAdiqyvMxrGl1N6vzFogKmaLgoM3L1kgtLicp2HP5fBJS8JrZKLVIZGVJAVg==} - engines: {node: '>=6.9.0'} - dev: true + '@babel/compat-data@7.27.5': {} - /@babel/core@7.27.4: - resolution: {integrity: sha512-bXYxrXFubeYdvB0NhD/NBB3Qi6aZeV20GOWVI47t2dkecCEoneR4NPVcb7abpXDEvejgrUfFtG6vG/zxAKmg+g==} - engines: {node: '>=6.9.0'} + '@babel/core@7.27.4': dependencies: '@ampproject/remapping': 2.3.0 '@babel/code-frame': 7.27.1 @@ -86,45 +1727,31 @@ packages: semver: 6.3.1 transitivePeerDependencies: - supports-color - dev: true - /@babel/generator@7.27.5: - resolution: {integrity: sha512-ZGhA37l0e/g2s1Cnzdix0O3aLYm66eF8aufiVteOgnwxgnRP8GoyMj7VWsgWnQbVKXyge7hqrFh2K2TQM6t1Hw==} - engines: {node: '>=6.9.0'} + '@babel/generator@7.27.5': dependencies: '@babel/parser': 7.27.5 '@babel/types': 7.27.6 '@jridgewell/gen-mapping': 0.3.8 '@jridgewell/trace-mapping': 0.3.25 jsesc: 3.1.0 - dev: true - /@babel/helper-compilation-targets@7.27.2: - resolution: {integrity: sha512-2+1thGUUWWjLTYTHZWK1n8Yga0ijBz1XAhUXcKy81rd5g6yh7hGqMp45v7cadSbEHc9G3OTv45SyneRN3ps4DQ==} - engines: {node: '>=6.9.0'} + '@babel/helper-compilation-targets@7.27.2': dependencies: '@babel/compat-data': 7.27.5 '@babel/helper-validator-option': 7.27.1 browserslist: 4.25.0 lru-cache: 5.1.1 semver: 6.3.1 - dev: true - /@babel/helper-module-imports@7.27.1: - resolution: {integrity: sha512-0gSFWUPNXNopqtIPQvlD5WgXYI5GY2kP2cCvoT8kczjbfcfuIljTbcWrulD1CIPIX2gt1wghbDy08yE1p+/r3w==} - engines: {node: '>=6.9.0'} + '@babel/helper-module-imports@7.27.1': dependencies: '@babel/traverse': 7.27.4 '@babel/types': 7.27.6 transitivePeerDependencies: - supports-color - dev: true - /@babel/helper-module-transforms@7.27.3(@babel/core@7.27.4): - resolution: {integrity: sha512-dSOvYwvyLsWBeIRyOeHXp5vPj5l1I011r52FM1+r1jCERv+aFXYk4whgQccYEGYxK2H3ZAIA8nuPkQ0HaUo3qg==} - engines: {node: '>=6.9.0'} - peerDependencies: - '@babel/core': ^7.0.0 + '@babel/helper-module-transforms@7.27.3(@babel/core@7.27.4)': dependencies: '@babel/core': 7.27.4 '@babel/helper-module-imports': 7.27.1 @@ -132,215 +1759,116 @@ packages: '@babel/traverse': 7.27.4 transitivePeerDependencies: - supports-color - dev: true - /@babel/helper-plugin-utils@7.27.1: - resolution: {integrity: sha512-1gn1Up5YXka3YYAHGKpbideQ5Yjf1tDa9qYcgysz+cNCXukyLl6DjPXhD3VRwSb8c0J9tA4b2+rHEZtc6R0tlw==} - engines: {node: '>=6.9.0'} - dev: true + '@babel/helper-plugin-utils@7.27.1': {} - /@babel/helper-string-parser@7.27.1: - resolution: {integrity: sha512-qMlSxKbpRlAridDExk92nSobyDdpPijUq2DW6oDnUqd0iOGxmQjyqhMIihI9+zv4LPyZdRje2cavWPbCbWm3eA==} - engines: {node: '>=6.9.0'} - dev: true + '@babel/helper-string-parser@7.27.1': {} - /@babel/helper-validator-identifier@7.27.1: - resolution: {integrity: sha512-D2hP9eA+Sqx1kBZgzxZh0y1trbuU+JoDkiEwqhQ36nodYqJwyEIhPSdMNd7lOm/4io72luTPWH20Yda0xOuUow==} - engines: {node: '>=6.9.0'} - dev: true + '@babel/helper-validator-identifier@7.27.1': {} - /@babel/helper-validator-option@7.27.1: - resolution: {integrity: sha512-YvjJow9FxbhFFKDSuFnVCe2WxXk1zWc22fFePVNEaWJEu8IrZVlda6N0uHwzZrUM1il7NC9Mlp4MaJYbYd9JSg==} - engines: {node: '>=6.9.0'} - dev: true + '@babel/helper-validator-option@7.27.1': {} - /@babel/helpers@7.27.6: - resolution: {integrity: sha512-muE8Tt8M22638HU31A3CgfSUciwz1fhATfoVai05aPXGor//CdWDCbnlY1yvBPo07njuVOCNGCSp/GTt12lIug==} - engines: {node: '>=6.9.0'} + '@babel/helpers@7.27.6': dependencies: '@babel/template': 7.27.2 '@babel/types': 7.27.6 - dev: true - /@babel/parser@7.27.5: - resolution: {integrity: sha512-OsQd175SxWkGlzbny8J3K8TnnDD0N3lrIUtB92xwyRpzaenGZhxDvxN/JgU00U3CDZNj9tPuDJ5H0WS4Nt3vKg==} - engines: {node: '>=6.0.0'} - hasBin: true + '@babel/parser@7.27.5': dependencies: '@babel/types': 7.27.6 - dev: true - /@babel/plugin-syntax-async-generators@7.8.4(@babel/core@7.27.4): - resolution: {integrity: sha512-tycmZxkGfZaxhMRbXlPXuVFpdWlXpir2W4AMhSJgRKzk/eDlIXOhb2LHWoLpDF7TEHylV5zNhykX6KAgHJmTNw==} - peerDependencies: - '@babel/core': ^7.0.0-0 + '@babel/plugin-syntax-async-generators@7.8.4(@babel/core@7.27.4)': dependencies: '@babel/core': 7.27.4 '@babel/helper-plugin-utils': 7.27.1 - dev: true - /@babel/plugin-syntax-bigint@7.8.3(@babel/core@7.27.4): - resolution: {integrity: sha512-wnTnFlG+YxQm3vDxpGE57Pj0srRU4sHE/mDkt1qv2YJJSeUAec2ma4WLUnUPeKjyrfntVwe/N6dCXpU+zL3Npg==} - peerDependencies: - '@babel/core': ^7.0.0-0 + '@babel/plugin-syntax-bigint@7.8.3(@babel/core@7.27.4)': dependencies: '@babel/core': 7.27.4 '@babel/helper-plugin-utils': 7.27.1 - dev: true - /@babel/plugin-syntax-class-properties@7.12.13(@babel/core@7.27.4): - resolution: {integrity: sha512-fm4idjKla0YahUNgFNLCB0qySdsoPiZP3iQE3rky0mBUtMZ23yDJ9SJdg6dXTSDnulOVqiF3Hgr9nbXvXTQZYA==} - peerDependencies: - '@babel/core': ^7.0.0-0 + '@babel/plugin-syntax-class-properties@7.12.13(@babel/core@7.27.4)': dependencies: '@babel/core': 7.27.4 '@babel/helper-plugin-utils': 7.27.1 - dev: true - /@babel/plugin-syntax-class-static-block@7.14.5(@babel/core@7.27.4): - resolution: {integrity: sha512-b+YyPmr6ldyNnM6sqYeMWE+bgJcJpO6yS4QD7ymxgH34GBPNDM/THBh8iunyvKIZztiwLH4CJZ0RxTk9emgpjw==} - engines: {node: '>=6.9.0'} - peerDependencies: - '@babel/core': ^7.0.0-0 + '@babel/plugin-syntax-class-static-block@7.14.5(@babel/core@7.27.4)': dependencies: '@babel/core': 7.27.4 '@babel/helper-plugin-utils': 7.27.1 - dev: true - /@babel/plugin-syntax-import-attributes@7.27.1(@babel/core@7.27.4): - resolution: {integrity: sha512-oFT0FrKHgF53f4vOsZGi2Hh3I35PfSmVs4IBFLFj4dnafP+hIWDLg3VyKmUHfLoLHlyxY4C7DGtmHuJgn+IGww==} - engines: {node: '>=6.9.0'} - peerDependencies: - '@babel/core': ^7.0.0-0 + '@babel/plugin-syntax-import-attributes@7.27.1(@babel/core@7.27.4)': dependencies: '@babel/core': 7.27.4 '@babel/helper-plugin-utils': 7.27.1 - dev: true - /@babel/plugin-syntax-import-meta@7.10.4(@babel/core@7.27.4): - resolution: {integrity: sha512-Yqfm+XDx0+Prh3VSeEQCPU81yC+JWZ2pDPFSS4ZdpfZhp4MkFMaDC1UqseovEKwSUpnIL7+vK+Clp7bfh0iD7g==} - peerDependencies: - '@babel/core': ^7.0.0-0 + '@babel/plugin-syntax-import-meta@7.10.4(@babel/core@7.27.4)': dependencies: '@babel/core': 7.27.4 '@babel/helper-plugin-utils': 7.27.1 - dev: true - /@babel/plugin-syntax-json-strings@7.8.3(@babel/core@7.27.4): - resolution: {integrity: sha512-lY6kdGpWHvjoe2vk4WrAapEuBR69EMxZl+RoGRhrFGNYVK8mOPAW8VfbT/ZgrFbXlDNiiaxQnAtgVCZ6jv30EA==} - peerDependencies: - '@babel/core': ^7.0.0-0 + '@babel/plugin-syntax-json-strings@7.8.3(@babel/core@7.27.4)': dependencies: '@babel/core': 7.27.4 '@babel/helper-plugin-utils': 7.27.1 - dev: true - /@babel/plugin-syntax-jsx@7.27.1(@babel/core@7.27.4): - resolution: {integrity: sha512-y8YTNIeKoyhGd9O0Jiyzyyqk8gdjnumGTQPsz0xOZOQ2RmkVJeZ1vmmfIvFEKqucBG6axJGBZDE/7iI5suUI/w==} - engines: {node: '>=6.9.0'} - peerDependencies: - '@babel/core': ^7.0.0-0 + '@babel/plugin-syntax-jsx@7.27.1(@babel/core@7.27.4)': dependencies: '@babel/core': 7.27.4 '@babel/helper-plugin-utils': 7.27.1 - dev: true - /@babel/plugin-syntax-logical-assignment-operators@7.10.4(@babel/core@7.27.4): - resolution: {integrity: sha512-d8waShlpFDinQ5MtvGU9xDAOzKH47+FFoney2baFIoMr952hKOLp1HR7VszoZvOsV/4+RRszNY7D17ba0te0ig==} - peerDependencies: - '@babel/core': ^7.0.0-0 + '@babel/plugin-syntax-logical-assignment-operators@7.10.4(@babel/core@7.27.4)': dependencies: '@babel/core': 7.27.4 '@babel/helper-plugin-utils': 7.27.1 - dev: true - /@babel/plugin-syntax-nullish-coalescing-operator@7.8.3(@babel/core@7.27.4): - resolution: {integrity: sha512-aSff4zPII1u2QD7y+F8oDsz19ew4IGEJg9SVW+bqwpwtfFleiQDMdzA/R+UlWDzfnHFCxxleFT0PMIrR36XLNQ==} - peerDependencies: - '@babel/core': ^7.0.0-0 + '@babel/plugin-syntax-nullish-coalescing-operator@7.8.3(@babel/core@7.27.4)': dependencies: '@babel/core': 7.27.4 '@babel/helper-plugin-utils': 7.27.1 - dev: true - /@babel/plugin-syntax-numeric-separator@7.10.4(@babel/core@7.27.4): - resolution: {integrity: sha512-9H6YdfkcK/uOnY/K7/aA2xpzaAgkQn37yzWUMRK7OaPOqOpGS1+n0H5hxT9AUw9EsSjPW8SVyMJwYRtWs3X3ug==} - peerDependencies: - '@babel/core': ^7.0.0-0 + '@babel/plugin-syntax-numeric-separator@7.10.4(@babel/core@7.27.4)': dependencies: '@babel/core': 7.27.4 '@babel/helper-plugin-utils': 7.27.1 - dev: true - /@babel/plugin-syntax-object-rest-spread@7.8.3(@babel/core@7.27.4): - resolution: {integrity: sha512-XoqMijGZb9y3y2XskN+P1wUGiVwWZ5JmoDRwx5+3GmEplNyVM2s2Dg8ILFQm8rWM48orGy5YpI5Bl8U1y7ydlA==} - peerDependencies: - '@babel/core': ^7.0.0-0 + '@babel/plugin-syntax-object-rest-spread@7.8.3(@babel/core@7.27.4)': dependencies: '@babel/core': 7.27.4 '@babel/helper-plugin-utils': 7.27.1 - dev: true - /@babel/plugin-syntax-optional-catch-binding@7.8.3(@babel/core@7.27.4): - resolution: {integrity: sha512-6VPD0Pc1lpTqw0aKoeRTMiB+kWhAoT24PA+ksWSBrFtl5SIRVpZlwN3NNPQjehA2E/91FV3RjLWoVTglWcSV3Q==} - peerDependencies: - '@babel/core': ^7.0.0-0 + '@babel/plugin-syntax-optional-catch-binding@7.8.3(@babel/core@7.27.4)': dependencies: '@babel/core': 7.27.4 '@babel/helper-plugin-utils': 7.27.1 - dev: true - /@babel/plugin-syntax-optional-chaining@7.8.3(@babel/core@7.27.4): - resolution: {integrity: sha512-KoK9ErH1MBlCPxV0VANkXW2/dw4vlbGDrFgz8bmUsBGYkFRcbRwMh6cIJubdPrkxRwuGdtCk0v/wPTKbQgBjkg==} - peerDependencies: - '@babel/core': ^7.0.0-0 + '@babel/plugin-syntax-optional-chaining@7.8.3(@babel/core@7.27.4)': dependencies: '@babel/core': 7.27.4 '@babel/helper-plugin-utils': 7.27.1 - dev: true - /@babel/plugin-syntax-private-property-in-object@7.14.5(@babel/core@7.27.4): - resolution: {integrity: sha512-0wVnp9dxJ72ZUJDV27ZfbSj6iHLoytYZmh3rFcxNnvsJF3ktkzLDZPy/mA17HGsaQT3/DQsWYX1f1QGWkCoVUg==} - engines: {node: '>=6.9.0'} - peerDependencies: - '@babel/core': ^7.0.0-0 + '@babel/plugin-syntax-private-property-in-object@7.14.5(@babel/core@7.27.4)': dependencies: '@babel/core': 7.27.4 '@babel/helper-plugin-utils': 7.27.1 - dev: true - /@babel/plugin-syntax-top-level-await@7.14.5(@babel/core@7.27.4): - resolution: {integrity: sha512-hx++upLv5U1rgYfwe1xBQUhRmU41NEvpUvrp8jkrSCdvGSnM5/qdRMtylJ6PG5OFkBaHkbTAKTnd3/YyESRHFw==} - engines: {node: '>=6.9.0'} - peerDependencies: - '@babel/core': ^7.0.0-0 + '@babel/plugin-syntax-top-level-await@7.14.5(@babel/core@7.27.4)': dependencies: '@babel/core': 7.27.4 '@babel/helper-plugin-utils': 7.27.1 - dev: true - /@babel/plugin-syntax-typescript@7.27.1(@babel/core@7.27.4): - resolution: {integrity: sha512-xfYCBMxveHrRMnAWl1ZlPXOZjzkN82THFvLhQhFXFt81Z5HnN+EtUkZhv/zcKpmT3fzmWZB0ywiBrbC3vogbwQ==} - engines: {node: '>=6.9.0'} - peerDependencies: - '@babel/core': ^7.0.0-0 + '@babel/plugin-syntax-typescript@7.27.1(@babel/core@7.27.4)': dependencies: '@babel/core': 7.27.4 '@babel/helper-plugin-utils': 7.27.1 - dev: true - /@babel/template@7.27.2: - resolution: {integrity: sha512-LPDZ85aEJyYSd18/DkjNh4/y1ntkE5KwUHWTiqgRxruuZL2F1yuHligVHLvcHY2vMHXttKFpJn6LwfI7cw7ODw==} - engines: {node: '>=6.9.0'} + '@babel/template@7.27.2': dependencies: '@babel/code-frame': 7.27.1 '@babel/parser': 7.27.5 '@babel/types': 7.27.6 - dev: true - /@babel/traverse@7.27.4: - resolution: {integrity: sha512-oNcu2QbHqts9BtOWJosOVJapWjBDSxGCpFvikNR5TGDYDQf3JwpIoMzIKrvfoti93cLfPJEG4tH9SPVeyCGgdA==} - engines: {node: '>=6.9.0'} + '@babel/traverse@7.27.4': dependencies: '@babel/code-frame': 7.27.1 '@babel/generator': 7.27.5 @@ -351,115 +1879,60 @@ packages: globals: 11.12.0 transitivePeerDependencies: - supports-color - dev: true - /@babel/types@7.27.6: - resolution: {integrity: sha512-ETyHEk2VHHvl9b9jZP5IHPavHYk57EhanlRRuae9XCpb/j5bDCbPPMOBfCWhnl/7EDJz0jEMCi/RhccCE8r1+Q==} - engines: {node: '>=6.9.0'} + '@babel/types@7.27.6': dependencies: '@babel/helper-string-parser': 7.27.1 '@babel/helper-validator-identifier': 7.27.1 - dev: true - /@bcoe/v8-coverage@0.2.3: - resolution: {integrity: sha512-0hYQ8SB4Db5zvZB4axdMHGwEaQjkZzFjQiN9LVYvIFB2nSUHW9tYpxWriPrWDASIxiaXax83REcLxuSdnGPZtw==} - dev: true + '@bcoe/v8-coverage@0.2.3': {} - /@cspotcode/source-map-support@0.8.1: - resolution: {integrity: sha512-IchNf6dN4tHoMFIn/7OE8LWZ19Y6q/67Bmf6vnGREv8RSbBVb9LPJxEcnwrcwX6ixSvaiGoomAUvu4YSxXrVgw==} - engines: {node: '>=12'} + '@cspotcode/source-map-support@0.8.1': dependencies: '@jridgewell/trace-mapping': 0.3.9 - /@emnapi/core@1.4.3: - resolution: {integrity: sha512-4m62DuCE07lw01soJwPiBGC0nAww0Q+RY70VZ+n49yDIO13yyinhbWCeNnaob0lakDtWQzSdtNWzJeOJt2ma+g==} - requiresBuild: true + '@emnapi/core@1.4.3': dependencies: '@emnapi/wasi-threads': 1.0.2 tslib: 2.8.1 - dev: true optional: true - /@emnapi/runtime@1.4.3: - resolution: {integrity: sha512-pBPWdu6MLKROBX05wSNKcNb++m5Er+KQ9QkB+WVM+pW2Kx9hoSrVTnu3BdkI5eBLZoKu/J6mW/B6i6bJB2ytXQ==} - requiresBuild: true + '@emnapi/runtime@1.4.3': dependencies: tslib: 2.8.1 - dev: true optional: true - /@emnapi/wasi-threads@1.0.2: - resolution: {integrity: sha512-5n3nTJblwRi8LlXkJ9eBzu+kZR8Yxcc7ubakyQTFzPMtIhFpUBRbsnc2Dv88IZDIbCDlBiWrknhB4Lsz7mg6BA==} - requiresBuild: true + '@emnapi/wasi-threads@1.0.2': dependencies: tslib: 2.8.1 - dev: true optional: true - /@fast-csv/format@5.0.2: - resolution: {integrity: sha512-fRYcWvI8vs0Zxa/8fXd/QlmQYWWkJqKZPAXM+vksnplb3owQFKTPPh9JqOtD0L3flQw/AZjjXdPkD7Kp/uHm8g==} - dependencies: - lodash.escaperegexp: 4.1.2 - lodash.isboolean: 3.0.3 - lodash.isequal: 4.5.0 - lodash.isfunction: 3.0.9 - lodash.isnil: 4.0.0 - dev: false - - /@fast-csv/parse@5.0.2: - resolution: {integrity: sha512-gMu1Btmm99TP+wc0tZnlH30E/F1Gw1Tah3oMDBHNPe9W8S68ixVHjt89Wg5lh7d9RuQMtwN+sGl5kxR891+fzw==} - dependencies: - lodash.escaperegexp: 4.1.2 - lodash.groupby: 4.6.0 - lodash.isfunction: 3.0.9 - lodash.isnil: 4.0.0 - lodash.isundefined: 3.0.1 - lodash.uniq: 4.5.0 - dev: false - - /@isaacs/balanced-match@4.0.1: - resolution: {integrity: sha512-yzMTt9lEb8Gv7zRioUilSglI0c0smZ9k5D65677DLWLtWJaXIS3CqcGyUFByYKlnUj6TkjLVs54fBl6+TiGQDQ==} - engines: {node: 20 || >=22} - dev: true + '@isaacs/balanced-match@4.0.1': {} - /@isaacs/brace-expansion@5.0.0: - resolution: {integrity: sha512-ZT55BDLV0yv0RBm2czMiZ+SqCGO7AvmOM3G/w2xhVPH+te0aKgFjmBvGlL1dH+ql2tgGO3MVrbb3jCKyvpgnxA==} - engines: {node: 20 || >=22} + '@isaacs/brace-expansion@5.0.0': dependencies: '@isaacs/balanced-match': 4.0.1 - dev: true - /@isaacs/cliui@8.0.2: - resolution: {integrity: sha512-O8jcjabXaleOG9DQ0+ARXWZBTfnP4WNAqzuiJK7ll44AmxGKv/J2M4TPjxjY3znBCfvBXFzucm1twdyFybFqEA==} - engines: {node: '>=12'} + '@isaacs/cliui@8.0.2': dependencies: string-width: 5.1.2 - string-width-cjs: /string-width@4.2.3 + string-width-cjs: string-width@4.2.3 strip-ansi: 7.1.0 - strip-ansi-cjs: /strip-ansi@6.0.1 + strip-ansi-cjs: strip-ansi@6.0.1 wrap-ansi: 8.1.0 - wrap-ansi-cjs: /wrap-ansi@7.0.0 - dev: true + wrap-ansi-cjs: wrap-ansi@7.0.0 - /@istanbuljs/load-nyc-config@1.1.0: - resolution: {integrity: sha512-VjeHSlIzpv/NyD3N0YuHfXOPDIixcA1q2ZV98wsMqcYlPmv2n3Yb2lYP9XMElnaFVXg5A7YLTeLu6V84uQDjmQ==} - engines: {node: '>=8'} + '@istanbuljs/load-nyc-config@1.1.0': dependencies: camelcase: 5.3.1 find-up: 4.1.0 get-package-type: 0.1.0 js-yaml: 3.14.1 resolve-from: 5.0.0 - dev: true - /@istanbuljs/schema@0.1.3: - resolution: {integrity: sha512-ZXRY4jNvVgSVQ8DL3LTcakaAtXwTVUxE81hslsyD2AtoXW/wVob10HkOJ1X/pAlcI7D+2YoZKg5do8G/w6RYgA==} - engines: {node: '>=8'} - dev: true + '@istanbuljs/schema@0.1.3': {} - /@jest/console@30.0.0: - resolution: {integrity: sha512-vfpJap6JZQ3I8sUN8dsFqNAKJYO4KIGxkcB+3Fw7Q/BJiWY5HwtMMiuT1oP0avsiDhjE/TCLaDgbGfHwDdBVeg==} - engines: {node: ^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0} + '@jest/console@30.0.0': dependencies: '@jest/types': 30.0.0 '@types/node': 24.0.1 @@ -467,16 +1940,8 @@ packages: jest-message-util: 30.0.0 jest-util: 30.0.0 slash: 3.0.0 - dev: true - /@jest/core@30.0.0(ts-node@10.9.2): - resolution: {integrity: sha512-1zU39zFtWSl5ZuDK3Rd6P8S28MmS4F11x6Z4CURrgJ99iaAJg68hmdJ2SAHEEO6ociaNk43UhUYtHxWKEWoNYw==} - engines: {node: ^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0} - peerDependencies: - node-notifier: ^8.0.1 || ^9.0.0 || ^10.0.0 - peerDependenciesMeta: - node-notifier: - optional: true + '@jest/core@30.0.0(ts-node@10.9.2(@types/node@24.0.1)(typescript@5.8.3))': dependencies: '@jest/console': 30.0.0 '@jest/pattern': 30.0.0 @@ -491,7 +1956,7 @@ packages: exit-x: 0.2.2 graceful-fs: 4.2.11 jest-changed-files: 30.0.0 - jest-config: 30.0.0(@types/node@24.0.1)(ts-node@10.9.2) + jest-config: 30.0.0(@types/node@24.0.1)(ts-node@10.9.2(@types/node@24.0.1)(typescript@5.8.3)) jest-haste-map: 30.0.0 jest-message-util: 30.0.0 jest-regex-util: 30.0.0 @@ -511,50 +1976,32 @@ packages: - esbuild-register - supports-color - ts-node - dev: true - /@jest/diff-sequences@30.0.0: - resolution: {integrity: sha512-xMbtoCeKJDto86GW6AiwVv7M4QAuI56R7dVBr1RNGYbOT44M2TIzOiske2RxopBqkumDY+A1H55pGvuribRY9A==} - engines: {node: ^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0} - dev: true + '@jest/diff-sequences@30.0.0': {} - /@jest/environment@30.0.0: - resolution: {integrity: sha512-09sFbMMgS5JxYnvgmmtwIHhvoyzvR5fUPrVl8nOCrC5KdzmmErTcAxfWyAhJ2bv3rvHNQaKiS+COSG+O7oNbXw==} - engines: {node: ^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0} + '@jest/environment@30.0.0': dependencies: '@jest/fake-timers': 30.0.0 '@jest/types': 30.0.0 '@types/node': 24.0.1 jest-mock: 30.0.0 - dev: true - /@jest/expect-utils@29.7.0: - resolution: {integrity: sha512-GlsNBWiFQFCVi9QVSx7f5AgMeLxe9YCCs5PuP2O2LdjDAA8Jh9eX7lA1Jq/xdXw3Wb3hyvlFNfZIfcRetSzYcA==} - engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} + '@jest/expect-utils@29.7.0': dependencies: jest-get-type: 29.6.3 - dev: true - /@jest/expect-utils@30.0.0: - resolution: {integrity: sha512-UiWfsqNi/+d7xepfOv8KDcbbzcYtkWBe3a3kVDtg6M1kuN6CJ7b4HzIp5e1YHrSaQaVS8sdCoyCMCZClTLNKFQ==} - engines: {node: ^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0} + '@jest/expect-utils@30.0.0': dependencies: '@jest/get-type': 30.0.0 - dev: true - /@jest/expect@30.0.0: - resolution: {integrity: sha512-XZ3j6syhMeKiBknmmc8V3mNIb44kxLTbOQtaXA4IFdHy+vEN0cnXRzbRjdGBtrp4k1PWyMWNU3Fjz3iejrhpQg==} - engines: {node: ^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0} + '@jest/expect@30.0.0': dependencies: expect: 30.0.0 jest-snapshot: 30.0.0 transitivePeerDependencies: - supports-color - dev: true - /@jest/fake-timers@30.0.0: - resolution: {integrity: sha512-yzBmJcrMHAMcAEbV2w1kbxmx8WFpEz8Cth3wjLMSkq+LO8VeGKRhpr5+BUp7PPK+x4njq/b6mVnDR8e/tPL5ng==} - engines: {node: ^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0} + '@jest/fake-timers@30.0.0': dependencies: '@jest/types': 30.0.0 '@sinonjs/fake-timers': 13.0.5 @@ -562,16 +2009,10 @@ packages: jest-message-util: 30.0.0 jest-mock: 30.0.0 jest-util: 30.0.0 - dev: true - /@jest/get-type@30.0.0: - resolution: {integrity: sha512-VZWMjrBzqfDKngQ7sUctKeLxanAbsBFoZnPxNIG6CmxK7Gv6K44yqd0nzveNIBfuhGZMmk1n5PGbvdSTOu0yTg==} - engines: {node: ^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0} - dev: true + '@jest/get-type@30.0.0': {} - /@jest/globals@30.0.0: - resolution: {integrity: sha512-OEzYes5A1xwBJVMPqFRa8NCao8Vr42nsUZuf/SpaJWoLE+4kyl6nCQZ1zqfipmCrIXQVALC5qJwKy/7NQQLPhw==} - engines: {node: ^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0} + '@jest/globals@30.0.0': dependencies: '@jest/environment': 30.0.0 '@jest/expect': 30.0.0 @@ -579,24 +2020,13 @@ packages: jest-mock: 30.0.0 transitivePeerDependencies: - supports-color - dev: true - /@jest/pattern@30.0.0: - resolution: {integrity: sha512-k+TpEThzLVXMkbdxf8KHjZ83Wl+G54ytVJoDIGWwS96Ql4xyASRjc6SU1hs5jHVql+hpyK9G8N7WuFhLpGHRpQ==} - engines: {node: ^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0} + '@jest/pattern@30.0.0': dependencies: '@types/node': 24.0.1 jest-regex-util: 30.0.0 - dev: true - /@jest/reporters@30.0.0: - resolution: {integrity: sha512-5WHNlLO0Ok+/o6ML5IzgVm1qyERtLHBNhwn67PAq92H4hZ+n5uW/BYj1VVwmTdxIcNrZLxdV9qtpdZkXf16HxA==} - engines: {node: ^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0} - peerDependencies: - node-notifier: ^8.0.1 || ^9.0.0 || ^10.0.0 - peerDependenciesMeta: - node-notifier: - optional: true + '@jest/reporters@30.0.0': dependencies: '@bcoe/v8-coverage': 0.2.3 '@jest/console': 30.0.0 @@ -623,64 +2053,43 @@ packages: v8-to-istanbul: 9.3.0 transitivePeerDependencies: - supports-color - dev: true - /@jest/schemas@29.6.3: - resolution: {integrity: sha512-mo5j5X+jIZmJQveBKeS/clAueipV7KgiX1vMgCxam1RNYiqE1w62n0/tJJnHtjW8ZHcQco5gY85jA3mi0L+nSA==} - engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} + '@jest/schemas@29.6.3': dependencies: '@sinclair/typebox': 0.27.8 - dev: true - /@jest/schemas@30.0.0: - resolution: {integrity: sha512-NID2VRyaEkevCRz6badhfqYwri/RvMbiHY81rk3AkK/LaiB0LSxi1RdVZ7MpZdTjNugtZeGfpL0mLs9Kp3MrQw==} - engines: {node: ^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0} + '@jest/schemas@30.0.0': dependencies: '@sinclair/typebox': 0.34.35 - dev: true - /@jest/snapshot-utils@30.0.0: - resolution: {integrity: sha512-C/QSFUmvZEYptg2Vin84FggAphwHvj6la39vkw1CNOZQORWZ7O/H0BXmdeeeGnvlXDYY8TlFM5jgFnxLAxpFjA==} - engines: {node: ^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0} + '@jest/snapshot-utils@30.0.0': dependencies: '@jest/types': 30.0.0 chalk: 4.1.2 graceful-fs: 4.2.11 natural-compare: 1.4.0 - dev: true - /@jest/source-map@30.0.0: - resolution: {integrity: sha512-oYBJ4d/NF4ZY3/7iq1VaeoERHRvlwKtrGClgescaXMIa1mmb+vfJd0xMgbW9yrI80IUA7qGbxpBWxlITrHkWoA==} - engines: {node: ^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0} + '@jest/source-map@30.0.0': dependencies: '@jridgewell/trace-mapping': 0.3.25 callsites: 3.1.0 graceful-fs: 4.2.11 - dev: true - /@jest/test-result@30.0.0: - resolution: {integrity: sha512-685zco9HdgBaaWiB9T4xjLtBuN0Q795wgaQPpmuAeZPHwHZSoKFAUnozUtU+ongfi4l5VCz8AclOE5LAQdyjxQ==} - engines: {node: ^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0} + '@jest/test-result@30.0.0': dependencies: '@jest/console': 30.0.0 '@jest/types': 30.0.0 '@types/istanbul-lib-coverage': 2.0.6 collect-v8-coverage: 1.0.2 - dev: true - /@jest/test-sequencer@30.0.0: - resolution: {integrity: sha512-Hmvv5Yg6UmghXIcVZIydkT0nAK7M/hlXx9WMHR5cLVwdmc14/qUQt3mC72T6GN0olPC6DhmKE6Cd/pHsgDbuqQ==} - engines: {node: ^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0} + '@jest/test-sequencer@30.0.0': dependencies: '@jest/test-result': 30.0.0 graceful-fs: 4.2.11 jest-haste-map: 30.0.0 slash: 3.0.0 - dev: true - /@jest/transform@30.0.0: - resolution: {integrity: sha512-8xhpsCGYJsUjqpJOgLyMkeOSSlhqggFZEWAnZquBsvATtueoEs7CkMRxOUmJliF3E5x+mXmZ7gEEsHank029Og==} - engines: {node: ^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0} + '@jest/transform@30.0.0': dependencies: '@babel/core': 7.27.4 '@jest/types': 30.0.0 @@ -699,11 +2108,8 @@ packages: write-file-atomic: 5.0.1 transitivePeerDependencies: - supports-color - dev: true - /@jest/types@29.6.3: - resolution: {integrity: sha512-u3UPsIilWKOM3F9CXtrG8LEJmNxwoCQC/XVj4IKYXvvpx7QIi/Kg1LI5uDmDpKlac62NUtX7eLjRh+jVZcLOzw==} - engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} + '@jest/types@29.6.3': dependencies: '@jest/schemas': 29.6.3 '@types/istanbul-lib-coverage': 2.0.6 @@ -711,11 +2117,8 @@ packages: '@types/node': 24.0.1 '@types/yargs': 17.0.33 chalk: 4.1.2 - dev: true - /@jest/types@30.0.0: - resolution: {integrity: sha512-1Nox8mAL52PKPfEnUQWBvKU/bp8FTT6AiDu76bFDEJj/qsRFSAVSldfCH3XYMqialti2zHXKvD5gN0AaHc0yKA==} - engines: {node: ^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0} + '@jest/types@30.0.0': dependencies: '@jest/pattern': 30.0.0 '@jest/schemas': 30.0.0 @@ -724,440 +2127,232 @@ packages: '@types/node': 24.0.1 '@types/yargs': 17.0.33 chalk: 4.1.2 - dev: true - /@jridgewell/gen-mapping@0.3.8: - resolution: {integrity: sha512-imAbBGkb+ebQyxKgzv5Hu2nmROxoDOXHh80evxdoXNOrvAnVx7zimzc1Oo5h9RlfV4vPXaE2iM5pOFbvOCClWA==} - engines: {node: '>=6.0.0'} + '@jridgewell/gen-mapping@0.3.8': dependencies: '@jridgewell/set-array': 1.2.1 '@jridgewell/sourcemap-codec': 1.5.0 '@jridgewell/trace-mapping': 0.3.25 - dev: true - /@jridgewell/resolve-uri@3.1.2: - resolution: {integrity: sha512-bRISgCIjP20/tbWSPWMEi54QVPRZExkuD9lJL+UIxUKtwVJA8wW1Trb1jMs1RFXo1CBTNZ/5hpC9QvmKWdopKw==} - engines: {node: '>=6.0.0'} + '@jridgewell/resolve-uri@3.1.2': {} - /@jridgewell/set-array@1.2.1: - resolution: {integrity: sha512-R8gLRTZeyp03ymzP/6Lil/28tGeGEzhx1q2k703KGWRAI1VdvPIXdG70VJc2pAMw3NA6JKL5hhFu1sJX0Mnn/A==} - engines: {node: '>=6.0.0'} - dev: true + '@jridgewell/set-array@1.2.1': {} - /@jridgewell/sourcemap-codec@1.5.0: - resolution: {integrity: sha512-gv3ZRaISU3fjPAgNsriBRqGWQL6quFx04YMPW/zD8XMLsU32mhCCbfbO6KZFLjvYpCZ8zyDEgqsgf+PwPaM7GQ==} + '@jridgewell/sourcemap-codec@1.5.0': {} - /@jridgewell/trace-mapping@0.3.25: - resolution: {integrity: sha512-vNk6aEwybGtawWmy/PzwnGDOjCkLWSD2wqvjGGAgOAwCGWySYXfYoxt00IJkTF+8Lb57DwOb3Aa0o9CApepiYQ==} + '@jridgewell/trace-mapping@0.3.25': dependencies: '@jridgewell/resolve-uri': 3.1.2 '@jridgewell/sourcemap-codec': 1.5.0 - dev: true - /@jridgewell/trace-mapping@0.3.9: - resolution: {integrity: sha512-3Belt6tdc8bPgAtbcmdtNJlirVoTmEb5e2gC94PnkwEW9jI6CAHUeoG85tjWP5WquqfavoMtMwiG4P926ZKKuQ==} + '@jridgewell/trace-mapping@0.3.9': dependencies: '@jridgewell/resolve-uri': 3.1.2 '@jridgewell/sourcemap-codec': 1.5.0 - /@napi-rs/wasm-runtime@0.2.11: - resolution: {integrity: sha512-9DPkXtvHydrcOsopiYpUgPHpmj0HWZKMUnL2dZqpvC42lsratuBG06V5ipyno0fUek5VlFsNQ+AcFATSrJXgMA==} - requiresBuild: true + '@napi-rs/wasm-runtime@0.2.11': dependencies: '@emnapi/core': 1.4.3 '@emnapi/runtime': 1.4.3 '@tybys/wasm-util': 0.9.0 - dev: true optional: true - /@pkgjs/parseargs@0.11.0: - resolution: {integrity: sha512-+1VkjdD0QBLPodGrJUeqarH8VAIvQODIbwh9XpP5Syisf7YoQgsJKPNFoqqLQlu+VQ/tVSshMR6loPMn8U+dPg==} - engines: {node: '>=14'} - requiresBuild: true - dev: true + '@pkgjs/parseargs@0.11.0': optional: true - /@pkgr/core@0.2.7: - resolution: {integrity: sha512-YLT9Zo3oNPJoBjBc4q8G2mjU4tqIbf5CEOORbUUr48dCD9q3umJ3IPlVqOqDakPfd2HuwccBaqlGhN4Gmr5OWg==} - engines: {node: ^12.20.0 || ^14.18.0 || >=16.0.0} - dev: true + '@pkgr/core@0.2.7': {} - /@sinclair/typebox@0.27.8: - resolution: {integrity: sha512-+Fj43pSMwJs4KRrH/938Uf+uAELIgVBmQzg/q1YG10djyfA3TnrU8N8XzqCh/okZdszqBQTZf96idMfE5lnwTA==} - dev: true + '@sinclair/typebox@0.27.8': {} - /@sinclair/typebox@0.34.35: - resolution: {integrity: sha512-C6ypdODf2VZkgRT6sFM8E1F8vR+HcffniX0Kp8MsU8PIfrlXbNCBz0jzj17GjdmjTx1OtZzdH8+iALL21UjF5A==} - dev: true + '@sinclair/typebox@0.34.35': {} - /@sinonjs/commons@3.0.1: - resolution: {integrity: sha512-K3mCHKQ9sVh8o1C9cxkwxaOmXoAMlDxC1mYyHrjqOWEcBjYr76t96zL2zlj5dUGZ3HSw240X1qgH3Mjf1yJWpQ==} + '@sinonjs/commons@3.0.1': dependencies: type-detect: 4.0.8 - dev: true - /@sinonjs/fake-timers@13.0.5: - resolution: {integrity: sha512-36/hTbH2uaWuGVERyC6da9YwGWnzUZXuPro/F2LfsdOsLnCojz/iSH8MxUt/FD2S5XBSVPhmArFUXcpCQ2Hkiw==} + '@sinonjs/fake-timers@13.0.5': dependencies: '@sinonjs/commons': 3.0.1 - dev: true - /@tsconfig/node10@1.0.11: - resolution: {integrity: sha512-DcRjDCujK/kCk/cUe8Xz8ZSpm8mS3mNNpta+jGCA6USEDfktlNvm1+IuZ9eTcDbNk41BHwpHHeW+N1lKCz4zOw==} + '@tsconfig/node10@1.0.11': {} - /@tsconfig/node12@1.0.11: - resolution: {integrity: sha512-cqefuRsh12pWyGsIoBKJA9luFu3mRxCA+ORZvA4ktLSzIuCUtWVxGIuXigEwO5/ywWFMZ2QEGKWvkZG1zDMTag==} + '@tsconfig/node12@1.0.11': {} - /@tsconfig/node14@1.0.3: - resolution: {integrity: sha512-ysT8mhdixWK6Hw3i1V2AeRqZ5WfXg1G43mqoYlM2nc6388Fq5jcXyr5mRsqViLx/GJYdoL0bfXD8nmF+Zn/Iow==} + '@tsconfig/node14@1.0.3': {} - /@tsconfig/node16@1.0.4: - resolution: {integrity: sha512-vxhUy4J8lyeyinH7Azl1pdd43GJhZH/tP2weN8TntQblOY+A0XbT8DJk1/oCPuOOyg/Ja757rG0CgHcWC8OfMA==} + '@tsconfig/node16@1.0.4': {} - /@tybys/wasm-util@0.9.0: - resolution: {integrity: sha512-6+7nlbMVX/PVDCwaIQ8nTOPveOcFLSt8GcXdx8hD0bt39uWxYT88uXzqTd4fTvqta7oeUJqudepapKNt2DYJFw==} - requiresBuild: true + '@tybys/wasm-util@0.9.0': dependencies: tslib: 2.8.1 - dev: true optional: true - /@types/babel__core@7.20.5: - resolution: {integrity: sha512-qoQprZvz5wQFJwMDqeseRXWv3rqMvhgpbXFfVyWhbx9X47POIA6i/+dXefEmZKoAgOaTdaIgNSMqMIU61yRyzA==} + '@types/babel__core@7.20.5': dependencies: '@babel/parser': 7.27.5 '@babel/types': 7.27.6 '@types/babel__generator': 7.27.0 '@types/babel__template': 7.4.4 '@types/babel__traverse': 7.20.7 - dev: true - /@types/babel__generator@7.27.0: - resolution: {integrity: sha512-ufFd2Xi92OAVPYsy+P4n7/U7e68fex0+Ee8gSG9KX7eo084CWiQ4sdxktvdl0bOPupXtVJPY19zk6EwWqUQ8lg==} + '@types/babel__generator@7.27.0': dependencies: '@babel/types': 7.27.6 - dev: true - /@types/babel__template@7.4.4: - resolution: {integrity: sha512-h/NUaSyG5EyxBIp8YRxo4RMe2/qQgvyowRwVMzhYhBCONbW8PUsg4lkFMrhgZhUe5z3L3MiLDuvyJ/CaPa2A8A==} + '@types/babel__template@7.4.4': dependencies: '@babel/parser': 7.27.5 '@babel/types': 7.27.6 - dev: true - /@types/babel__traverse@7.20.7: - resolution: {integrity: sha512-dkO5fhS7+/oos4ciWxyEyjWe48zmG6wbCheo/G2ZnHx4fs3EU6YC6UM8rk56gAjNJ9P3MTH2jo5jb92/K6wbng==} + '@types/babel__traverse@7.20.7': dependencies: '@babel/types': 7.27.6 - dev: true - /@types/istanbul-lib-coverage@2.0.6: - resolution: {integrity: sha512-2QF/t/auWm0lsy8XtKVPG19v3sSOQlJe/YHZgfjb/KBBHOGSV+J2q/S671rcq9uTBrLAXmZpqJiaQbMT+zNU1w==} - dev: true + '@types/istanbul-lib-coverage@2.0.6': {} - /@types/istanbul-lib-report@3.0.3: - resolution: {integrity: sha512-NQn7AHQnk/RSLOxrBbGyJM/aVQ+pjj5HCgasFxc0K/KhoATfQ/47AyUl15I2yBUpihjmas+a+VJBOqecrFH+uA==} + '@types/istanbul-lib-report@3.0.3': dependencies: '@types/istanbul-lib-coverage': 2.0.6 - dev: true - /@types/istanbul-reports@3.0.4: - resolution: {integrity: sha512-pk2B1NWalF9toCRu6gjBzR69syFjP4Od8WRAX+0mmf9lAjCRicLOWc+ZrxZHx/0XRjotgkF9t6iaMJ+aXcOdZQ==} + '@types/istanbul-reports@3.0.4': dependencies: '@types/istanbul-lib-report': 3.0.3 - dev: true - /@types/jest@29.5.14: - resolution: {integrity: sha512-ZN+4sdnLUbo8EVvVc2ao0GFW6oVrQRPn4K2lglySj7APvSrgzxHiNNK99us4WDMi57xxA2yggblIAMNhXOotLQ==} + '@types/jest@29.5.14': dependencies: expect: 29.7.0 pretty-format: 29.7.0 - dev: true - /@types/lodash@4.17.17: - resolution: {integrity: sha512-RRVJ+J3J+WmyOTqnz3PiBLA501eKwXl2noseKOrNo/6+XEHjTAxO4xHvxQB6QuNm+s4WRbn6rSiap8+EA+ykFQ==} - dev: true + '@types/lodash@4.17.17': {} - /@types/node@24.0.1: - resolution: {integrity: sha512-MX4Zioh39chHlDJbKmEgydJDS3tspMP/lnQC67G3SWsTnb9NeYVWOjkxpOSy4oMfPs4StcWHwBrvUb4ybfnuaw==} + '@types/node@24.0.1': dependencies: undici-types: 7.8.0 - /@types/stack-utils@2.0.3: - resolution: {integrity: sha512-9aEbYZ3TbYMznPdcdr3SmIrLXwC/AKZXQeCf9Pgao5CKb8CyHuEX5jzWPTkvregvhRJHcpRO6BFoGW9ycaOkYw==} - dev: true + '@types/stack-utils@2.0.3': {} - /@types/yargs-parser@21.0.3: - resolution: {integrity: sha512-I4q9QU9MQv4oEOz4tAHJtNz1cwuLxn2F3xcc2iV5WdqLPpUnj30aUuxt1mAxYTG+oe8CZMV/+6rU4S4gRDzqtQ==} - dev: true + '@types/yargs-parser@21.0.3': {} - /@types/yargs@17.0.33: - resolution: {integrity: sha512-WpxBCKWPLr4xSsHgz511rFJAM+wS28w2zEO1QDNY5zM/S8ok70NNfztH0xwhqKyaK0OHCbN98LDAZuy1ctxDkA==} + '@types/yargs@17.0.33': dependencies: '@types/yargs-parser': 21.0.3 - dev: true - /@ungap/structured-clone@1.3.0: - resolution: {integrity: sha512-WmoN8qaIAo7WTYWbAZuG8PYEhn5fkz7dZrqTBZ7dtt//lL2Gwms1IcnQ5yHqjDfX8Ft5j4YzDM23f87zBfDe9g==} - dev: true + '@ungap/structured-clone@1.3.0': {} - /@unrs/resolver-binding-android-arm-eabi@1.9.0: - resolution: {integrity: sha512-h1T2c2Di49ekF2TE8ZCoJkb+jwETKUIPDJ/nO3tJBKlLFPu+fyd93f0rGP/BvArKx2k2HlRM4kqkNarj3dvZlg==} - cpu: [arm] - os: [android] - requiresBuild: true - dev: true + '@unrs/resolver-binding-android-arm-eabi@1.9.0': optional: true - /@unrs/resolver-binding-android-arm64@1.9.0: - resolution: {integrity: sha512-sG1NHtgXtX8owEkJ11yn34vt0Xqzi3k9TJ8zppDmyG8GZV4kVWw44FHwKwHeEFl07uKPeC4ZoyuQaGh5ruJYPA==} - cpu: [arm64] - os: [android] - requiresBuild: true - dev: true + '@unrs/resolver-binding-android-arm64@1.9.0': optional: true - /@unrs/resolver-binding-darwin-arm64@1.9.0: - resolution: {integrity: sha512-nJ9z47kfFnCxN1z/oYZS7HSNsFh43y2asePzTEZpEvK7kGyuShSl3RRXnm/1QaqFL+iP+BjMwuB+DYUymOkA5A==} - cpu: [arm64] - os: [darwin] - requiresBuild: true - dev: true + '@unrs/resolver-binding-darwin-arm64@1.9.0': optional: true - /@unrs/resolver-binding-darwin-x64@1.9.0: - resolution: {integrity: sha512-TK+UA1TTa0qS53rjWn7cVlEKVGz2B6JYe0C++TdQjvWYIyx83ruwh0wd4LRxYBM5HeuAzXcylA9BH2trARXJTw==} - cpu: [x64] - os: [darwin] - requiresBuild: true - dev: true + '@unrs/resolver-binding-darwin-x64@1.9.0': optional: true - /@unrs/resolver-binding-freebsd-x64@1.9.0: - resolution: {integrity: sha512-6uZwzMRFcD7CcCd0vz3Hp+9qIL2jseE/bx3ZjaLwn8t714nYGwiE84WpaMCYjU+IQET8Vu/+BNAGtYD7BG/0yA==} - cpu: [x64] - os: [freebsd] - requiresBuild: true - dev: true + '@unrs/resolver-binding-freebsd-x64@1.9.0': optional: true - /@unrs/resolver-binding-linux-arm-gnueabihf@1.9.0: - resolution: {integrity: sha512-bPUBksQfrgcfv2+mm+AZinaKq8LCFvt5PThYqRotqSuuZK1TVKkhbVMS/jvSRfYl7jr3AoZLYbDkItxgqMKRkg==} - cpu: [arm] - os: [linux] - requiresBuild: true - dev: true + '@unrs/resolver-binding-linux-arm-gnueabihf@1.9.0': optional: true - /@unrs/resolver-binding-linux-arm-musleabihf@1.9.0: - resolution: {integrity: sha512-uT6E7UBIrTdCsFQ+y0tQd3g5oudmrS/hds5pbU3h4s2t/1vsGWbbSKhBSCD9mcqaqkBwoqlECpUrRJCmldl8PA==} - cpu: [arm] - os: [linux] - requiresBuild: true - dev: true + '@unrs/resolver-binding-linux-arm-musleabihf@1.9.0': optional: true - /@unrs/resolver-binding-linux-arm64-gnu@1.9.0: - resolution: {integrity: sha512-vdqBh911wc5awE2bX2zx3eflbyv8U9xbE/jVKAm425eRoOVv/VseGZsqi3A3SykckSpF4wSROkbQPvbQFn8EsA==} - cpu: [arm64] - os: [linux] - requiresBuild: true - dev: true + '@unrs/resolver-binding-linux-arm64-gnu@1.9.0': optional: true - /@unrs/resolver-binding-linux-arm64-musl@1.9.0: - resolution: {integrity: sha512-/8JFZ/SnuDr1lLEVsxsuVwrsGquTvT51RZGvyDB/dOK3oYK2UqeXzgeyq6Otp8FZXQcEYqJwxb9v+gtdXn03eQ==} - cpu: [arm64] - os: [linux] - requiresBuild: true - dev: true + '@unrs/resolver-binding-linux-arm64-musl@1.9.0': optional: true - /@unrs/resolver-binding-linux-ppc64-gnu@1.9.0: - resolution: {integrity: sha512-FkJjybtrl+rajTw4loI3L6YqSOpeZfDls4SstL/5lsP2bka9TiHUjgMBjygeZEis1oC8LfJTS8FSgpKPaQx2tQ==} - cpu: [ppc64] - os: [linux] - requiresBuild: true - dev: true + '@unrs/resolver-binding-linux-ppc64-gnu@1.9.0': optional: true - /@unrs/resolver-binding-linux-riscv64-gnu@1.9.0: - resolution: {integrity: sha512-w/NZfHNeDusbqSZ8r/hp8iL4S39h4+vQMc9/vvzuIKMWKppyUGKm3IST0Qv0aOZ1rzIbl9SrDeIqK86ZpUK37w==} - cpu: [riscv64] - os: [linux] - requiresBuild: true - dev: true + '@unrs/resolver-binding-linux-riscv64-gnu@1.9.0': optional: true - /@unrs/resolver-binding-linux-riscv64-musl@1.9.0: - resolution: {integrity: sha512-bEPBosut8/8KQbUixPry8zg/fOzVOWyvwzOfz0C0Rw6dp+wIBseyiHKjkcSyZKv/98edrbMknBaMNJfA/UEdqw==} - cpu: [riscv64] - os: [linux] - requiresBuild: true - dev: true + '@unrs/resolver-binding-linux-riscv64-musl@1.9.0': optional: true - /@unrs/resolver-binding-linux-s390x-gnu@1.9.0: - resolution: {integrity: sha512-LDtMT7moE3gK753gG4pc31AAqGUC86j3AplaFusc717EUGF9ZFJ356sdQzzZzkBk1XzMdxFyZ4f/i35NKM/lFA==} - cpu: [s390x] - os: [linux] - requiresBuild: true - dev: true + '@unrs/resolver-binding-linux-s390x-gnu@1.9.0': optional: true - /@unrs/resolver-binding-linux-x64-gnu@1.9.0: - resolution: {integrity: sha512-WmFd5KINHIXj8o1mPaT8QRjA9HgSXhN1gl9Da4IZihARihEnOylu4co7i/yeaIpcfsI6sYs33cNZKyHYDh0lrA==} - cpu: [x64] - os: [linux] - requiresBuild: true - dev: true + '@unrs/resolver-binding-linux-x64-gnu@1.9.0': optional: true - /@unrs/resolver-binding-linux-x64-musl@1.9.0: - resolution: {integrity: sha512-CYuXbANW+WgzVRIl8/QvZmDaZxrqvOldOwlbUjIM4pQ46FJ0W5cinJ/Ghwa/Ng1ZPMJMk1VFdsD/XwmCGIXBWg==} - cpu: [x64] - os: [linux] - requiresBuild: true - dev: true + '@unrs/resolver-binding-linux-x64-musl@1.9.0': optional: true - /@unrs/resolver-binding-wasm32-wasi@1.9.0: - resolution: {integrity: sha512-6Rp2WH0OoitMYR57Z6VE8Y6corX8C6QEMWLgOV6qXiJIeZ1F9WGXY/yQ8yDC4iTraotyLOeJ2Asea0urWj2fKQ==} - engines: {node: '>=14.0.0'} - cpu: [wasm32] - requiresBuild: true + '@unrs/resolver-binding-wasm32-wasi@1.9.0': dependencies: '@napi-rs/wasm-runtime': 0.2.11 - dev: true optional: true - /@unrs/resolver-binding-win32-arm64-msvc@1.9.0: - resolution: {integrity: sha512-rknkrTRuvujprrbPmGeHi8wYWxmNVlBoNW8+4XF2hXUnASOjmuC9FNF1tGbDiRQWn264q9U/oGtixyO3BT8adQ==} - cpu: [arm64] - os: [win32] - requiresBuild: true - dev: true + '@unrs/resolver-binding-win32-arm64-msvc@1.9.0': optional: true - /@unrs/resolver-binding-win32-ia32-msvc@1.9.0: - resolution: {integrity: sha512-Ceymm+iBl+bgAICtgiHyMLz6hjxmLJKqBim8tDzpX61wpZOx2bPK6Gjuor7I2RiUynVjvvkoRIkrPyMwzBzF3A==} - cpu: [ia32] - os: [win32] - requiresBuild: true - dev: true + '@unrs/resolver-binding-win32-ia32-msvc@1.9.0': optional: true - /@unrs/resolver-binding-win32-x64-msvc@1.9.0: - resolution: {integrity: sha512-k59o9ZyeyS0hAlcaKFezYSH2agQeRFEB7KoQLXl3Nb3rgkqT1NY9Vwy+SqODiLmYnEjxWJVRE/yq2jFVqdIxZw==} - cpu: [x64] - os: [win32] - requiresBuild: true - dev: true + '@unrs/resolver-binding-win32-x64-msvc@1.9.0': optional: true - /acorn-walk@8.3.4: - resolution: {integrity: sha512-ueEepnujpqee2o5aIYnvHU6C0A42MNdsIDeqy5BydrkuC5R1ZuUFnm27EeFJGoEHJQgn3uleRvmTXaJgfXbt4g==} - engines: {node: '>=0.4.0'} + acorn-walk@8.3.4: dependencies: acorn: 8.15.0 - /acorn@8.15.0: - resolution: {integrity: sha512-NZyJarBfL7nWwIq+FDL6Zp/yHEhePMNnnJ0y3qfieCrmNvYct8uvtiV41UvlSe6apAfk0fY1FbWx+NwfmpvtTg==} - engines: {node: '>=0.4.0'} - hasBin: true + acorn@8.15.0: {} - /ajv@6.12.6: - resolution: {integrity: sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==} + ajv@6.12.6: dependencies: fast-deep-equal: 3.1.3 fast-json-stable-stringify: 2.1.0 json-schema-traverse: 0.4.1 uri-js: 4.4.1 - dev: true - /ansi-escapes@4.3.2: - resolution: {integrity: sha512-gKXj5ALrKWQLsYG9jlTRmR/xKluxHV+Z9QEwNIgCfM1/uwPMCuzVVnh5mwTd+OuBZcwSIMbqssNWRm1lE51QaQ==} - engines: {node: '>=8'} + ansi-escapes@4.3.2: dependencies: type-fest: 0.21.3 - dev: true - /ansi-regex@5.0.1: - resolution: {integrity: sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==} - engines: {node: '>=8'} - dev: true + ansi-regex@5.0.1: {} - /ansi-regex@6.1.0: - resolution: {integrity: sha512-7HSX4QQb4CspciLpVFwyRe79O3xsIZDDLER21kERQ71oaPodF8jL725AgJMFAYbooIqolJoRLuM81SpeUkpkvA==} - engines: {node: '>=12'} - dev: true + ansi-regex@6.1.0: {} - /ansi-styles@4.3.0: - resolution: {integrity: sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==} - engines: {node: '>=8'} + ansi-styles@4.3.0: dependencies: color-convert: 2.0.1 - dev: true - /ansi-styles@5.2.0: - resolution: {integrity: sha512-Cxwpt2SfTzTtXcfOlzGEee8O+c+MmUgGrNiBcXnuWxuFJHe6a5Hz7qwhwe5OgaSYI0IJvkLqWX1ASG+cJOkEiA==} - engines: {node: '>=10'} - dev: true + ansi-styles@5.2.0: {} - /ansi-styles@6.2.1: - resolution: {integrity: sha512-bN798gFfQX+viw3R7yrGWRqnrN2oRkEkUjjl4JNn4E8GxxbjtG3FbrEIIY3l8/hrwUwIeCZvi4QuOTP4MErVug==} - engines: {node: '>=12'} - dev: true + ansi-styles@6.2.1: {} - /anymatch@3.1.3: - resolution: {integrity: sha512-KMReFUr0B4t+D+OBkjR3KYqvocp2XaSzO55UcB6mgQMd3KbcE+mWTyvVV7D/zsdEbNnV6acZUutkiHQXvTr1Rw==} - engines: {node: '>= 8'} + anymatch@3.1.3: dependencies: normalize-path: 3.0.0 picomatch: 2.3.1 - dev: true - /arg@4.1.3: - resolution: {integrity: sha512-58S9QDqG0Xx27YwPSt9fJxivjYl432YCwfDMfZ+71RAqUrZef7LrKQZ3LHLOwCS4FLNBplP533Zx895SeOCHvA==} + arg@4.1.3: {} - /argparse@1.0.10: - resolution: {integrity: sha512-o5Roy6tNG4SL/FOkCAN6RzjiakZS25RLYFrcMttJqbdd8BWrnA+fGz57iN5Pb06pvBGvl5gQ0B48dJlslXvoTg==} + argparse@1.0.10: dependencies: sprintf-js: 1.0.3 - dev: true - /asn1@0.2.6: - resolution: {integrity: sha512-ix/FxPn0MDjeyJ7i/yoHGFt/EX6LyNbxSEhPPXODPL+KB0VPk86UYfL0lMdy+KCnv+fmvIzySwaK5COwqVbWTQ==} + asn1@0.2.6: dependencies: safer-buffer: 2.1.2 - dev: true - /assert-plus@1.0.0: - resolution: {integrity: sha512-NfJ4UzBCcQGLDlQq7nHxH+tv3kyZ0hHQqF5BO6J7tNJeP5do1llPr8dZ8zHonfhAu0PHAdMkSo+8o0wxg9lZWw==} - engines: {node: '>=0.8'} - dev: true + assert-plus@1.0.0: {} - /async@3.2.6: - resolution: {integrity: sha512-htCUDlxyyCLMgaM3xXg0C0LW2xqfuQ6p05pCEIsXuyQ+a1koYKTuBMzRNwmybfLgvJDMd0r1LTn4+E0Ti6C2AA==} - dev: true + async@3.2.6: {} - /asynckit@0.4.0: - resolution: {integrity: sha512-Oei9OH4tRh0YqU3GxhX79dM/mwVgvbZJaSNaRk+bshkj0S5cfHcgYakreBjrHwatXKbz+IoIdYLxrKim2MjW0Q==} - dev: true + asynckit@0.4.0: {} - /aws-sign2@0.7.0: - resolution: {integrity: sha512-08kcGqnYf/YmjoRhfxyu+CLxBjUtHLXLXX/vUfx9l2LYzG3c1m61nrpyFUZI6zeS+Li/wWMMidD9KgrqtGq3mA==} - dev: true + aws-sign2@0.7.0: {} - /aws4@1.13.2: - resolution: {integrity: sha512-lHe62zvbTB5eEABUVi/AwVh0ZKY9rMMDhmm+eeyuuUQbQ3+J+fONVQOZyj+DdrvD4BY33uYniyRJ4UJIaSKAfw==} - dev: true + aws4@1.13.2: {} - /babel-jest@30.0.0(@babel/core@7.27.4): - resolution: {integrity: sha512-JQ0DhdFjODbSawDf0026uZuwaqfKkQzk+9mwWkq2XkKFIaMhFVOxlVmbFCOnnC76jATdxrff3IiUAvOAJec6tw==} - engines: {node: ^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0} - peerDependencies: - '@babel/core': ^7.11.0 + babel-jest@30.0.0(@babel/core@7.27.4): dependencies: '@babel/core': 7.27.4 '@jest/transform': 30.0.0 @@ -1169,11 +2364,8 @@ packages: slash: 3.0.0 transitivePeerDependencies: - supports-color - dev: true - /babel-plugin-istanbul@7.0.0: - resolution: {integrity: sha512-C5OzENSx/A+gt7t4VH1I2XsflxyPUmXRFPKBxt33xncdOmq7oROVM3bZv9Ysjjkv8OJYDMa+tKuKMvqU/H3xdw==} - engines: {node: '>=12'} + babel-plugin-istanbul@7.0.0: dependencies: '@babel/helper-plugin-utils': 7.27.1 '@istanbuljs/load-nyc-config': 1.1.0 @@ -1182,21 +2374,14 @@ packages: test-exclude: 6.0.0 transitivePeerDependencies: - supports-color - dev: true - /babel-plugin-jest-hoist@30.0.0: - resolution: {integrity: sha512-DSRm+US/FCB4xPDD6Rnslb6PAF9Bej1DZ+1u4aTiqJnk7ZX12eHsnDiIOqjGvITCq+u6wLqUhgS+faCNbVY8+g==} - engines: {node: ^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0} + babel-plugin-jest-hoist@30.0.0: dependencies: '@babel/template': 7.27.2 '@babel/types': 7.27.6 '@types/babel__core': 7.20.5 - dev: true - /babel-preset-current-node-syntax@1.1.0(@babel/core@7.27.4): - resolution: {integrity: sha512-ldYss8SbBlWva1bs28q78Ju5Zq1F+8BrqBZZ0VFhLBvhh6lCpC2o3gDJi/5DRLs9FgYZCnmPYIVFU4lRXCkyUw==} - peerDependencies: - '@babel/core': ^7.0.0 + babel-preset-current-node-syntax@1.1.0(@babel/core@7.27.4): dependencies: '@babel/core': 7.27.4 '@babel/plugin-syntax-async-generators': 7.8.4(@babel/core@7.27.4) @@ -1214,317 +2399,166 @@ packages: '@babel/plugin-syntax-optional-chaining': 7.8.3(@babel/core@7.27.4) '@babel/plugin-syntax-private-property-in-object': 7.14.5(@babel/core@7.27.4) '@babel/plugin-syntax-top-level-await': 7.14.5(@babel/core@7.27.4) - dev: true - /babel-preset-jest@30.0.0(@babel/core@7.27.4): - resolution: {integrity: sha512-hgEuu/W7gk8QOWUA9+m3Zk+WpGvKc1Egp6rFQEfYxEoM9Fk/q8nuTXNL65OkhwGrTApauEGgakOoWVXj+UfhKw==} - engines: {node: ^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0} - peerDependencies: - '@babel/core': ^7.11.0 + babel-preset-jest@30.0.0(@babel/core@7.27.4): dependencies: '@babel/core': 7.27.4 babel-plugin-jest-hoist: 30.0.0 babel-preset-current-node-syntax: 1.1.0(@babel/core@7.27.4) - dev: true - /balanced-match@1.0.2: - resolution: {integrity: sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==} - dev: true + balanced-match@1.0.2: {} - /bcrypt-pbkdf@1.0.2: - resolution: {integrity: sha512-qeFIXtP4MSoi6NLqO12WfqARWWuCKi2Rn/9hJLEmtB5yTNr9DqFWkJRCf2qShWzPeAMRnOgCrq0sg/KLv5ES9w==} + bcrypt-pbkdf@1.0.2: dependencies: tweetnacl: 0.14.5 - dev: true - /brace-expansion@1.1.12: - resolution: {integrity: sha512-9T9UjW3r0UW5c1Q7GTwllptXwhvYmEzFhzMfZ9H7FQWt+uZePjZPjBP/W1ZEyZ1twGWom5/56TF4lPcqjnDHcg==} + brace-expansion@1.1.12: dependencies: balanced-match: 1.0.2 concat-map: 0.0.1 - dev: true - /brace-expansion@2.0.2: - resolution: {integrity: sha512-Jt0vHyM+jmUBqojB7E1NIYadt0vI0Qxjxd2TErW94wDz+E2LAm5vKMXXwg6ZZBTHPuUlDgQHKXvjGBdfcF1ZDQ==} + brace-expansion@2.0.2: dependencies: balanced-match: 1.0.2 - dev: true - /braces@3.0.3: - resolution: {integrity: sha512-yQbXgO/OSZVD2IsiLlro+7Hf6Q18EJrKSEsdoMzKePKXct3gvD8oLcOQdIzGupr5Fj+EDe8gO/lxc1BzfMpxvA==} - engines: {node: '>=8'} + braces@3.0.3: dependencies: fill-range: 7.1.1 - dev: true - /browserslist@4.25.0: - resolution: {integrity: sha512-PJ8gYKeS5e/whHBh8xrwYK+dAvEj7JXtz6uTucnMRB8OiGTsKccFekoRrjajPBHV8oOY+2tI4uxeceSimKwMFA==} - engines: {node: ^6 || ^7 || ^8 || ^9 || ^10 || ^11 || ^12 || >=13.7} - hasBin: true + browserslist@4.25.0: dependencies: caniuse-lite: 1.0.30001723 electron-to-chromium: 1.5.167 node-releases: 2.0.19 update-browserslist-db: 1.1.3(browserslist@4.25.0) - dev: true - /bs-logger@0.2.6: - resolution: {integrity: sha512-pd8DCoxmbgc7hyPKOvxtqNcjYoOsABPQdcCUjGp3d42VR2CX1ORhk2A87oqqu5R1kk+76nsxZupkmyd+MVtCog==} - engines: {node: '>= 6'} + bs-logger@0.2.6: dependencies: fast-json-stable-stringify: 2.1.0 - dev: true - /bser@2.1.1: - resolution: {integrity: sha512-gQxTNE/GAfIIrmHLUE3oJyp5FO6HRBfhjnw4/wMmA63ZGDJnWBmgY/lyQBpnDUkGmAhbSe39tx2d/iTOAfglwQ==} + bser@2.1.1: dependencies: node-int64: 0.4.0 - dev: true - /buffer-from@1.1.2: - resolution: {integrity: sha512-E+XQCRwSbaaiChtv6k6Dwgc+bx+Bs6vuKJHHl5kox/BaKbhiXzqQOwK4cO22yElGp2OCmjwVhT3HmxgyPGnJfQ==} - dev: true + buffer-from@1.1.2: {} - /callsites@3.1.0: - resolution: {integrity: sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ==} - engines: {node: '>=6'} - dev: true + callsites@3.1.0: {} - /camelcase@5.3.1: - resolution: {integrity: sha512-L28STB170nwWS63UjtlEOE3dldQApaJXZkOI1uMFfzf3rRuPegHaHesyee+YxQ+W6SvRDQV6UrdOdRiR153wJg==} - engines: {node: '>=6'} - dev: true + camelcase@5.3.1: {} - /camelcase@6.3.0: - resolution: {integrity: sha512-Gmy6FhYlCY7uOElZUSbxo2UCDH8owEk996gkbrpsgGtrJLM3J7jGxl9Ic7Qwwj4ivOE5AWZWRMecDdF7hqGjFA==} - engines: {node: '>=10'} - dev: true + camelcase@6.3.0: {} - /caniuse-lite@1.0.30001723: - resolution: {integrity: sha512-1R/elMjtehrFejxwmexeXAtae5UO9iSyFn6G/I806CYC/BLyyBk1EPhrKBkWhy6wM6Xnm47dSJQec+tLJ39WHw==} - dev: true + caniuse-lite@1.0.30001723: {} - /caseless@0.12.0: - resolution: {integrity: sha512-4tYFyifaFfGacoiObjJegolkwSU4xQNGbVgUiNYVUxbQ2x2lUsFvY4hVgVzGiIe6WLOPqycWXA40l+PWsxthUw==} - dev: true + caseless@0.12.0: {} - /chalk@4.1.2: - resolution: {integrity: sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==} - engines: {node: '>=10'} + chalk@4.1.2: dependencies: ansi-styles: 4.3.0 supports-color: 7.2.0 - dev: true - /char-regex@1.0.2: - resolution: {integrity: sha512-kWWXztvZ5SBQV+eRgKFeh8q5sLuZY2+8WUIzlxWVTg+oGwY14qylx1KbKzHd8P6ZYkAg0xyIDU9JMHhyJMZ1jw==} - engines: {node: '>=10'} - dev: true + char-regex@1.0.2: {} - /ci-info@3.9.0: - resolution: {integrity: sha512-NIxF55hv4nSqQswkAeiOi1r83xy8JldOFDTWiug55KBu9Jnblncd2U6ViHmYgHf01TPZS77NJBhBMKdWj9HQMQ==} - engines: {node: '>=8'} - dev: true + ci-info@3.9.0: {} - /ci-info@4.2.0: - resolution: {integrity: sha512-cYY9mypksY8NRqgDB1XD1RiJL338v/551niynFTGkZOO2LHuB2OmOYxDIe/ttN9AHwrqdum1360G3ald0W9kCg==} - engines: {node: '>=8'} - dev: true + ci-info@4.2.0: {} - /cjs-module-lexer@2.1.0: - resolution: {integrity: sha512-UX0OwmYRYQQetfrLEZeewIFFI+wSTofC+pMBLNuH3RUuu/xzG1oz84UCEDOSoQlN3fZ4+AzmV50ZYvGqkMh9yA==} - dev: true + cjs-module-lexer@2.1.0: {} - /cliui@8.0.1: - resolution: {integrity: sha512-BSeNnyus75C4//NQ9gQt1/csTXyo/8Sb+afLAkzAptFuMsod9HFokGNudZpi/oQV73hnVK+sR+5PVRMd+Dr7YQ==} - engines: {node: '>=12'} + cliui@8.0.1: dependencies: string-width: 4.2.3 strip-ansi: 6.0.1 wrap-ansi: 7.0.0 - dev: true - /co@4.6.0: - resolution: {integrity: sha512-QVb0dM5HvG+uaxitm8wONl7jltx8dqhfU33DcqtOZcLSVIKSDDLDi7+0LbAKiyI8hD9u42m2YxXSkMGWThaecQ==} - engines: {iojs: '>= 1.0.0', node: '>= 0.12.0'} - dev: true + co@4.6.0: {} - /collect-v8-coverage@1.0.2: - resolution: {integrity: sha512-lHl4d5/ONEbLlJvaJNtsF/Lz+WvB07u2ycqTYbdrq7UypDXailES4valYb2eWiJFxZlVmpGekfqoxQhzyFdT4Q==} - dev: true + collect-v8-coverage@1.0.2: {} - /color-convert@2.0.1: - resolution: {integrity: sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==} - engines: {node: '>=7.0.0'} + color-convert@2.0.1: dependencies: color-name: 1.1.4 - dev: true - /color-name@1.1.4: - resolution: {integrity: sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==} - dev: true + color-name@1.1.4: {} - /combined-stream@1.0.8: - resolution: {integrity: sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg==} - engines: {node: '>= 0.8'} + combined-stream@1.0.8: dependencies: delayed-stream: 1.0.0 - dev: true - /commander@14.0.0: - resolution: {integrity: sha512-2uM9rYjPvyq39NwLRqaiLtWHyDC1FvryJDa2ATTVims5YAS4PupsEQsDvP14FqhFr0P49CYDugi59xaxJlTXRA==} - engines: {node: '>=20'} - dev: false + commander@14.0.0: {} - /concat-map@0.0.1: - resolution: {integrity: sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==} - dev: true + concat-map@0.0.1: {} - /convert-source-map@2.0.0: - resolution: {integrity: sha512-Kvp459HrV2FEJ1CAsi1Ku+MY3kasH19TFykTz2xWmMeq6bk2NU3XXvfJ+Q61m0xktWwt+1HSYf3JZsTms3aRJg==} - dev: true + convert-source-map@2.0.0: {} - /core-util-is@1.0.2: - resolution: {integrity: sha512-3lqz5YjWTYnW6dlDa5TLaTCcShfar1e40rmcJVwCBJC6mWlFuj0eCHIElmG1g5kyuJ/GD+8Wn4FFCcz4gJPfaQ==} - dev: true + core-util-is@1.0.2: {} - /coveralls@3.1.1: - resolution: {integrity: sha512-+dxnG2NHncSD1NrqbSM3dn/lE57O6Qf/koe9+I7c+wzkqRmEvcp0kgJdxKInzYzkICKkFMZsX3Vct3++tsF9ww==} - engines: {node: '>=6'} - hasBin: true + coveralls@3.1.1: dependencies: js-yaml: 3.14.1 lcov-parse: 1.0.0 log-driver: 1.2.7 minimist: 1.2.8 request: 2.88.2 - dev: true - /create-require@1.1.1: - resolution: {integrity: sha512-dcKFX3jn0MpIaXjisoRvexIJVEKzaq7z2rZKxf+MSr9TkdmHmsU4m2lcLojrj/FHl8mk5VxMmYA+ftRkP/3oKQ==} + create-require@1.1.1: {} - /cross-spawn@7.0.6: - resolution: {integrity: sha512-uV2QOWP2nWzsy2aMp8aRibhi9dlzF5Hgh5SHaB9OiTGEyDTiJJyx0uy51QXdyWbtAHNua4XJzUKca3OzKUd3vA==} - engines: {node: '>= 8'} + cross-spawn@7.0.6: dependencies: path-key: 3.1.1 shebang-command: 2.0.0 which: 2.0.2 - dev: true - /dashdash@1.14.1: - resolution: {integrity: sha512-jRFi8UDGo6j+odZiEpjazZaWqEal3w/basFjQHQEwVtZJGDpxbH1MeYluwCS8Xq5wmLJooDlMgvVarmWfGM44g==} - engines: {node: '>=0.10'} + dashdash@1.14.1: dependencies: assert-plus: 1.0.0 - dev: true - /debug@4.4.1: - resolution: {integrity: sha512-KcKCqiftBJcZr++7ykoDIEwSa3XWowTfNPo92BYxjXiyYEVrUQh2aLyhxBCwww+heortUFxEJYcRzosstTEBYQ==} - engines: {node: '>=6.0'} - peerDependencies: - supports-color: '*' - peerDependenciesMeta: - supports-color: - optional: true + debug@4.4.1: dependencies: ms: 2.1.3 - dev: true - /dedent@1.6.0: - resolution: {integrity: sha512-F1Z+5UCFpmQUzJa11agbyPVMbpgT/qA3/SKyJ1jyBgm7dUcUEa8v9JwDkerSQXfakBwFljIxhOJqGkjUwZ9FSA==} - peerDependencies: - babel-plugin-macros: ^3.1.0 - peerDependenciesMeta: - babel-plugin-macros: - optional: true - dev: true + dedent@1.6.0: {} - /deepmerge@4.3.1: - resolution: {integrity: sha512-3sUqbMEc77XqpdNO7FRyRog+eW3ph+GYCbj+rK+uYyRMuwsVy0rMiVtPn+QJlKFvWP/1PYpapqYn0Me2knFn+A==} - engines: {node: '>=0.10.0'} - dev: true + deepmerge@4.3.1: {} - /delayed-stream@1.0.0: - resolution: {integrity: sha512-ZySD7Nf91aLB0RxL4KGrKHBXl7Eds1DAmEdcoVawXnLD7SDhpNgtuII2aAkg7a7QS41jxPSZ17p4VdGnMHk3MQ==} - engines: {node: '>=0.4.0'} - dev: true + delayed-stream@1.0.0: {} - /detect-newline@3.1.0: - resolution: {integrity: sha512-TLz+x/vEXm/Y7P7wn1EJFNLxYpUD4TgMosxY6fAVJUnJMbupHBOncxyWUG9OpTaH9EBD7uFI5LfEgmMOc54DsA==} - engines: {node: '>=8'} - dev: true + detect-newline@3.1.0: {} - /diff-sequences@29.6.3: - resolution: {integrity: sha512-EjePK1srD3P08o2j4f0ExnylqRs5B9tJjcp9t1krH2qRi8CCdsYfwe9JgSLurFBWwq4uOlipzfk5fHNvwFKr8Q==} - engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} - dev: true + diff-sequences@29.6.3: {} - /diff@4.0.2: - resolution: {integrity: sha512-58lmxKSA4BNyLz+HHMUzlOEpg09FV+ev6ZMe3vJihgdxzgcwZ8VoEEPmALCZG9LmqfVoNMMKpttIYTVG6uDY7A==} - engines: {node: '>=0.3.1'} + diff@4.0.2: {} - /eastasianwidth@0.2.0: - resolution: {integrity: sha512-I88TYZWc9XiYHRQ4/3c5rjjfgkjhLyW2luGIheGERbNQ6OY7yTybanSpDXZa8y7VUP9YmDcYa+eyq4ca7iLqWA==} - dev: true + eastasianwidth@0.2.0: {} - /ecc-jsbn@0.1.2: - resolution: {integrity: sha512-eh9O+hwRHNbG4BLTjEl3nw044CkGm5X6LoaCf7LPp7UU8Qrt47JYNi6nPX8xjW97TKGKm1ouctg0QSpZe9qrnw==} + ecc-jsbn@0.1.2: dependencies: jsbn: 0.1.1 safer-buffer: 2.1.2 - dev: true - /ejs@3.1.10: - resolution: {integrity: sha512-UeJmFfOrAQS8OJWPZ4qtgHyWExa088/MtK5UEyoJGFH67cDEXkZSviOiKRCZ4Xij0zxI3JECgYs3oKx+AizQBA==} - engines: {node: '>=0.10.0'} - hasBin: true + ejs@3.1.10: dependencies: jake: 10.9.2 - dev: true - /electron-to-chromium@1.5.167: - resolution: {integrity: sha512-LxcRvnYO5ez2bMOFpbuuVuAI5QNeY1ncVytE/KXaL6ZNfzX1yPlAO0nSOyIHx2fVAuUprMqPs/TdVhUFZy7SIQ==} - dev: true + electron-to-chromium@1.5.167: {} - /emittery@0.13.1: - resolution: {integrity: sha512-DeWwawk6r5yR9jFgnDKYt4sLS0LmHJJi3ZOnb5/JdbYwj3nW+FxQnHIjhBKz8YLC7oRNPVM9NQ47I3CVx34eqQ==} - engines: {node: '>=12'} - dev: true + emittery@0.13.1: {} - /emoji-regex@8.0.0: - resolution: {integrity: sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==} - dev: true + emoji-regex@8.0.0: {} - /emoji-regex@9.2.2: - resolution: {integrity: sha512-L18DaJsXSUk2+42pv8mLs5jJT2hqFkFE4j21wOmgbUqsZ2hL72NsUU785g9RXgo3s0ZNgVl42TiHp3ZtOv/Vyg==} - dev: true + emoji-regex@9.2.2: {} - /error-ex@1.3.2: - resolution: {integrity: sha512-7dFHNmqeFSEt2ZBsCriorKnn3Z2pj+fd9kmI6QoWw4//DL+icEBfc0U7qJCisqrTsKTjw4fNFy2pW9OqStD84g==} + error-ex@1.3.2: dependencies: is-arrayish: 0.2.1 - dev: true - /escalade@3.2.0: - resolution: {integrity: sha512-WUj2qlxaQtO4g6Pq5c29GTcWGDyd8itL8zTlipgECz3JesAiiOKotd8JU6otB3PACgG6xkJUyVhboMS+bje/jA==} - engines: {node: '>=6'} - dev: true + escalade@3.2.0: {} - /escape-string-regexp@2.0.0: - resolution: {integrity: sha512-UpzcLCXolUWcNu5HtVMHYdXJjArjsF9C0aNnquZYY4uW/Vu0miy5YoWvbV345HauVvcAUnpRuhMMcqTcGOY2+w==} - engines: {node: '>=8'} - dev: true + escape-string-regexp@2.0.0: {} - /esprima@4.0.1: - resolution: {integrity: sha512-eGuFFw7Upda+g4p+QHvnW0RyTX/SVeJBDM/gCtMARO0cLuT2HcEKnTPvhjV6aGeqrCB/sbNop0Kszm0jsaWU4A==} - engines: {node: '>=4'} - hasBin: true - dev: true + esprima@4.0.1: {} - /execa@5.1.1: - resolution: {integrity: sha512-8uSpZZocAZRBAPIEINJj3Lo9HyGitllczc27Eh5YYojjMFMn8yHMDMaUHE2Jqfq05D/wucwI4JGURyXt1vchyg==} - engines: {node: '>=10'} + execa@5.1.1: dependencies: cross-spawn: 7.0.6 get-stream: 6.0.1 @@ -1535,27 +2569,18 @@ packages: onetime: 5.1.2 signal-exit: 3.0.7 strip-final-newline: 2.0.0 - dev: true - /exit-x@0.2.2: - resolution: {integrity: sha512-+I6B/IkJc1o/2tiURyz/ivu/O0nKNEArIUB5O7zBrlDVJr22SCLH3xTeEry428LvFhRzIA1g8izguxJ/gbNcVQ==} - engines: {node: '>= 0.8.0'} - dev: true + exit-x@0.2.2: {} - /expect@29.7.0: - resolution: {integrity: sha512-2Zks0hf1VLFYI1kbh0I5jP3KHHyCHpkfyHBzsSXRFgl/Bg9mWYfMW8oD+PdMPlEwy5HNsR9JutYy6pMeOh61nw==} - engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} + expect@29.7.0: dependencies: '@jest/expect-utils': 29.7.0 jest-get-type: 29.6.3 jest-matcher-utils: 29.7.0 jest-message-util: 29.7.0 jest-util: 29.7.0 - dev: true - /expect@30.0.0: - resolution: {integrity: sha512-xCdPp6gwiR9q9lsPCHANarIkFTN/IMZso6Kkq03sOm9IIGtzK/UJqml0dkhHibGh8HKOj8BIDIpZ0BZuU7QK6w==} - engines: {node: ^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0} + expect@30.0.0: dependencies: '@jest/expect-utils': 30.0.0 '@jest/get-type': 30.0.0 @@ -1563,122 +2588,63 @@ packages: jest-message-util: 30.0.0 jest-mock: 30.0.0 jest-util: 30.0.0 - dev: true - - /extend@3.0.2: - resolution: {integrity: sha512-fjquC59cD7CyW6urNXK0FBufkZcoiGG80wTuPujX590cB5Ttln20E2UB4S/WARVqhXffZl2LNgS+gQdPIIim/g==} - dev: true - /extsprintf@1.3.0: - resolution: {integrity: sha512-11Ndz7Nv+mvAC1j0ktTa7fAb0vLyGGX+rMHNBYQviQDGU0Hw7lhctJANqbPhu9nV9/izT/IntTgZ7Im/9LJs9g==} - engines: {'0': node >=0.6.0} - dev: true + extend@3.0.2: {} - /fast-csv@5.0.2: - resolution: {integrity: sha512-CnB2zYAzzeh5Ta0UhSf32NexLy2SsEsSMY+fMWPV40k1OgaLEbm9Hf5dms3z/9fASZHBjB6i834079gVeksEqQ==} - engines: {node: '>=10.0.0'} - dependencies: - '@fast-csv/format': 5.0.2 - '@fast-csv/parse': 5.0.2 - dev: false + extsprintf@1.3.0: {} - /fast-deep-equal@3.1.3: - resolution: {integrity: sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==} - dev: true + fast-deep-equal@3.1.3: {} - /fast-json-stable-stringify@2.1.0: - resolution: {integrity: sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw==} - dev: true + fast-json-stable-stringify@2.1.0: {} - /fb-watchman@2.0.2: - resolution: {integrity: sha512-p5161BqbuCaSnB8jIbzQHOlpgsPmK5rJVDfDKO91Axs5NC1uu3HRQm6wt9cd9/+GtQQIO53JdGXXoyDpTAsgYA==} + fb-watchman@2.0.2: dependencies: bser: 2.1.1 - dev: true - /filelist@1.0.4: - resolution: {integrity: sha512-w1cEuf3S+DrLCQL7ET6kz+gmlJdbq9J7yXCSjK/OZCPA+qEN1WyF4ZAf0YYJa4/shHJra2t/d/r8SV4Ji+x+8Q==} + filelist@1.0.4: dependencies: minimatch: 5.1.6 - dev: true - /fill-range@7.1.1: - resolution: {integrity: sha512-YsGpe3WHLK8ZYi4tWDg2Jy3ebRz2rXowDxnld4bkQB00cc/1Zw9AWnC0i9ztDJitivtQvaI9KaLyKrc+hBW0yg==} - engines: {node: '>=8'} + fill-range@7.1.1: dependencies: to-regex-range: 5.0.1 - dev: true - /find-up@4.1.0: - resolution: {integrity: sha512-PpOwAdQ/YlXQ2vj8a3h8IipDuYRi3wceVQQGYWxNINccq40Anw7BlsEXCMbt1Zt+OLA6Fq9suIpIWD0OsnISlw==} - engines: {node: '>=8'} + find-up@4.1.0: dependencies: locate-path: 5.0.0 path-exists: 4.0.0 - dev: true - /foreground-child@3.3.1: - resolution: {integrity: sha512-gIXjKqtFuWEgzFRJA9WCQeSJLZDjgJUOMCMzxtvFq/37KojM1BFGufqsCy0r4qSQmYLsZYMeyRqzIWOMup03sw==} - engines: {node: '>=14'} + foreground-child@3.3.1: dependencies: cross-spawn: 7.0.6 signal-exit: 4.1.0 - dev: true - /forever-agent@0.6.1: - resolution: {integrity: sha512-j0KLYPhm6zeac4lz3oJ3o65qvgQCcPubiyotZrXqEaG4hNagNYO8qdlUrX5vwqv9ohqeT/Z3j6+yW067yWWdUw==} - dev: true + forever-agent@0.6.1: {} - /form-data@2.3.3: - resolution: {integrity: sha512-1lLKB2Mu3aGP1Q/2eCOx0fNbRMe7XdwktwOruhfqqd0rIJWwN4Dh+E3hrPSlDCXnSR7UtZ1N38rVXm+6+MEhJQ==} - engines: {node: '>= 0.12'} + form-data@2.3.3: dependencies: asynckit: 0.4.0 combined-stream: 1.0.8 mime-types: 2.1.35 - dev: true - /fs.realpath@1.0.0: - resolution: {integrity: sha512-OO0pH2lK6a0hZnAdau5ItzHPI6pUlvI7jMVnxUQRtw4owF2wk8lOSabtGDCTP4Ggrg2MbGnWO9X8K1t4+fGMDw==} - dev: true + fs.realpath@1.0.0: {} - /fsevents@2.3.3: - resolution: {integrity: sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==} - engines: {node: ^8.16.0 || ^10.6.0 || >=11.0.0} - os: [darwin] - requiresBuild: true - dev: true + fsevents@2.3.3: optional: true - /gensync@1.0.0-beta.2: - resolution: {integrity: sha512-3hN7NaskYvMDLQY55gnW3NQ+mesEAepTqlg+VEbj7zzqEMBVNhzcGYYeqFo/TlYz6eQiFcp1HcsCZO+nGgS8zg==} - engines: {node: '>=6.9.0'} - dev: true + gensync@1.0.0-beta.2: {} - /get-caller-file@2.0.5: - resolution: {integrity: sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg==} - engines: {node: 6.* || 8.* || >= 10.*} - dev: true + get-caller-file@2.0.5: {} - /get-package-type@0.1.0: - resolution: {integrity: sha512-pjzuKtY64GYfWizNAJ0fr9VqttZkNiK2iS430LtIHzjBEr6bX8Am2zm4sW4Ro5wjWW5cAlRL1qAMTcXbjNAO2Q==} - engines: {node: '>=8.0.0'} - dev: true + get-package-type@0.1.0: {} - /get-stream@6.0.1: - resolution: {integrity: sha512-ts6Wi+2j3jQjqi70w5AlN8DFnkSwC+MqmxEzdEALB2qXZYV3X/b1CTfgPLGJNMeAWxdPfU8FO1ms3NUfaHCPYg==} - engines: {node: '>=10'} - dev: true + get-stream@6.0.1: {} - /getpass@0.1.7: - resolution: {integrity: sha512-0fzj9JxOLfJ+XGLhR8ze3unN0KZCgZwiSSDz168VERjK8Wl8kVSdcu2kspd4s4wtAa1y/qrVRiAA0WclVsu0ng==} + getpass@0.1.7: dependencies: assert-plus: 1.0.0 - dev: true - /glob@10.4.5: - resolution: {integrity: sha512-7Bv8RF0k6xjo7d4A/PxYLbUCfb6c+Vpd2/mB2yRDlew7Jb5hEXiCD9ibfO7wpk8i4sevK6DFny9h7EYbM3/sHg==} - hasBin: true + glob@10.4.5: dependencies: foreground-child: 3.3.1 jackspeak: 3.4.3 @@ -1686,12 +2652,8 @@ packages: minipass: 7.1.2 package-json-from-dist: 1.0.1 path-scurry: 1.11.1 - dev: true - /glob@11.0.3: - resolution: {integrity: sha512-2Nim7dha1KVkaiF4q6Dj+ngPPMdfvLJEOpZk/jKiUAkqKebpGAWQXAq9z1xu9HKu5lWfqw/FASuccEjyznjPaA==} - engines: {node: 20 || >=22} - hasBin: true + glob@11.0.3: dependencies: foreground-child: 3.3.1 jackspeak: 4.1.1 @@ -1699,11 +2661,8 @@ packages: minipass: 7.1.2 package-json-from-dist: 1.0.1 path-scurry: 2.0.0 - dev: true - /glob@7.2.3: - resolution: {integrity: sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q==} - deprecated: Glob versions prior to v9 are no longer supported + glob@7.2.3: dependencies: fs.realpath: 1.0.0 inflight: 1.0.6 @@ -1711,124 +2670,63 @@ packages: minimatch: 3.1.2 once: 1.4.0 path-is-absolute: 1.0.1 - dev: true - /globals@11.12.0: - resolution: {integrity: sha512-WOBp/EEGUiIsJSp7wcv/y6MO+lV9UoncWqxuFfm8eBwzWNgyfBd6Gz+IeKQ9jCmyhoH99g15M3T+QaVHFjizVA==} - engines: {node: '>=4'} - dev: true + globals@11.12.0: {} - /graceful-fs@4.2.11: - resolution: {integrity: sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ==} - dev: true + graceful-fs@4.2.11: {} - /har-schema@2.0.0: - resolution: {integrity: sha512-Oqluz6zhGX8cyRaTQlFMPw80bSJVG2x/cFb8ZPhUILGgHka9SsokCCOQgpveePerqidZOrT14ipqfJb7ILcW5Q==} - engines: {node: '>=4'} - dev: true + har-schema@2.0.0: {} - /har-validator@5.1.5: - resolution: {integrity: sha512-nmT2T0lljbxdQZfspsno9hgrG3Uir6Ks5afism62poxqBM6sDnMEuPmzTq8XN0OEwqKLLdh1jQI3qyE66Nzb3w==} - engines: {node: '>=6'} - deprecated: this library is no longer supported + har-validator@5.1.5: dependencies: ajv: 6.12.6 har-schema: 2.0.0 - dev: true - /has-flag@4.0.0: - resolution: {integrity: sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==} - engines: {node: '>=8'} - dev: true + has-flag@4.0.0: {} - /html-escaper@2.0.2: - resolution: {integrity: sha512-H2iMtd0I4Mt5eYiapRdIDjp+XzelXQ0tFE4JS7YFwFevXXMmOp9myNrUvCg0D6ws8iqkRPBfKHgbwig1SmlLfg==} - dev: true + html-escaper@2.0.2: {} - /http-signature@1.2.0: - resolution: {integrity: sha512-CAbnr6Rz4CYQkLYUtSNXxQPUH2gK8f3iWexVlsnMeD+GjlsQ0Xsy1cOX+mN3dtxYomRy21CiOzU8Uhw6OwncEQ==} - engines: {node: '>=0.8', npm: '>=1.3.7'} + http-signature@1.2.0: dependencies: assert-plus: 1.0.0 jsprim: 1.4.2 sshpk: 1.18.0 - dev: true - /human-signals@2.1.0: - resolution: {integrity: sha512-B4FFZ6q/T2jhhksgkbEW3HBvWIfDW85snkQgawt07S7J5QXTk6BkNV+0yAeZrM5QpMAdYlocGoljn0sJ/WQkFw==} - engines: {node: '>=10.17.0'} - dev: true + human-signals@2.1.0: {} - /import-local@3.2.0: - resolution: {integrity: sha512-2SPlun1JUPWoM6t3F0dw0FkCF/jWY8kttcY4f599GLTSjh2OCuuhdTkJQsEcZzBqbXZGKMK2OqW1oZsjtf/gQA==} - engines: {node: '>=8'} - hasBin: true + import-local@3.2.0: dependencies: pkg-dir: 4.2.0 resolve-cwd: 3.0.0 - dev: true - /imurmurhash@0.1.4: - resolution: {integrity: sha512-JmXMZ6wuvDmLiHEml9ykzqO6lwFbof0GG4IkcGaENdCRDDmMVnny7s5HsIgHCbaq0w2MyPhDqkhTUgS2LU2PHA==} - engines: {node: '>=0.8.19'} - dev: true + imurmurhash@0.1.4: {} - /inflight@1.0.6: - resolution: {integrity: sha512-k92I/b08q4wvFscXCLvqfsHCrjrF7yiXsQuIVvVE7N82W3+aqpzuUdBbfhWcy/FZR3/4IgflMgKLOsvPDrGCJA==} - deprecated: This module is not supported, and leaks memory. Do not use it. Check out lru-cache if you want a good and tested way to coalesce async requests by a key value, which is much more comprehensive and powerful. + inflight@1.0.6: dependencies: once: 1.4.0 wrappy: 1.0.2 - dev: true - /inherits@2.0.4: - resolution: {integrity: sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==} - dev: true + inherits@2.0.4: {} - /is-arrayish@0.2.1: - resolution: {integrity: sha512-zz06S8t0ozoDXMG+ube26zeCTNXcKIPJZJi8hBrF4idCLms4CG9QtK7qBl1boi5ODzFpjswb5JPmHCbMpjaYzg==} - dev: true + is-arrayish@0.2.1: {} - /is-fullwidth-code-point@3.0.0: - resolution: {integrity: sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==} - engines: {node: '>=8'} - dev: true + is-fullwidth-code-point@3.0.0: {} - /is-generator-fn@2.1.0: - resolution: {integrity: sha512-cTIB4yPYL/Grw0EaSzASzg6bBy9gqCofvWN8okThAYIxKJZC+udlRAmGbM0XLeniEJSs8uEgHPGuHSe1XsOLSQ==} - engines: {node: '>=6'} - dev: true + is-generator-fn@2.1.0: {} - /is-number@7.0.0: - resolution: {integrity: sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==} - engines: {node: '>=0.12.0'} - dev: true + is-number@7.0.0: {} - /is-stream@2.0.1: - resolution: {integrity: sha512-hFoiJiTl63nn+kstHGBtewWSKnQLpyb155KHheA1l39uvtO9nWIop1p3udqPcUd/xbF1VLMO4n7OI6p7RbngDg==} - engines: {node: '>=8'} - dev: true + is-stream@2.0.1: {} - /is-typedarray@1.0.0: - resolution: {integrity: sha512-cyA56iCMHAh5CdzjJIa4aohJyeO1YbwLi3Jc35MmRU6poroFjIGZzUzupGiRPOjgHg9TLu43xbpwXk523fMxKA==} - dev: true + is-typedarray@1.0.0: {} - /isexe@2.0.0: - resolution: {integrity: sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==} - dev: true + isexe@2.0.0: {} - /isstream@0.1.2: - resolution: {integrity: sha512-Yljz7ffyPbrLpLngrMtZ7NduUgVvi6wG9RJ9IUcyCd59YQ911PBJphODUcbOVbqYfxe1wuYf/LJ8PauMRwsM/g==} - dev: true + isstream@0.1.2: {} - /istanbul-lib-coverage@3.2.2: - resolution: {integrity: sha512-O8dpsF+r0WV/8MNRKfnmrtCWhuKjxrq2w+jpzBL5UZKTi2LeVWnWOmWRxFlesJONmc+wLAGvKQZEOanko0LFTg==} - engines: {node: '>=8'} - dev: true + istanbul-lib-coverage@3.2.2: {} - /istanbul-lib-instrument@6.0.3: - resolution: {integrity: sha512-Vtgk7L/R2JHyyGW07spoFlB8/lpjiOLTjMdms6AFMraYt3BaJauod/NGrfnVG/y4Ix1JEuMRPDPEj2ua+zz1/Q==} - engines: {node: '>=10'} + istanbul-lib-instrument@6.0.3: dependencies: '@babel/core': 7.27.4 '@babel/parser': 7.27.5 @@ -1837,74 +2735,50 @@ packages: semver: 7.7.2 transitivePeerDependencies: - supports-color - dev: true - /istanbul-lib-report@3.0.1: - resolution: {integrity: sha512-GCfE1mtsHGOELCU8e/Z7YWzpmybrx/+dSTfLrvY8qRmaY6zXTKWn6WQIjaAFw069icm6GVMNkgu0NzI4iPZUNw==} - engines: {node: '>=10'} + istanbul-lib-report@3.0.1: dependencies: istanbul-lib-coverage: 3.2.2 make-dir: 4.0.0 supports-color: 7.2.0 - dev: true - /istanbul-lib-source-maps@5.0.6: - resolution: {integrity: sha512-yg2d+Em4KizZC5niWhQaIomgf5WlL4vOOjZ5xGCmF8SnPE/mDWWXgvRExdcpCgh9lLRRa1/fSYp2ymmbJ1pI+A==} - engines: {node: '>=10'} + istanbul-lib-source-maps@5.0.6: dependencies: '@jridgewell/trace-mapping': 0.3.25 debug: 4.4.1 istanbul-lib-coverage: 3.2.2 transitivePeerDependencies: - supports-color - dev: true - /istanbul-reports@3.1.7: - resolution: {integrity: sha512-BewmUXImeuRk2YY0PVbxgKAysvhRPUQE0h5QRM++nVWyubKGV0l8qQ5op8+B2DOmwSe63Jivj0BjkPQVf8fP5g==} - engines: {node: '>=8'} + istanbul-reports@3.1.7: dependencies: html-escaper: 2.0.2 istanbul-lib-report: 3.0.1 - dev: true - /jackspeak@3.4.3: - resolution: {integrity: sha512-OGlZQpz2yfahA/Rd1Y8Cd9SIEsqvXkLVoSw/cgwhnhFMDbsQFeZYoJJ7bIZBS9BcamUW96asq/npPWugM+RQBw==} + jackspeak@3.4.3: dependencies: '@isaacs/cliui': 8.0.2 optionalDependencies: '@pkgjs/parseargs': 0.11.0 - dev: true - /jackspeak@4.1.1: - resolution: {integrity: sha512-zptv57P3GpL+O0I7VdMJNBZCu+BPHVQUk55Ft8/QCJjTVxrnJHuVuX/0Bl2A6/+2oyR/ZMEuFKwmzqqZ/U5nPQ==} - engines: {node: 20 || >=22} + jackspeak@4.1.1: dependencies: '@isaacs/cliui': 8.0.2 - dev: true - /jake@10.9.2: - resolution: {integrity: sha512-2P4SQ0HrLQ+fw6llpLnOaGAvN2Zu6778SJMrCUwns4fOoG9ayrTiZk3VV8sCPkVZF8ab0zksVpS8FDY5pRCNBA==} - engines: {node: '>=10'} - hasBin: true + jake@10.9.2: dependencies: async: 3.2.6 chalk: 4.1.2 filelist: 1.0.4 minimatch: 3.1.2 - dev: true - /jest-changed-files@30.0.0: - resolution: {integrity: sha512-rzGpvCdPdEV1Ma83c1GbZif0L2KAm3vXSXGRlpx7yCt0vhruwCNouKNRh3SiVcISHP1mb3iJzjb7tAEnNu1laQ==} - engines: {node: ^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0} + jest-changed-files@30.0.0: dependencies: execa: 5.1.1 jest-util: 30.0.0 p-limit: 3.1.0 - dev: true - /jest-circus@30.0.0: - resolution: {integrity: sha512-nTwah78qcKVyndBS650hAkaEmwWGaVsMMoWdJwMnH77XArRJow2Ir7hc+8p/mATtxVZuM9OTkA/3hQocRIK5Dw==} - engines: {node: ^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0} + jest-circus@30.0.0: dependencies: '@jest/environment': 30.0.0 '@jest/expect': 30.0.0 @@ -1929,25 +2803,16 @@ packages: transitivePeerDependencies: - babel-plugin-macros - supports-color - dev: true - /jest-cli@30.0.0(@types/node@24.0.1)(ts-node@10.9.2): - resolution: {integrity: sha512-fWKAgrhlwVVCfeizsmIrPRTBYTzO82WSba3gJniZNR3PKXADgdC0mmCSK+M+t7N8RCXOVfY6kvCkvjUNtzmHYQ==} - engines: {node: ^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0} - hasBin: true - peerDependencies: - node-notifier: ^8.0.1 || ^9.0.0 || ^10.0.0 - peerDependenciesMeta: - node-notifier: - optional: true + jest-cli@30.0.0(@types/node@24.0.1)(ts-node@10.9.2(@types/node@24.0.1)(typescript@5.8.3)): dependencies: - '@jest/core': 30.0.0(ts-node@10.9.2) + '@jest/core': 30.0.0(ts-node@10.9.2(@types/node@24.0.1)(typescript@5.8.3)) '@jest/test-result': 30.0.0 '@jest/types': 30.0.0 chalk: 4.1.2 exit-x: 0.2.2 import-local: 3.2.0 - jest-config: 30.0.0(@types/node@24.0.1)(ts-node@10.9.2) + jest-config: 30.0.0(@types/node@24.0.1)(ts-node@10.9.2(@types/node@24.0.1)(typescript@5.8.3)) jest-util: 30.0.0 jest-validate: 30.0.0 yargs: 17.7.2 @@ -1957,29 +2822,14 @@ packages: - esbuild-register - supports-color - ts-node - dev: true - /jest-config@30.0.0(@types/node@24.0.1)(ts-node@10.9.2): - resolution: {integrity: sha512-p13a/zun+sbOMrBnTEUdq/5N7bZMOGd1yMfqtAJniPNuzURMay4I+vxZLK1XSDbjvIhmeVdG8h8RznqYyjctyg==} - engines: {node: ^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0} - peerDependencies: - '@types/node': '*' - esbuild-register: '>=3.4.0' - ts-node: '>=9.0.0' - peerDependenciesMeta: - '@types/node': - optional: true - esbuild-register: - optional: true - ts-node: - optional: true + jest-config@30.0.0(@types/node@24.0.1)(ts-node@10.9.2(@types/node@24.0.1)(typescript@5.8.3)): dependencies: '@babel/core': 7.27.4 '@jest/get-type': 30.0.0 '@jest/pattern': 30.0.0 '@jest/test-sequencer': 30.0.0 '@jest/types': 30.0.0 - '@types/node': 24.0.1 babel-jest: 30.0.0(@babel/core@7.27.4) chalk: 4.1.2 ci-info: 4.2.0 @@ -1999,53 +2849,40 @@ packages: pretty-format: 30.0.0 slash: 3.0.0 strip-json-comments: 3.1.1 + optionalDependencies: + '@types/node': 24.0.1 ts-node: 10.9.2(@types/node@24.0.1)(typescript@5.8.3) transitivePeerDependencies: - babel-plugin-macros - supports-color - dev: true - /jest-diff@29.7.0: - resolution: {integrity: sha512-LMIgiIrhigmPrs03JHpxUh2yISK3vLFPkAodPeo0+BuF7wA2FoQbkEg1u8gBYBThncu7e1oEDUfIXVuTqLRUjw==} - engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} + jest-diff@29.7.0: dependencies: chalk: 4.1.2 diff-sequences: 29.6.3 jest-get-type: 29.6.3 pretty-format: 29.7.0 - dev: true - /jest-diff@30.0.0: - resolution: {integrity: sha512-TgT1+KipV8JTLXXeFX0qSvIJR/UXiNNojjxb/awh3vYlBZyChU/NEmyKmq+wijKjWEztyrGJFL790nqMqNjTHA==} - engines: {node: ^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0} + jest-diff@30.0.0: dependencies: '@jest/diff-sequences': 30.0.0 '@jest/get-type': 30.0.0 chalk: 4.1.2 pretty-format: 30.0.0 - dev: true - /jest-docblock@30.0.0: - resolution: {integrity: sha512-By/iQ0nvTzghEecGzUMCp1axLtBh+8wB4Hpoi5o+x1stycjEmPcH1mHugL4D9Q+YKV++vKeX/3ZTW90QC8ICPg==} - engines: {node: ^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0} + jest-docblock@30.0.0: dependencies: detect-newline: 3.1.0 - dev: true - /jest-each@30.0.0: - resolution: {integrity: sha512-qkFEW3cfytEjG2KtrhwtldZfXYnWSanO8xUMXLe4A6yaiHMHJUalk0Yyv4MQH6aeaxgi4sGVrukvF0lPMM7U1w==} - engines: {node: ^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0} + jest-each@30.0.0: dependencies: '@jest/get-type': 30.0.0 '@jest/types': 30.0.0 chalk: 4.1.2 jest-util: 30.0.0 pretty-format: 30.0.0 - dev: true - /jest-environment-node@30.0.0: - resolution: {integrity: sha512-sF6lxyA25dIURyDk4voYmGU9Uwz2rQKMfjxKnDd19yk+qxKGrimFqS5YsPHWTlAVBo+YhWzXsqZoaMzrTFvqfg==} - engines: {node: ^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0} + jest-environment-node@30.0.0: dependencies: '@jest/environment': 30.0.0 '@jest/fake-timers': 30.0.0 @@ -2054,16 +2891,10 @@ packages: jest-mock: 30.0.0 jest-util: 30.0.0 jest-validate: 30.0.0 - dev: true - /jest-get-type@29.6.3: - resolution: {integrity: sha512-zrteXnqYxfQh7l5FHyL38jL39di8H8rHoecLH3JNxH3BwOrBsNeabdap5e0I23lD4HHI8W5VFBZqG4Eaq5LNcw==} - engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} - dev: true + jest-get-type@29.6.3: {} - /jest-haste-map@30.0.0: - resolution: {integrity: sha512-p4bXAhXTawTsADgQgTpbymdLaTyPW1xWNu1oIGG7/N3LIAbZVkH2JMJqS8/IUcnGR8Kc7WFE+vWbJvsqGCWZXw==} - engines: {node: ^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0} + jest-haste-map@30.0.0: dependencies: '@jest/types': 30.0.0 '@types/node': 24.0.1 @@ -2077,39 +2908,27 @@ packages: walker: 1.0.8 optionalDependencies: fsevents: 2.3.3 - dev: true - /jest-leak-detector@30.0.0: - resolution: {integrity: sha512-E/ly1azdVVbZrS0T6FIpyYHvsdek4FNaThJTtggjV/8IpKxh3p9NLndeUZy2+sjAI3ncS+aM0uLLon/dBg8htA==} - engines: {node: ^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0} + jest-leak-detector@30.0.0: dependencies: '@jest/get-type': 30.0.0 pretty-format: 30.0.0 - dev: true - /jest-matcher-utils@29.7.0: - resolution: {integrity: sha512-sBkD+Xi9DtcChsI3L3u0+N0opgPYnCRPtGcQYrgXmR+hmt/fYfWAL0xRXYU8eWOdfuLgBe0YCW3AFtnRLagq/g==} - engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} + jest-matcher-utils@29.7.0: dependencies: chalk: 4.1.2 jest-diff: 29.7.0 jest-get-type: 29.6.3 pretty-format: 29.7.0 - dev: true - /jest-matcher-utils@30.0.0: - resolution: {integrity: sha512-m5mrunqopkrqwG1mMdJxe1J4uGmS9AHHKYUmoxeQOxBcLjEvirIrIDwuKmUYrecPHVB/PUBpXs2gPoeA2FSSLQ==} - engines: {node: ^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0} + jest-matcher-utils@30.0.0: dependencies: '@jest/get-type': 30.0.0 chalk: 4.1.2 jest-diff: 30.0.0 pretty-format: 30.0.0 - dev: true - /jest-message-util@29.7.0: - resolution: {integrity: sha512-GBEV4GRADeP+qtB2+6u61stea8mGcOT4mCtrYISZwfu9/ISHFJ/5zOMXYbpBE9RsS5+Gb63DW4FgmnKJ79Kf6w==} - engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} + jest-message-util@29.7.0: dependencies: '@babel/code-frame': 7.27.1 '@jest/types': 29.6.3 @@ -2120,11 +2939,8 @@ packages: pretty-format: 29.7.0 slash: 3.0.0 stack-utils: 2.0.6 - dev: true - /jest-message-util@30.0.0: - resolution: {integrity: sha512-pV3qcrb4utEsa/U7UI2VayNzSDQcmCllBZLSoIucrESRu0geKThFZOjjh0kACDJFJRAQwsK7GVsmS6SpEceD8w==} - engines: {node: ^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0} + jest-message-util@30.0.0: dependencies: '@babel/code-frame': 7.27.1 '@jest/types': 30.0.0 @@ -2135,47 +2951,27 @@ packages: pretty-format: 30.0.0 slash: 3.0.0 stack-utils: 2.0.6 - dev: true - /jest-mock@30.0.0: - resolution: {integrity: sha512-W2sRA4ALXILrEetEOh2ooZG6fZ01iwVs0OWMKSSWRcUlaLr4ESHuiKXDNTg+ZVgOq8Ei5445i/Yxrv59VT+XkA==} - engines: {node: ^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0} + jest-mock@30.0.0: dependencies: '@jest/types': 30.0.0 '@types/node': 24.0.1 jest-util: 30.0.0 - dev: true - /jest-pnp-resolver@1.2.3(jest-resolve@30.0.0): - resolution: {integrity: sha512-+3NpwQEnRoIBtx4fyhblQDPgJI0H1IEIkX7ShLUjPGA7TtUTvI1oiKi3SR4oBR0hQhQR80l4WAe5RrXBwWMA8w==} - engines: {node: '>=6'} - peerDependencies: - jest-resolve: '*' - peerDependenciesMeta: - jest-resolve: - optional: true - dependencies: + jest-pnp-resolver@1.2.3(jest-resolve@30.0.0): + optionalDependencies: jest-resolve: 30.0.0 - dev: true - /jest-regex-util@30.0.0: - resolution: {integrity: sha512-rT84010qRu/5OOU7a9TeidC2Tp3Qgt9Sty4pOZ/VSDuEmRupIjKZAb53gU3jr4ooMlhwScrgC9UixJxWzVu9oQ==} - engines: {node: ^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0} - dev: true + jest-regex-util@30.0.0: {} - /jest-resolve-dependencies@30.0.0: - resolution: {integrity: sha512-Yhh7odCAUNXhluK1bCpwIlHrN1wycYaTlZwq1GdfNBEESNNI/z1j1a7dUEWHbmB9LGgv0sanxw3JPmWU8NeebQ==} - engines: {node: ^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0} + jest-resolve-dependencies@30.0.0: dependencies: jest-regex-util: 30.0.0 jest-snapshot: 30.0.0 transitivePeerDependencies: - supports-color - dev: true - /jest-resolve@30.0.0: - resolution: {integrity: sha512-zwWl1P15CcAfuQCEuxszjiKdsValhnWcj/aXg/R3aMHs8HVoCWHC4B/+5+1BirMoOud8NnN85GSP2LEZCbj3OA==} - engines: {node: ^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0} + jest-resolve@30.0.0: dependencies: chalk: 4.1.2 graceful-fs: 4.2.11 @@ -2185,11 +2981,8 @@ packages: jest-validate: 30.0.0 slash: 3.0.0 unrs-resolver: 1.9.0 - dev: true - /jest-runner@30.0.0: - resolution: {integrity: sha512-xbhmvWIc8X1IQ8G7xTv0AQJXKjBVyxoVJEJgy7A4RXsSaO+k/1ZSBbHwjnUhvYqMvwQPomWssDkUx6EoidEhlw==} - engines: {node: ^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0} + jest-runner@30.0.0: dependencies: '@jest/console': 30.0.0 '@jest/environment': 30.0.0 @@ -2215,11 +3008,8 @@ packages: source-map-support: 0.5.13 transitivePeerDependencies: - supports-color - dev: true - /jest-runtime@30.0.0: - resolution: {integrity: sha512-/O07qVgFrFAOGKGigojmdR3jUGz/y3+a/v9S/Yi2MHxsD+v6WcPppglZJw0gNJkRBArRDK8CFAwpM/VuEiiRjA==} - engines: {node: ^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0} + jest-runtime@30.0.0: dependencies: '@jest/environment': 30.0.0 '@jest/fake-timers': 30.0.0 @@ -2245,11 +3035,8 @@ packages: strip-bom: 4.0.0 transitivePeerDependencies: - supports-color - dev: true - /jest-snapshot@30.0.0: - resolution: {integrity: sha512-6oCnzjpvfj/UIOMTqKZ6gedWAUgaycMdV8Y8h2dRJPvc2wSjckN03pzeoonw8y33uVngfx7WMo1ygdRGEKOT7w==} - engines: {node: ^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0} + jest-snapshot@30.0.0: dependencies: '@babel/core': 7.27.4 '@babel/generator': 7.27.5 @@ -2274,11 +3061,8 @@ packages: synckit: 0.11.8 transitivePeerDependencies: - supports-color - dev: true - /jest-util@29.7.0: - resolution: {integrity: sha512-z6EbKajIpqGKU56y5KBUgy1dt1ihhQJgWzUlZHArA/+X2ad7Cb5iF+AK1EWVL/Bo7Rz9uurpqw6SiBCefUbCGA==} - engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} + jest-util@29.7.0: dependencies: '@jest/types': 29.6.3 '@types/node': 24.0.1 @@ -2286,11 +3070,8 @@ packages: ci-info: 3.9.0 graceful-fs: 4.2.11 picomatch: 2.3.1 - dev: true - /jest-util@30.0.0: - resolution: {integrity: sha512-fhNBBM9uSUbd4Lzsf8l/kcAdaHD/4SgoI48en3HXcBEMwKwoleKFMZ6cYEYs21SB779PRuRCyNLmymApAm8tZw==} - engines: {node: ^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0} + jest-util@30.0.0: dependencies: '@jest/types': 30.0.0 '@types/node': 24.0.1 @@ -2298,11 +3079,8 @@ packages: ci-info: 4.2.0 graceful-fs: 4.2.11 picomatch: 4.0.2 - dev: true - /jest-validate@30.0.0: - resolution: {integrity: sha512-d6OkzsdlWItHAikUDs1hlLmpOIRhsZoXTCliV2XXalVQ3ZOeb9dy0CQ6AKulJu/XOZqpOEr/FiMH+FeOBVV+nw==} - engines: {node: ^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0} + jest-validate@30.0.0: dependencies: '@jest/get-type': 30.0.0 '@jest/types': 30.0.0 @@ -2310,11 +3088,8 @@ packages: chalk: 4.1.2 leven: 3.1.0 pretty-format: 30.0.0 - dev: true - /jest-watcher@30.0.0: - resolution: {integrity: sha512-fbAkojcyS53bOL/B7XYhahORq9cIaPwOgd/p9qW/hybbC8l6CzxfWJJxjlPBAIVN8dRipLR0zdhpGQdam+YBtw==} - engines: {node: ^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0} + jest-watcher@30.0.0: dependencies: '@jest/test-result': 30.0.0 '@jest/types': 30.0.0 @@ -2324,456 +3099,229 @@ packages: emittery: 0.13.1 jest-util: 30.0.0 string-length: 4.0.2 - dev: true - /jest-worker@30.0.0: - resolution: {integrity: sha512-VZvxfWIybIvwK8N/Bsfe43LfQgd/rD0c4h5nLUx78CAqPxIQcW2qDjsVAC53iUR8yxzFIeCFFvWOh8en8hGzdg==} - engines: {node: ^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0} + jest-worker@30.0.0: dependencies: '@types/node': 24.0.1 '@ungap/structured-clone': 1.3.0 jest-util: 30.0.0 merge-stream: 2.0.0 supports-color: 8.1.1 - dev: true - /jest@30.0.0(@types/node@24.0.1)(ts-node@10.9.2): - resolution: {integrity: sha512-/3G2iFwsUY95vkflmlDn/IdLyLWqpQXcftptooaPH4qkyU52V7qVYf1BjmdSPlp1+0fs6BmNtrGaSFwOfV07ew==} - engines: {node: ^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0} - hasBin: true - peerDependencies: - node-notifier: ^8.0.1 || ^9.0.0 || ^10.0.0 - peerDependenciesMeta: - node-notifier: - optional: true + jest@30.0.0(@types/node@24.0.1)(ts-node@10.9.2(@types/node@24.0.1)(typescript@5.8.3)): dependencies: - '@jest/core': 30.0.0(ts-node@10.9.2) + '@jest/core': 30.0.0(ts-node@10.9.2(@types/node@24.0.1)(typescript@5.8.3)) '@jest/types': 30.0.0 import-local: 3.2.0 - jest-cli: 30.0.0(@types/node@24.0.1)(ts-node@10.9.2) + jest-cli: 30.0.0(@types/node@24.0.1)(ts-node@10.9.2(@types/node@24.0.1)(typescript@5.8.3)) transitivePeerDependencies: - '@types/node' - babel-plugin-macros - esbuild-register - supports-color - ts-node - dev: true - /js-tokens@4.0.0: - resolution: {integrity: sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==} - dev: true + js-tokens@4.0.0: {} - /js-yaml@3.14.1: - resolution: {integrity: sha512-okMH7OXXJ7YrN9Ok3/SXrnu4iX9yOk+25nqX4imS2npuvTYDmo/QEZoqwZkYaIDk3jVvBOTOIEgEhaLOynBS9g==} - hasBin: true + js-yaml@3.14.1: dependencies: argparse: 1.0.10 esprima: 4.0.1 - dev: true - - /jsbn@0.1.1: - resolution: {integrity: sha512-UVU9dibq2JcFWxQPA6KCqj5O42VOmAY3zQUfEKxU0KpTGXwNoCjkX1e13eHNvw/xPynt6pU0rZ1htjWTNTSXsg==} - dev: true - - /jsesc@3.1.0: - resolution: {integrity: sha512-/sM3dO2FOzXjKQhJuo0Q173wf2KOo8t4I8vHy6lF9poUp7bKT0/NHE8fPX23PwfhnykfqnC2xRxOnVw5XuGIaA==} - engines: {node: '>=6'} - hasBin: true - dev: true - - /json-parse-even-better-errors@2.3.1: - resolution: {integrity: sha512-xyFwyhro/JEof6Ghe2iz2NcXoj2sloNsWr/XsERDK/oiPCfaNhl5ONfp+jQdAZRQQ0IJWNzH9zIZF7li91kh2w==} - dev: true - - /json-schema-traverse@0.4.1: - resolution: {integrity: sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==} - dev: true - - /json-schema@0.4.0: - resolution: {integrity: sha512-es94M3nTIfsEPisRafak+HDLfHXnKBhV3vU5eqPcS3flIWqcxJWgXHXiey3YrpaNsanY5ei1VoYEbOzijuq9BA==} - dev: true - - /json-stringify-safe@5.0.1: - resolution: {integrity: sha512-ZClg6AaYvamvYEE82d3Iyd3vSSIjQ+odgjaTzRuO3s7toCdFKczob2i0zCh7JE8kWn17yvAWhUVxvqGwUalsRA==} - dev: true - - /json5@2.2.3: - resolution: {integrity: sha512-XmOWe7eyHYH14cLdVPoyg+GOH3rYX++KpzrylJwSW98t3Nk+U8XOl8FWKOgwtzdb8lXGf6zYwDUzeHMWfxasyg==} - engines: {node: '>=6'} - hasBin: true - dev: true - - /jsprim@1.4.2: - resolution: {integrity: sha512-P2bSOMAc/ciLz6DzgjVlGJP9+BrJWu5UDGK70C2iweC5QBIeFf0ZXRvGjEj2uYgrY2MkAAhsSWHDWlFtEroZWw==} - engines: {node: '>=0.6.0'} - dependencies: - assert-plus: 1.0.0 - extsprintf: 1.3.0 - json-schema: 0.4.0 - verror: 1.10.0 - dev: true - - /lcov-parse@1.0.0: - resolution: {integrity: sha512-aprLII/vPzuQvYZnDRU78Fns9I2Ag3gi4Ipga/hxnVMCZC8DnR2nI7XBqrPoywGfxqIx/DgarGvDJZAD3YBTgQ==} - hasBin: true - dev: true - /leven@3.1.0: - resolution: {integrity: sha512-qsda+H8jTaUaN/x5vzW2rzc+8Rw4TAQ/4KjB46IwK5VH+IlVeeeje/EoZRpiXvIqjFgK84QffqPztGI3VBLG1A==} - engines: {node: '>=6'} - dev: true - - /lines-and-columns@1.2.4: - resolution: {integrity: sha512-7ylylesZQ/PV29jhEDl3Ufjo6ZX7gCqJr5F7PKrqc93v7fzSymt1BpwEU8nAUXs8qzzvqhbjhK5QZg6Mt/HkBg==} - dev: true + jsbn@0.1.1: {} - /locate-path@5.0.0: - resolution: {integrity: sha512-t7hw9pI+WvuwNJXwk5zVHpyhIqzg2qTlklJOf0mVxGSbe3Fp2VieZcduNYjaLDoy6p9uGpQEGWG87WpMKlNq8g==} - engines: {node: '>=8'} - dependencies: - p-locate: 4.1.0 - dev: true + jsesc@3.1.0: {} - /lodash.escaperegexp@4.1.2: - resolution: {integrity: sha512-TM9YBvyC84ZxE3rgfefxUWiQKLilstD6k7PTGt6wfbtXF8ixIJLOL3VYyV/z+ZiPLsVxAsKAFVwWlWeb2Y8Yyw==} - dev: false + json-parse-even-better-errors@2.3.1: {} - /lodash.groupby@4.6.0: - resolution: {integrity: sha512-5dcWxm23+VAoz+awKmBaiBvzox8+RqMgFhi7UvX9DHZr2HdxHXM/Wrf8cfKpsW37RNrvtPn6hSwNqurSILbmJw==} - dev: false + json-schema-traverse@0.4.1: {} - /lodash.isboolean@3.0.3: - resolution: {integrity: sha512-Bz5mupy2SVbPHURB98VAcw+aHh4vRV5IPNhILUCsOzRmsTmSQ17jIuqopAentWoehktxGd9e/hbIXq980/1QJg==} - dev: false + json-schema@0.4.0: {} - /lodash.isequal@4.5.0: - resolution: {integrity: sha512-pDo3lu8Jhfjqls6GkMgpahsF9kCyayhgykjyLMNFTKWrpVdAQtYyB4muAMWozBB4ig/dtWAmsMxLEI8wuz+DYQ==} - deprecated: This package is deprecated. Use require('node:util').isDeepStrictEqual instead. - dev: false + json-stringify-safe@5.0.1: {} - /lodash.isfunction@3.0.9: - resolution: {integrity: sha512-AirXNj15uRIMMPihnkInB4i3NHeb4iBtNg9WRWuK2o31S+ePwwNmDPaTL3o7dTJ+VXNZim7rFs4rxN4YU1oUJw==} - dev: false + json5@2.2.3: {} - /lodash.isnil@4.0.0: - resolution: {integrity: sha512-up2Mzq3545mwVnMhTDMdfoG1OurpA/s5t88JmQX809eH3C8491iu2sfKhTfhQtKY78oPNhiaHJUpT/dUDAAtng==} - dev: false + jsprim@1.4.2: + dependencies: + assert-plus: 1.0.0 + extsprintf: 1.3.0 + json-schema: 0.4.0 + verror: 1.10.0 - /lodash.isundefined@3.0.1: - resolution: {integrity: sha512-MXB1is3s899/cD8jheYYE2V9qTHwKvt+npCwpD+1Sxm3Q3cECXCiYHjeHWXNwr6Q0SOBPrYUDxendrO6goVTEA==} - dev: false + lcov-parse@1.0.0: {} - /lodash.memoize@4.1.2: - resolution: {integrity: sha512-t7j+NzmgnQzTAYXcsHYLgimltOV1MXHtlOWf6GjL9Kj8GK5FInw5JotxvbOs+IvV1/Dzo04/fCGfLVs7aXb4Ag==} - dev: true + leven@3.1.0: {} - /lodash.uniq@4.5.0: - resolution: {integrity: sha512-xfBaXQd9ryd9dlSDvnvI0lvxfLJlYAZzXomUYzLKtUeOQvOP5piqAWuGtrhWeqaXK9hhoM/iyJc5AV+XfsX3HQ==} - dev: false + lines-and-columns@1.2.4: {} - /lodash@4.17.21: - resolution: {integrity: sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==} - dev: false + locate-path@5.0.0: + dependencies: + p-locate: 4.1.0 - /log-driver@1.2.7: - resolution: {integrity: sha512-U7KCmLdqsGHBLeWqYlFA0V0Sl6P08EE1ZrmA9cxjUE0WVqT9qnyVDPz1kzpFEP0jdJuFnasWIfSd7fsaNXkpbg==} - engines: {node: '>=0.8.6'} - dev: true + lodash.memoize@4.1.2: {} - /lru-cache@10.4.3: - resolution: {integrity: sha512-JNAzZcXrCt42VGLuYz0zfAzDfAvJWW6AfYlDBQyDV5DClI2m5sAmK+OIO7s59XfsRsWHp02jAJrRadPRGTt6SQ==} - dev: true + lodash@4.17.21: {} - /lru-cache@11.1.0: - resolution: {integrity: sha512-QIXZUBJUx+2zHUdQujWejBkcD9+cs94tLn0+YL8UrCh+D5sCXZ4c7LaEH48pNwRY3MLDgqUFyhlCyjJPf1WP0A==} - engines: {node: 20 || >=22} - dev: true + log-driver@1.2.7: {} - /lru-cache@5.1.1: - resolution: {integrity: sha512-KpNARQA3Iwv+jTA0utUVVbrh+Jlrr1Fv0e56GGzAFOXN7dk/FviaDW8LHmK52DlcH4WP2n6gI8vN1aesBFgo9w==} + lru-cache@10.4.3: {} + + lru-cache@11.1.0: {} + + lru-cache@5.1.1: dependencies: yallist: 3.1.1 - dev: true - /make-dir@4.0.0: - resolution: {integrity: sha512-hXdUTZYIVOt1Ex//jAQi+wTZZpUpwBj/0QsOzqegb3rGMMeJiSEu5xLHnYfBrRV4RH2+OCSOO95Is/7x1WJ4bw==} - engines: {node: '>=10'} + make-dir@4.0.0: dependencies: semver: 7.7.2 - dev: true - /make-error@1.3.6: - resolution: {integrity: sha512-s8UhlNe7vPKomQhC1qFelMokr/Sc3AgNbso3n74mVPA5LTZwkB9NlXf4XPamLxJE8h0gh73rM94xvwRT2CVInw==} + make-error@1.3.6: {} - /makeerror@1.0.12: - resolution: {integrity: sha512-JmqCvUhmt43madlpFzG4BQzG2Z3m6tvQDNKdClZnO3VbIudJYmxsT0FNJMeiB2+JTSlTQTSbU8QdesVmwJcmLg==} + makeerror@1.0.12: dependencies: tmpl: 1.0.5 - dev: true - /merge-stream@2.0.0: - resolution: {integrity: sha512-abv/qOcuPfk3URPfDzmZU1LKmuw8kT+0nIHvKrKgFrwifol/doWcdA4ZqsWQ8ENrFKkd67Mfpo/LovbIUsbt3w==} - dev: true + merge-stream@2.0.0: {} - /micromatch@4.0.8: - resolution: {integrity: sha512-PXwfBhYu0hBCPw8Dn0E+WDYb7af3dSLVWKi3HGv84IdF4TyFoC0ysxFd0Goxw7nSv4T/PzEJQxsYsEiFCKo2BA==} - engines: {node: '>=8.6'} + micromatch@4.0.8: dependencies: braces: 3.0.3 picomatch: 2.3.1 - dev: true - /mime-db@1.52.0: - resolution: {integrity: sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg==} - engines: {node: '>= 0.6'} - dev: true + mime-db@1.52.0: {} - /mime-types@2.1.35: - resolution: {integrity: sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw==} - engines: {node: '>= 0.6'} + mime-types@2.1.35: dependencies: mime-db: 1.52.0 - dev: true - /mimic-fn@2.1.0: - resolution: {integrity: sha512-OqbOk5oEQeAZ8WXWydlu9HJjz9WVdEIvamMCcXmuqUYjTknH/sqsWvhQ3vgwKFRR1HpjvNBKQ37nbJgYzGqGcg==} - engines: {node: '>=6'} - dev: true + mimic-fn@2.1.0: {} - /minimatch@10.0.3: - resolution: {integrity: sha512-IPZ167aShDZZUMdRk66cyQAW3qr0WzbHkPdMYa8bzZhlHhO3jALbKdxcaak7W9FfT2rZNpQuUu4Od7ILEpXSaw==} - engines: {node: 20 || >=22} + minimatch@10.0.3: dependencies: '@isaacs/brace-expansion': 5.0.0 - dev: true - /minimatch@3.1.2: - resolution: {integrity: sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==} + minimatch@3.1.2: dependencies: brace-expansion: 1.1.12 - dev: true - /minimatch@5.1.6: - resolution: {integrity: sha512-lKwV/1brpG6mBUFHtb7NUmtABCb2WZZmm2wNiOA5hAb8VdCS4B3dtMWyvcoViccwAW/COERjXLt0zP1zXUN26g==} - engines: {node: '>=10'} + minimatch@5.1.6: dependencies: brace-expansion: 2.0.2 - dev: true - /minimatch@9.0.5: - resolution: {integrity: sha512-G6T0ZX48xgozx7587koeX9Ys2NYy6Gmv//P89sEte9V9whIapMNF4idKxnW2QtCcLiTWlb/wfCabAtAFWhhBow==} - engines: {node: '>=16 || 14 >=14.17'} + minimatch@9.0.5: dependencies: brace-expansion: 2.0.2 - dev: true - /minimist@1.2.8: - resolution: {integrity: sha512-2yyAR8qBkN3YuheJanUpWC5U3bb5osDywNB8RzDVlDwDHbocAJveqqj1u8+SVD7jkWT4yvsHCpWqqWqAxb0zCA==} - dev: true + minimist@1.2.8: {} - /minipass@7.1.2: - resolution: {integrity: sha512-qOOzS1cBTWYF4BH8fVePDBOO9iptMnGUEZwNc/cMWnTV2nVLZ7VoNWEPHkYczZA0pdoA7dl6e7FL659nX9S2aw==} - engines: {node: '>=16 || 14 >=14.17'} - dev: true + minipass@7.1.2: {} - /ms@2.1.3: - resolution: {integrity: sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==} - dev: true + ms@2.1.3: {} - /napi-postinstall@0.2.4: - resolution: {integrity: sha512-ZEzHJwBhZ8qQSbknHqYcdtQVr8zUgGyM/q6h6qAyhtyVMNrSgDhrC4disf03dYW0e+czXyLnZINnCTEkWy0eJg==} - engines: {node: ^12.20.0 || ^14.18.0 || >=16.0.0} - hasBin: true - dev: true + napi-postinstall@0.2.4: {} - /natural-compare@1.4.0: - resolution: {integrity: sha512-OWND8ei3VtNC9h7V60qff3SVobHr996CTwgxubgyQYEpg290h9J0buyECNNJexkFm5sOajh5G116RYA1c8ZMSw==} - dev: true + natural-compare@1.4.0: {} - /node-int64@0.4.0: - resolution: {integrity: sha512-O5lz91xSOeoXP6DulyHfllpq+Eg00MWitZIbtPfoSEvqIHdl5gfcY6hYzDWnj0qD5tz52PI08u9qUvSVeUBeHw==} - dev: true + node-int64@0.4.0: {} - /node-releases@2.0.19: - resolution: {integrity: sha512-xxOWJsBKtzAq7DY0J+DTzuz58K8e7sJbdgwkbMWQe8UYB6ekmsQ45q0M/tJDsGaZmbC+l7n57UV8Hl5tHxO9uw==} - dev: true + node-releases@2.0.19: {} - /normalize-path@3.0.0: - resolution: {integrity: sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==} - engines: {node: '>=0.10.0'} - dev: true + normalize-path@3.0.0: {} - /npm-run-path@4.0.1: - resolution: {integrity: sha512-S48WzZW777zhNIrn7gxOlISNAqi9ZC/uQFnRdbeIHhZhCA6UqpkOT8T1G7BvfdgP4Er8gF4sUbaS0i7QvIfCWw==} - engines: {node: '>=8'} + npm-run-path@4.0.1: dependencies: path-key: 3.1.1 - dev: true - /oauth-sign@0.9.0: - resolution: {integrity: sha512-fexhUFFPTGV8ybAtSIGbV6gOkSv8UtRbDBnAyLQw4QPKkgNlsH2ByPGtMUqdWkos6YCRmAqViwgZrJc/mRDzZQ==} - dev: true + oauth-sign@0.9.0: {} - /once@1.4.0: - resolution: {integrity: sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w==} + once@1.4.0: dependencies: wrappy: 1.0.2 - dev: true - /onetime@5.1.2: - resolution: {integrity: sha512-kbpaSSGJTWdAY5KPVeMOKXSrPtr8C8C7wodJbcsd51jRnmD+GZu8Y0VoU6Dm5Z4vWr0Ig/1NKuWRKf7j5aaYSg==} - engines: {node: '>=6'} + onetime@5.1.2: dependencies: mimic-fn: 2.1.0 - dev: true - /p-limit@2.3.0: - resolution: {integrity: sha512-//88mFWSJx8lxCzwdAABTJL2MyWB12+eIY7MDL2SqLmAkeKU9qxRvWuSyTjm3FUmpBEMuFfckAIqEaVGUDxb6w==} - engines: {node: '>=6'} + p-limit@2.3.0: dependencies: p-try: 2.2.0 - dev: true - /p-limit@3.1.0: - resolution: {integrity: sha512-TYOanM3wGwNGsZN2cVTYPArw454xnXj5qmWF1bEoAc4+cU/ol7GVh7odevjp1FNHduHc3KZMcFduxU5Xc6uJRQ==} - engines: {node: '>=10'} + p-limit@3.1.0: dependencies: yocto-queue: 0.1.0 - dev: true - /p-locate@4.1.0: - resolution: {integrity: sha512-R79ZZ/0wAxKGu3oYMlz8jy/kbhsNrS7SKZ7PxEHBgJ5+F2mtFW2fK2cOtBh1cHYkQsbzFV7I+EoRKe6Yt0oK7A==} - engines: {node: '>=8'} + p-locate@4.1.0: dependencies: p-limit: 2.3.0 - dev: true - /p-try@2.2.0: - resolution: {integrity: sha512-R4nPAVTAU0B9D35/Gk3uJf/7XYbQcyohSKdvAxIRSNghFl4e71hVoGnBNQz9cWaXxO2I10KTC+3jMdvvoKw6dQ==} - engines: {node: '>=6'} - dev: true + p-try@2.2.0: {} - /package-json-from-dist@1.0.1: - resolution: {integrity: sha512-UEZIS3/by4OC8vL3P2dTXRETpebLI2NiI5vIrjaD/5UtrkFX/tNbwjTSRAGC/+7CAo2pIcBaRgWmcBBHcsaCIw==} - dev: true + package-json-from-dist@1.0.1: {} - /parse-json@5.2.0: - resolution: {integrity: sha512-ayCKvm/phCGxOkYRSCM82iDwct8/EonSEgCSxWxD7ve6jHggsFl4fZVQBPRNgQoKiuV/odhFrGzQXZwbifC8Rg==} - engines: {node: '>=8'} + parse-json@5.2.0: dependencies: '@babel/code-frame': 7.27.1 error-ex: 1.3.2 json-parse-even-better-errors: 2.3.1 lines-and-columns: 1.2.4 - dev: true - /path-exists@4.0.0: - resolution: {integrity: sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w==} - engines: {node: '>=8'} - dev: true + path-exists@4.0.0: {} - /path-is-absolute@1.0.1: - resolution: {integrity: sha512-AVbw3UJ2e9bq64vSaS9Am0fje1Pa8pbGqTTsmXfaIiMpnr5DlDhfJOuLj9Sf95ZPVDAUerDfEk88MPmPe7UCQg==} - engines: {node: '>=0.10.0'} - dev: true + path-is-absolute@1.0.1: {} - /path-key@3.1.1: - resolution: {integrity: sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==} - engines: {node: '>=8'} - dev: true + path-key@3.1.1: {} - /path-scurry@1.11.1: - resolution: {integrity: sha512-Xa4Nw17FS9ApQFJ9umLiJS4orGjm7ZzwUrwamcGQuHSzDyth9boKDaycYdDcZDuqYATXw4HFXgaqWTctW/v1HA==} - engines: {node: '>=16 || 14 >=14.18'} + path-scurry@1.11.1: dependencies: lru-cache: 10.4.3 minipass: 7.1.2 - dev: true - /path-scurry@2.0.0: - resolution: {integrity: sha512-ypGJsmGtdXUOeM5u93TyeIEfEhM6s+ljAhrk5vAvSx8uyY/02OvrZnA0YNGUrPXfpJMgI1ODd3nwz8Npx4O4cg==} - engines: {node: 20 || >=22} + path-scurry@2.0.0: dependencies: lru-cache: 11.1.0 minipass: 7.1.2 - dev: true - /performance-now@2.1.0: - resolution: {integrity: sha512-7EAHlyLHI56VEIdK57uwHdHKIaAGbnXPiw0yWbarQZOKaKpvUIgW0jWRVLiatnM+XXlSwsanIBH/hzGMJulMow==} - dev: true + performance-now@2.1.0: {} - /picocolors@1.1.1: - resolution: {integrity: sha512-xceH2snhtb5M9liqDsmEw56le376mTZkEX/jEb/RxNFyegNul7eNslCXP9FDj/Lcu0X8KEyMceP2ntpaHrDEVA==} - dev: true + picocolors@1.1.1: {} - /picomatch@2.3.1: - resolution: {integrity: sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==} - engines: {node: '>=8.6'} - dev: true + picomatch@2.3.1: {} - /picomatch@4.0.2: - resolution: {integrity: sha512-M7BAV6Rlcy5u+m6oPhAPFgJTzAioX/6B0DxyvDlo9l8+T3nLKbrczg2WLUyzd45L8RqfUMyGPzekbMvX2Ldkwg==} - engines: {node: '>=12'} - dev: true + picomatch@4.0.2: {} - /pirates@4.0.7: - resolution: {integrity: sha512-TfySrs/5nm8fQJDcBDuUng3VOUKsd7S+zqvbOTiGXHfxX4wK31ard+hoNuvkicM/2YFzlpDgABOevKSsB4G/FA==} - engines: {node: '>= 6'} - dev: true + pirates@4.0.7: {} - /pkg-dir@4.2.0: - resolution: {integrity: sha512-HRDzbaKjC+AOWVXxAU/x54COGeIv9eb+6CkDSQoNTt4XyWoIJvuPsXizxu/Fr23EiekbtZwmh1IcIG/l/a10GQ==} - engines: {node: '>=8'} + pkg-dir@4.2.0: dependencies: find-up: 4.1.0 - dev: true - /pretty-format@29.7.0: - resolution: {integrity: sha512-Pdlw/oPxN+aXdmM9R00JVC9WVFoCLTKJvDVLgmJ+qAffBMxsV85l/Lu7sNx4zSzPyoL2euImuEwHhOXdEgNFZQ==} - engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} + pretty-format@29.7.0: dependencies: '@jest/schemas': 29.6.3 ansi-styles: 5.2.0 react-is: 18.3.1 - dev: true - /pretty-format@30.0.0: - resolution: {integrity: sha512-18NAOUr4ZOQiIR+BgI5NhQE7uREdx4ZyV0dyay5izh4yfQ+1T7BSvggxvRGoXocrRyevqW5OhScUjbi9GB8R8Q==} - engines: {node: ^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0} + pretty-format@30.0.0: dependencies: '@jest/schemas': 30.0.0 ansi-styles: 5.2.0 react-is: 18.3.1 - dev: true - /psl@1.15.0: - resolution: {integrity: sha512-JZd3gMVBAVQkSs6HdNZo9Sdo0LNcQeMNP3CozBJb3JYC/QUYZTnKxP+f8oWRX4rHP5EurWxqAHTSwUCjlNKa1w==} + psl@1.15.0: dependencies: punycode: 2.3.1 - dev: true - /punycode@2.3.1: - resolution: {integrity: sha512-vYt7UD1U9Wg6138shLtLOvdAu+8DsC/ilFtEVHcH+wydcSpNE20AfSOduf6MkRFahL5FY7X1oU7nKVZFtfq8Fg==} - engines: {node: '>=6'} - dev: true + punycode@2.3.1: {} - /pure-rand@7.0.1: - resolution: {integrity: sha512-oTUZM/NAZS8p7ANR3SHh30kXB+zK2r2BPcEn/awJIbOvq82WoMN4p62AWWp3Hhw50G0xMsw1mhIBLqHw64EcNQ==} - dev: true + pure-rand@7.0.1: {} - /qs@6.5.3: - resolution: {integrity: sha512-qxXIEh4pCGfHICj1mAJQ2/2XVZkjCDTcEgfoSQxc/fYivUZxTkk7L3bDBJSoNrEzXI17oUO5Dp07ktqE5KzczA==} - engines: {node: '>=0.6'} - dev: true + qs@6.5.3: {} - /react-is@18.3.1: - resolution: {integrity: sha512-/LLMVyas0ljjAtoYiPqYiL8VWXzUUdThrmU5+n20DZv+a+ClRoevUzw5JxU+Ieh5/c87ytoTBV9G1FiKfNJdmg==} - dev: true + react-is@18.3.1: {} - /request@2.88.2: - resolution: {integrity: sha512-MsvtOrfG9ZcrOwAW+Qi+F6HbD0CWXEh9ou77uOb7FM2WPhwT7smM833PzanhJLsgXjN89Ir6V2PczXNnMpwKhw==} - engines: {node: '>= 6'} - deprecated: request has been deprecated, see https://github.com/request/request/issues/3142 + request@2.88.2: dependencies: aws-sign2: 0.7.0 aws4: 1.13.2 @@ -2795,99 +3343,50 @@ packages: tough-cookie: 2.5.0 tunnel-agent: 0.6.0 uuid: 3.4.0 - dev: true - /require-directory@2.1.1: - resolution: {integrity: sha512-fGxEI7+wsG9xrvdjsrlmL22OMTTiHRwAMroiEeMgq8gzoLC/PQr7RsRDSTLUg/bZAZtF+TVIkHc6/4RIKrui+Q==} - engines: {node: '>=0.10.0'} - dev: true + require-directory@2.1.1: {} - /resolve-cwd@3.0.0: - resolution: {integrity: sha512-OrZaX2Mb+rJCpH/6CpSqt9xFVpN++x01XnN2ie9g6P5/3xelLAkXWVADpdz1IHD/KFfEXyE6V0U01OQ3UO2rEg==} - engines: {node: '>=8'} + resolve-cwd@3.0.0: dependencies: resolve-from: 5.0.0 - dev: true - /resolve-from@5.0.0: - resolution: {integrity: sha512-qYg9KP24dD5qka9J47d0aVky0N+b4fTU89LN9iDnjB5waksiC49rvMB0PrUJQGoTmH50XPiqOvAjDfaijGxYZw==} - engines: {node: '>=8'} - dev: true + resolve-from@5.0.0: {} - /rimraf@6.0.1: - resolution: {integrity: sha512-9dkvaxAsk/xNXSJzMgFqqMCuFgt2+KsOFek3TMLfo8NCPfWpBmqwyNn5Y+NX56QUYfCtsyhF3ayiboEoUmJk/A==} - engines: {node: 20 || >=22} - hasBin: true + rimraf@6.0.1: dependencies: glob: 11.0.3 package-json-from-dist: 1.0.1 - dev: true - /safe-buffer@5.2.1: - resolution: {integrity: sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==} - dev: true + safe-buffer@5.2.1: {} - /safer-buffer@2.1.2: - resolution: {integrity: sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==} - dev: true + safer-buffer@2.1.2: {} - /semver@6.3.1: - resolution: {integrity: sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==} - hasBin: true - dev: true + semver@6.3.1: {} - /semver@7.7.2: - resolution: {integrity: sha512-RF0Fw+rO5AMf9MAyaRXI4AV0Ulj5lMHqVxxdSgiVbixSCXoEmmX/jk0CuJw4+3SqroYO9VoUh+HcuJivvtJemA==} - engines: {node: '>=10'} - hasBin: true - dev: true + semver@7.7.2: {} - /shebang-command@2.0.0: - resolution: {integrity: sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==} - engines: {node: '>=8'} + shebang-command@2.0.0: dependencies: shebang-regex: 3.0.0 - dev: true - /shebang-regex@3.0.0: - resolution: {integrity: sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==} - engines: {node: '>=8'} - dev: true + shebang-regex@3.0.0: {} - /signal-exit@3.0.7: - resolution: {integrity: sha512-wnD2ZE+l+SPC/uoS0vXeE9L1+0wuaMqKlfz9AMUo38JsyLSBWSFcHR1Rri62LZc12vLr1gb3jl7iwQhgwpAbGQ==} - dev: true + signal-exit@3.0.7: {} - /signal-exit@4.1.0: - resolution: {integrity: sha512-bzyZ1e88w9O1iNJbKnOlvYTrWPDl46O1bG0D3XInv+9tkPrxrN8jUUTiFlDkkmKWgn1M6CfIA13SuGqOa9Korw==} - engines: {node: '>=14'} - dev: true + signal-exit@4.1.0: {} - /slash@3.0.0: - resolution: {integrity: sha512-g9Q1haeby36OSStwb4ntCGGGaKsaVSjQ68fBxoQcutl5fS1vuY18H3wSt3jFyFtrkx+Kz0V1G85A4MyAdDMi2Q==} - engines: {node: '>=8'} - dev: true + slash@3.0.0: {} - /source-map-support@0.5.13: - resolution: {integrity: sha512-SHSKFHadjVA5oR4PPqhtAVdcBWwRYVd6g6cAXnIbRiIwc2EhPrTuKUBdSLvlEKyIP3GCf89fltvcZiP9MMFA1w==} + source-map-support@0.5.13: dependencies: buffer-from: 1.1.2 source-map: 0.6.1 - dev: true - /source-map@0.6.1: - resolution: {integrity: sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==} - engines: {node: '>=0.10.0'} - dev: true + source-map@0.6.1: {} - /sprintf-js@1.0.3: - resolution: {integrity: sha512-D9cPgkvLlV3t3IzL0D0YLvGA9Ahk4PcvVwUbN0dSGr1aP0Nrt4AEnTUbuGvquEC0mA64Gqt1fzirlRs5ibXx8g==} - dev: true + sprintf-js@1.0.3: {} - /sshpk@1.18.0: - resolution: {integrity: sha512-2p2KJZTSqQ/I3+HX42EpYOa2l3f8Erv8MWKsy2I9uf4wA7yFIkXRffYdsx86y6z4vHtV8u7g+pPlr8/4ouAxsQ==} - engines: {node: '>=0.10.0'} - hasBin: true + sshpk@1.18.0: dependencies: asn1: 0.2.6 assert-plus: 1.0.0 @@ -2898,151 +3397,77 @@ packages: jsbn: 0.1.1 safer-buffer: 2.1.2 tweetnacl: 0.14.5 - dev: true - /stack-utils@2.0.6: - resolution: {integrity: sha512-XlkWvfIm6RmsWtNJx+uqtKLS8eqFbxUg0ZzLXqY0caEy9l7hruX8IpiDnjsLavoBgqCCR71TqWO8MaXYheJ3RQ==} - engines: {node: '>=10'} + stack-utils@2.0.6: dependencies: escape-string-regexp: 2.0.0 - dev: true - /string-length@4.0.2: - resolution: {integrity: sha512-+l6rNN5fYHNhZZy41RXsYptCjA2Igmq4EG7kZAYFQI1E1VTXarr6ZPXBg6eq7Y6eK4FEhY6AJlyuFIb/v/S0VQ==} - engines: {node: '>=10'} + string-length@4.0.2: dependencies: char-regex: 1.0.2 strip-ansi: 6.0.1 - dev: true - /string-width@4.2.3: - resolution: {integrity: sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==} - engines: {node: '>=8'} + string-width@4.2.3: dependencies: emoji-regex: 8.0.0 is-fullwidth-code-point: 3.0.0 strip-ansi: 6.0.1 - dev: true - /string-width@5.1.2: - resolution: {integrity: sha512-HnLOCR3vjcY8beoNLtcjZ5/nxn2afmME6lhrDrebokqMap+XbeW8n9TXpPDOqdGK5qcI3oT0GKTW6wC7EMiVqA==} - engines: {node: '>=12'} + string-width@5.1.2: dependencies: eastasianwidth: 0.2.0 emoji-regex: 9.2.2 strip-ansi: 7.1.0 - dev: true - /strip-ansi@6.0.1: - resolution: {integrity: sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==} - engines: {node: '>=8'} + strip-ansi@6.0.1: dependencies: ansi-regex: 5.0.1 - dev: true - /strip-ansi@7.1.0: - resolution: {integrity: sha512-iq6eVVI64nQQTRYq2KtEg2d2uU7LElhTJwsH4YzIHZshxlgZms/wIc4VoDQTlG/IvVIrBKG06CrZnp0qv7hkcQ==} - engines: {node: '>=12'} + strip-ansi@7.1.0: dependencies: ansi-regex: 6.1.0 - dev: true - /strip-bom@4.0.0: - resolution: {integrity: sha512-3xurFv5tEgii33Zi8Jtp55wEIILR9eh34FAW00PZf+JnSsTmV/ioewSgQl97JHvgjoRGwPShsWm+IdrxB35d0w==} - engines: {node: '>=8'} - dev: true + strip-bom@4.0.0: {} - /strip-final-newline@2.0.0: - resolution: {integrity: sha512-BrpvfNAE3dcvq7ll3xVumzjKjZQ5tI1sEUIKr3Uoks0XUl45St3FlatVqef9prk4jRDzhW6WZg+3bk93y6pLjA==} - engines: {node: '>=6'} - dev: true + strip-final-newline@2.0.0: {} - /strip-json-comments@3.1.1: - resolution: {integrity: sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig==} - engines: {node: '>=8'} - dev: true + strip-json-comments@3.1.1: {} - /supports-color@7.2.0: - resolution: {integrity: sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==} - engines: {node: '>=8'} + supports-color@7.2.0: dependencies: has-flag: 4.0.0 - dev: true - /supports-color@8.1.1: - resolution: {integrity: sha512-MpUEN2OodtUzxvKQl72cUF7RQ5EiHsGvSsVG0ia9c5RbWGL2CI4C7EpPS8UTBIplnlzZiNuV56w+FuNxy3ty2Q==} - engines: {node: '>=10'} + supports-color@8.1.1: dependencies: has-flag: 4.0.0 - dev: true - /synckit@0.11.8: - resolution: {integrity: sha512-+XZ+r1XGIJGeQk3VvXhT6xx/VpbHsRzsTkGgF6E5RX9TTXD0118l87puaEBZ566FhqblC6U0d4XnubznJDm30A==} - engines: {node: ^14.18.0 || >=16.0.0} + synckit@0.11.8: dependencies: '@pkgr/core': 0.2.7 - dev: true - /test-exclude@6.0.0: - resolution: {integrity: sha512-cAGWPIyOHU6zlmg88jwm7VRyXnMN7iV68OGAbYDk/Mh/xC/pzVPlQtY6ngoIH/5/tciuhGfvESU8GrHrcxD56w==} - engines: {node: '>=8'} + test-exclude@6.0.0: dependencies: '@istanbuljs/schema': 0.1.3 glob: 7.2.3 minimatch: 3.1.2 - dev: true - /tmpl@1.0.5: - resolution: {integrity: sha512-3f0uOEAQwIqGuWW2MVzYg8fV/QNnc/IpuJNG837rLuczAaLVHslWHZQj4IGiEl5Hs3kkbhwL9Ab7Hrsmuj+Smw==} - dev: true + tmpl@1.0.5: {} - /to-regex-range@5.0.1: - resolution: {integrity: sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==} - engines: {node: '>=8.0'} + to-regex-range@5.0.1: dependencies: is-number: 7.0.0 - dev: true - /tough-cookie@2.5.0: - resolution: {integrity: sha512-nlLsUzgm1kfLXSXfRZMc1KLAugd4hqJHDTvc2hDIwS3mZAfMEuMbc03SujMF+GEcpaX/qboeycw6iO8JwVv2+g==} - engines: {node: '>=0.8'} + tough-cookie@2.5.0: dependencies: psl: 1.15.0 punycode: 2.3.1 - dev: true - /ts-jest@29.4.0(@babel/core@7.27.4)(jest@30.0.0)(typescript@5.8.3): - resolution: {integrity: sha512-d423TJMnJGu80/eSgfQ5w/R+0zFJvdtTxwtF9KzFFunOpSeD+79lHJQIiAhluJoyGRbvj9NZJsl9WjCUo0ND7Q==} - engines: {node: ^14.15.0 || ^16.10.0 || ^18.0.0 || >=20.0.0} - hasBin: true - peerDependencies: - '@babel/core': '>=7.0.0-beta.0 <8' - '@jest/transform': ^29.0.0 || ^30.0.0 - '@jest/types': ^29.0.0 || ^30.0.0 - babel-jest: ^29.0.0 || ^30.0.0 - esbuild: '*' - jest: ^29.0.0 || ^30.0.0 - jest-util: ^29.0.0 || ^30.0.0 - typescript: '>=4.3 <6' - peerDependenciesMeta: - '@babel/core': - optional: true - '@jest/transform': - optional: true - '@jest/types': - optional: true - babel-jest: - optional: true - esbuild: - optional: true - jest-util: - optional: true + ts-jest@29.4.0(@babel/core@7.27.4)(@jest/transform@30.0.0)(@jest/types@30.0.0)(babel-jest@30.0.0(@babel/core@7.27.4))(jest-util@30.0.0)(jest@30.0.0(@types/node@24.0.1)(ts-node@10.9.2(@types/node@24.0.1)(typescript@5.8.3)))(typescript@5.8.3): dependencies: - '@babel/core': 7.27.4 bs-logger: 0.2.6 ejs: 3.1.10 fast-json-stable-stringify: 2.1.0 - jest: 30.0.0(@types/node@24.0.1)(ts-node@10.9.2) + jest: 30.0.0(@types/node@24.0.1)(ts-node@10.9.2(@types/node@24.0.1)(typescript@5.8.3)) json5: 2.2.3 lodash.memoize: 4.1.2 make-error: 1.3.6 @@ -3050,21 +3475,14 @@ packages: type-fest: 4.41.0 typescript: 5.8.3 yargs-parser: 21.1.1 - dev: true + optionalDependencies: + '@babel/core': 7.27.4 + '@jest/transform': 30.0.0 + '@jest/types': 30.0.0 + babel-jest: 30.0.0(@babel/core@7.27.4) + jest-util: 30.0.0 - /ts-node@10.9.2(@types/node@24.0.1)(typescript@5.8.3): - resolution: {integrity: sha512-f0FFpIdcHgn8zcPSbf1dRevwt047YMnaiJM3u2w2RewrB+fob/zePZcrOyQoLMMO7aBIddLcQIEK5dYjkLnGrQ==} - hasBin: true - peerDependencies: - '@swc/core': '>=1.2.50' - '@swc/wasm': '>=1.2.50' - '@types/node': '*' - typescript: '>=2.7' - peerDependenciesMeta: - '@swc/core': - optional: true - '@swc/wasm': - optional: true + ts-node@10.9.2(@types/node@24.0.1)(typescript@5.8.3): dependencies: '@cspotcode/source-map-support': 0.8.1 '@tsconfig/node10': 1.0.11 @@ -3082,48 +3500,26 @@ packages: v8-compile-cache-lib: 3.0.1 yn: 3.1.1 - /tslib@2.8.1: - resolution: {integrity: sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w==} - requiresBuild: true - dev: true + tslib@2.8.1: optional: true - /tunnel-agent@0.6.0: - resolution: {integrity: sha512-McnNiV1l8RYeY8tBgEpuodCC1mLUdbSN+CYBL7kJsJNInOP8UjDDEwdk6Mw60vdLLrr5NHKZhMAOSrR2NZuQ+w==} + tunnel-agent@0.6.0: dependencies: safe-buffer: 5.2.1 - dev: true - /tweetnacl@0.14.5: - resolution: {integrity: sha512-KXXFFdAbFXY4geFIwoyNK+f5Z1b7swfXABfL7HXCmoIWMKU3dmS26672A4EeQtDzLKy7SXmfBu51JolvEKwtGA==} - dev: true + tweetnacl@0.14.5: {} - /type-detect@4.0.8: - resolution: {integrity: sha512-0fr/mIH1dlO+x7TlcMy+bIDqKPsw/70tVyeHW787goQjhmqaZe10uwLujubK9q9Lg6Fiho1KUKDYz0Z7k7g5/g==} - engines: {node: '>=4'} - dev: true + type-detect@4.0.8: {} - /type-fest@0.21.3: - resolution: {integrity: sha512-t0rzBq87m3fVcduHDUFhKmyyX+9eo6WQjZvf51Ea/M0Q7+T374Jp1aUiyUl0GKxp8M/OETVHSDvmkyPgvX+X2w==} - engines: {node: '>=10'} - dev: true + type-fest@0.21.3: {} - /type-fest@4.41.0: - resolution: {integrity: sha512-TeTSQ6H5YHvpqVwBRcnLDCBnDOHWYu7IvGbHT6N8AOymcr9PJGjc1GTtiWZTYg0NCgYwvnYWEkVChQAr9bjfwA==} - engines: {node: '>=16'} - dev: true + type-fest@4.41.0: {} - /typescript@5.8.3: - resolution: {integrity: sha512-p1diW6TqL9L07nNxvRMM7hMMw4c5XOo/1ibL4aAIGmSAt9slTE1Xgw5KWuof2uTOvCg9BY7ZRi+GaF+7sfgPeQ==} - engines: {node: '>=14.17'} - hasBin: true + typescript@5.8.3: {} - /undici-types@7.8.0: - resolution: {integrity: sha512-9UJ2xGDvQ43tYyVMpuHlsgApydB8ZKfVYTsLDhXkFL/6gfkp+U8xTGdh8pMJv1SpZna0zxG1DwsKZsreLbXBxw==} + undici-types@7.8.0: {} - /unrs-resolver@1.9.0: - resolution: {integrity: sha512-wqaRu4UnzBD2ABTC1kLfBjAqIDZ5YUTr/MLGa7By47JV1bJDSW7jq/ZSLigB7enLe7ubNaJhtnBXgrc/50cEhg==} - requiresBuild: true + unrs-resolver@1.9.0: dependencies: napi-postinstall: 0.2.4 optionalDependencies: @@ -3146,113 +3542,67 @@ packages: '@unrs/resolver-binding-win32-arm64-msvc': 1.9.0 '@unrs/resolver-binding-win32-ia32-msvc': 1.9.0 '@unrs/resolver-binding-win32-x64-msvc': 1.9.0 - dev: true - /update-browserslist-db@1.1.3(browserslist@4.25.0): - resolution: {integrity: sha512-UxhIZQ+QInVdunkDAaiazvvT/+fXL5Osr0JZlJulepYu6Jd7qJtDZjlur0emRlT71EN3ScPoE7gvsuIKKNavKw==} - hasBin: true - peerDependencies: - browserslist: '>= 4.21.0' + update-browserslist-db@1.1.3(browserslist@4.25.0): dependencies: browserslist: 4.25.0 escalade: 3.2.0 picocolors: 1.1.1 - dev: true - /uri-js@4.4.1: - resolution: {integrity: sha512-7rKUyy33Q1yc98pQ1DAmLtwX109F7TIfWlW1Ydo8Wl1ii1SeHieeh0HHfPeL2fMXK6z0s8ecKs9frCuLJvndBg==} + uri-js@4.4.1: dependencies: punycode: 2.3.1 - dev: true - /uuid@3.4.0: - resolution: {integrity: sha512-HjSDRw6gZE5JMggctHBcjVak08+KEVhSIiDzFnT9S9aegmp85S/bReBVTb4QTFaRNptJ9kuYaNhnbNEOkbKb/A==} - deprecated: Please upgrade to version 7 or higher. Older versions may use Math.random() in certain circumstances, which is known to be problematic. See https://v8.dev/blog/math-random for details. - hasBin: true - dev: true + uuid@3.4.0: {} - /v8-compile-cache-lib@3.0.1: - resolution: {integrity: sha512-wa7YjyUGfNZngI/vtK0UHAN+lgDCxBPCylVXGp0zu59Fz5aiGtNXaq3DhIov063MorB+VfufLh3JlF2KdTK3xg==} + v8-compile-cache-lib@3.0.1: {} - /v8-to-istanbul@9.3.0: - resolution: {integrity: sha512-kiGUalWN+rgBJ/1OHZsBtU4rXZOfj/7rKQxULKlIzwzQSvMJUUNgPwJEEh7gU6xEVxC0ahoOBvN2YI8GH6FNgA==} - engines: {node: '>=10.12.0'} + v8-to-istanbul@9.3.0: dependencies: '@jridgewell/trace-mapping': 0.3.25 '@types/istanbul-lib-coverage': 2.0.6 convert-source-map: 2.0.0 - dev: true - /verror@1.10.0: - resolution: {integrity: sha512-ZZKSmDAEFOijERBLkmYfJ+vmk3w+7hOLYDNkRCuRuMJGEmqYNCNLyBBFwWKVMhfwaEF3WOd0Zlw86U/WC/+nYw==} - engines: {'0': node >=0.6.0} + verror@1.10.0: dependencies: assert-plus: 1.0.0 core-util-is: 1.0.2 extsprintf: 1.3.0 - dev: true - /walker@1.0.8: - resolution: {integrity: sha512-ts/8E8l5b7kY0vlWLewOkDXMmPdLcVV4GmOQLyxuSswIJsweeFZtAsMF7k1Nszz+TYBQrlYRmzOnr398y1JemQ==} + walker@1.0.8: dependencies: makeerror: 1.0.12 - dev: true - /which@2.0.2: - resolution: {integrity: sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==} - engines: {node: '>= 8'} - hasBin: true + which@2.0.2: dependencies: isexe: 2.0.0 - dev: true - /wrap-ansi@7.0.0: - resolution: {integrity: sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==} - engines: {node: '>=10'} + wrap-ansi@7.0.0: dependencies: ansi-styles: 4.3.0 string-width: 4.2.3 strip-ansi: 6.0.1 - dev: true - /wrap-ansi@8.1.0: - resolution: {integrity: sha512-si7QWI6zUMq56bESFvagtmzMdGOtoxfR+Sez11Mobfc7tm+VkUckk9bW2UeffTGVUbOksxmSw0AA2gs8g71NCQ==} - engines: {node: '>=12'} + wrap-ansi@8.1.0: dependencies: ansi-styles: 6.2.1 string-width: 5.1.2 strip-ansi: 7.1.0 - dev: true - /wrappy@1.0.2: - resolution: {integrity: sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==} - dev: true + wrappy@1.0.2: {} - /write-file-atomic@5.0.1: - resolution: {integrity: sha512-+QU2zd6OTD8XWIJCbffaiQeH9U73qIqafo1x6V1snCWYGJf6cVE0cDR4D8xRzcEnfI21IFrUPzPGtcPf8AC+Rw==} - engines: {node: ^14.17.0 || ^16.13.0 || >=18.0.0} + write-file-atomic@5.0.1: dependencies: imurmurhash: 0.1.4 signal-exit: 4.1.0 - dev: true - /y18n@5.0.8: - resolution: {integrity: sha512-0pfFzegeDWJHJIAmTLRP2DwHjdF5s7jo9tuztdQxAhINCdvS+3nGINqPd00AphqJR/0LhANUS6/+7SCb98YOfA==} - engines: {node: '>=10'} - dev: true + y18n@5.0.8: {} - /yallist@3.1.1: - resolution: {integrity: sha512-a4UGQaWPH59mOXUYnAG2ewncQS4i4F43Tv3JoAM+s2VDAmS9NsK8GpDMLrCHPksFT7h3K6TOoUNn2pb7RoXx4g==} - dev: true + yallist@3.1.1: {} - /yargs-parser@21.1.1: - resolution: {integrity: sha512-tVpsJW7DdjecAiFpbIB1e3qxIQsE6NoPc5/eTdrbbIC4h0LVsWhnoa3g+m2HclBIujHzsxZ4VJVA+GUuc2/LBw==} - engines: {node: '>=12'} - dev: true + yargs-parser@21.1.1: {} - /yargs@17.7.2: - resolution: {integrity: sha512-7dSzzRQ++CKnNI/krKnYRV7JKKPUXMEh61soaHKg9mrWEhzFWhFnxPxGl+69cD1Ou63C13NUPCnmIcrvqCuM6w==} - engines: {node: '>=12'} + yargs@17.7.2: dependencies: cliui: 8.0.1 escalade: 3.2.0 @@ -3261,13 +3611,7 @@ packages: string-width: 4.2.3 y18n: 5.0.8 yargs-parser: 21.1.1 - dev: true - /yn@3.1.1: - resolution: {integrity: sha512-Ux4ygGWsu2c7isFWe8Yu1YluJmqVhxqK2cLXNQA5AcC3QfbGNpM7fu0Y8b/z16pXLnFxZYvWhd3fhBY9DLmC6Q==} - engines: {node: '>=6'} + yn@3.1.1: {} - /yocto-queue@0.1.0: - resolution: {integrity: sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q==} - engines: {node: '>=10'} - dev: true + yocto-queue@0.1.0: {} diff --git a/src/cli.ts b/src/cli.ts index ca81af5..9dffe3f 100644 --- a/src/cli.ts +++ b/src/cli.ts @@ -3,10 +3,76 @@ import * as path from 'path'; import * as fs from 'fs'; import { program as commanderProgram } from 'commander'; -import * as csv from 'fast-csv'; -import { OHLCV, IOHLCV } from './types'; +import { IOHLCV } from './types'; import { resampleOhlcv } from './lib'; -import { Readable, Writable } from 'stream'; + +export function parseCSV(data: string): IOHLCV[] { + const trimmed = data.trim(); + if (!trimmed) { + throw new Error('Error: CSV must have at least one row'); + } + const lines = trimmed.split('\n'); + let headers: string[]; + let startIndex: number; + const requiredFields = ['time', 'open', 'high', 'low', 'close', 'volume']; + + // If the first line matches the required fields, treat as header + const firstLine = lines[0].trim(); + const firstLineFields = firstLine.split(',').map(h => h.trim()); + if (requiredFields.every((f, i) => firstLineFields[i] === f)) { + headers = firstLineFields; + startIndex = 1; + } else { + headers = requiredFields; + startIndex = 0; + } + + const rows: IOHLCV[] = []; + for (let i = startIndex; i < lines.length; i++) { + if (!lines[i].trim()) continue; // skip empty lines + const values = lines[i].split(',').map(v => v.trim()); + if (values.length !== headers.length) { + // Skip lines that do not have exactly 5 commas (6 columns) + continue; + } + const row: any = {}; + headers.forEach((header, index) => { + row[header] = values[index]; + }); + const missingValues = requiredFields.filter(field => row[field] === undefined || row[field] === ''); + if (missingValues.length > 0) { + // Skip lines with missing required values + continue; + } + // Skip lines with non-numeric values + if (isNaN(Number(row.time)) || isNaN(Number(row.open)) || isNaN(Number(row.high)) || isNaN(Number(row.low)) || isNaN(Number(row.close)) || isNaN(Number(row.volume))) { + continue; + } + rows.push({ + time: Number(row.time), + open: Number(row.open), + high: Number(row.high), + low: Number(row.low), + close: Number(row.close), + volume: Number(row.volume) + }); + } + return rows; +} + +export function detectFormat(data: string): 'csv' | 'json' { + try { + JSON.parse(data); + return 'json'; + } catch { + const firstLine = data.split('\n')[0].trim(); + // If the first line has exactly 5 commas, it's likely CSV (6 columns) + if ((firstLine.match(/,/g) || []).length === 5) { + return 'csv'; + } + throw new Error('Could not detect input format. Please specify --input-format'); + } +} export async function runCli( argv: string[], @@ -31,32 +97,6 @@ export async function runCli( const options = program.opts(); - function detectFormat(data: string): 'csv' | 'json' { - try { - JSON.parse(data); - return 'json'; - } catch { - const firstLine = data.split('\n')[0].trim(); - if (firstLine.includes(',')) { - const headers = firstLine.toLowerCase().split(','); - if ( - headers.includes('time') && - headers.includes('open') && - headers.includes('high') && - headers.includes('low') && - headers.includes('close') && - headers.includes('volume') - ) { - return 'csv'; - } - if (headers.length === 6 && headers.every(h => !isNaN(Number(h)))) { - return 'csv'; - } - } - throw new Error('Could not detect input format. Please specify --input-format'); - } - } - async function readFileData(filePath: string): Promise { try { const inFormat = path.extname(filePath).slice(1).toLowerCase(); @@ -65,57 +105,8 @@ export async function runCli( } const inPath = path.resolve(filePath); if (inFormat === 'csv') { - return await new Promise((resolve, reject) => { - const rows: any[] = []; - let errored = false; - const fileStream = fs.createReadStream(inPath) - .on('error', (err: any) => { - if (errored) return; - errored = true; - const msg = err && err.message && typeof err.message === 'string' && err.message.startsWith('Error:') ? err.message : 'Error: ' + (err && err.message ? err.message : String(err)); - reject(new Error(msg)); - }); - const csvStream = csv.parse({ headers: true }) - .on('data', (row) => { - if (errored) return; - rows.push(row); - }) - .on('end', () => { - if (errored) return; - if (rows.length === 0) { - errored = true; - reject(new Error('Error: No valid CSV data found')); - return; - } - const requiredFields = ['time', 'open', 'high', 'low', 'close', 'volume']; - for (const row of rows) { - const missingFields = requiredFields.filter(field => row[field] === undefined); - if (missingFields.length > 0) { - errored = true; - fileStream.destroy(); - csvStream.destroy(); - reject(new Error('Error: Missing required fields in CSV: ' + missingFields.join(', '))); - return; - } - } - const results = rows.map(row => ({ - time: Number(row.time), - open: Number(row.open), - high: Number(row.high), - low: Number(row.low), - close: Number(row.close), - volume: Number(row.volume) - })); - resolve(results); - }) - .on('error', (err: any) => { - if (errored) return; - errored = true; - const msg = err && err.message && typeof err.message === 'string' && err.message.startsWith('Error:') ? err.message : 'Error: ' + (err && err.message ? err.message : String(err)); - reject(new Error(msg)); - }); - fileStream.pipe(csvStream); - }); + const data = await fs.promises.readFile(inPath, 'utf8'); + return parseCSV(data); } else { const inBuffer = await fs.promises.readFile(inPath); try { @@ -131,85 +122,67 @@ export async function runCli( } } - async function readPipeData(input: NodeJS.ReadableStream): Promise { + async function readPipeData(stdin: NodeJS.ReadableStream): Promise { return new Promise((resolve, reject) => { - const chunks: Buffer[] = []; - input - .on('data', (chunk) => { - chunks.push(Buffer.from(chunk)); - }) - .on('end', () => { - try { - const data = Buffer.concat(chunks).toString(); - const format = options.inputFormat === 'auto' ? detectFormat(data) : options.inputFormat; - if (format === 'json') { - try { - const jsonData = JSON.parse(data); - resolve(jsonData); - } catch (err) { - reject(new Error('Error: ' + (err instanceof Error ? err.message : String(err)))); - } - } else { - const results: IOHLCV[] = []; - const lines = data.trim().split('\n'); - const hasHeaders = lines[0].toLowerCase().includes('time'); - const csvData = hasHeaders ? data : 'time,open,high,low,close,volume\n' + data; - let hadData = false; - csv.parseString(csvData, { headers: true }) - .on('data', (row) => { - hadData = true; - results.push({ - time: Number(row.time), - open: Number(row.open), - high: Number(row.high), - low: Number(row.low), - close: Number(row.close), - volume: Number(row.volume) - }); - }) - .on('end', () => { - if (!hadData) { - reject(new Error('Error: No valid CSV data found')); - } else { - resolve(results); - } - }) - .on('error', (err) => { - reject(new Error('Error: ' + (err instanceof Error ? err.message : String(err)))); - }); - } - } catch (error) { - reject(new Error('Error: ' + (error instanceof Error ? error.message : String(error)))); + let data = ''; + stdin.on('data', (chunk) => { + data += chunk; + }); + stdin.on('end', () => { + try { + const inFormat = data.trim().startsWith('[') ? 'json' : 'csv'; + if (inFormat === 'csv') { + resolve(parseCSV(data)); + } else { + resolve(JSON.parse(data)); } - }) - .on('error', (err) => { - reject(new Error('Error: ' + (err instanceof Error ? err.message : String(err)))); - }); + } catch (err: any) { + const msg = err && err.message && typeof err.message === 'string' && err.message.startsWith('Error:') ? err.message : 'Error: ' + (err && err.message ? err.message : String(err)); + reject(new Error(msg)); + } + }); + stdin.on('error', (err: any) => { + const msg = err && err.message && typeof err.message === 'string' && err.message.startsWith('Error:') ? err.message : 'Error: ' + (err && err.message ? err.message : String(err)); + reject(new Error(msg)); + }); }); } - async function writeOutput(data: IOHLCV[], outputPath?: string): Promise { - let outStream: NodeJS.WritableStream; + async function writeOutput(data: IOHLCV[], format: 'csv' | 'json', outputPath?: string, stdoutStream: NodeJS.WritableStream = process.stdout): Promise { if (outputPath) { - outStream = fs.createWriteStream(outputPath); - } else { - outStream = stdout; - } - if (options.format === 'csv') { - return new Promise((resolve, reject) => { - const csvStream = csv.write(data, { headers: true }); - csvStream.pipe(outStream); - csvStream.on('error', reject); + const outStream = fs.createWriteStream(outputPath); + await new Promise((resolve, reject) => { outStream.on('error', reject); outStream.on('finish', resolve); + if (format === 'json') { + outStream.write(JSON.stringify(data, null, 2), () => outStream.end()); + } else { + outStream.write('time,open,high,low,close,volume\n'); + data.forEach((row, idx) => { + const line = `${row.time},${row.open},${row.high},${row.low},${row.close},${row.volume}`; + if (idx < data.length - 1) { + outStream.write(line + '\n'); + } else { + outStream.write(line); + } + }); + outStream.end(); + } }); } else { - return new Promise((resolve, reject) => { - outStream.write(JSON.stringify(data, null, 2), (err) => { - if (err) reject(err); - else resolve(); + if (format === 'json') { + stdoutStream.write(JSON.stringify(data, null, 2)); + } else { + stdoutStream.write('time,open,high,low,close,volume\n'); + data.forEach((row, idx) => { + const line = `${row.time},${row.open},${row.high},${row.low},${row.close},${row.volume}`; + if (idx < data.length - 1) { + stdoutStream.write(line + '\n'); + } else { + stdoutStream.write(line); + } }); - }); + } } } @@ -226,7 +199,7 @@ export async function runCli( throw new Error('New timeframe must be greater than base timeframe'); } const resampledData = resampleOhlcv(data, { baseTimeframe, newTimeframe }) as IOHLCV[]; - await writeOutput(resampledData, options.output); + await writeOutput(resampledData, options.format, options.output, stdout); } catch (error: unknown) { stderr.write((error instanceof Error ? error.message : String(error)) + '\n'); process.exitCode = 1; From 4e068f42fd4a327e7bda5683142fa26ca88198a7 Mon Sep 17 00:00:00 2001 From: Adil Date: Mon, 16 Jun 2025 00:59:27 +0500 Subject: [PATCH 12/13] docs: improve function documentation to focus on behavior --- src/cli.ts | 73 +++++++++++++++++++++++++++++++++++++++++++++++++----- 1 file changed, 67 insertions(+), 6 deletions(-) diff --git a/src/cli.ts b/src/cli.ts index 9dffe3f..763292a 100644 --- a/src/cli.ts +++ b/src/cli.ts @@ -6,7 +6,17 @@ import { program as commanderProgram } from 'commander'; import { IOHLCV } from './types'; import { resampleOhlcv } from './lib'; -export function parseCSV(data: string): IOHLCV[] { +/** + * Parse CSV data containing OHLCV (Open, High, Low, Close, Volume) information + * into a structured array of objects. Each row in the CSV should contain + * timestamp and OHLCV values in the correct order. + * + * @throws Error if the CSV is empty or has invalid format + */ +export function parseCSV( + /** The CSV data string to parse */ + data: string +): IOHLCV[] { const trimmed = data.trim(); if (!trimmed) { throw new Error('Error: CSV must have at least one row'); @@ -60,7 +70,17 @@ export function parseCSV(data: string): IOHLCV[] { return rows; } -export function detectFormat(data: string): 'csv' | 'json' { +/** + * Detect whether the input data contains CSV or JSON formatted OHLCV data. + * The detection is based on the presence of JSON-specific characters and + * structure. + * + * @throws Error if the format cannot be detected + */ +export function detectFormat( + /** The input data string to analyze */ + data: string +): 'csv' | 'json' { try { JSON.parse(data); return 'json'; @@ -74,12 +94,22 @@ export function detectFormat(data: string): 'csv' | 'json' { } } +/** + * Process command-line arguments and execute the OHLCV resampling workflow. + * Coordinates the data flow from input to output, applying the specified + * resampling rules. + */ export async function runCli( + /** Command line arguments array */ argv: string[], + /** Input stream (defaults to process.stdin) */ stdin: NodeJS.ReadableStream = process.stdin, + /** Output stream (defaults to process.stdout) */ stdout: NodeJS.WritableStream = process.stdout, + /** Error stream (defaults to process.stderr) */ stderr: NodeJS.WritableStream = process.stderr, - isTTY: boolean = process.stdin.isTTY // allow override for tests + /** Whether the input is a TTY (defaults to process.stdin.isTTY) */ + isTTY: boolean = process.stdin.isTTY ): Promise { const program = commanderProgram.createCommand(); program @@ -97,7 +127,16 @@ export async function runCli( const options = program.opts(); - async function readFileData(filePath: string): Promise { + /** + * Transform file contents into an array of OHLCV objects. Automatically + * detects and handles both CSV and JSON input formats. + * + * @throws Error if the file cannot be read or parsed + */ + async function readFileData( + /** Path to the input file */ + filePath: string + ): Promise { try { const inFormat = path.extname(filePath).slice(1).toLowerCase(); if (!['csv', 'json'].includes(inFormat)) { @@ -122,7 +161,16 @@ export async function runCli( } } - async function readPipeData(stdin: NodeJS.ReadableStream): Promise { + /** + * Transform stdin data into an array of OHLCV objects. Processes the + * input stream line by line, handling both CSV and JSON formats. + * + * @throws Error if the data cannot be read or parsed + */ + async function readPipeData( + /** The input stream to read from */ + stdin: NodeJS.ReadableStream + ): Promise { return new Promise((resolve, reject) => { let data = ''; stdin.on('data', (chunk) => { @@ -148,7 +196,20 @@ export async function runCli( }); } - async function writeOutput(data: IOHLCV[], format: 'csv' | 'json', outputPath?: string, stdoutStream: NodeJS.WritableStream = process.stdout): Promise { + /** + * Transform OHLCV data into the specified output format. Converts the + * array of objects into either CSV or JSON string representation. + */ + async function writeOutput( + /** Array of OHLCV objects to write */ + data: IOHLCV[], + /** Output format ('csv' or 'json') */ + format: 'csv' | 'json', + /** Optional path to write the output file */ + outputPath?: string, + /** Stream to write to if no outputPath is provided */ + stdoutStream: NodeJS.WritableStream = process.stdout + ): Promise { if (outputPath) { const outStream = fs.createWriteStream(outputPath); await new Promise((resolve, reject) => { From fdbce6fe51bc28ba9ce38a8d5242a5045318d85d Mon Sep 17 00:00:00 2001 From: Adil Date: Mon, 16 Jun 2025 01:03:47 +0500 Subject: [PATCH 13/13] docs: update CLI usage documentation to match current implementation --- README.md | 57 ++++++++++++++++++++++--------------------------------- 1 file changed, 23 insertions(+), 34 deletions(-) diff --git a/README.md b/README.md index 45bedac..89f6fbd 100644 --- a/README.md +++ b/README.md @@ -189,10 +189,24 @@ ohlc-resample -i input.csv # Resample JSON file with custom timeframes ohlc-resample -i input.json -b 60 -n 300 -# Save output to file +# Save output to file with specific format ohlc-resample -i input.csv -o output.json -f json ``` +### Options + +```bash +Options: + -V, --version Show version number + -i, --input Input file path (csv, json) or use pipe + -o, --output Output file path (csv, json) or use pipe + -f, --format Output file format (csv, json) (default: "json") + --input-format Input format when using pipe (csv, json, auto) (default: "auto") + -b, --base-timeframe Base timeframe in seconds (default: "60") + -n, --new-timeframe New timeframe in seconds (default: "300") + -h, --help Display help for command +``` + ### Input Formats The CLI supports both CSV and JSON input formats: @@ -226,55 +240,30 @@ You can pipe data into the CLI from other commands. The format is automatically # Auto-detect format cat data.json | ohlc-resample cat data.csv | ohlc-resample -echo '1609459200000,100,105,95,102,1000' | ohlc-resample # Force specific format cat data.json | ohlc-resample --input-format json cat data.csv | ohlc-resample --input-format csv ``` -The CLI supports three types of pipe input: +The CLI supports two types of pipe input: 1. JSON files/strings with OHLCV objects 2. CSV files/strings with headers (time,open,high,low,close,volume) -3. Raw CSV text without headers (6 comma-separated numbers per line) - -Example of raw CSV text input: -```bash -# Single line -echo '1609459200000,100,105,95,102,1000' | ohlc-resample - -# Multiple lines -echo -e '1609459200000,100,105,95,102,1000\n1609459260000,102,107,101,106,1200' | ohlc-resample -``` - -### Options - -- `-i, --input `: Input file path (CSV or JSON) -- `-o, --output `: Output file path (optional, defaults to stdout) -- `-f, --format `: Output format (csv or json, default: csv) -- `-if, --input-format `: Input format when using pipe (csv, json, or auto, default: auto) -- `-b, --base-timeframe `: Base timeframe in seconds (default: 60) -- `-n, --new-timeframe `: New timeframe in seconds (default: 300) -- `-h, --help`: Display help information -- `-V, --version`: Display version information ### Examples ```bash # Resample 1-minute data to 5-minute candles -ohlc-resample -i data.csv - -# Resample 1-minute data to 15-minute candles -ohlc-resample -i data.csv -b 60 -n 900 +ohlc-resample -i data.csv -b 60 -n 300 -# Convert CSV to JSON -ohlc-resample -i data.csv -o data.json -f json +# Convert CSV to JSON format +ohlc-resample -i data.csv -f json -# Pipe CSV data and save as JSON -cat data.csv | ohlc-resample -o output.json -f json +# Pipe data and save to file +cat data.csv | ohlc-resample -o output.json -# Pipe JSON data with forced format -cat data.json | ohlc-resample --input-format json -o output.csv -f csv +# Resample with custom timeframes and save as CSV +ohlc-resample -i data.json -b 300 -n 3600 -f csv -o output.csv ``` ## Contributors