Initial CLI support

This commit is contained in:
2025-05-27 23:54:20 -04:00
parent 8043c10df2
commit 411e21ca7a
6 changed files with 1035 additions and 362 deletions

1
.gitignore vendored Normal file
View File

@ -0,0 +1 @@
/node_modules

91
ebay_command_line_tool.js Normal file
View File

@ -0,0 +1,91 @@
// ebay_command_line_tool.js
// A Node.js script to scrape eBay search results and output JSON.
// Uses ebay_core.js for parsing and extraction logic.
// Usage: node ebay_command_line_tool.js "EBAY_SEARCH_URL"
const puppeteer = require('puppeteer');
const fs = require('fs');
const path = require('path');
// --- Main Scraping Function ---
async function scrapeEbayFromCommandLine(url) {
if (!url) {
console.error("Error: eBay search URL is required as the first argument.");
console.log("Example Usage: node ebay_command_line_tool.js \"https://www.ebay.com/sch/i.html?_nkw=ssd\"");
process.exit(1);
}
// --- Load Core Script ---
// This assumes ebay_core.js is in the same directory as this script.
const coreScriptPath = path.join(__dirname, 'ebay_core.js');
let ebayCoreScriptContent;
try {
ebayCoreScriptContent = fs.readFileSync(coreScriptPath, 'utf8');
if (!ebayCoreScriptContent) {
throw new Error("ebay_core.js is empty or could not be read properly.");
}
} catch (e) {
console.error(`Error: Could not read ebay_core.js from ${coreScriptPath}`);
console.error("Please ensure 'ebay_core.js' exists in the same directory as this script.");
console.error(e.message);
process.exit(1);
}
console.log(`Attempting to scrape: ${url}`);
let browser; // Declare browser outside try so it can be closed in finally
try {
browser = await puppeteer.launch({
headless: true, // Set to false for debugging to see the browser
args: ['--no-sandbox', '--disable-setuid-sandbox'] // Common args for server environments
});
const page = await browser.newPage();
await page.setUserAgent('Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/98.0.4758.102 Safari/537.36');
// Increase navigation timeout and wait until network is idle
await page.goto(url, { waitUntil: 'networkidle2', timeout: 90000 });
// --- Inject and Execute Core Logic ---
// Inject the core parser script into the page context
// This makes the EbayParser object available in the page's window scope
await page.evaluate(ebayCoreScriptContent);
// Now call the extraction function from the injected script
const extractedResults = await page.evaluate(() => {
// EbayParser should now be available on the window object
if (typeof window.EbayParser === 'undefined' || typeof window.EbayParser.extractDataFromPage !== 'function') {
// This error will be caught by the outer try/catch if thrown
throw new Error("EbayParser or EbayParser.extractDataFromPage function was not properly injected or is missing in ebay_core.js!");
}
return window.EbayParser.extractDataFromPage(); // This calls the function defined in ebay_core.js
});
return extractedResults;
} catch (e) {
console.error("An error occurred during the scraping process:", e.message);
// If running in a visible mode, a screenshot can be helpful.
// if (browser && page) { // Check if page exists
// try {
// await page.screenshot({ path: 'ebay_scraping_error.png' });
// console.log("A screenshot 'ebay_scraping_error.png' has been saved for debugging.");
// } catch(se) { console.error("Could not save screenshot:", se.message); }
// }
return []; // Return empty array on error
} finally {
if (browser) {
await browser.close();
}
}
}
// --- Script Execution ---
// The first actual argument to the script (process.argv[0] is node, process.argv[1] is the script path)
const searchUrl = process.argv[2];
(async () => {
const data = await scrapeEbayFromCommandLine(searchUrl);
if (data && data.length > 0) {
console.log(JSON.stringify(data, null, 2));
} else {
console.log("No data extracted. This could be due to an error, an empty page, or incorrect selectors in ebay_core.js.");
}
})();

190
ebay_core.js Normal file
View File

@ -0,0 +1,190 @@
// ebay_core.js - Shared Parsing & Extraction Logic
(function (root, factory) {
if (typeof module === 'object' && module.exports) {
// Node.js. Does not work with strict CommonJS, but
// works in a Node environment for use with fs.readFileSync + injection.
module.exports = factory();
} else {
// Browser globals (Greasemonkey via @require)
root.EbayParser = factory();
}
}(typeof self !== 'undefined' ? self : this, function () {
'use strict';
const EbayParser = {}; // The object we will export/attach
EbayParser.parseSizeAndQuantity = function(title) {
title = title ? title.toUpperCase() : "";
let totalTB = 0;
let quantity = 1;
let needed_description_check = false;
let individualSizeTB = 0;
const explicitQtyPatterns = [
/\b(?:LOT\s+OF|LOT)\s*\(?\s*(\d+)\s*\)?/i,
/\b(?:LOT\s+OF|LOT)\s*\*\s*(\d+)/i,
/\b(?:PACK\s+OF|PACK|BULK)\s*\(?\s*(\d+)\s*\)?/i,
/\b(\d+)\s*-\s*PACK\b/i,
/\b(\d+)\s*COUNT\b/i
];
for (const pattern of explicitQtyPatterns) {
const qtyMatch = title.match(pattern);
if (qtyMatch && qtyMatch[1]) {
const parsedQty = parseInt(qtyMatch[1], 10);
if (parsedQty > 0 && parsedQty < 500) {
quantity = parsedQty;
break;
}
}
}
const sizeMatches = [];
const sizeRegex = /(\d+(?:\.\d+)?)\s*(TB|GB)(?:\b|(?=\s|-|,|\(|\)|$))/g;
let match;
while ((match = sizeRegex.exec(title)) !== null) {
sizeMatches.push({ value: parseFloat(match[1]), unit: match[2].toUpperCase() });
}
if (sizeMatches.length > 0) {
const uniqueSizesTB = [...new Set(
sizeMatches.map(sm => sm.unit === 'GB' ? sm.value / 1000 : sm.value)
)].sort((a, b) => a - b);
if (uniqueSizesTB.length > 0) {
individualSizeTB = uniqueSizesTB[0];
if (uniqueSizesTB.length > 1) needed_description_check = true;
}
}
if (title.match(/\d+(?:\.\d+)?\s*(?:GB|TB)\s*(?:-|&|OR|TO)\s*\d+(?:\.\d+)?\s*(?:GB|TB)/i)) {
needed_description_check = true;
}
if (quantity > 1 && title.includes("MIXED")) {
needed_description_check = true;
}
if (title.includes("CHECK THE DESCRIPTION") || title.includes("CHECK DESCRIPTION") || title.includes("SEE DESCRIPTION")) {
if (quantity > 1 || sizeMatches.length === 0 || sizeMatches.length > 1) {
needed_description_check = true;
}
}
if (individualSizeTB > 0) {
totalTB = individualSizeTB * quantity;
}
if (quantity > 1 && totalTB === 0) {
needed_description_check = true;
}
if (quantity === 1 && sizeMatches.length === 1 && !needed_description_check) {
needed_description_check = false;
}
return { totalTB: parseFloat(totalTB.toFixed(4)), quantity, needed_description_check };
};
EbayParser.parsePrice = function(priceText) {
priceText = priceText || "";
if (priceText.toLowerCase().includes(' to ')) {
return null;
}
const priceMatch = priceText.match(/\$?([\d,]+\.?\d*)/);
if (priceMatch) {
return parseFloat(priceMatch[1].replace(/,/g, ''));
}
return null;
};
EbayParser.runUnitTests = function() {
// Ensure console exists (for Node vs Browser safety, though Node has it)
const log = typeof console !== 'undefined' ? console.log : function() {};
const error = typeof console !== 'undefined' ? console.error : function() {};
log("Ebay Cost/TB: --- Running Unit Tests ---");
const testCases = [
{ title: "LOT OF (9) MAJOR BRAND 2.5\" 7MM SSD * Kingston, Samsung, SanDisk& PNY*120-250GB", expected: { totalTB: 1.080, quantity: 9, needed_description_check: true } },
{ title: "Lot of 10 Intel 256 GB 2.5\" SATA SSD different Model check the Description", expected: { totalTB: 2.560, quantity: 10, needed_description_check: true } },
{ title: "Lot of*10 Mixed brands 240GB-256GB 2.5\" SATA SSD Drives Working & tested", expected: { totalTB: 2.400, quantity: 10, needed_description_check: true } },
{ title: "Lot of 9 SSD 120&128 GB 2.5\" SATA different brands check the description", expected: { totalTB: 1.080, quantity: 9, needed_description_check: true } },
{ title: "Bulk 5 Lot Samsung 870 EVO 500GB SSD SATA - Used - Tested Passed Smart Test", expected: { totalTB: 2.500, quantity: 5, needed_description_check: false } },
{ title: "Samsung 1.6TB NVME PCIe 3.0 x8 2.75\" SSD MZPLK1T6HCHP PM1725 Series TLC", expected: { totalTB: 1.6, quantity: 1, needed_description_check: false } },
{ title: "Brand New Crucial X6 2TB Portable External SSD (CT2000X6SSD9)", expected: { totalTB: 2.0, quantity: 1, needed_description_check: false } },
{ title: "Western Digital WD_BLACK SN850X 2TB NVMe Internal SSD", expected: { totalTB: 2.0, quantity: 1, needed_description_check: false } },
{ title: "Corsair Force Series MP600 1TB Gen4 PCIe X4 NVMe M.2 SSD Up to 4950 MB/s CSSD...", expected: { totalTB: 1.0, quantity: 1, needed_description_check: false } },
{ title: "Micron 5100 MAX 1.84TB SATA 6Gb/s 2.5\" SSD MTFDDAK1T9TCC-1AR1ZABYY", expected: { totalTB: 1.84, quantity: 1, needed_description_check: false } },
{ title: "Dell 0HGX92 1.6TB 2.5” PCIe NVMe Gen4 SSD Intel D7-P5600 SSDPF2KE016T9T HGX92 ES", expected: { totalTB: 1.6, quantity: 1, needed_description_check: false } },
{ title: "10-PACK 1TB SSD", expected: { totalTB: 10.0, quantity: 10, needed_description_check: false } },
{ title: "LOT OF 2X 1TB SSDs", expected: { totalTB: 2.0, quantity: 2, needed_description_check: false } }
];
let testsPassed = 0;
let testsFailed = 0;
testCases.forEach((test, index) => {
const result = EbayParser.parseSizeAndQuantity(test.title);
const totalTBCheck = Math.abs(result.totalTB - test.expected.totalTB) < 0.0001;
const quantityCheck = result.quantity === test.expected.quantity;
const neededCheck = result.needed_description_check === test.expected.needed_description_check;
if (totalTBCheck && quantityCheck && neededCheck) {
testsPassed++;
} else {
error(`Test ${index + 1}: FAILED - "${test.title}"`);
error(` Expected: totalTB=${test.expected.totalTB.toFixed(4)}, Q=${test.expected.quantity}, Check=${test.expected.needed_description_check}`);
error(` Actual: totalTB=${result.totalTB.toFixed(4)}, Q=${result.quantity}, Check=${result.needed_description_check}`);
testsFailed++;
}
});
log(`--- Unit Test Summary: ${testsPassed} Passed, ${testsFailed} Failed ---`);
return testsFailed === 0;
};
// This function is INTENDED TO RUN IN THE BROWSER via Puppeteer
EbayParser.extractDataFromPage = function() {
const itemSelector = 'li.s-item, li.srp-results__item, div.s-item[role="listitem"]';
const itemElements = document.querySelectorAll(itemSelector);
const items = [];
const today = new Date().toISOString();
itemElements.forEach(item => {
const titleElement = item.querySelector('.s-item__title, .srp-results__title');
const priceElement = item.querySelector('.s-item__price, .srp-results__price');
const linkElement = item.querySelector('.s-item__link, a[href*="/itm/"]');
const title = titleElement ? titleElement.innerText.trim() : null;
const priceText = priceElement ? priceElement.innerText.trim() : null;
const itemUrl = linkElement ? linkElement.href : null;
if (!title || !priceText || !itemUrl) return;
// Use the parser functions (assuming 'EbayParser' is global/available)
const listingPrice = EbayParser.parsePrice(priceText);
const parsedInfo = EbayParser.parseSizeAndQuantity(title);
const totalTB = parsedInfo.totalTB;
const needed_description_check = parsedInfo.needed_description_check;
let costPerTB = null;
if (listingPrice !== null && totalTB > 0) {
costPerTB = listingPrice / totalTB;
}
let itemId = null;
const itemMatch = itemUrl.match(/\/itm\/(\d+)/);
if (itemMatch && itemMatch[1]) {
itemId = itemMatch[1];
}
items.push({
title,
itemId,
dateFound: today,
listingPrice,
totalTB: totalTB > 0 ? parseFloat(totalTB.toFixed(3)) : null,
costPerTB: costPerTB !== null ? parseFloat(costPerTB.toFixed(2)) : null,
needed_description_check,
itemUrl
});
});
return items;
};
return EbayParser; // Return the object
}));

View File

@ -1,169 +1,25 @@
// Ebay Cost/TB Calculator & Sorter V2.6
// For use with Tampermonkey @require directive.
// Original author: Your Name / AI Assistant
// Description: Calculates and displays cost per TB for eBay listings, allows sorting,
// handles ambiguous titles, and includes unit tests for parsing logic.
(function() { (function() {
'use strict'; 'use strict';
// Ensure EbayParser is loaded
if (typeof EbayParser === 'undefined') {
console.error("Ebay Cost/TB: CRITICAL - ebay_core.js was not loaded. @require path might be incorrect.");
return;
}
const DEBUG_MODE = true; // Set to true to run unit tests on load const DEBUG_MODE = true; // Set to true to run unit tests on load
// --- Global Variables --- // --- Global Variables (UI/State specific) ---
let originalOrderMap = new Map(); // Stores { itemId: originalIndex } let originalOrderMap = new Map();
let isSorted = false; let isSorted = false;
let mainListParentElement = null; // Cached parent element let mainListParentElement = null;
let observer = null; // MutationObserver instance let observer = null;
let observerTargetNode = null; // Node the observer is attached to let observerTargetNode = null;
const observerConfig = { childList: true, subtree: true }; // Observer configuration const observerConfig = { childList: true, subtree: true };
let processTimer = null; // Timer for debouncing observer callback let processTimer = null;
// --- Core Parsing Functions --- // --- UI & DOM Functions ---
function parseSizeAndQuantity(title) { function addStyles() { /* ... (Keep existing addStyles function) ... */
title = title.toUpperCase();
let totalTB = 0;
let quantity = 1; // Default to 1
let needed_description_check = false;
let individualSizeTB = 0;
// 1. Parse Quantity - More conservative approach
// Prioritize explicit "LOT OF N", "PACK OF N", "N PACK", "N LOT", "BULK N"
const explicitQtyPatterns = [
/\b(?:LOT\s+OF|LOT)\s*\(?\s*(\d+)\s*\)?/i, // e.g., "LOT OF (9)", "LOT (9)", "LOT 9"
/\b(?:LOT\s+OF|LOT)\s*\*\s*(\d+)/i, // e.g., "Lot of*10"
/\b(?:PACK\s+OF|PACK|BULK)\s*\(?\s*(\d+)\s*\)?/i, // e.g., "PACK OF 5", "5 PACK", "BULK 5"
/\b(\d+)\s*-\s*PACK\b/i, // e.g., "10-PACK"
/\b(\d+)\s*COUNT\b/i // e.g., "10 COUNT"
];
for (const pattern of explicitQtyPatterns) {
const qtyMatch = title.match(pattern);
if (qtyMatch && qtyMatch[1]) {
const parsedQty = parseInt(qtyMatch[1], 10);
// Added a sanity check for quantity (e.g., not excessively large from a model number)
if (parsedQty > 0 && parsedQty < 500) {
quantity = parsedQty;
break; // Found a valid quantity
}
}
}
// 2. Parse Size
const sizeMatches = [];
// Refined regex: TB/GB must be followed by a word boundary or specific terminators (space, hyphen, comma, parens, end of string)
// This prevents matching "GB" in "6GB/S" or "6GBPS"
const sizeRegex = /(\d+(?:\.\d+)?)\s*(TB|GB)(?:\b|(?=\s|-|,|\(|\)|$))/g;
let match;
while ((match = sizeRegex.exec(title)) !== null) {
sizeMatches.push({ value: parseFloat(match[1]), unit: match[2].toUpperCase() });
}
if (sizeMatches.length > 0) {
const uniqueSizesTB = [...new Set(
sizeMatches.map(sm => sm.unit === 'GB' ? sm.value / 1000 : sm.value)
)].sort((a, b) => a - b);
if (uniqueSizesTB.length > 0) {
individualSizeTB = uniqueSizesTB[0]; // Pick the smallest detected size
if (uniqueSizesTB.length > 1) {
needed_description_check = true; // Multiple different sizes mentioned
}
}
}
// 3. Further checks for ambiguity for needed_description_check
if (title.match(/\d+(?:\.\d+)?\s*(?:GB|TB)\s*(?:-|&|OR|TO)\s*\d+(?:\.\d+)?\s*(?:GB|TB)/i)) {
needed_description_check = true; // e.g. "120GB-250GB" or "120GB & 250GB"
}
if (quantity > 1 && title.includes("MIXED")) {
needed_description_check = true;
}
// If "CHECK DESCRIPTION" or similar is present, and there's ambiguity in quantity or size
if (title.includes("CHECK THE DESCRIPTION") || title.includes("CHECK DESCRIPTION") || title.includes("SEE DESCRIPTION")) {
if (quantity > 1 || sizeMatches.length === 0 || sizeMatches.length > 1) {
needed_description_check = true;
}
}
if (individualSizeTB > 0) {
totalTB = individualSizeTB * quantity;
}
// If it's a lot (quantity > 1) and no size could be determined (totalTB is 0), flag for check.
if (quantity > 1 && totalTB === 0) {
needed_description_check = true;
}
// If only one size was found and quantity is 1, ensure check is false unless other flags hit
if (quantity === 1 && sizeMatches.length === 1 && !needed_description_check) {
needed_description_check = false;
}
return { totalTB: parseFloat(totalTB.toFixed(4)), quantity, needed_description_check }; // Return totalTB with more precision
}
function parsePrice(priceText) {
if (priceText.toLowerCase().includes(' to ')) {
return null; // Price range, cannot calculate
}
const priceMatch = priceText.match(/\$?([\d,]+\.?\d*)/);
if (priceMatch) {
return parseFloat(priceMatch[1].replace(/,/g, ''));
}
return null;
}
// --- Unit Testing ---
function runUnitTests() {
console.log("Ebay Cost/TB: --- Running Unit Tests for parseSizeAndQuantity ---");
const testCases = [
{ title: "LOT OF (9) MAJOR BRAND 2.5\" 7MM SSD * Kingston, Samsung, SanDisk& PNY*120-250GB", expected: { totalTB: 9 * 0.120, quantity: 9, needed_description_check: true } },
{ title: "Lot of 10 Intel 256 GB 2.5\" SATA SSD different Model check the Description", expected: { totalTB: 10 * 0.256, quantity: 10, needed_description_check: true } },
{ title: "Lot of*10 Mixed brands 240GB-256GB 2.5\" SATA SSD Drives Working & tested", expected: { totalTB: 10 * 0.240, quantity: 10, needed_description_check: true } },
{ title: "Lot of 9 SSD 120&128 GB 2.5\" SATA different brands check the description", expected: { totalTB: 9 * 0.120, quantity: 9, needed_description_check: true } },
{ title: "Bulk 5 Lot Samsung 870 EVO 500GB SSD SATA - Used - Tested Passed Smart Test", expected: { totalTB: 5 * 0.500, quantity: 5, needed_description_check: false } },
{ title: "Samsung 1.6TB NVME PCIe 3.0 x8 2.75\" SSD MZPLK1T6HCHP PM1725 Series TLC", expected: { totalTB: 1.6, quantity: 1, needed_description_check: false } },
{ title: "Brand New Crucial X6 2TB Portable External SSD (CT2000X6SSD9)", expected: { totalTB: 2.0, quantity: 1, needed_description_check: false } },
{ title: "Western Digital WD_BLACK SN850X 2TB NVMe Internal SSD", expected: { totalTB: 2.0, quantity: 1, needed_description_check: false } },
{ title: "Corsair Force Series MP600 1TB Gen4 PCIe X4 NVMe M.2 SSD Up to 4950 MB/s CSSD...", expected: { totalTB: 1.0, quantity: 1, needed_description_check: false } },
{ title: "Micron 5100 MAX 1.84TB SATA 6Gb/s 2.5\" SSD MTFDDAK1T9TCC-1AR1ZABYY", expected: { totalTB: 1.84, quantity: 1, needed_description_check: false } },
{ title: "Dell 0HGX92 1.6TB 2.5” PCIe NVMe Gen4 SSD Intel D7-P5600 SSDPF2KE016T9T HGX92 ES", expected: { totalTB: 1.6, quantity: 1, needed_description_check: false } },
{ title: "2 X 4TB SSDs Lot", expected: { totalTB: 4.0, quantity: 1, needed_description_check: false } }, // Current simplified Q parsing will result in Q=1, totalTB=4TB. To get Q=2 needs more complex logic.
{ title: "LOT OF 2X 1TB SSDs", expected: { totalTB: 2 * 1.0, quantity: 2, needed_description_check: false } }, // Should be caught by "LOT OF (N)" if "2X" is seen as "2"
{ title: "10-PACK 1TB SSD", expected: { totalTB: 10 * 1.0, quantity: 10, needed_description_check: false } },
{ title: "SSD 5 COUNT 256GB", expected: { totalTB: 5 * 0.256, quantity: 5, needed_description_check: false } },
{ title: "Single 2TB Drive", expected: { totalTB: 2.0, quantity: 1, needed_description_check: false } },
{ title: "Lot of 2 (512GB SSDs)", expected: { totalTB: 2 * 0.512, quantity: 2, needed_description_check: false } },
{ title: "Mixed Lot SSDs 120GB, 240GB, 500GB - Total 3 drives", expected: { totalTB: 0.120, quantity: 1, needed_description_check: true } } // Q parsing for "Total N drives" not implemented, smallest size taken. Q will be 1.
];
let testsPassed = 0;
let testsFailed = 0;
testCases.forEach((test, index) => {
const result = parseSizeAndQuantity(test.title);
// Using a small tolerance for floating point comparison of totalTB
const totalTBCheck = Math.abs(result.totalTB - test.expected.totalTB) < 0.0001;
const quantityCheck = result.quantity === test.expected.quantity;
const neededCheck = result.needed_description_check === test.expected.needed_description_check;
if (totalTBCheck && quantityCheck && neededCheck) {
// console.log(`Test ${index + 1}: PASSED - "${test.title}"`);
testsPassed++;
} else {
console.error(`Test ${index + 1}: FAILED - "${test.title}"`);
console.error(` Expected: totalTB=${test.expected.totalTB.toFixed(4)}, Q=${test.expected.quantity}, Check=${test.expected.needed_description_check}`);
console.error(` Actual: totalTB=${result.totalTB.toFixed(4)}, Q=${result.quantity}, Check=${result.needed_description_check}`);
testsFailed++;
}
});
console.log(`--- Unit Test Summary: ${testsPassed} Passed, ${testsFailed} Failed ---`);
}
// --- DOM Manipulation & Display ---
function addStyles() {
const css = ` const css = `
li.s-item, li.srp-results__item { li.s-item, li.srp-results__item {
position: relative !important; overflow: visible !important; padding-bottom: 5px !important; position: relative !important; overflow: visible !important; padding-bottom: 5px !important;
@ -176,15 +32,11 @@
box-shadow: 1px 1px 3px rgba(0,0,0,0.5); transition: transform 0.2s ease; box-shadow: 1px 1px 3px rgba(0,0,0,0.5); transition: transform 0.2s ease;
} }
.cost-per-tb-info:hover { transform: scale(1.05); } .cost-per-tb-info:hover { transform: scale(1.05); }
.cost-per-tb-info small.check-desc-note { .cost-per-tb-info small.check-desc-note { color: #FFD700; font-weight: bold; }
color: #FFD700; /* Gold */
font-weight: bold;
}
#costPerTbSortControl { #costPerTbSortControl {
display: inline-block; margin-left: 20px; padding: 8px 12px; display: inline-block; margin-left: 20px; padding: 8px 12px;
border: 1px solid #ccc; border-radius: 4px; background-color: #f0f0f0; border: 1px solid #ccc; border-radius: 4px; background-color: #f0f0f0;
vertical-align: middle; color: #333; cursor: pointer; vertical-align: middle; color: #333; cursor: pointer; font-size: 14px;
font-size: 14px;
} }
#costPerTbSortControl:hover { background-color: #e9e9e9; } #costPerTbSortControl:hover { background-color: #e9e9e9; }
#costPerTbSortControl input[type="checkbox"] { margin-right: 8px; vertical-align: middle; } #costPerTbSortControl input[type="checkbox"] { margin-right: 8px; vertical-align: middle; }
@ -192,22 +44,17 @@
`; `;
try { try {
const styleSheet = document.createElement("style"); const styleSheet = document.createElement("style");
styleSheet.type = "text/css"; styleSheet.type = "text/css"; styleSheet.innerText = css;
styleSheet.innerText = css;
document.head.appendChild(styleSheet); document.head.appendChild(styleSheet);
} catch (e) { } catch (e) { console.error("Ebay Cost/TB: Failed to add styles:", e); }
console.error("Ebay Cost/TB: Failed to add styles:", e);
} }
} function getItemSelector() { /* ... (Keep existing getItemSelector function) ... */
function getItemSelector() {
if (document.querySelector('li.s-item')) return 'li.s-item'; if (document.querySelector('li.s-item')) return 'li.s-item';
if (document.querySelector('li.srp-results__item')) return 'li.srp-results__item'; if (document.querySelector('li.srp-results__item')) return 'li.srp-results__item';
if (document.querySelector('div.s-item')) return 'div.s-item'; if (document.querySelector('div.s-item')) return 'div.s-item';
return 'li[class*="s-item"], div[class*="s-item"]'; return 'li[class*="s-item"], div[class*="s-item"]';
} }
function getMainListParent() { /* ... (Keep existing getMainListParent function) ... */
function getMainListParent() {
if (mainListParentElement && document.body.contains(mainListParentElement)) { if (mainListParentElement && document.body.contains(mainListParentElement)) {
return mainListParentElement; return mainListParentElement;
} }
@ -228,13 +75,9 @@
} }
} }
} }
if (!mainListParentElement) {
console.error("Ebay Cost/TB: CRITICAL - Could not find main list parent element.");
}
return mainListParentElement; return mainListParentElement;
} }
function storeOriginalOrder(itemsNodeList) { /* ... (Keep existing storeOriginalOrder function) ... */
function storeOriginalOrder(itemsNodeList) {
if (originalOrderMap.size > 0 && itemsNodeList.length === originalOrderMap.size) { if (originalOrderMap.size > 0 && itemsNodeList.length === originalOrderMap.size) {
return; return;
} }
@ -246,18 +89,12 @@
if (linkWithItemId && linkWithItemId.href) { if (linkWithItemId && linkWithItemId.href) {
const match = linkWithItemId.href.match(/\/itm\/(\d+)/); const match = linkWithItemId.href.match(/\/itm\/(\d+)/);
if (match && match[1]) { if (match && match[1]) {
itemId = "ebayitem_" + match[1]; itemId = "ebayitem_" + match[1]; itemElement.id = itemId;
itemElement.id = itemId;
} }
} }
} }
if (itemId && !originalOrderMap.has(itemId)) { if (itemId && !originalOrderMap.has(itemId)) originalOrderMap.set(itemId, index);
originalOrderMap.set(itemId, index);
} else if (!itemId) {
// console.warn("Ebay Cost/TB: Item found without a usable ID during storeOriginalOrder.", itemElement);
}
}); });
// console.log("Ebay Cost/TB: Stored original order for", originalOrderMap.size, "items.");
} }
function processResults() { function processResults() {
@ -274,8 +111,10 @@
if (titleElement && priceElement) { if (titleElement && priceElement) {
const title = titleElement.innerText; const title = titleElement.innerText;
const priceText = priceElement.innerText; const priceText = priceElement.innerText;
const price = parsePrice(priceText); // --- Use Core Parser ---
const parsedInfo = parseSizeAndQuantity(title); // Returns totalTB with more precision const price = EbayParser.parsePrice(priceText);
const parsedInfo = EbayParser.parseSizeAndQuantity(title);
// -----------------------
const totalTB = parsedInfo.totalTB; const totalTB = parsedInfo.totalTB;
const needed_description_check = parsedInfo.needed_description_check; const needed_description_check = parsedInfo.needed_description_check;
@ -289,16 +128,13 @@
if (imageContainer && imageContainer.parentNode) { if (imageContainer && imageContainer.parentNode) {
imageContainer.parentNode.style.position = 'relative'; imageContainer.parentNode.style.position = 'relative';
imageContainer.parentNode.appendChild(displayElement); imageContainer.parentNode.appendChild(displayElement);
} else { } else { item.appendChild(displayElement); }
item.appendChild(displayElement);
}
} }
if (price !== null && totalTB > 0) { if (price !== null && totalTB > 0) {
const costPerTB = price / totalTB; const costPerTB = price / totalTB;
if (needed_description_check) { if (needed_description_check) {
item.dataset.costPerTb = '9999999'; // Sentinel for sorting item.dataset.costPerTb = '9999999';
// Display totalTB.toFixed(2) for consistency in UI
displayElement.innerHTML = `$${costPerTB.toFixed(2)}*<span> / TB</span><br><small class="check-desc-note">(${totalTB.toFixed(2)} TB, Check Desc.)</small>`; displayElement.innerHTML = `$${costPerTB.toFixed(2)}*<span> / TB</span><br><small class="check-desc-note">(${totalTB.toFixed(2)} TB, Check Desc.)</small>`;
} else { } else {
item.dataset.costPerTb = costPerTB; item.dataset.costPerTb = costPerTB;
@ -307,21 +143,15 @@
} else { } else {
item.dataset.costPerTb = '9999999'; item.dataset.costPerTb = '9999999';
let ambiguousNote = needed_description_check || (parsedInfo.quantity > 1 && totalTB === 0) ? "(Check Desc.)" : "(Details N/A)"; let ambiguousNote = needed_description_check || (parsedInfo.quantity > 1 && totalTB === 0) ? "(Check Desc.)" : "(Details N/A)";
// Display totalTB.toFixed(2) if totalTB > 0 but price is null, else ambiguousNote
let tbDisplay = totalTB > 0 ? `(${totalTB.toFixed(2)} TB, Price N/A)` : ambiguousNote; let tbDisplay = totalTB > 0 ? `(${totalTB.toFixed(2)} TB, Price N/A)` : ambiguousNote;
if (totalTB === 0 && parsedInfo.quantity > 1) tbDisplay = ambiguousNote; // Explicitly show check desc if lot with no size if (totalTB === 0) tbDisplay = ambiguousNote;
else if (totalTB === 0) tbDisplay = "(Size N/A)";
displayElement.innerHTML = `<i>Details unclear</i><br><small class="check-desc-note">${tbDisplay}</small>`; displayElement.innerHTML = `<i>Details unclear</i><br><small class="check-desc-note">${tbDisplay}</small>`;
} }
if(displayElement.querySelector('span')) displayElement.querySelector('span').style.fontSize = '0.8em'; if(displayElement.querySelector('span')) displayElement.querySelector('span').style.fontSize = '0.8em';
if(displayElement.querySelector('small')) displayElement.querySelector('small').style.fontSize = '0.7em'; if(displayElement.querySelector('small')) displayElement.querySelector('small').style.fontSize = '0.7em';
} else { } else { item.dataset.costPerTb = '9999999'; }
item.dataset.costPerTb = '9999999';
}
item.classList.add('cost-per-tb-processed-flag'); item.classList.add('cost-per-tb-processed-flag');
item.dataset.costPerTbProcessed = 'true'; item.dataset.costPerTbProcessed = 'true';
}); });
@ -330,156 +160,52 @@
if (originalOrderMap.size === 0 || Math.abs(originalOrderMap.size - allItems.length) > 5) { if (originalOrderMap.size === 0 || Math.abs(originalOrderMap.size - allItems.length) > 5) {
if (allItems.length > 0) storeOriginalOrder(allItems); if (allItems.length > 0) storeOriginalOrder(allItems);
} }
if (isSorted) sortResults();
if (isSorted) {
sortResults();
}
} }
function sortResults() { function sortResults() { /* ... (Keep existing sortResults function) ... */
const parent = getMainListParent(); const parent = getMainListParent(); if (!parent) return;
if (!parent) return; const itemSelector = getItemSelector(); let itemsArray = Array.from(parent.querySelectorAll(itemSelector));
if (originalOrderMap.size === 0 && itemsArray.length > 0) storeOriginalOrder(itemsArray);
const itemSelector = getItemSelector(); itemsArray.sort((a, b) => parseFloat(a.dataset.costPerTb || '9999999') - parseFloat(b.dataset.costPerTb || '9999999'));
let itemsArray = Array.from(parent.querySelectorAll(itemSelector)); if (observer) observer.disconnect(); itemsArray.forEach(item => parent.appendChild(item));
if (observer && observerTargetNode) observer.observe(observerTargetNode, observerConfig);
if (originalOrderMap.size === 0 && itemsArray.length > 0) {
storeOriginalOrder(itemsArray);
} }
function restoreOriginalOrder() { /* ... (Keep existing restoreOriginalOrder function) ... */
itemsArray.sort((a, b) => { const parent = getMainListParent(); if (!parent) return; if (originalOrderMap.size === 0) return;
const costA = parseFloat(a.dataset.costPerTb || '9999999');
const costB = parseFloat(b.dataset.costPerTb || '9999999');
return costA - costB;
});
if (observer) observer.disconnect();
itemsArray.forEach(item => parent.appendChild(item));
if (observer && observerTargetNode) {
observer.observe(observerTargetNode, observerConfig);
} else if (observer && !observerTargetNode) {
setupObserver();
}
// console.log("Ebay Cost/TB: Sorted by cost per TB.");
}
function restoreOriginalOrder() {
const parent = getMainListParent();
if (!parent) return;
if (originalOrderMap.size === 0) {
const itemSelector = getItemSelector();
const currentItems = parent.querySelectorAll(itemSelector);
if (currentItems.length > 0) storeOriginalOrder(currentItems);
if (originalOrderMap.size === 0) return;
}
let itemsToReorder = []; let itemsToReorder = [];
originalOrderMap.forEach((originalIndex, itemId) => { originalOrderMap.forEach((originalIndex, itemId) => {
const itemElement = document.getElementById(itemId) || parent.querySelector(`[id="${itemId}"]`); const itemElement = document.getElementById(itemId) || parent.querySelector(`[id="${itemId}"]`);
if (itemElement && parent.contains(itemElement)) { if (itemElement && parent.contains(itemElement)) itemsToReorder.push({ element: itemElement, originalIndex: originalIndex });
itemsToReorder.push({ element: itemElement, originalIndex: originalIndex, id: itemId });
}
}); });
const itemSelector = getItemSelector(); const currentItemsInDOM = parent.querySelectorAll(itemSelector); let newItemsCount = 0;
const itemSelector = getItemSelector();
const currentItemsInDOM = parent.querySelectorAll(itemSelector);
let newItemsCount = 0;
currentItemsInDOM.forEach(domItem => { currentItemsInDOM.forEach(domItem => {
let itemId = domItem.id; if (domItem.id && !originalOrderMap.has(domItem.id)) itemsToReorder.push({ element: domItem, originalIndex: 900000 + newItemsCount++ });
if (!itemId) {
const linkWithItemId = domItem.querySelector('a[href*="/itm/"]');
if (linkWithItemId && linkWithItemId.href) {
const match = linkWithItemId.href.match(/\/itm\/(\d+)/);
if (match && match[1]) itemId = "ebayitem_" + match[1];
}
}
if (itemId && !originalOrderMap.has(itemId)) {
itemsToReorder.push({ element: domItem, originalIndex: 900000 + (Array.from(domItem.parentNode.children).indexOf(domItem)), id: itemId || 'new_item_' + newItemsCount++ });
} else if (!itemId && !itemsToReorder.some(entry => entry.element === domItem)) {
itemsToReorder.push({ element: domItem, originalIndex: 950000 + (Array.from(domItem.parentNode.children).indexOf(domItem)), id: 'no_id_item_' + newItemsCount++ });
}
}); });
itemsToReorder.sort((a, b) => a.originalIndex - b.originalIndex); itemsToReorder.sort((a, b) => a.originalIndex - b.originalIndex);
if (observer) observer.disconnect(); itemsToReorder.forEach(entry => parent.appendChild(entry.element));
if (observer) observer.disconnect(); if (observer && observerTargetNode) observer.observe(observerTargetNode, observerConfig);
itemsToReorder.forEach(entry => parent.appendChild(entry.element));
if (observer && observerTargetNode) {
observer.observe(observerTargetNode, observerConfig);
} else if (observer && !observerTargetNode) {
setupObserver();
} }
// console.log("Ebay Cost/TB: Restored original order."); function handleSortToggle(event) { /* ... (Keep existing handleSortToggle function) ... */
isSorted = event.currentTarget.checked;
if (isSorted) sortResults(); else restoreOriginalOrder();
} }
function addSortControl() { /* ... (Keep existing addSortControl function) ... */
function handleSortToggle(event) {
const checkbox = event.currentTarget;
if (checkbox.checked) {
isSorted = true;
sortResults();
} else {
isSorted = false;
restoreOriginalOrder();
}
}
function addSortControl() {
let controlsContainer = document.querySelector('.srp-controls__sort- σήμερα') || document.querySelector('.srp-controls__sort') || document.querySelector('div[class*="srp-controls__sort"]'); let controlsContainer = document.querySelector('.srp-controls__sort- σήμερα') || document.querySelector('.srp-controls__sort') || document.querySelector('div[class*="srp-controls__sort"]');
if (!controlsContainer) { if (!controlsContainer) controlsContainer = document.querySelector('.srp-sort, .srp-controls');
controlsContainer = document.querySelector('.srp-sort, .srp-controls'); if (!controlsContainer || document.getElementById('costPerTbSortControlWrapper')) return;
if (controlsContainer && controlsContainer.firstChild && controlsContainer.firstChild.nodeName === "UL") { const controlWrapper = document.createElement('div'); controlWrapper.id = 'costPerTbSortControlWrapper'; controlWrapper.style.display = 'inline-block'; controlWrapper.style.marginLeft = '20px'; controlWrapper.style.verticalAlign = 'middle';
controlsContainer = controlsContainer.firstChild; const controlDiv = document.createElement('div'); controlDiv.id = 'costPerTbSortControl';
} const checkbox = document.createElement('input'); checkbox.type = 'checkbox'; checkbox.id = 'costPerTbSortCheckbox'; checkbox.checked = isSorted; checkbox.style.verticalAlign = 'middle';
} const label = document.createElement('label'); label.htmlFor = 'costPerTbSortCheckbox'; label.innerText = 'Sort by $/TB'; label.style.verticalAlign = 'middle'; label.style.marginLeft = '5px';
controlDiv.appendChild(checkbox); controlDiv.appendChild(label); controlWrapper.appendChild(controlDiv);
if (!controlsContainer) { controlDiv.addEventListener('click', (e) => { if (e.target !== checkbox) { checkbox.checked = !checkbox.checked; checkbox.dispatchEvent(new Event('change', { bubbles: true })); } });
const fallbackContainer = document.querySelector('.srp-river-main') || document.querySelector('#srp-river-results') || document.body;
if (fallbackContainer) {
controlsContainer = document.createElement('div');
controlsContainer.style.textAlign = 'center'; controlsContainer.style.margin = '10px 0';
fallbackContainer.insertBefore(controlsContainer, fallbackContainer.firstChild);
} else { return; }
}
if (document.getElementById('costPerTbSortControlWrapper')) return;
const controlWrapper = document.createElement('div');
controlWrapper.id = 'costPerTbSortControlWrapper';
controlWrapper.style.display = 'inline-block'; controlWrapper.style.marginLeft = '20px'; controlWrapper.style.verticalAlign = 'middle';
const controlDiv = document.createElement('div');
controlDiv.id = 'costPerTbSortControl';
const checkbox = document.createElement('input');
checkbox.type = 'checkbox'; checkbox.id = 'costPerTbSortCheckbox'; checkbox.checked = isSorted; checkbox.style.verticalAlign = 'middle';
const label = document.createElement('label');
label.htmlFor = 'costPerTbSortCheckbox'; label.innerText = 'Sort by $/TB'; label.style.verticalAlign = 'middle'; label.style.marginLeft = '5px';
controlDiv.appendChild(checkbox); controlDiv.appendChild(label);
controlWrapper.appendChild(controlDiv);
controlDiv.addEventListener('click', (e) => {
if (e.target !== checkbox) {
checkbox.checked = !checkbox.checked;
checkbox.dispatchEvent(new Event('change', { bubbles: true }));
}
});
checkbox.addEventListener('change', handleSortToggle); checkbox.addEventListener('change', handleSortToggle);
if (controlsContainer.nextSibling) controlsContainer.parentNode.insertBefore(controlWrapper, controlsContainer.nextSibling);
if (controlsContainer.nextSibling) { else controlsContainer.parentNode.appendChild(controlWrapper);
controlsContainer.parentNode.insertBefore(controlWrapper, controlsContainer.nextSibling);
} else {
controlsContainer.parentNode.appendChild(controlWrapper);
} }
} function setupObserver() { /* ... (Keep existing setupObserver function but without needsProcessing/callback logic, just call process/addControl) ... */
observerTargetNode = getMainListParent() || document.body; if (!observerTargetNode) return;
function setupObserver() {
observerTargetNode = getMainListParent();
if (!observerTargetNode) {
observerTargetNode = document.querySelector('#srp-river-results') || document.body;
}
if (!observerTargetNode) return;
const itemSelector = getItemSelector(); const itemSelector = getItemSelector();
const callback = function(mutationsList, obs) { const callback = function(mutationsList, obs) {
let needsProcessing = false; let needsProcessing = false;
@ -492,37 +218,27 @@
} }
}); });
} }
if (mutation.removedNodes.length > 0 && !isSorted) {
mutation.removedNodes.forEach(node => {
if (node.nodeType === 1 && node.matches && node.matches(itemSelector)) {
needsProcessing = true; originalOrderMap.clear();
} }
}); if (!document.getElementById('costPerTbSortControlWrapper') && document.querySelector('.srp-controls__sort')) {
} needsProcessing = true;
}
if (!document.getElementById('costPerTbSortControlWrapper')) {
const sortControlsArea = document.querySelector('.srp-controls__sort, div[class*="srp-controls__sort"], .srp-sort, .srp-controls');
if (sortControlsArea) needsProcessing = true;
} }
} }
if (needsProcessing) { if (needsProcessing) {
clearTimeout(processTimer); clearTimeout(processTimer);
processTimer = setTimeout(() => { processTimer = setTimeout(() => { processResults(); addSortControl(); }, 750);
processResults();
addSortControl();
}, 750);
} }
}; };
if (observer) observer.disconnect(); if (observer) observer.disconnect(); observer = new MutationObserver(callback);
observer = new MutationObserver(callback);
observer.observe(observerTargetNode, observerConfig); observer.observe(observerTargetNode, observerConfig);
// console.log("Ebay Cost/TB: MutationObserver set up on:", observerTargetNode);
} }
// --- Main Execution ---
function init() { function init() {
console.log("Ebay Cost/TB V2.6 (for Tampermonkey @require) starting..."); console.log("Ebay Cost/TB V2.7 (Refactored) starting...");
if (DEBUG_MODE) { if (DEBUG_MODE) {
runUnitTests(); // --- Use Core Unit Tests ---
EbayParser.runUnitTests();
// --------------------------
} }
addStyles(); addStyles();
setTimeout(() => { setTimeout(() => {
@ -532,9 +248,6 @@
}, 2000); }, 2000);
} }
if (document.readyState === "complete" || document.readyState === "interactive") { init(); // Run-at document-idle handles load state
init();
} else {
window.addEventListener('load', init);
}
})(); })();

12
package.json Normal file
View File

@ -0,0 +1,12 @@
{
"name": "greasemonkey",
"version": "1.0.0",
"main": "ebay_command_line_tool.js",
"license": "MIT",
"dependencies": {
"puppeteer": "^24.9.0"
},
"scripts": {
"scrape": "node ebay_command_line_tool.js"
}
}

666
yarn.lock Normal file
View File

@ -0,0 +1,666 @@
# THIS IS AN AUTOGENERATED FILE. DO NOT EDIT THIS FILE DIRECTLY.
# yarn lockfile v1
"@babel/code-frame@^7.0.0":
version "7.27.1"
resolved "https://registry.yarnpkg.com/@babel/code-frame/-/code-frame-7.27.1.tgz#200f715e66d52a23b221a9435534a91cc13ad5be"
integrity sha512-cjQ7ZlQ0Mv3b47hABuTevyTuYN4i+loJKGeV9flcCgIK37cCXRh+L1bd3iBHlynerhQ7BhCkn2BPbQUL+rGqFg==
dependencies:
"@babel/helper-validator-identifier" "^7.27.1"
js-tokens "^4.0.0"
picocolors "^1.1.1"
"@babel/helper-validator-identifier@^7.27.1":
version "7.27.1"
resolved "https://registry.yarnpkg.com/@babel/helper-validator-identifier/-/helper-validator-identifier-7.27.1.tgz#a7054dcc145a967dd4dc8fee845a57c1316c9df8"
integrity sha512-D2hP9eA+Sqx1kBZgzxZh0y1trbuU+JoDkiEwqhQ36nodYqJwyEIhPSdMNd7lOm/4io72luTPWH20Yda0xOuUow==
"@puppeteer/browsers@2.10.5":
version "2.10.5"
resolved "https://registry.yarnpkg.com/@puppeteer/browsers/-/browsers-2.10.5.tgz#dddb8f8716ae6364f6f2d31125e76f311dd4a49d"
integrity sha512-eifa0o+i8dERnngJwKrfp3dEq7ia5XFyoqB17S4gK8GhsQE4/P8nxOfQSE0zQHxzzLo/cmF+7+ywEQ7wK7Fb+w==
dependencies:
debug "^4.4.1"
extract-zip "^2.0.1"
progress "^2.0.3"
proxy-agent "^6.5.0"
semver "^7.7.2"
tar-fs "^3.0.8"
yargs "^17.7.2"
"@tootallnate/quickjs-emscripten@^0.23.0":
version "0.23.0"
resolved "https://registry.yarnpkg.com/@tootallnate/quickjs-emscripten/-/quickjs-emscripten-0.23.0.tgz#db4ecfd499a9765ab24002c3b696d02e6d32a12c"
integrity sha512-C5Mc6rdnsaJDjO3UpGW/CQTHtCKaYlScZTly4JIu97Jxo/odCiH0ITnDXSJPTOrEKk/ycSZ0AOgTmkDtkOsvIA==
"@types/node@*":
version "22.15.23"
resolved "https://registry.yarnpkg.com/@types/node/-/node-22.15.23.tgz#a0b7c03f951f1ffe381a6a345c68d80e48043dd0"
integrity sha512-7Ec1zaFPF4RJ0eXu1YT/xgiebqwqoJz8rYPDi/O2BcZ++Wpt0Kq9cl0eg6NN6bYbPnR67ZLo7St5Q3UK0SnARw==
dependencies:
undici-types "~6.21.0"
"@types/yauzl@^2.9.1":
version "2.10.3"
resolved "https://registry.yarnpkg.com/@types/yauzl/-/yauzl-2.10.3.tgz#e9b2808b4f109504a03cda958259876f61017999"
integrity sha512-oJoftv0LSuaDZE3Le4DbKX+KS9G36NzOeSap90UIK0yMA/NhKJhqlSGtNDORNRaIbQfzjXDrQa0ytJ6mNRGz/Q==
dependencies:
"@types/node" "*"
agent-base@^7.1.0, agent-base@^7.1.2:
version "7.1.3"
resolved "https://registry.yarnpkg.com/agent-base/-/agent-base-7.1.3.tgz#29435eb821bc4194633a5b89e5bc4703bafc25a1"
integrity sha512-jRR5wdylq8CkOe6hei19GGZnxM6rBGwFl3Bg0YItGDimvjGtAvdZk4Pu6Cl4u4Igsws4a1fd1Vq3ezrhn4KmFw==
ansi-regex@^5.0.1:
version "5.0.1"
resolved "https://registry.yarnpkg.com/ansi-regex/-/ansi-regex-5.0.1.tgz#082cb2c89c9fe8659a311a53bd6a4dc5301db304"
integrity sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==
ansi-styles@^4.0.0:
version "4.3.0"
resolved "https://registry.yarnpkg.com/ansi-styles/-/ansi-styles-4.3.0.tgz#edd803628ae71c04c85ae7a0906edad34b648937"
integrity sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==
dependencies:
color-convert "^2.0.1"
argparse@^2.0.1:
version "2.0.1"
resolved "https://registry.yarnpkg.com/argparse/-/argparse-2.0.1.tgz#246f50f3ca78a3240f6c997e8a9bd1eac49e4b38"
integrity sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==
ast-types@^0.13.4:
version "0.13.4"
resolved "https://registry.yarnpkg.com/ast-types/-/ast-types-0.13.4.tgz#ee0d77b343263965ecc3fb62da16e7222b2b6782"
integrity sha512-x1FCFnFifvYDDzTaLII71vG5uvDwgtmDTEVWAxrgeiR8VjMONcCXJx7E+USjDtHlwFmt9MysbqgF9b9Vjr6w+w==
dependencies:
tslib "^2.0.1"
b4a@^1.6.4:
version "1.6.7"
resolved "https://registry.yarnpkg.com/b4a/-/b4a-1.6.7.tgz#a99587d4ebbfbd5a6e3b21bdb5d5fa385767abe4"
integrity sha512-OnAYlL5b7LEkALw87fUVafQw5rVR9RjwGd4KUwNQ6DrrNmaVaUCgLipfVlzrPQ4tWOR9P0IXGNOx50jYCCdSJg==
bare-events@^2.2.0, bare-events@^2.5.4:
version "2.5.4"
resolved "https://registry.yarnpkg.com/bare-events/-/bare-events-2.5.4.tgz#16143d435e1ed9eafd1ab85f12b89b3357a41745"
integrity sha512-+gFfDkR8pj4/TrWCGUGWmJIkBwuxPS5F+a5yWjOHQt2hHvNZd5YLzadjmDUtFmMM4y429bnKLa8bYBMHcYdnQA==
bare-fs@^4.0.1:
version "4.1.5"
resolved "https://registry.yarnpkg.com/bare-fs/-/bare-fs-4.1.5.tgz#1d06c076e68cc8bf97010d29af9e3ac3808cdcf7"
integrity sha512-1zccWBMypln0jEE05LzZt+V/8y8AQsQQqxtklqaIyg5nu6OAYFhZxPXinJTSG+kU5qyNmeLgcn9AW7eHiCHVLA==
dependencies:
bare-events "^2.5.4"
bare-path "^3.0.0"
bare-stream "^2.6.4"
bare-os@^3.0.1:
version "3.6.1"
resolved "https://registry.yarnpkg.com/bare-os/-/bare-os-3.6.1.tgz#9921f6f59edbe81afa9f56910658422c0f4858d4"
integrity sha512-uaIjxokhFidJP+bmmvKSgiMzj2sV5GPHaZVAIktcxcpCyBFFWO+YlikVAdhmUo2vYFvFhOXIAlldqV29L8126g==
bare-path@^3.0.0:
version "3.0.0"
resolved "https://registry.yarnpkg.com/bare-path/-/bare-path-3.0.0.tgz#b59d18130ba52a6af9276db3e96a2e3d3ea52178"
integrity sha512-tyfW2cQcB5NN8Saijrhqn0Zh7AnFNsnczRcuWODH0eYAXBsJ5gVxAUuNr7tsHSC6IZ77cA0SitzT+s47kot8Mw==
dependencies:
bare-os "^3.0.1"
bare-stream@^2.6.4:
version "2.6.5"
resolved "https://registry.yarnpkg.com/bare-stream/-/bare-stream-2.6.5.tgz#bba8e879674c4c27f7e27805df005c15d7a2ca07"
integrity sha512-jSmxKJNJmHySi6hC42zlZnq00rga4jjxcgNZjY9N5WlOe/iOoGRtdwGsHzQv2RlH2KOYMwGUXhf2zXd32BA9RA==
dependencies:
streamx "^2.21.0"
basic-ftp@^5.0.2:
version "5.0.5"
resolved "https://registry.yarnpkg.com/basic-ftp/-/basic-ftp-5.0.5.tgz#14a474f5fffecca1f4f406f1c26b18f800225ac0"
integrity sha512-4Bcg1P8xhUuqcii/S0Z9wiHIrQVPMermM1any+MX5GeGD7faD3/msQUDGLol9wOcz4/jbg/WJnGqoJF6LiBdtg==
buffer-crc32@~0.2.3:
version "0.2.13"
resolved "https://registry.yarnpkg.com/buffer-crc32/-/buffer-crc32-0.2.13.tgz#0d333e3f00eac50aa1454abd30ef8c2a5d9a7242"
integrity sha512-VO9Ht/+p3SN7SKWqcrgEzjGbRSJYTx+Q1pTQC0wrWqHx0vpJraQ6GtHx8tvcg1rlK1byhU5gccxgOgj7B0TDkQ==
callsites@^3.0.0:
version "3.1.0"
resolved "https://registry.yarnpkg.com/callsites/-/callsites-3.1.0.tgz#b3630abd8943432f54b3f0519238e33cd7df2f73"
integrity sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ==
chromium-bidi@5.1.0:
version "5.1.0"
resolved "https://registry.yarnpkg.com/chromium-bidi/-/chromium-bidi-5.1.0.tgz#8d0e47f7ac9270262df29792318dd5378e983e62"
integrity sha512-9MSRhWRVoRPDG0TgzkHrshFSJJNZzfY5UFqUMuksg7zL1yoZIZ3jLB0YAgHclbiAxPI86pBnwDX1tbzoiV8aFw==
dependencies:
mitt "^3.0.1"
zod "^3.24.1"
cliui@^8.0.1:
version "8.0.1"
resolved "https://registry.yarnpkg.com/cliui/-/cliui-8.0.1.tgz#0c04b075db02cbfe60dc8e6cf2f5486b1a3608aa"
integrity sha512-BSeNnyus75C4//NQ9gQt1/csTXyo/8Sb+afLAkzAptFuMsod9HFokGNudZpi/oQV73hnVK+sR+5PVRMd+Dr7YQ==
dependencies:
string-width "^4.2.0"
strip-ansi "^6.0.1"
wrap-ansi "^7.0.0"
color-convert@^2.0.1:
version "2.0.1"
resolved "https://registry.yarnpkg.com/color-convert/-/color-convert-2.0.1.tgz#72d3a68d598c9bdb3af2ad1e84f21d896abd4de3"
integrity sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==
dependencies:
color-name "~1.1.4"
color-name@~1.1.4:
version "1.1.4"
resolved "https://registry.yarnpkg.com/color-name/-/color-name-1.1.4.tgz#c2a09a87acbde69543de6f63fa3995c826c536a2"
integrity sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==
cosmiconfig@^9.0.0:
version "9.0.0"
resolved "https://registry.yarnpkg.com/cosmiconfig/-/cosmiconfig-9.0.0.tgz#34c3fc58287b915f3ae905ab6dc3de258b55ad9d"
integrity sha512-itvL5h8RETACmOTFc4UfIyB2RfEHi71Ax6E/PivVxq9NseKbOWpeyHEOIbmAw1rs8Ak0VursQNww7lf7YtUwzg==
dependencies:
env-paths "^2.2.1"
import-fresh "^3.3.0"
js-yaml "^4.1.0"
parse-json "^5.2.0"
data-uri-to-buffer@^6.0.2:
version "6.0.2"
resolved "https://registry.yarnpkg.com/data-uri-to-buffer/-/data-uri-to-buffer-6.0.2.tgz#8a58bb67384b261a38ef18bea1810cb01badd28b"
integrity sha512-7hvf7/GW8e86rW0ptuwS3OcBGDjIi6SZva7hCyWC0yYry2cOPmLIjXAUHI6DK2HsnwJd9ifmt57i8eV2n4YNpw==
debug@4, debug@^4.1.1, debug@^4.3.4, debug@^4.4.1:
version "4.4.1"
resolved "https://registry.yarnpkg.com/debug/-/debug-4.4.1.tgz#e5a8bc6cbc4c6cd3e64308b0693a3d4fa550189b"
integrity sha512-KcKCqiftBJcZr++7ykoDIEwSa3XWowTfNPo92BYxjXiyYEVrUQh2aLyhxBCwww+heortUFxEJYcRzosstTEBYQ==
dependencies:
ms "^2.1.3"
degenerator@^5.0.0:
version "5.0.1"
resolved "https://registry.yarnpkg.com/degenerator/-/degenerator-5.0.1.tgz#9403bf297c6dad9a1ece409b37db27954f91f2f5"
integrity sha512-TllpMR/t0M5sqCXfj85i4XaAzxmS5tVA16dqvdkMwGmzI+dXLXnw3J+3Vdv7VKw+ThlTMboK6i9rnZ6Nntj5CQ==
dependencies:
ast-types "^0.13.4"
escodegen "^2.1.0"
esprima "^4.0.1"
devtools-protocol@0.0.1439962:
version "0.0.1439962"
resolved "https://registry.yarnpkg.com/devtools-protocol/-/devtools-protocol-0.0.1439962.tgz#395c5ca1cd83aa451c667056a025f9873c4598c1"
integrity sha512-jJF48UdryzKiWhJ1bLKr7BFWUQCEIT5uCNbDLqkQJBtkFxYzILJH44WN0PDKMIlGDN7Utb8vyUY85C3w4R/t2g==
emoji-regex@^8.0.0:
version "8.0.0"
resolved "https://registry.yarnpkg.com/emoji-regex/-/emoji-regex-8.0.0.tgz#e818fd69ce5ccfcb404594f842963bf53164cc37"
integrity sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==
end-of-stream@^1.1.0:
version "1.4.4"
resolved "https://registry.yarnpkg.com/end-of-stream/-/end-of-stream-1.4.4.tgz#5ae64a5f45057baf3626ec14da0ca5e4b2431eb0"
integrity sha512-+uw1inIHVPQoaVuHzRyXd21icM+cnt4CzD5rW+NC1wjOUSTOs+Te7FOv7AhN7vS9x/oIyhLP5PR1H+phQAHu5Q==
dependencies:
once "^1.4.0"
env-paths@^2.2.1:
version "2.2.1"
resolved "https://registry.yarnpkg.com/env-paths/-/env-paths-2.2.1.tgz#420399d416ce1fbe9bc0a07c62fa68d67fd0f8f2"
integrity sha512-+h1lkLKhZMTYjog1VEpJNG7NZJWcuc2DDk/qsqSTRRCOXiLjeQ1d1/udrUGhqMxUgAlwKNZ0cf2uqan5GLuS2A==
error-ex@^1.3.1:
version "1.3.2"
resolved "https://registry.yarnpkg.com/error-ex/-/error-ex-1.3.2.tgz#b4ac40648107fdcdcfae242f428bea8a14d4f1bf"
integrity sha512-7dFHNmqeFSEt2ZBsCriorKnn3Z2pj+fd9kmI6QoWw4//DL+icEBfc0U7qJCisqrTsKTjw4fNFy2pW9OqStD84g==
dependencies:
is-arrayish "^0.2.1"
escalade@^3.1.1:
version "3.2.0"
resolved "https://registry.yarnpkg.com/escalade/-/escalade-3.2.0.tgz#011a3f69856ba189dffa7dc8fcce99d2a87903e5"
integrity sha512-WUj2qlxaQtO4g6Pq5c29GTcWGDyd8itL8zTlipgECz3JesAiiOKotd8JU6otB3PACgG6xkJUyVhboMS+bje/jA==
escodegen@^2.1.0:
version "2.1.0"
resolved "https://registry.yarnpkg.com/escodegen/-/escodegen-2.1.0.tgz#ba93bbb7a43986d29d6041f99f5262da773e2e17"
integrity sha512-2NlIDTwUWJN0mRPQOdtQBzbUHvdGY2P1VXSyU83Q3xKxM7WHX2Ql8dKq782Q9TgQUNOLEzEYu9bzLNj1q88I5w==
dependencies:
esprima "^4.0.1"
estraverse "^5.2.0"
esutils "^2.0.2"
optionalDependencies:
source-map "~0.6.1"
esprima@^4.0.1:
version "4.0.1"
resolved "https://registry.yarnpkg.com/esprima/-/esprima-4.0.1.tgz#13b04cdb3e6c5d19df91ab6987a8695619b0aa71"
integrity sha512-eGuFFw7Upda+g4p+QHvnW0RyTX/SVeJBDM/gCtMARO0cLuT2HcEKnTPvhjV6aGeqrCB/sbNop0Kszm0jsaWU4A==
estraverse@^5.2.0:
version "5.3.0"
resolved "https://registry.yarnpkg.com/estraverse/-/estraverse-5.3.0.tgz#2eea5290702f26ab8fe5370370ff86c965d21123"
integrity sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA==
esutils@^2.0.2:
version "2.0.3"
resolved "https://registry.yarnpkg.com/esutils/-/esutils-2.0.3.tgz#74d2eb4de0b8da1293711910d50775b9b710ef64"
integrity sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g==
extract-zip@^2.0.1:
version "2.0.1"
resolved "https://registry.yarnpkg.com/extract-zip/-/extract-zip-2.0.1.tgz#663dca56fe46df890d5f131ef4a06d22bb8ba13a"
integrity sha512-GDhU9ntwuKyGXdZBUgTIe+vXnWj0fppUEtMDL0+idd5Sta8TGpHssn/eusA9mrPr9qNDym6SxAYZjNvCn/9RBg==
dependencies:
debug "^4.1.1"
get-stream "^5.1.0"
yauzl "^2.10.0"
optionalDependencies:
"@types/yauzl" "^2.9.1"
fast-fifo@^1.2.0, fast-fifo@^1.3.2:
version "1.3.2"
resolved "https://registry.yarnpkg.com/fast-fifo/-/fast-fifo-1.3.2.tgz#286e31de96eb96d38a97899815740ba2a4f3640c"
integrity sha512-/d9sfos4yxzpwkDkuN7k2SqFKtYNmCTzgfEpz82x34IM9/zc8KGxQoXg1liNC/izpRM/MBdt44Nmx41ZWqk+FQ==
fd-slicer@~1.1.0:
version "1.1.0"
resolved "https://registry.yarnpkg.com/fd-slicer/-/fd-slicer-1.1.0.tgz#25c7c89cb1f9077f8891bbe61d8f390eae256f1e"
integrity sha512-cE1qsB/VwyQozZ+q1dGxR8LBYNZeofhEdUNGSMbQD3Gw2lAzX9Zb3uIU6Ebc/Fmyjo9AWWfnn0AUCHqtevs/8g==
dependencies:
pend "~1.2.0"
get-caller-file@^2.0.5:
version "2.0.5"
resolved "https://registry.yarnpkg.com/get-caller-file/-/get-caller-file-2.0.5.tgz#4f94412a82db32f36e3b0b9741f8a97feb031f7e"
integrity sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg==
get-stream@^5.1.0:
version "5.2.0"
resolved "https://registry.yarnpkg.com/get-stream/-/get-stream-5.2.0.tgz#4966a1795ee5ace65e706c4b7beb71257d6e22d3"
integrity sha512-nBF+F1rAZVCu/p7rjzgA+Yb4lfYXrpl7a6VmJrU8wF9I1CKvP/QwPNZHnOlwbTkY6dvtFIzFMSyQXbLoTQPRpA==
dependencies:
pump "^3.0.0"
get-uri@^6.0.1:
version "6.0.4"
resolved "https://registry.yarnpkg.com/get-uri/-/get-uri-6.0.4.tgz#6daaee9e12f9759e19e55ba313956883ef50e0a7"
integrity sha512-E1b1lFFLvLgak2whF2xDBcOy6NLVGZBqqjJjsIhvopKfWWEi64pLVTWWehV8KlLerZkfNTA95sTe2OdJKm1OzQ==
dependencies:
basic-ftp "^5.0.2"
data-uri-to-buffer "^6.0.2"
debug "^4.3.4"
http-proxy-agent@^7.0.0, http-proxy-agent@^7.0.1:
version "7.0.2"
resolved "https://registry.yarnpkg.com/http-proxy-agent/-/http-proxy-agent-7.0.2.tgz#9a8b1f246866c028509486585f62b8f2c18c270e"
integrity sha512-T1gkAiYYDWYx3V5Bmyu7HcfcvL7mUrTWiM6yOfa3PIphViJ/gFPbvidQ+veqSOHci/PxBcDabeUNCzpOODJZig==
dependencies:
agent-base "^7.1.0"
debug "^4.3.4"
https-proxy-agent@^7.0.6:
version "7.0.6"
resolved "https://registry.yarnpkg.com/https-proxy-agent/-/https-proxy-agent-7.0.6.tgz#da8dfeac7da130b05c2ba4b59c9b6cd66611a6b9"
integrity sha512-vK9P5/iUfdl95AI+JVyUuIcVtd4ofvtrOr3HNtM2yxC9bnMbEdp3x01OhQNnjb8IJYi38VlTE3mBXwcfvywuSw==
dependencies:
agent-base "^7.1.2"
debug "4"
import-fresh@^3.3.0:
version "3.3.1"
resolved "https://registry.yarnpkg.com/import-fresh/-/import-fresh-3.3.1.tgz#9cecb56503c0ada1f2741dbbd6546e4b13b57ccf"
integrity sha512-TR3KfrTZTYLPB6jUjfx6MF9WcWrHL9su5TObK4ZkYgBdWKPOFoSoQIdEuTuR82pmtxH2spWG9h6etwfr1pLBqQ==
dependencies:
parent-module "^1.0.0"
resolve-from "^4.0.0"
ip-address@^9.0.5:
version "9.0.5"
resolved "https://registry.yarnpkg.com/ip-address/-/ip-address-9.0.5.tgz#117a960819b08780c3bd1f14ef3c1cc1d3f3ea5a"
integrity sha512-zHtQzGojZXTwZTHQqra+ETKd4Sn3vgi7uBmlPoXVWZqYvuKmtI0l/VZTjqGmJY9x88GGOaZ9+G9ES8hC4T4X8g==
dependencies:
jsbn "1.1.0"
sprintf-js "^1.1.3"
is-arrayish@^0.2.1:
version "0.2.1"
resolved "https://registry.yarnpkg.com/is-arrayish/-/is-arrayish-0.2.1.tgz#77c99840527aa8ecb1a8ba697b80645a7a926a9d"
integrity sha512-zz06S8t0ozoDXMG+ube26zeCTNXcKIPJZJi8hBrF4idCLms4CG9QtK7qBl1boi5ODzFpjswb5JPmHCbMpjaYzg==
is-fullwidth-code-point@^3.0.0:
version "3.0.0"
resolved "https://registry.yarnpkg.com/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz#f116f8064fe90b3f7844a38997c0b75051269f1d"
integrity sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==
js-tokens@^4.0.0:
version "4.0.0"
resolved "https://registry.yarnpkg.com/js-tokens/-/js-tokens-4.0.0.tgz#19203fb59991df98e3a287050d4647cdeaf32499"
integrity sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==
js-yaml@^4.1.0:
version "4.1.0"
resolved "https://registry.yarnpkg.com/js-yaml/-/js-yaml-4.1.0.tgz#c1fb65f8f5017901cdd2c951864ba18458a10602"
integrity sha512-wpxZs9NoxZaJESJGIZTyDEaYpl0FKSA+FB9aJiyemKhMwkxQg63h4T1KJgUGHpTqPDNRcmmYLugrRjJlBtWvRA==
dependencies:
argparse "^2.0.1"
jsbn@1.1.0:
version "1.1.0"
resolved "https://registry.yarnpkg.com/jsbn/-/jsbn-1.1.0.tgz#b01307cb29b618a1ed26ec79e911f803c4da0040"
integrity sha512-4bYVV3aAMtDTTu4+xsDYa6sy9GyJ69/amsu9sYF2zqjiEoZA5xJi3BrfX3uY+/IekIu7MwdObdbDWpoZdBv3/A==
json-parse-even-better-errors@^2.3.0:
version "2.3.1"
resolved "https://registry.yarnpkg.com/json-parse-even-better-errors/-/json-parse-even-better-errors-2.3.1.tgz#7c47805a94319928e05777405dc12e1f7a4ee02d"
integrity sha512-xyFwyhro/JEof6Ghe2iz2NcXoj2sloNsWr/XsERDK/oiPCfaNhl5ONfp+jQdAZRQQ0IJWNzH9zIZF7li91kh2w==
lines-and-columns@^1.1.6:
version "1.2.4"
resolved "https://registry.yarnpkg.com/lines-and-columns/-/lines-and-columns-1.2.4.tgz#eca284f75d2965079309dc0ad9255abb2ebc1632"
integrity sha512-7ylylesZQ/PV29jhEDl3Ufjo6ZX7gCqJr5F7PKrqc93v7fzSymt1BpwEU8nAUXs8qzzvqhbjhK5QZg6Mt/HkBg==
lru-cache@^7.14.1:
version "7.18.3"
resolved "https://registry.yarnpkg.com/lru-cache/-/lru-cache-7.18.3.tgz#f793896e0fd0e954a59dfdd82f0773808df6aa89"
integrity sha512-jumlc0BIUrS3qJGgIkWZsyfAM7NCWiBcCDhnd+3NNM5KbBmLTgHVfWBcg6W+rLUsIpzpERPsvwUP7CckAQSOoA==
mitt@^3.0.1:
version "3.0.1"
resolved "https://registry.yarnpkg.com/mitt/-/mitt-3.0.1.tgz#ea36cf0cc30403601ae074c8f77b7092cdab36d1"
integrity sha512-vKivATfr97l2/QBCYAkXYDbrIWPM2IIKEl7YPhjCvKlG3kE2gm+uBo6nEXK3M5/Ffh/FLpKExzOQ3JJoJGFKBw==
ms@^2.1.3:
version "2.1.3"
resolved "https://registry.yarnpkg.com/ms/-/ms-2.1.3.tgz#574c8138ce1d2b5861f0b44579dbadd60c6615b2"
integrity sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==
netmask@^2.0.2:
version "2.0.2"
resolved "https://registry.yarnpkg.com/netmask/-/netmask-2.0.2.tgz#8b01a07644065d536383835823bc52004ebac5e7"
integrity sha512-dBpDMdxv9Irdq66304OLfEmQ9tbNRFnFTuZiLo+bD+r332bBmMJ8GBLXklIXXgxd3+v9+KUnZaUR5PJMa75Gsg==
once@^1.3.1, once@^1.4.0:
version "1.4.0"
resolved "https://registry.yarnpkg.com/once/-/once-1.4.0.tgz#583b1aa775961d4b113ac17d9c50baef9dd76bd1"
integrity sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w==
dependencies:
wrappy "1"
pac-proxy-agent@^7.1.0:
version "7.2.0"
resolved "https://registry.yarnpkg.com/pac-proxy-agent/-/pac-proxy-agent-7.2.0.tgz#9cfaf33ff25da36f6147a20844230ec92c06e5df"
integrity sha512-TEB8ESquiLMc0lV8vcd5Ql/JAKAoyzHFXaStwjkzpOpC5Yv+pIzLfHvjTSdf3vpa2bMiUQrg9i6276yn8666aA==
dependencies:
"@tootallnate/quickjs-emscripten" "^0.23.0"
agent-base "^7.1.2"
debug "^4.3.4"
get-uri "^6.0.1"
http-proxy-agent "^7.0.0"
https-proxy-agent "^7.0.6"
pac-resolver "^7.0.1"
socks-proxy-agent "^8.0.5"
pac-resolver@^7.0.1:
version "7.0.1"
resolved "https://registry.yarnpkg.com/pac-resolver/-/pac-resolver-7.0.1.tgz#54675558ea368b64d210fd9c92a640b5f3b8abb6"
integrity sha512-5NPgf87AT2STgwa2ntRMr45jTKrYBGkVU36yT0ig/n/GMAa3oPqhZfIQ2kMEimReg0+t9kZViDVZ83qfVUlckg==
dependencies:
degenerator "^5.0.0"
netmask "^2.0.2"
parent-module@^1.0.0:
version "1.0.1"
resolved "https://registry.yarnpkg.com/parent-module/-/parent-module-1.0.1.tgz#691d2709e78c79fae3a156622452d00762caaaa2"
integrity sha512-GQ2EWRpQV8/o+Aw8YqtfZZPfNRWZYkbidE9k5rpl/hC3vtHHBfGm2Ifi6qWV+coDGkrUKZAxE3Lot5kcsRlh+g==
dependencies:
callsites "^3.0.0"
parse-json@^5.2.0:
version "5.2.0"
resolved "https://registry.yarnpkg.com/parse-json/-/parse-json-5.2.0.tgz#c76fc66dee54231c962b22bcc8a72cf2f99753cd"
integrity sha512-ayCKvm/phCGxOkYRSCM82iDwct8/EonSEgCSxWxD7ve6jHggsFl4fZVQBPRNgQoKiuV/odhFrGzQXZwbifC8Rg==
dependencies:
"@babel/code-frame" "^7.0.0"
error-ex "^1.3.1"
json-parse-even-better-errors "^2.3.0"
lines-and-columns "^1.1.6"
pend@~1.2.0:
version "1.2.0"
resolved "https://registry.yarnpkg.com/pend/-/pend-1.2.0.tgz#7a57eb550a6783f9115331fcf4663d5c8e007a50"
integrity sha512-F3asv42UuXchdzt+xXqfW1OGlVBe+mxa2mqI0pg5yAHZPvFmY3Y6drSf/GQ1A86WgWEN9Kzh/WrgKa6iGcHXLg==
picocolors@^1.1.1:
version "1.1.1"
resolved "https://registry.yarnpkg.com/picocolors/-/picocolors-1.1.1.tgz#3d321af3eab939b083c8f929a1d12cda81c26b6b"
integrity sha512-xceH2snhtb5M9liqDsmEw56le376mTZkEX/jEb/RxNFyegNul7eNslCXP9FDj/Lcu0X8KEyMceP2ntpaHrDEVA==
progress@^2.0.3:
version "2.0.3"
resolved "https://registry.yarnpkg.com/progress/-/progress-2.0.3.tgz#7e8cf8d8f5b8f239c1bc68beb4eb78567d572ef8"
integrity sha512-7PiHtLll5LdnKIMw100I+8xJXR5gW2QwWYkT6iJva0bXitZKa/XMrSbdmg3r2Xnaidz9Qumd0VPaMrZlF9V9sA==
proxy-agent@^6.5.0:
version "6.5.0"
resolved "https://registry.yarnpkg.com/proxy-agent/-/proxy-agent-6.5.0.tgz#9e49acba8e4ee234aacb539f89ed9c23d02f232d"
integrity sha512-TmatMXdr2KlRiA2CyDu8GqR8EjahTG3aY3nXjdzFyoZbmB8hrBsTyMezhULIXKnC0jpfjlmiZ3+EaCzoInSu/A==
dependencies:
agent-base "^7.1.2"
debug "^4.3.4"
http-proxy-agent "^7.0.1"
https-proxy-agent "^7.0.6"
lru-cache "^7.14.1"
pac-proxy-agent "^7.1.0"
proxy-from-env "^1.1.0"
socks-proxy-agent "^8.0.5"
proxy-from-env@^1.1.0:
version "1.1.0"
resolved "https://registry.yarnpkg.com/proxy-from-env/-/proxy-from-env-1.1.0.tgz#e102f16ca355424865755d2c9e8ea4f24d58c3e2"
integrity sha512-D+zkORCbA9f1tdWRK0RaCR3GPv50cMxcrz4X8k5LTSUD1Dkw47mKJEZQNunItRTkWwgtaUSo1RVFRIG9ZXiFYg==
pump@^3.0.0:
version "3.0.2"
resolved "https://registry.yarnpkg.com/pump/-/pump-3.0.2.tgz#836f3edd6bc2ee599256c924ffe0d88573ddcbf8"
integrity sha512-tUPXtzlGM8FE3P0ZL6DVs/3P58k9nk8/jZeQCurTJylQA8qFYzHFfhBJkuqyE0FifOsQ0uKWekiZ5g8wtr28cw==
dependencies:
end-of-stream "^1.1.0"
once "^1.3.1"
puppeteer-core@24.9.0:
version "24.9.0"
resolved "https://registry.yarnpkg.com/puppeteer-core/-/puppeteer-core-24.9.0.tgz#fc489e83bf65db1dc72e53a78140ee567efd847e"
integrity sha512-HFdCeH/wx6QPz8EncafbCqJBqaCG1ENW75xg3cLFMRUoqZDgByT6HSueiumetT2uClZxwqj0qS4qMVZwLHRHHw==
dependencies:
"@puppeteer/browsers" "2.10.5"
chromium-bidi "5.1.0"
debug "^4.4.1"
devtools-protocol "0.0.1439962"
typed-query-selector "^2.12.0"
ws "^8.18.2"
puppeteer@^24.9.0:
version "24.9.0"
resolved "https://registry.yarnpkg.com/puppeteer/-/puppeteer-24.9.0.tgz#1d3f805e0170ca481b637a47c71a09b815594dae"
integrity sha512-L0pOtALIx8rgDt24Y+COm8X52v78gNtBOW6EmUcEPci0TYD72SAuaXKqasRIx4JXxmg2Tkw5ySKcpPOwN8xXnQ==
dependencies:
"@puppeteer/browsers" "2.10.5"
chromium-bidi "5.1.0"
cosmiconfig "^9.0.0"
devtools-protocol "0.0.1439962"
puppeteer-core "24.9.0"
typed-query-selector "^2.12.0"
require-directory@^2.1.1:
version "2.1.1"
resolved "https://registry.yarnpkg.com/require-directory/-/require-directory-2.1.1.tgz#8c64ad5fd30dab1c976e2344ffe7f792a6a6df42"
integrity sha512-fGxEI7+wsG9xrvdjsrlmL22OMTTiHRwAMroiEeMgq8gzoLC/PQr7RsRDSTLUg/bZAZtF+TVIkHc6/4RIKrui+Q==
resolve-from@^4.0.0:
version "4.0.0"
resolved "https://registry.yarnpkg.com/resolve-from/-/resolve-from-4.0.0.tgz#4abcd852ad32dd7baabfe9b40e00a36db5f392e6"
integrity sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g==
semver@^7.7.2:
version "7.7.2"
resolved "https://registry.yarnpkg.com/semver/-/semver-7.7.2.tgz#67d99fdcd35cec21e6f8b87a7fd515a33f982b58"
integrity sha512-RF0Fw+rO5AMf9MAyaRXI4AV0Ulj5lMHqVxxdSgiVbixSCXoEmmX/jk0CuJw4+3SqroYO9VoUh+HcuJivvtJemA==
smart-buffer@^4.2.0:
version "4.2.0"
resolved "https://registry.yarnpkg.com/smart-buffer/-/smart-buffer-4.2.0.tgz#6e1d71fa4f18c05f7d0ff216dd16a481d0e8d9ae"
integrity sha512-94hK0Hh8rPqQl2xXc3HsaBoOXKV20MToPkcXvwbISWLEs+64sBq5kFgn2kJDHb1Pry9yrP0dxrCI9RRci7RXKg==
socks-proxy-agent@^8.0.5:
version "8.0.5"
resolved "https://registry.yarnpkg.com/socks-proxy-agent/-/socks-proxy-agent-8.0.5.tgz#b9cdb4e7e998509d7659d689ce7697ac21645bee"
integrity sha512-HehCEsotFqbPW9sJ8WVYB6UbmIMv7kUUORIF2Nncq4VQvBfNBLibW9YZR5dlYCSUhwcD628pRllm7n+E+YTzJw==
dependencies:
agent-base "^7.1.2"
debug "^4.3.4"
socks "^2.8.3"
socks@^2.8.3:
version "2.8.4"
resolved "https://registry.yarnpkg.com/socks/-/socks-2.8.4.tgz#07109755cdd4da03269bda4725baa061ab56d5cc"
integrity sha512-D3YaD0aRxR3mEcqnidIs7ReYJFVzWdd6fXJYUM8ixcQcJRGTka/b3saV0KflYhyVJXKhb947GndU35SxYNResQ==
dependencies:
ip-address "^9.0.5"
smart-buffer "^4.2.0"
source-map@~0.6.1:
version "0.6.1"
resolved "https://registry.yarnpkg.com/source-map/-/source-map-0.6.1.tgz#74722af32e9614e9c287a8d0bbde48b5e2f1a263"
integrity sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==
sprintf-js@^1.1.3:
version "1.1.3"
resolved "https://registry.yarnpkg.com/sprintf-js/-/sprintf-js-1.1.3.tgz#4914b903a2f8b685d17fdf78a70e917e872e444a"
integrity sha512-Oo+0REFV59/rz3gfJNKQiBlwfHaSESl1pcGyABQsnnIfWOFt6JNj5gCog2U6MLZ//IGYD+nA8nI+mTShREReaA==
streamx@^2.15.0, streamx@^2.21.0:
version "2.22.0"
resolved "https://registry.yarnpkg.com/streamx/-/streamx-2.22.0.tgz#cd7b5e57c95aaef0ff9b2aef7905afa62ec6e4a7"
integrity sha512-sLh1evHOzBy/iWRiR6d1zRcLao4gGZr3C1kzNz4fopCOKJb6xD9ub8Mpi9Mr1R6id5o43S+d93fI48UC5uM9aw==
dependencies:
fast-fifo "^1.3.2"
text-decoder "^1.1.0"
optionalDependencies:
bare-events "^2.2.0"
string-width@^4.1.0, string-width@^4.2.0, string-width@^4.2.3:
version "4.2.3"
resolved "https://registry.yarnpkg.com/string-width/-/string-width-4.2.3.tgz#269c7117d27b05ad2e536830a8ec895ef9c6d010"
integrity sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==
dependencies:
emoji-regex "^8.0.0"
is-fullwidth-code-point "^3.0.0"
strip-ansi "^6.0.1"
strip-ansi@^6.0.0, strip-ansi@^6.0.1:
version "6.0.1"
resolved "https://registry.yarnpkg.com/strip-ansi/-/strip-ansi-6.0.1.tgz#9e26c63d30f53443e9489495b2105d37b67a85d9"
integrity sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==
dependencies:
ansi-regex "^5.0.1"
tar-fs@^3.0.8:
version "3.0.9"
resolved "https://registry.yarnpkg.com/tar-fs/-/tar-fs-3.0.9.tgz#d570793c6370d7078926c41fa422891566a0b617"
integrity sha512-XF4w9Xp+ZQgifKakjZYmFdkLoSWd34VGKcsTCwlNWM7QG3ZbaxnTsaBwnjFZqHRf/rROxaR8rXnbtwdvaDI+lA==
dependencies:
pump "^3.0.0"
tar-stream "^3.1.5"
optionalDependencies:
bare-fs "^4.0.1"
bare-path "^3.0.0"
tar-stream@^3.1.5:
version "3.1.7"
resolved "https://registry.yarnpkg.com/tar-stream/-/tar-stream-3.1.7.tgz#24b3fb5eabada19fe7338ed6d26e5f7c482e792b"
integrity sha512-qJj60CXt7IU1Ffyc3NJMjh6EkuCFej46zUqJ4J7pqYlThyd9bO0XBTmcOIhSzZJVWfsLks0+nle/j538YAW9RQ==
dependencies:
b4a "^1.6.4"
fast-fifo "^1.2.0"
streamx "^2.15.0"
text-decoder@^1.1.0:
version "1.2.3"
resolved "https://registry.yarnpkg.com/text-decoder/-/text-decoder-1.2.3.tgz#b19da364d981b2326d5f43099c310cc80d770c65"
integrity sha512-3/o9z3X0X0fTupwsYvR03pJ/DjWuqqrfwBgTQzdWDiQSm9KitAyz/9WqsT2JQW7KV2m+bC2ol/zqpW37NHxLaA==
dependencies:
b4a "^1.6.4"
tslib@^2.0.1:
version "2.8.1"
resolved "https://registry.yarnpkg.com/tslib/-/tslib-2.8.1.tgz#612efe4ed235d567e8aba5f2a5fab70280ade83f"
integrity sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w==
typed-query-selector@^2.12.0:
version "2.12.0"
resolved "https://registry.yarnpkg.com/typed-query-selector/-/typed-query-selector-2.12.0.tgz#92b65dbc0a42655fccf4aeb1a08b1dddce8af5f2"
integrity sha512-SbklCd1F0EiZOyPiW192rrHZzZ5sBijB6xM+cpmrwDqObvdtunOHHIk9fCGsoK5JVIYXoyEp4iEdE3upFH3PAg==
undici-types@~6.21.0:
version "6.21.0"
resolved "https://registry.yarnpkg.com/undici-types/-/undici-types-6.21.0.tgz#691d00af3909be93a7faa13be61b3a5b50ef12cb"
integrity sha512-iwDZqg0QAGrg9Rav5H4n0M64c3mkR59cJ6wQp+7C4nI0gsmExaedaYLNO44eT4AtBBwjbTiGPMlt2Md0T9H9JQ==
wrap-ansi@^7.0.0:
version "7.0.0"
resolved "https://registry.yarnpkg.com/wrap-ansi/-/wrap-ansi-7.0.0.tgz#67e145cff510a6a6984bdf1152911d69d2eb9e43"
integrity sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==
dependencies:
ansi-styles "^4.0.0"
string-width "^4.1.0"
strip-ansi "^6.0.0"
wrappy@1:
version "1.0.2"
resolved "https://registry.yarnpkg.com/wrappy/-/wrappy-1.0.2.tgz#b5243d8f3ec1aa35f1364605bc0d1036e30ab69f"
integrity sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==
ws@^8.18.2:
version "8.18.2"
resolved "https://registry.yarnpkg.com/ws/-/ws-8.18.2.tgz#42738b2be57ced85f46154320aabb51ab003705a"
integrity sha512-DMricUmwGZUVr++AEAe2uiVM7UoO9MAVZMDu05UQOaUII0lp+zOzLLU4Xqh/JvTqklB1T4uELaaPBKyjE1r4fQ==
y18n@^5.0.5:
version "5.0.8"
resolved "https://registry.yarnpkg.com/y18n/-/y18n-5.0.8.tgz#7f4934d0f7ca8c56f95314939ddcd2dd91ce1d55"
integrity sha512-0pfFzegeDWJHJIAmTLRP2DwHjdF5s7jo9tuztdQxAhINCdvS+3nGINqPd00AphqJR/0LhANUS6/+7SCb98YOfA==
yargs-parser@^21.1.1:
version "21.1.1"
resolved "https://registry.yarnpkg.com/yargs-parser/-/yargs-parser-21.1.1.tgz#9096bceebf990d21bb31fa9516e0ede294a77d35"
integrity sha512-tVpsJW7DdjecAiFpbIB1e3qxIQsE6NoPc5/eTdrbbIC4h0LVsWhnoa3g+m2HclBIujHzsxZ4VJVA+GUuc2/LBw==
yargs@^17.7.2:
version "17.7.2"
resolved "https://registry.yarnpkg.com/yargs/-/yargs-17.7.2.tgz#991df39aca675a192b816e1e0363f9d75d2aa269"
integrity sha512-7dSzzRQ++CKnNI/krKnYRV7JKKPUXMEh61soaHKg9mrWEhzFWhFnxPxGl+69cD1Ou63C13NUPCnmIcrvqCuM6w==
dependencies:
cliui "^8.0.1"
escalade "^3.1.1"
get-caller-file "^2.0.5"
require-directory "^2.1.1"
string-width "^4.2.3"
y18n "^5.0.5"
yargs-parser "^21.1.1"
yauzl@^2.10.0:
version "2.10.0"
resolved "https://registry.yarnpkg.com/yauzl/-/yauzl-2.10.0.tgz#c7eb17c93e112cb1086fa6d8e51fb0667b79a5f9"
integrity sha512-p4a9I6X6nu6IhoGmBqAcbJy1mlC4j27vEPZX9F4L4/vZT3Lyq1VkFHw/V/PUcB9Buo+DG3iHkT0x3Qya58zc3g==
dependencies:
buffer-crc32 "~0.2.3"
fd-slicer "~1.1.0"
zod@^3.24.1:
version "3.25.32"
resolved "https://registry.yarnpkg.com/zod/-/zod-3.25.32.tgz#769cc684072df780fc8f38130b0cd9283a8d3818"
integrity sha512-OSm2xTIRfW8CV5/QKgngwmQW/8aPfGdaQFlrGoErlgg/Epm7cjb6K6VEyExfe65a3VybUOnu381edLb0dfJl0g==