From 1b70302ce6f6d4fb23c023b62d266098e30db7cd Mon Sep 17 00:00:00 2001 From: hawkeyexl Date: Thu, 18 Dec 2025 11:49:17 -0800 Subject: [PATCH 1/9] feat: Implement Heretto CMS uploader for automatic screenshot synchronization - Added HerettoUploader class to handle file uploads to Heretto CMS. - Integrated uploader into the existing upload process for changed screenshots. - Enhanced screenshot saving logic to track changes and source integration metadata. - Created documentation for Heretto screenshot sync feature, detailing the upload process and architecture. - Updated resolver to build file mappings and handle Heretto-specific configurations. - Introduced utility functions to find Heretto integrations based on file paths. - Added error handling and logging for upload operations to improve reliability. --- src/integrations/heretto.js | 260 ++++++++++++++++++++++++++++++++++++ src/integrations/index.js | 231 ++++++++++++++++++++++++++++++++ src/tests.js | 19 +++ src/tests/saveScreenshot.js | 24 +++- 4 files changed, 533 insertions(+), 1 deletion(-) create mode 100644 src/integrations/heretto.js create mode 100644 src/integrations/index.js diff --git a/src/integrations/heretto.js b/src/integrations/heretto.js new file mode 100644 index 0000000..3393590 --- /dev/null +++ b/src/integrations/heretto.js @@ -0,0 +1,260 @@ +/** + * Heretto CMS uploader - handles uploading files back to Heretto CMS. + */ + +const fs = require("fs"); +const path = require("path"); +const https = require("https"); +const http = require("http"); +const { URL } = require("url"); + +/** + * Heretto uploader class implementing the uploader interface. + */ +class HerettoUploader { + /** + * Checks if this uploader can handle the given source integration. + * @param {Object} sourceIntegration - Source integration metadata + * @returns {boolean} True if this uploader handles Heretto integrations + */ + canHandle(sourceIntegration) { + return sourceIntegration?.type === "heretto"; + } + + /** + * Uploads a file to Heretto CMS. + * @param {Object} options - Upload options + * @param {Object} options.config - Doc Detective config + * @param {Object} options.integrationConfig - Heretto integration config + * @param {string} options.localFilePath - Local file path to upload + * @param {Object} options.sourceIntegration - Source integration metadata + * @param {Function} options.log - Logging function + * @returns {Promise} Upload result with status and description + */ + async upload({ config, integrationConfig, localFilePath, sourceIntegration, log }) { + const result = { + status: "FAIL", + description: "", + }; + + // Validate we have the necessary configuration + if (!integrationConfig) { + result.description = "No Heretto integration configuration found"; + return result; + } + + if (!integrationConfig.apiBaseUrl || !integrationConfig.apiToken) { + result.description = "Heretto integration missing apiBaseUrl or apiToken"; + return result; + } + + // Resolve the file ID + let fileId = sourceIntegration.fileId; + + if (!fileId) { + log(config, "debug", `No fileId found, searching for file by path: ${sourceIntegration.filePath}`); + + try { + fileId = await this.searchFileByName({ + apiBaseUrl: integrationConfig.apiBaseUrl, + apiToken: integrationConfig.apiToken, + username: integrationConfig.username || "", + filename: path.basename(sourceIntegration.filePath), + log: (level, msg) => log(config, level, msg), + }); + + if (!fileId) { + result.description = `Could not find file in Heretto: ${sourceIntegration.filePath}`; + return result; + } + } catch (error) { + result.description = `Error searching for file: ${error.message}`; + return result; + } + } + + // Read the local file + if (!fs.existsSync(localFilePath)) { + result.description = `Local file not found: ${localFilePath}`; + return result; + } + + const fileContent = fs.readFileSync(localFilePath); + const contentType = this.getContentType(localFilePath); + + // Upload to Heretto + try { + await this.uploadFile({ + apiBaseUrl: integrationConfig.apiBaseUrl, + apiToken: integrationConfig.apiToken, + username: integrationConfig.username || "", + documentId: fileId, + content: fileContent, + contentType, + log: (level, msg) => log(config, level, msg), + }); + + result.status = "PASS"; + result.description = `Successfully uploaded to Heretto (document ID: ${fileId})`; + } catch (error) { + result.description = `Upload failed: ${error.message}`; + } + + return result; + } + + /** + * Searches for a file in Heretto by filename. + * @param {Object} options - Search options + * @returns {Promise} Document ID if found, null otherwise + */ + async searchFileByName({ apiBaseUrl, apiToken, username, filename, log }) { + const searchUrl = new URL("/ezdnxtgen/api/search", apiBaseUrl); + + const searchBody = JSON.stringify({ + queryString: filename, + searchResultType: "FILES", + }); + + return new Promise((resolve, reject) => { + const protocol = searchUrl.protocol === "https:" ? https : http; + const authString = Buffer.from(`${username}:${apiToken}`).toString("base64"); + + const options = { + hostname: searchUrl.hostname, + port: searchUrl.port || (searchUrl.protocol === "https:" ? 443 : 80), + path: searchUrl.pathname, + method: "POST", + headers: { + "Content-Type": "application/json", + "Authorization": `Basic ${authString}`, + "Content-Length": Buffer.byteLength(searchBody), + }, + }; + + const req = protocol.request(options, (res) => { + let data = ""; + + res.on("data", (chunk) => { + data += chunk; + }); + + res.on("end", () => { + if (res.statusCode >= 200 && res.statusCode < 300) { + try { + const result = JSON.parse(data); + // Find the matching file in results + if (result.searchResults && result.searchResults.length > 0) { + // Look for exact filename match + const match = result.searchResults.find( + (r) => r.name === filename || r.title === filename + ); + if (match) { + resolve(match.uuid || match.id); + } else { + // Take first result as fallback + resolve(result.searchResults[0].uuid || result.searchResults[0].id); + } + } else { + resolve(null); + } + } catch (parseError) { + reject(new Error(`Failed to parse search response: ${parseError.message}`)); + } + } else { + reject(new Error(`Search request failed with status ${res.statusCode}: ${data}`)); + } + }); + }); + + req.on("error", (error) => { + reject(new Error(`Search request error: ${error.message}`)); + }); + + req.write(searchBody); + req.end(); + }); + } + + /** + * Uploads file content to Heretto. + * @param {Object} options - Upload options + * @returns {Promise} + */ + async uploadFile({ apiBaseUrl, apiToken, username, documentId, content, contentType, log }) { + const uploadUrl = new URL(`/rest/all-files/${documentId}/content`, apiBaseUrl); + + return new Promise((resolve, reject) => { + const protocol = uploadUrl.protocol === "https:" ? https : http; + const authString = Buffer.from(`${username}:${apiToken}`).toString("base64"); + + const options = { + hostname: uploadUrl.hostname, + port: uploadUrl.port || (uploadUrl.protocol === "https:" ? 443 : 80), + path: uploadUrl.pathname, + method: "PUT", + headers: { + "Content-Type": contentType, + "Authorization": `Basic ${authString}`, + "Content-Length": Buffer.byteLength(content), + }, + }; + + log("debug", `Uploading to ${uploadUrl.toString()}`); + + const req = protocol.request(options, (res) => { + let data = ""; + + res.on("data", (chunk) => { + data += chunk; + }); + + res.on("end", () => { + if (res.statusCode >= 200 && res.statusCode < 300) { + log("debug", `Upload successful: ${res.statusCode}`); + resolve(); + } else { + reject(new Error(`Upload failed with status ${res.statusCode}: ${data}`)); + } + }); + }); + + req.on("error", (error) => { + reject(new Error(`Upload request error: ${error.message}`)); + }); + + req.write(content); + req.end(); + }); + } + + /** + * Determines the content type based on file extension. + * @param {string} filePath - File path + * @returns {string} MIME content type + */ + getContentType(filePath) { + const ext = path.extname(filePath).toLowerCase(); + + const contentTypes = { + ".png": "image/png", + ".jpg": "image/jpeg", + ".jpeg": "image/jpeg", + ".gif": "image/gif", + ".svg": "image/svg+xml", + ".webp": "image/webp", + ".bmp": "image/bmp", + ".ico": "image/x-icon", + ".pdf": "application/pdf", + ".xml": "application/xml", + ".dita": "application/xml", + ".ditamap": "application/xml", + }; + + return contentTypes[ext] || "application/octet-stream"; + } +} + +module.exports = { + HerettoUploader, +}; diff --git a/src/integrations/index.js b/src/integrations/index.js new file mode 100644 index 0000000..847cc66 --- /dev/null +++ b/src/integrations/index.js @@ -0,0 +1,231 @@ +/** + * Integration uploader module - provides extensible file upload capability + * for different CMS integrations. + * + * Each integration uploader implements a common interface: + * - canHandle(sourceIntegration) - returns true if this uploader handles the integration type + * - upload({ config, localFilePath, sourceIntegration, log }) - uploads the file + */ + +const { HerettoUploader } = require("./heretto"); + +// Registry of available uploaders +const uploaders = [ + new HerettoUploader(), +]; + +/** + * Finds the appropriate uploader for a given source integration. + * @param {Object} sourceIntegration - Source integration metadata from step result + * @returns {Object|null} Uploader instance or null if none found + */ +function getUploader(sourceIntegration) { + if (!sourceIntegration?.type) return null; + + for (const uploader of uploaders) { + if (uploader.canHandle(sourceIntegration)) { + return uploader; + } + } + + return null; +} + +/** + * Collects all changed files from a test report that have source integrations. + * @param {Object} report - Test execution report + * @returns {Array} Array of { localPath, sourceIntegration } objects + */ +function collectChangedFiles(report) { + const changedFiles = []; + + if (!report?.specs) return changedFiles; + + for (const spec of report.specs) { + for (const test of spec.tests || []) { + for (const context of test.contexts || []) { + for (const step of context.steps || []) { + // Check if this step has a changed screenshot with source integration + if ( + step.screenshot && + step.outputs?.changed === true && + step.outputs?.sourceIntegration + ) { + changedFiles.push({ + localPath: step.outputs.screenshotPath, + sourceIntegration: step.outputs.sourceIntegration, + stepId: step.stepId, + testId: test.testId, + specId: spec.specId, + }); + } + } + } + } + } + + return changedFiles; +} + +/** + * Uploads all changed files back to their source integrations. + * Uses best-effort approach - continues uploading even if individual uploads fail. + * @param {Object} options - Upload options + * @param {Object} options.config - Doc Detective config + * @param {Object} options.report - Test execution report + * @param {Function} options.log - Logging function + * @returns {Promise} Upload results summary + */ +async function uploadChangedFiles({ config, report, log }) { + const results = { + total: 0, + successful: 0, + failed: 0, + skipped: 0, + details: [], + }; + + const changedFiles = collectChangedFiles(report); + results.total = changedFiles.length; + + if (changedFiles.length === 0) { + log(config, "debug", "No changed files to upload."); + return results; + } + + log(config, "info", `Found ${changedFiles.length} changed file(s) to upload.`); + + for (const file of changedFiles) { + const uploader = getUploader(file.sourceIntegration); + + if (!uploader) { + log( + config, + "warning", + `No uploader found for integration type: ${file.sourceIntegration.type}` + ); + results.skipped++; + results.details.push({ + localPath: file.localPath, + status: "SKIPPED", + reason: `No uploader for type: ${file.sourceIntegration.type}`, + }); + continue; + } + + // Get the integration config for API credentials + const integrationConfig = getIntegrationConfig( + config, + file.sourceIntegration + ); + + if (!integrationConfig) { + log( + config, + "warning", + `No integration config found for: ${file.sourceIntegration.integrationName}` + ); + results.skipped++; + results.details.push({ + localPath: file.localPath, + status: "SKIPPED", + reason: `No integration config found for: ${file.sourceIntegration.integrationName}`, + }); + continue; + } + + try { + log( + config, + "info", + `Uploading ${file.localPath} to ${file.sourceIntegration.type}...` + ); + + const uploadResult = await uploader.upload({ + config, + integrationConfig, + localFilePath: file.localPath, + sourceIntegration: file.sourceIntegration, + log, + }); + + if (uploadResult.status === "PASS") { + results.successful++; + log(config, "info", `Successfully uploaded: ${file.localPath}`); + } else { + results.failed++; + log( + config, + "warning", + `Failed to upload ${file.localPath}: ${uploadResult.description}` + ); + } + + results.details.push({ + localPath: file.localPath, + status: uploadResult.status, + description: uploadResult.description, + }); + } catch (error) { + results.failed++; + log( + config, + "warning", + `Error uploading ${file.localPath}: ${error.message}` + ); + results.details.push({ + localPath: file.localPath, + status: "FAIL", + description: error.message, + }); + } + } + + log( + config, + "info", + `Upload complete: ${results.successful} successful, ${results.failed} failed, ${results.skipped} skipped` + ); + + return results; +} + +/** + * Gets the integration configuration for a source integration. + * @param {Object} config - Doc Detective config + * @param {Object} sourceIntegration - Source integration metadata + * @returns {Object|null} Integration configuration or null if not found + */ +function getIntegrationConfig(config, sourceIntegration) { + if (!sourceIntegration?.type || !sourceIntegration?.integrationName) { + return null; + } + + switch (sourceIntegration.type) { + case "heretto": + return config?.integrations?.heretto?.find( + (h) => h.name === sourceIntegration.integrationName + ); + default: + return null; + } +} + +/** + * Registers a new uploader. + * @param {Object} uploader - Uploader instance implementing canHandle and upload methods + */ +function registerUploader(uploader) { + if (typeof uploader.canHandle !== "function" || typeof uploader.upload !== "function") { + throw new Error("Uploader must implement canHandle and upload methods"); + } + uploaders.push(uploader); +} + +module.exports = { + getUploader, + collectChangedFiles, + uploadChangedFiles, + getIntegrationConfig, + registerUploader, +}; diff --git a/src/tests.js b/src/tests.js index 5787966..39eb9c8 100644 --- a/src/tests.js +++ b/src/tests.js @@ -26,6 +26,7 @@ const { randomUUID } = require("crypto"); const { setAppiumHome } = require("./appium"); const { resolveExpression } = require("./expressions"); const { getEnvironment, getAvailableApps } = require("./config"); +const { uploadChangedFiles } = require("./integrations"); exports.runSpecs = runSpecs; exports.runViaApi = runViaApi; @@ -797,6 +798,24 @@ async function runSpecs({ resolvedTests }) { kill(appium.pid); } + // Upload changed files back to source integrations (best-effort) + // This automatically syncs any changed screenshots back to their source CMS + if (config?.integrations?.heretto?.length > 0) { + try { + const uploadResults = await uploadChangedFiles({ config, report, log }); + report.uploadResults = uploadResults; + } catch (error) { + log(config, "warning", `Failed to upload changed files: ${error.message}`); + report.uploadResults = { + total: 0, + successful: 0, + failed: 0, + skipped: 0, + error: error.message, + }; + } + } + return report; } diff --git a/src/tests/saveScreenshot.js b/src/tests/saveScreenshot.js index b339df6..fa55e7e 100644 --- a/src/tests/saveScreenshot.js +++ b/src/tests/saveScreenshot.js @@ -21,7 +21,9 @@ async function saveScreenshot({ config, step, driver }) { let result = { status: "PASS", description: "Saved screenshot.", - outputs: {}, + outputs: { + changed: false, // Indicates if screenshot was changed/replaced + }, }; let element; @@ -362,11 +364,22 @@ async function saveScreenshot({ config, step, driver }) { )}) is greater than the max accepted variation (${ step.screenshot.maxVariation }).`; + result.outputs.changed = true; + result.outputs.screenshotPath = existFilePath; + // Preserve sourceIntegration metadata for upload processing + if (step.screenshot.sourceIntegration) { + result.outputs.sourceIntegration = step.screenshot.sourceIntegration; + } return result; } else { result.description += ` Screenshots are within maximum accepted variation: ${fractionalDiff.toFixed( 2 )}.`; + result.outputs.screenshotPath = existFilePath; + // Preserve sourceIntegration metadata + if (step.screenshot.sourceIntegration) { + result.outputs.sourceIntegration = step.screenshot.sourceIntegration; + } if (step.screenshot.overwrite != "true") { fs.unlinkSync(filePath); } @@ -374,6 +387,15 @@ async function saveScreenshot({ config, step, driver }) { } } + // Set output path for new screenshots + if (!result.outputs.screenshotPath) { + result.outputs.screenshotPath = filePath; + // Preserve sourceIntegration metadata + if (step.screenshot.sourceIntegration) { + result.outputs.sourceIntegration = step.screenshot.sourceIntegration; + } + } + // PASS return result; } From 1c20c0eafaae7870c4fc0858f2fb5858f1efe431 Mon Sep 17 00:00:00 2001 From: hawkeyexl Date: Mon, 22 Dec 2025 15:40:40 -0800 Subject: [PATCH 2/9] Implement screenshot handling and upload functionality - Update `saveScreenshot.js` to mark new screenshots as changed for upload. - Add a new test file `screenshot.test.js` to verify sourceIntegration preservation and changed status for screenshots. - Create a new test file `upload.test.js` to validate the upload module, including collecting changed files and integration configuration. - Modify `package-lock.json` to link to local `doc-detective-common` instead of a versioned package. - Enhance `heretto.js` to retrieve resource dependencies from the Heretto REST API, including detailed logging and XML parsing. --- dev/index.js | 2 + package-lock.json | 777 +++++++----------------------------- package.json | 4 +- src/integrations/heretto.js | 469 +++++++++++++++++++++- src/tests/saveScreenshot.js | 2 + test/screenshot.test.js | 273 +++++++++++++ test/upload.test.js | 641 +++++++++++++++++++++++++++++ 7 files changed, 1527 insertions(+), 641 deletions(-) create mode 100644 test/screenshot.test.js create mode 100644 test/upload.test.js diff --git a/dev/index.js b/dev/index.js index deb49b7..2fc5bd7 100644 --- a/dev/index.js +++ b/dev/index.js @@ -8,6 +8,7 @@ require("dotenv").config({ path: path.join(__dirname, ".env") }); async function main() { const json = { input: ["heretto:example"], + // input: ["c:\\Users\\hawkeyexl\\AppData\\Local\\Temp\\doc-detective\\heretto_c96e625d5c1ee50972362046445a5ca4\\ot-output\\dita\\_topics\\espresso.dita"], logLevel: "debug", runOn: [ { @@ -30,6 +31,7 @@ async function main() { organizationId: process.env.HERETTO_ORG_ID, // Organization ID is the subdomain of your Heretto instance (e.g., "silva" for "silva.heretto.com") username: process.env.HERETTO_USERNAME, // Your Heretto username/email apiToken: process.env.HERETTO_TOKEN, // Your Heretto API token (https://help.heretto.com/en/heretto-ccms/api/ccms-api-authentication/basic-authentication) + uploadOnChange: true, // Upload changed screenshots back to Heretto }, ], }, diff --git a/package-lock.json b/package-lock.json index 25b9037..8e6989c 100644 --- a/package-lock.json +++ b/package-lock.json @@ -19,8 +19,8 @@ "appium-geckodriver": "^2.1.4", "appium-safari-driver": "^4.1.4", "axios": "^1.13.2", - "doc-detective-common": "3.6.0-dev.1", - "doc-detective-resolver": "3.6.1-dev.1", + "doc-detective-common": "file:../common", + "doc-detective-resolver": "file:../resolver", "dotenv": "^17.2.3", "geckodriver": "^6.1.0", "jq-web": "^0.6.2", @@ -72,6 +72,51 @@ "@img/sharp-win32-x64": "^0.34.5" } }, + "../common": { + "name": "doc-detective-common", + "version": "3.6.0-dev.1", + "license": "AGPL-3.0-only", + "dependencies": { + "@apidevtools/json-schema-ref-parser": "^15.1.3", + "ajv": "^8.17.1", + "ajv-errors": "^3.0.0", + "ajv-formats": "^3.0.1", + "ajv-keywords": "^5.1.0", + "axios": "^1.13.2", + "yaml": "^2.8.2" + }, + "devDependencies": { + "chai": "^6.2.1", + "mocha": "^11.7.5", + "sinon": "^21.0.0" + } + }, + "../resolver": { + "name": "doc-detective-resolver", + "version": "3.6.1-dev.1", + "license": "AGPL-3.0-only", + "dependencies": { + "@apidevtools/json-schema-ref-parser": "^15.1.3", + "adm-zip": "^0.5.16", + "ajv": "^8.17.1", + "axios": "^1.13.2", + "doc-detective-common": "file:../common", + "dotenv": "^17.2.3", + "fast-xml-parser": "^5.3.3", + "json-schema-faker": "^0.5.9", + "posthog-node": "^5.17.2" + }, + "devDependencies": { + "body-parser": "^2.2.1", + "chai": "^6.2.1", + "express": "^5.2.1", + "mocha": "^11.7.5", + "proxyquire": "^2.1.3", + "semver": "^7.7.3", + "sinon": "^21.0.0", + "yaml": "^2.8.2" + } + }, "node_modules/@apidevtools/json-schema-ref-parser": { "version": "15.1.3", "license": "MIT", @@ -1579,15 +1624,6 @@ "node": ">= 0.6" } }, - "node_modules/adm-zip": { - "version": "0.5.16", - "resolved": "https://registry.npmjs.org/adm-zip/-/adm-zip-0.5.16.tgz", - "integrity": "sha512-TGw5yVi4saajsSEgz25grObGHEUaDrniwvA2qwSC060KfqGPdglhvPMA2lPIoxs3PQIItj2iag35fONcQqgUaQ==", - "license": "MIT", - "engines": { - "node": ">=12.0" - } - }, "node_modules/agent-base": { "version": "7.1.4", "license": "MIT", @@ -1598,6 +1634,7 @@ "node_modules/ajv": { "version": "8.17.1", "license": "MIT", + "peer": true, "dependencies": { "fast-deep-equal": "^3.1.3", "fast-uri": "^3.0.1", @@ -1609,13 +1646,6 @@ "url": "https://github.com/sponsors/epoberezkin" } }, - "node_modules/ajv-errors": { - "version": "3.0.0", - "license": "MIT", - "peerDependencies": { - "ajv": "^8.0.1" - } - }, "node_modules/ajv-formats": { "version": "3.0.1", "license": "MIT", @@ -1631,16 +1661,6 @@ } } }, - "node_modules/ajv-keywords": { - "version": "5.1.0", - "license": "MIT", - "dependencies": { - "fast-deep-equal": "^3.1.3" - }, - "peerDependencies": { - "ajv": "^8.8.2" - } - }, "node_modules/ansi-regex": { "version": "6.2.2", "license": "MIT", @@ -1670,6 +1690,7 @@ "integrity": "sha512-MIifVZdSLdFBRY084PaaQyU8ilG+fgGoVdzGkRLj9Q8hZ2x/ENwjiOveyWLxcjsWMYYwUtm3TTKRvWGrJvX3Iw==", "hasInstallScript": true, "license": "Apache-2.0", + "peer": true, "dependencies": { "@appium/base-driver": "^10.1.2", "@appium/base-plugin": "^3.0.5", @@ -6091,7 +6112,6 @@ "resolved": "https://registry.npmjs.org/@appium/base-driver/-/base-driver-10.1.2.tgz", "integrity": "sha512-AxCYznylRw4xpOx30dAIQ8m5GsVM9ob/MPwc/KyiKhtofLNxQQlFLvLs7SeX7s8iwvwr0puMasOqlWrWy3gVbA==", "license": "Apache-2.0", - "peer": true, "dependencies": { "@appium/support": "^7.0.4", "@appium/types": "^1.1.2", @@ -6126,7 +6146,6 @@ "resolved": "https://registry.npmjs.org/@appium/base-plugin/-/base-plugin-3.0.5.tgz", "integrity": "sha512-w27EqXQ3zY7xKp61IizbzhZGlxQvFr8uKxeELP5TU/+YxnjU8MyVYmWCG7RXp0dh9n7mZen/WPjZtvqdiBOsMQ==", "license": "Apache-2.0", - "peer": true, "dependencies": { "@appium/base-driver": "^10.1.2", "@appium/support": "^7.0.4" @@ -6141,7 +6160,6 @@ "resolved": "https://registry.npmjs.org/@appium/docutils/-/docutils-2.2.0.tgz", "integrity": "sha512-bwZIShYLRnWCRdGEgjBX+POXyI0X8fbZ3FNHWDlNzYjCBodYckiMw8X48WDwMRd0AeP5mzjBbHSpH7DKfebuFg==", "license": "Apache-2.0", - "peer": true, "dependencies": { "@appium/support": "^7.0.4", "chalk": "4.1.2", @@ -6171,7 +6189,6 @@ "resolved": "https://registry.npmjs.org/teen_process/-/teen_process-3.0.4.tgz", "integrity": "sha512-NQA/5PdJWEAxuYoBRW7RajnAyWmfh5iGMY1kEXiAzobtv0ztERcfDnfszpUTuvhFXrvh3E4GvHt9yWbS/EndzQ==", "license": "Apache-2.0", - "peer": true, "dependencies": { "bluebird": "^3.7.2", "lodash": "^4.17.21", @@ -6345,7 +6362,6 @@ "resolved": "https://registry.npmjs.org/@dabh/diagnostics/-/diagnostics-2.0.8.tgz", "integrity": "sha512-R4MSXTVnuMzGD7bzHdW2ZhhdPC/igELENcq5IjEverBvq5hn1SXCWcsi6eSsdWP0/Ur+SItRRjAktmdoX/8R/Q==", "license": "MIT", - "peer": true, "dependencies": { "@so-ric/colorspace": "^1.1.6", "enabled": "2.0.x", @@ -6547,7 +6563,6 @@ "resolved": "https://registry.npmjs.org/@sidvind/better-ajv-errors/-/better-ajv-errors-4.0.1.tgz", "integrity": "sha512-6arF1ssKxItxgitPYXafUoLmsVBA6K7m9+ZGj6hLDoBl7nWpJ33EInwQUdHTle2METeWGxgQiqSex20KZRykew==", "license": "Apache-2.0", - "peer": true, "dependencies": { "kleur": "^4.1.0" }, @@ -6563,7 +6578,6 @@ "resolved": "https://registry.npmjs.org/@so-ric/colorspace/-/colorspace-1.1.6.tgz", "integrity": "sha512-/KiKkpHNOBgkFJwu9sh48LkHSMYGyuTcSFK/qMBdnOAlrRJzRSXAOFB5qwzaVQuDl8wAvHVMkaASQDReTahxuw==", "license": "MIT", - "peer": true, "dependencies": { "color": "^5.0.2", "text-hex": "1.0.x" @@ -6585,8 +6599,7 @@ "version": "1.3.5", "resolved": "https://registry.npmjs.org/@types/triple-beam/-/triple-beam-1.3.5.tgz", "integrity": "sha512-6WaYesThRMCl19iryMYP7/x2OVgCtbIVflDGFpWnb9irXI3UjYE4AzmYuiUKY1AJstGijoY+MgUszMgRxIYTYw==", - "license": "MIT", - "peer": true + "license": "MIT" }, "node_modules/appium-geckodriver/node_modules/@xmldom/xmldom": { "version": "0.8.11", @@ -6614,7 +6627,6 @@ "resolved": "https://registry.npmjs.org/accepts/-/accepts-2.0.0.tgz", "integrity": "sha512-5cvg6CtKwfgdmVqY1WIiXKc3Q1bkRqGLi+2W/6ao+6Y7gu/RCwRuAhGEzh5B4KlszSuTLgZYuqFqo5bImjNKng==", "license": "MIT", - "peer": true, "dependencies": { "mime-types": "^3.0.0", "negotiator": "^1.0.0" @@ -6628,7 +6640,6 @@ "resolved": "https://registry.npmjs.org/ajv-formats/-/ajv-formats-3.0.1.tgz", "integrity": "sha512-8iUql50EUR+uUcdRQ3HDqa6EVyo3docL8g5WJ3FNcWmu62IbkGUue/pEyLBW8VGKKucTPgqeks4fIU1DA4yowQ==", "license": "MIT", - "peer": true, "dependencies": { "ajv": "^8.0.0" }, @@ -6674,7 +6685,6 @@ "integrity": "sha512-MIifVZdSLdFBRY084PaaQyU8ilG+fgGoVdzGkRLj9Q8hZ2x/ENwjiOveyWLxcjsWMYYwUtm3TTKRvWGrJvX3Iw==", "hasInstallScript": true, "license": "Apache-2.0", - "peer": true, "dependencies": { "@appium/base-driver": "^10.1.2", "@appium/base-plugin": "^3.0.5", @@ -6740,7 +6750,6 @@ "resolved": "https://registry.npmjs.org/teen_process/-/teen_process-3.0.4.tgz", "integrity": "sha512-NQA/5PdJWEAxuYoBRW7RajnAyWmfh5iGMY1kEXiAzobtv0ztERcfDnfszpUTuvhFXrvh3E4GvHt9yWbS/EndzQ==", "license": "Apache-2.0", - "peer": true, "dependencies": { "bluebird": "^3.7.2", "lodash": "^4.17.21", @@ -6858,8 +6867,7 @@ "version": "2.0.1", "resolved": "https://registry.npmjs.org/argparse/-/argparse-2.0.1.tgz", "integrity": "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==", - "license": "Python-2.0", - "peer": true + "license": "Python-2.0" }, "node_modules/appium-geckodriver/node_modules/async": { "version": "3.2.6", @@ -6969,7 +6977,6 @@ "resolved": "https://registry.npmjs.org/basic-auth/-/basic-auth-2.0.1.tgz", "integrity": "sha512-NF+epuEdnUYVlGuhaxbbq+dvJttwLnGY+YixlXlME5KpQ5W3CnXA5cVTneY3SPbPDRkcjMbifrwmFYcClgOZeg==", "license": "MIT", - "peer": true, "dependencies": { "safe-buffer": "5.1.2" }, @@ -6991,7 +6998,6 @@ "resolved": "https://registry.npmjs.org/bl/-/bl-4.1.0.tgz", "integrity": "sha512-1W07cM9gS6DcLperZfFSj+bWLtaPGSOHWhPiGzXmvVJbRLdG82sH/Kn8EtW1VqWVA54AKf2h5k5BbnIbwF3h6w==", "license": "MIT", - "peer": true, "dependencies": { "buffer": "^5.5.0", "inherits": "^2.0.4", @@ -7003,7 +7009,6 @@ "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.2.tgz", "integrity": "sha512-9u/sniCrY3D5WdsERHzHE4G2YCXqoG5FTHUiCC4SIbr6XcLZBY05ya9EKjYek9O5xOAwjGq+1JdGBAS7Q9ScoA==", "license": "MIT", - "peer": true, "dependencies": { "inherits": "^2.0.3", "string_decoder": "^1.1.1", @@ -7024,7 +7029,6 @@ "resolved": "https://registry.npmjs.org/body-parser/-/body-parser-2.2.1.tgz", "integrity": "sha512-nfDwkulwiZYQIGwxdy0RUmowMhKcFVcYXUU7m4QlKYim1rUtg83xm2yjZ40QjDuc291AJjjeSc9b++AWHSgSHw==", "license": "MIT", - "peer": true, "dependencies": { "bytes": "^3.1.2", "content-type": "^1.0.5", @@ -7084,7 +7088,6 @@ } ], "license": "MIT", - "peer": true, "dependencies": { "base64-js": "^1.3.1", "ieee754": "^1.1.13" @@ -7110,7 +7113,6 @@ "resolved": "https://registry.npmjs.org/bytes/-/bytes-3.1.2.tgz", "integrity": "sha512-/Nf7TyzTx6S3yRJObOAV7956r8cr2+Oj8AC5dt8wSP3BQAoeX58NoHyCU8P8zGkNXStjTSi6fzO6F0pBdcYbEg==", "license": "MIT", - "peer": true, "engines": { "node": ">= 0.8" } @@ -7133,7 +7135,6 @@ "resolved": "https://registry.npmjs.org/call-bound/-/call-bound-1.0.4.tgz", "integrity": "sha512-+ys997U96po4Kx/ABpBCqhA9EuxJaQWDQg7295H4hBphv3IZg0boBKuwYpt4YXp6MZ5AmZQnU/tyMTlRpaSejg==", "license": "MIT", - "peer": true, "dependencies": { "call-bind-apply-helpers": "^1.0.2", "get-intrinsic": "^1.3.0" @@ -7178,7 +7179,6 @@ "resolved": "https://registry.npmjs.org/cli-cursor/-/cli-cursor-3.1.0.tgz", "integrity": "sha512-I/zHAwsKf9FqGoXM4WWRACob9+SNukZTd94DWF57E4toouRulbCxcUh6RKUEOQlYTHJnzkPMySvPNaaSLNfLZw==", "license": "MIT", - "peer": true, "dependencies": { "restore-cursor": "^3.1.0" }, @@ -7191,7 +7191,6 @@ "resolved": "https://registry.npmjs.org/cli-spinners/-/cli-spinners-2.9.2.tgz", "integrity": "sha512-ywqV+5MmyL4E7ybXgKys4DugZbX0FC6LnwrhjuykIjnK9k8OQacQ7axGKnjDXWNhns0xot3bZI5h55H8yo9cJg==", "license": "MIT", - "peer": true, "engines": { "node": ">=6" }, @@ -7204,7 +7203,6 @@ "resolved": "https://registry.npmjs.org/cliui/-/cliui-9.0.1.tgz", "integrity": "sha512-k7ndgKhwoQveBL+/1tqGJYNz097I7WOvwbmmU2AR5+magtbjPWQTS1C5vzGkBC8Ym8UWRzfKUzUUqFLypY4Q+w==", "license": "ISC", - "peer": true, "dependencies": { "string-width": "^7.2.0", "strip-ansi": "^7.1.0", @@ -7219,7 +7217,6 @@ "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-6.2.3.tgz", "integrity": "sha512-4Dj6M28JB+oAH8kFkTLUo+a2jwOFkuqb3yucU0CANcRRUbxS0cP0nZYCGjcc3BNXwRIsUVmDGgzawme7zvJHvg==", "license": "MIT", - "peer": true, "engines": { "node": ">=12" }, @@ -7231,15 +7228,13 @@ "version": "10.6.0", "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-10.6.0.tgz", "integrity": "sha512-toUI84YS5YmxW219erniWD0CIVOo46xGKColeNQRgOzDorgBi1v4D71/OFzgD9GO2UGKIv1C3Sp8DAn0+j5w7A==", - "license": "MIT", - "peer": true + "license": "MIT" }, "node_modules/appium-geckodriver/node_modules/cliui/node_modules/string-width": { "version": "7.2.0", "resolved": "https://registry.npmjs.org/string-width/-/string-width-7.2.0.tgz", "integrity": "sha512-tsaTIkKW9b4N+AEj+SVA+WhJzV7/zMhcSu78mLKWSk7cXMOSHsBKFWUs0fWwq8QyK3MgJBQRX6Gbi4kYbdvGkQ==", "license": "MIT", - "peer": true, "dependencies": { "emoji-regex": "^10.3.0", "get-east-asian-width": "^1.0.0", @@ -7257,7 +7252,6 @@ "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-7.1.2.tgz", "integrity": "sha512-gmBGslpoQJtgnMAvOVqGZpEz9dyoKTCzy2nfz/n8aIFhN/jCE/rCmcxabB6jOOHV+0WNnylOxaxBQPSvcWklhA==", "license": "MIT", - "peer": true, "dependencies": { "ansi-regex": "^6.0.1" }, @@ -7273,7 +7267,6 @@ "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-9.0.2.tgz", "integrity": "sha512-42AtmgqjV+X1VpdOfyTGOYRi0/zsoLqtXQckTmqTeybT+BDIbM/Guxo7x3pE2vtpr1ok6xRqM9OpBe+Jyoqyww==", "license": "MIT", - "peer": true, "dependencies": { "ansi-styles": "^6.2.1", "string-width": "^7.0.0", @@ -7291,7 +7284,6 @@ "resolved": "https://registry.npmjs.org/clone/-/clone-1.0.4.tgz", "integrity": "sha512-JQHZ2QMW6l3aH/j6xCqQThY/9OH4D/9ls34cgkUBiEeocRTU04tHfKPBsUK1PqZCUQM7GiA0IIXJSuXHI64Kbg==", "license": "MIT", - "peer": true, "engines": { "node": ">=0.8" } @@ -7301,7 +7293,6 @@ "resolved": "https://registry.npmjs.org/color/-/color-5.0.3.tgz", "integrity": "sha512-ezmVcLR3xAVp8kYOm4GS45ZLLgIE6SPAFoduLr6hTDajwb3KZ2F46gulK3XpcwRFb5KKGCSezCBAY4Dw4HsyXA==", "license": "MIT", - "peer": true, "dependencies": { "color-convert": "^3.1.3", "color-string": "^2.1.3" @@ -7333,7 +7324,6 @@ "resolved": "https://registry.npmjs.org/color-string/-/color-string-2.1.4.tgz", "integrity": "sha512-Bb6Cq8oq0IjDOe8wJmi4JeNn763Xs9cfrBcaylK1tPypWzyoy2G3l90v9k64kjphl/ZJjPIShFztenRomi8WTg==", "license": "MIT", - "peer": true, "dependencies": { "color-name": "^2.0.0" }, @@ -7346,7 +7336,6 @@ "resolved": "https://registry.npmjs.org/color-name/-/color-name-2.1.0.tgz", "integrity": "sha512-1bPaDNFm0axzE4MEAzKPuqKWeRaT43U/hyxKPBdqTfmPF+d6n7FSoTFxLVULUJOmiLp01KjhIPPH+HrXZJN4Rg==", "license": "MIT", - "peer": true, "engines": { "node": ">=12.20" } @@ -7356,7 +7345,6 @@ "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-3.1.3.tgz", "integrity": "sha512-fasDH2ont2GqF5HpyO4w0+BcewlhHEZOFn9c1ckZdHpJ56Qb7MHhH/IcJZbBGgvdtwdwNbLvxiBEdg336iA9Sg==", "license": "MIT", - "peer": true, "dependencies": { "color-name": "^2.0.0" }, @@ -7369,7 +7357,6 @@ "resolved": "https://registry.npmjs.org/color-name/-/color-name-2.1.0.tgz", "integrity": "sha512-1bPaDNFm0axzE4MEAzKPuqKWeRaT43U/hyxKPBdqTfmPF+d6n7FSoTFxLVULUJOmiLp01KjhIPPH+HrXZJN4Rg==", "license": "MIT", - "peer": true, "engines": { "node": ">=12.20" } @@ -7391,7 +7378,6 @@ "resolved": "https://registry.npmjs.org/commander/-/commander-6.2.1.tgz", "integrity": "sha512-U7VdrJFnJgo4xjrHpTzu0yrHPGImdsmD95ZlgYSEajAn2JKzDhDTPG9kBTefmObL2w/ngeZnilk+OV9CG3d7UA==", "license": "MIT", - "peer": true, "engines": { "node": ">= 6" } @@ -7417,7 +7403,6 @@ "resolved": "https://registry.npmjs.org/consola/-/consola-3.4.2.tgz", "integrity": "sha512-5IKcdX0nnYavi6G7TtOhwkYzyjfJlatbjMjuLSfE2kYT5pMDOilZ4OvMhi637CcDICTmz3wARPoyhqyX1Y+XvA==", "license": "MIT", - "peer": true, "engines": { "node": "^14.18.0 || >=16.10.0" } @@ -7433,7 +7418,6 @@ "resolved": "https://registry.npmjs.org/content-disposition/-/content-disposition-1.0.1.tgz", "integrity": "sha512-oIXISMynqSqm241k6kcQ5UwttDILMK4BiurCfGEREw6+X9jkkpEe5T9FZaApyLGGOnFuyMWZpdolTXMtvEJ08Q==", "license": "MIT", - "peer": true, "engines": { "node": ">=18" }, @@ -7447,7 +7431,6 @@ "resolved": "https://registry.npmjs.org/content-type/-/content-type-1.0.5.tgz", "integrity": "sha512-nTjqfcBFEipKdXCv4YDQWCfmcLZKm81ldF0pAopTvyrFGVbcR6P/VAAd5G7N+0tTr8QqiU0tFadD6FK4NtJwOA==", "license": "MIT", - "peer": true, "engines": { "node": ">= 0.6" } @@ -7457,7 +7440,6 @@ "resolved": "https://registry.npmjs.org/cookie/-/cookie-0.7.2.tgz", "integrity": "sha512-yki5XnKuf750l50uGTllt6kKILY4nQ1eNIQatoXEByZ5dWgnKqbnqmTrBE5B4N7lrMJKQ2ytWMiTO2o0v6Ew/w==", "license": "MIT", - "peer": true, "engines": { "node": ">= 0.6" } @@ -7467,7 +7449,6 @@ "resolved": "https://registry.npmjs.org/cookie-signature/-/cookie-signature-1.2.2.tgz", "integrity": "sha512-D76uU73ulSXrD1UXF4KE2TMxVVwhsnCgfAyTg9k8P6KGZjlXKrOLe4dJQKI3Bxi5wjesZoFXJWElNWBjPZMbhg==", "license": "MIT", - "peer": true, "engines": { "node": ">=6.6.0" } @@ -7543,7 +7524,6 @@ "resolved": "https://registry.npmjs.org/debug/-/debug-4.4.3.tgz", "integrity": "sha512-RGwwWnwQvkVfavKVt22FGLw+xYSdzARwm0ru6DhTVA3umU5hZc28V3kO4stgYryrTlLpuvgI9GiijltAjNbcqA==", "license": "MIT", - "peer": true, "dependencies": { "ms": "^2.1.3" }, @@ -7561,7 +7541,6 @@ "resolved": "https://registry.npmjs.org/defaults/-/defaults-1.0.4.tgz", "integrity": "sha512-eFuaLoy/Rxalv2kr+lqMlUnrDWV+3j4pljOIJgLIhI058IQfWJ7vXhyEIHu+HtC738klGALYxOKDO0bQP3tg8A==", "license": "MIT", - "peer": true, "dependencies": { "clone": "^1.0.2" }, @@ -7583,7 +7562,6 @@ "resolved": "https://registry.npmjs.org/depd/-/depd-2.0.0.tgz", "integrity": "sha512-g7nH6P6dyDioJogAAGprGpCtVImJhpPk/roCzdb3fIh61/s/nPsfR6onyMwkCAR/OlC3yBC0lESvUoQEAssIrw==", "license": "MIT", - "peer": true, "engines": { "node": ">= 0.8" } @@ -7603,15 +7581,13 @@ "resolved": "https://registry.npmjs.org/detect-node/-/detect-node-2.1.0.tgz", "integrity": "sha512-T0NIuQpnTvFDATNuHN5roPwSBG83rFsuO+MXXH9/3N1eFbn4wcPjttvjMLEPWJ0RGUYgQE7cGgS3tNxbqCGM7g==", "license": "MIT", - "optional": true, - "peer": true + "optional": true }, "node_modules/appium-geckodriver/node_modules/diff": { "version": "8.0.2", "resolved": "https://registry.npmjs.org/diff/-/diff-8.0.2.tgz", "integrity": "sha512-sSuxWU5j5SR9QQji/o2qMvqRNYRDOcBTgsJ/DeCf4iSN4gW+gNMXM7wFIP+fdXZxoNiAnHUTGjCr+TSWXdRDKg==", "license": "BSD-3-Clause", - "peer": true, "engines": { "node": ">=0.3.1" } @@ -7646,8 +7622,7 @@ "version": "1.1.1", "resolved": "https://registry.npmjs.org/ee-first/-/ee-first-1.1.1.tgz", "integrity": "sha512-WMwm9LhRUo+WUaRN+vRuETqG89IgZphVSNkdFgeb6sS/E4OrDIN7t48CAewSHXc6C8lefD8KKfr5vY61brQlow==", - "license": "MIT", - "peer": true + "license": "MIT" }, "node_modules/appium-geckodriver/node_modules/emoji-regex": { "version": "8.0.0", @@ -7659,15 +7634,13 @@ "version": "2.0.0", "resolved": "https://registry.npmjs.org/enabled/-/enabled-2.0.0.tgz", "integrity": "sha512-AKrN98kuwOzMIdAizXGI86UFBoo26CL21UM763y1h/GMSJ4/OHU9k2YlsmBpyScFo/wbLzWQJBMCW4+IO3/+OQ==", - "license": "MIT", - "peer": true + "license": "MIT" }, "node_modules/appium-geckodriver/node_modules/encodeurl": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/encodeurl/-/encodeurl-2.0.0.tgz", "integrity": "sha512-Q0n9HRi4m6JuGIV1eFlmvJB7ZEVxu93IrMyiMsGC0lrMJMWzRgx6WGquyfQgZVb31vhGgXnfmPNNXmxnOkRBrg==", "license": "MIT", - "peer": true, "engines": { "node": ">= 0.8" } @@ -7731,7 +7704,6 @@ "resolved": "https://registry.npmjs.org/escalade/-/escalade-3.2.0.tgz", "integrity": "sha512-WUj2qlxaQtO4g6Pq5c29GTcWGDyd8itL8zTlipgECz3JesAiiOKotd8JU6otB3PACgG6xkJUyVhboMS+bje/jA==", "license": "MIT", - "peer": true, "engines": { "node": ">=6" } @@ -7740,15 +7712,13 @@ "version": "1.0.3", "resolved": "https://registry.npmjs.org/escape-html/-/escape-html-1.0.3.tgz", "integrity": "sha512-NiSupZ4OeuGwr68lGIeym/ksIZMJodUGOSCZ/FSnTxcrekbvqrgdUxlJOMpijaKZVjAJrWrGs/6Jy8OMuyj9ow==", - "license": "MIT", - "peer": true + "license": "MIT" }, "node_modules/appium-geckodriver/node_modules/etag": { "version": "1.8.1", "resolved": "https://registry.npmjs.org/etag/-/etag-1.8.1.tgz", "integrity": "sha512-aIL5Fx7mawVa300al2BnEE4iNvo1qETxLrPI/o05L7z6go7fCw1J6EQmbK4FmJ2AS7kgVF/KEZWufBfdClMcPg==", "license": "MIT", - "peer": true, "engines": { "node": ">= 0.6" } @@ -7785,7 +7755,6 @@ "resolved": "https://registry.npmjs.org/express/-/express-5.2.1.tgz", "integrity": "sha512-hIS4idWWai69NezIdRt2xFVofaF4j+6INOpJlVOLDO8zXGpUVEVzIYk12UUi2JzjEzWL3IOAxcTubgz9Po0yXw==", "license": "MIT", - "peer": true, "dependencies": { "accepts": "^2.0.0", "body-parser": "^2.2.1", @@ -7859,7 +7828,6 @@ "resolved": "https://registry.npmjs.org/fastest-levenshtein/-/fastest-levenshtein-1.0.16.tgz", "integrity": "sha512-eRnCtTTtGZFpQCwhJiUOuxPQWRXVKYDn0b2PeHfXL6/Zi53SLAzAHfVhVWK2AryC/WH05kGfxhFIPvTF0SXQzg==", "license": "MIT", - "peer": true, "engines": { "node": ">= 4.9.1" } @@ -7868,15 +7836,13 @@ "version": "4.2.3", "resolved": "https://registry.npmjs.org/fecha/-/fecha-4.2.3.tgz", "integrity": "sha512-OP2IUU6HeYKJi3i0z4A19kHMQoLVs4Hc+DPqqxI2h/DPZHTm/vjsfC6P0b4jCMy14XizLBqvndQ+UilD7707Jw==", - "license": "MIT", - "peer": true + "license": "MIT" }, "node_modules/appium-geckodriver/node_modules/finalhandler": { "version": "2.1.1", "resolved": "https://registry.npmjs.org/finalhandler/-/finalhandler-2.1.1.tgz", "integrity": "sha512-S8KoZgRZN+a5rNwqTxlZZePjT/4cnm0ROV70LedRHZ0p8u9fRID0hJUZQpkKLzro8LfmC8sx23bY6tVNxv8pQA==", "license": "MIT", - "peer": true, "dependencies": { "debug": "^4.4.0", "encodeurl": "^2.0.0", @@ -7913,8 +7879,7 @@ "version": "1.1.0", "resolved": "https://registry.npmjs.org/fn.name/-/fn.name-1.1.0.tgz", "integrity": "sha512-GRnmB5gPyJpAhTQdSZTSp9uaPSvl09KoYcMQtsB9rQoOmzs9dH6ffeccH+Z+cv6P68Hu5bC6JjRh4Ah/mHSNRw==", - "license": "MIT", - "peer": true + "license": "MIT" }, "node_modules/appium-geckodriver/node_modules/follow-redirects": { "version": "1.15.11", @@ -8006,7 +7971,6 @@ "resolved": "https://registry.npmjs.org/forwarded/-/forwarded-0.2.0.tgz", "integrity": "sha512-buRG0fpBtRHSTCOASe6hD258tEubFoRLb4ZNA6NxMVHNw2gOcwHo9wyablzMzOA5z9xA9L1KNjk/Nt6MT9aYow==", "license": "MIT", - "peer": true, "engines": { "node": ">= 0.6" } @@ -8016,7 +7980,6 @@ "resolved": "https://registry.npmjs.org/fresh/-/fresh-2.0.0.tgz", "integrity": "sha512-Rx/WycZ60HOaqLKAi6cHRKKI7zxWbJ31MhntmtwMoaTeF7XFH9hhBp8vITaMidfljRQ6eYWCKkaTK+ykVJHP2A==", "license": "MIT", - "peer": true, "engines": { "node": ">= 0.8" } @@ -8070,7 +8033,6 @@ "resolved": "https://registry.npmjs.org/get-caller-file/-/get-caller-file-2.0.5.tgz", "integrity": "sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg==", "license": "ISC", - "peer": true, "engines": { "node": "6.* || 8.* || >= 10.*" } @@ -8080,7 +8042,6 @@ "resolved": "https://registry.npmjs.org/get-east-asian-width/-/get-east-asian-width-1.4.0.tgz", "integrity": "sha512-QZjmEOC+IT1uk6Rx0sX22V6uHWVwbdbxf1faPqJ1QhLdGgsRGCZoyaQBm/piRdJy/D2um6hM1UP7ZEeQ4EkP+Q==", "license": "MIT", - "peer": true, "engines": { "node": ">=18" }, @@ -8192,8 +8153,7 @@ "resolved": "https://registry.npmjs.org/handle-thing/-/handle-thing-2.0.1.tgz", "integrity": "sha512-9Qn4yBxelxoh2Ow62nP+Ka/kMnOXRi8BXnRaUwezLNhqelnN49xKz4F/dPP8OYLxLxq6JDtZb2i9XznUQbNPTg==", "license": "MIT", - "optional": true, - "peer": true + "optional": true }, "node_modules/appium-geckodriver/node_modules/has-flag": { "version": "4.0.0", @@ -8255,7 +8215,6 @@ "integrity": "sha512-zJxVehUdMGIKsRaNt7apO2Gqp0BdqW5yaiGHXXmbpvxgBYVZnAql+BJb4RO5ad2MgpbZKn5G6nMnegrH1FcNYQ==", "license": "MIT", "optional": true, - "peer": true, "dependencies": { "inherits": "^2.0.1", "obuf": "^1.0.0", @@ -8268,8 +8227,7 @@ "resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz", "integrity": "sha512-VLghIWNM6ELQzo7zwmcg0NmTVyWKYjvIeM83yjp0wRDTmUnrM678fQbcKBo6n2CJEF0szoG//ytg+TKla89ALQ==", "license": "MIT", - "optional": true, - "peer": true + "optional": true }, "node_modules/appium-geckodriver/node_modules/hpack.js/node_modules/readable-stream": { "version": "2.3.8", @@ -8277,7 +8235,6 @@ "integrity": "sha512-8p0AUk4XODgIewSi0l8Epjs+EVnWiK7NoDIEGU0HhE7+ZyY8D1IMY7odu5lRrFXGg71L15KG8QrPmum45RTtdA==", "license": "MIT", "optional": true, - "peer": true, "dependencies": { "core-util-is": "~1.0.0", "inherits": "~2.0.3", @@ -8294,7 +8251,6 @@ "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==", "license": "MIT", "optional": true, - "peer": true, "dependencies": { "safe-buffer": "~5.1.0" } @@ -8304,15 +8260,13 @@ "resolved": "https://registry.npmjs.org/http-deceiver/-/http-deceiver-1.2.7.tgz", "integrity": "sha512-LmpOGxTfbpgtGVxJrj5k7asXHCgNZp5nLfp+hWc8QQRqtb7fUy6kRY3BO1h9ddF6yIPYUARgxGOwB42DnxIaNw==", "license": "MIT", - "optional": true, - "peer": true + "optional": true }, "node_modules/appium-geckodriver/node_modules/http-errors": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/http-errors/-/http-errors-2.0.1.tgz", "integrity": "sha512-4FbRdAX+bSdmo4AUFuS0WNiPz8NgFt+r8ThgNWmlrjQjt1Q7ZR9+zTlce2859x4KSXrwIsaeTqDoKQmtP8pLmQ==", "license": "MIT", - "peer": true, "dependencies": { "depd": "~2.0.0", "inherits": "~2.0.4", @@ -8332,15 +8286,13 @@ "version": "2.3.0", "resolved": "https://registry.npmjs.org/http-status-codes/-/http-status-codes-2.3.0.tgz", "integrity": "sha512-RJ8XvFvpPM/Dmc5SV+dC4y5PCeOhT3x1Hq0NU3rjGeg5a/CqlhZ7uudknPwZFz4aeAXDcbAyaeP7GAo9lvngtA==", - "license": "MIT", - "peer": true + "license": "MIT" }, "node_modules/appium-geckodriver/node_modules/iconv-lite": { "version": "0.7.1", "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.7.1.tgz", "integrity": "sha512-2Tth85cXwGFHfvRgZWszZSvdo+0Xsqmw8k8ZwxScfcBneNUraK+dxRxRm24nszx80Y0TVio8kKLt5sLE7ZCLlw==", "license": "MIT", - "peer": true, "dependencies": { "safer-buffer": ">= 2.1.2 < 3.0.0" }, @@ -8392,7 +8344,6 @@ "resolved": "https://registry.npmjs.org/ipaddr.js/-/ipaddr.js-1.9.1.tgz", "integrity": "sha512-0KI/607xoxSToH7GjN1FfSbLoU0+btTicjsQSWQlh/hZykN8KpmMf7uYwPW3R+akZ6R/w18ZlXSHBYXiYUPO3g==", "license": "MIT", - "peer": true, "engines": { "node": ">= 0.10" } @@ -8432,7 +8383,6 @@ "resolved": "https://registry.npmjs.org/is-interactive/-/is-interactive-1.0.0.tgz", "integrity": "sha512-2HvIEKRoqS62guEC+qBjpvRubdX910WCMuJTZ+I9yvqKU2/12eSL549HMwtabb4oupdj2sMP50k+XJfB/8JE6w==", "license": "MIT", - "peer": true, "engines": { "node": ">=8" } @@ -8450,8 +8400,7 @@ "version": "4.0.0", "resolved": "https://registry.npmjs.org/is-promise/-/is-promise-4.0.0.tgz", "integrity": "sha512-hvpoI6korhJMnej285dSg6nu1+e6uxs7zG3BYAm5byqDsgJNWwxzM6z6iZiAgQR4TJ30JmBTOwqZUw3WlyH3AQ==", - "license": "MIT", - "peer": true + "license": "MIT" }, "node_modules/appium-geckodriver/node_modules/is-stream": { "version": "2.0.1", @@ -8566,7 +8515,6 @@ "resolved": "https://registry.npmjs.org/kleur/-/kleur-4.1.5.tgz", "integrity": "sha512-o+NO+8WrRiQEE4/7nwRJhN1HWpVmJm511pBHUxPLtp0BUISzlBplORYSmTclCnJvQq2tKu/sgl3xVpkc7ZWuQQ==", "license": "MIT", - "peer": true, "engines": { "node": ">=6" } @@ -8575,8 +8523,7 @@ "version": "2.0.0", "resolved": "https://registry.npmjs.org/kuler/-/kuler-2.0.0.tgz", "integrity": "sha512-Xq9nH7KlWZmXAtodXDDRE7vs6DU1gTU8zYDHDiWLSip45Egwq3plLHzPn27NgvzL2r1LMPC1vdqh98sQxtqj4A==", - "license": "MIT", - "peer": true + "license": "MIT" }, "node_modules/appium-geckodriver/node_modules/lazystream": { "version": "1.0.1", @@ -8625,7 +8572,6 @@ "resolved": "https://registry.npmjs.org/lilconfig/-/lilconfig-3.1.3.tgz", "integrity": "sha512-/vlFKAoH5Cgt3Ie+JLhRbwOsCQePABiU3tJ1egGvyQ+33R/vcwM2Zl2QR/LzjsBeItPt3oSVXapn+m4nQDvpzw==", "license": "MIT", - "peer": true, "engines": { "node": ">=14" }, @@ -8696,7 +8642,6 @@ "resolved": "https://registry.npmjs.org/logform/-/logform-2.7.0.tgz", "integrity": "sha512-TFYA4jnP7PVbmlBIfhlSe+WKxs9dklXMTEGcBCIvLhE/Tn3H6Gk1norupVW7m5Cnd4bLcr08AytbyV/xj7f/kQ==", "license": "MIT", - "peer": true, "dependencies": { "@colors/colors": "1.6.0", "@types/triple-beam": "^1.3.2", @@ -8732,7 +8677,6 @@ "resolved": "https://registry.npmjs.org/media-typer/-/media-typer-1.1.0.tgz", "integrity": "sha512-aisnrDP4GNe06UcKFnV5bfMNPBUw4jsLGaWwWfnH3v02GnBuXX2MCVn5RbrWo0j3pczUilYblq7fQ7Nw2t5XKw==", "license": "MIT", - "peer": true, "engines": { "node": ">= 0.8" } @@ -8742,7 +8686,6 @@ "resolved": "https://registry.npmjs.org/merge-descriptors/-/merge-descriptors-2.0.0.tgz", "integrity": "sha512-Snk314V5ayFLhp3fkUREub6WtjBfPdCPY1Ln8/8munuLuiYhsABgBVWsozAG+MWMbVEvcdcpbi9R7ww22l9Q3g==", "license": "MIT", - "peer": true, "engines": { "node": ">=18" }, @@ -8755,7 +8698,6 @@ "resolved": "https://registry.npmjs.org/method-override/-/method-override-3.0.0.tgz", "integrity": "sha512-IJ2NNN/mSl9w3kzWB92rcdHpz+HjkxhDJWNDBqSlas+zQdP8wBiJzITPg08M/k2uVvMow7Sk41atndNtt/PHSA==", "license": "MIT", - "peer": true, "dependencies": { "debug": "3.1.0", "methods": "~1.1.2", @@ -8771,7 +8713,6 @@ "resolved": "https://registry.npmjs.org/debug/-/debug-3.1.0.tgz", "integrity": "sha512-OX8XqP7/1a9cqkxYw2yXss15f26NKWBpDXQd0/uK/KPqdQhxbPa994hnzjcE2VqQpDslf55723cKPUOGSmMY3g==", "license": "MIT", - "peer": true, "dependencies": { "ms": "2.0.0" } @@ -8780,15 +8721,13 @@ "version": "2.0.0", "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==", - "license": "MIT", - "peer": true + "license": "MIT" }, "node_modules/appium-geckodriver/node_modules/methods": { "version": "1.1.2", "resolved": "https://registry.npmjs.org/methods/-/methods-1.1.2.tgz", "integrity": "sha512-iclAHeNqNm68zFtnZ0e+1L2yUIdvzNoauKU4WBA3VvH/vPFieF7qfRlwUZU+DA9P9bPXIS90ulxoUoCH23sV2w==", "license": "MIT", - "peer": true, "engines": { "node": ">= 0.6" } @@ -8798,7 +8737,6 @@ "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.54.0.tgz", "integrity": "sha512-aU5EJuIN2WDemCcAp2vFBfp/m4EAhWJnUNSSw0ixs7/kXbd6Pg64EmwJkNdFhB8aWt1sH2CTXrLxo/iAGV3oPQ==", "license": "MIT", - "peer": true, "engines": { "node": ">= 0.6" } @@ -8808,7 +8746,6 @@ "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-3.0.2.tgz", "integrity": "sha512-Lbgzdk0h4juoQ9fCKXW4by0UJqj+nOOrI9MJ1sSj4nI8aI2eo1qmvQEie4VD1glsS250n15LsWsYtCugiStS5A==", "license": "MIT", - "peer": true, "dependencies": { "mime-db": "^1.54.0" }, @@ -8825,7 +8762,6 @@ "resolved": "https://registry.npmjs.org/mimic-fn/-/mimic-fn-2.1.0.tgz", "integrity": "sha512-OqbOk5oEQeAZ8WXWydlu9HJjz9WVdEIvamMCcXmuqUYjTknH/sqsWvhQ3vgwKFRR1HpjvNBKQ37nbJgYzGqGcg==", "license": "MIT", - "peer": true, "engines": { "node": ">=6" } @@ -8835,8 +8771,7 @@ "resolved": "https://registry.npmjs.org/minimalistic-assert/-/minimalistic-assert-1.0.1.tgz", "integrity": "sha512-UtJcAD4yEaGtjPezWuO9wC4nwUnVH/8/Im3yEHQP4b67cXlD/Qr9hdITCU1xDbSEXg2XKNaP8jsReV7vQd00/A==", "license": "ISC", - "optional": true, - "peer": true + "optional": true }, "node_modules/appium-geckodriver/node_modules/minipass": { "version": "7.1.2", @@ -8861,7 +8796,6 @@ "resolved": "https://registry.npmjs.org/morgan/-/morgan-1.10.1.tgz", "integrity": "sha512-223dMRJtI/l25dJKWpgij2cMtywuG/WiUKXdvwfbhGKBhy1puASqXwFzmWZ7+K73vUPoR7SS2Qz2cI/g9MKw0A==", "license": "MIT", - "peer": true, "dependencies": { "basic-auth": "~2.0.1", "debug": "2.6.9", @@ -8878,7 +8812,6 @@ "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", "license": "MIT", - "peer": true, "dependencies": { "ms": "2.0.0" } @@ -8887,15 +8820,13 @@ "version": "2.0.0", "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==", - "license": "MIT", - "peer": true + "license": "MIT" }, "node_modules/appium-geckodriver/node_modules/morgan/node_modules/on-finished": { "version": "2.3.0", "resolved": "https://registry.npmjs.org/on-finished/-/on-finished-2.3.0.tgz", "integrity": "sha512-ikqdkGAAyf/X/gPhXGvfgAytDZtDbr+bkNUJ0N9h5MI/dmdgCs3l6hoHrcUv41sRKew3jIwrp4qQDXiK99Utww==", "license": "MIT", - "peer": true, "dependencies": { "ee-first": "1.1.1" }, @@ -8923,7 +8854,6 @@ "resolved": "https://registry.npmjs.org/negotiator/-/negotiator-1.0.0.tgz", "integrity": "sha512-8Ofs/AUQh8MaEcrlq5xOX0CQ9ypTF5dl78mjlMNfOK08fzpgTHQRQPBxcPlEtIw0yRpws+Zo/3r+5WRby7u3Gg==", "license": "MIT", - "peer": true, "engines": { "node": ">= 0.6" } @@ -8963,7 +8893,6 @@ "resolved": "https://registry.npmjs.org/object-inspect/-/object-inspect-1.13.4.tgz", "integrity": "sha512-W67iLl4J2EXEGTbfeHCffrjDfitvLANg0UlX3wFUUSTx92KXRFegMHUVgSqE+wvhAbi4WqjGg9czysTV2Epbew==", "license": "MIT", - "peer": true, "engines": { "node": ">= 0.4" }, @@ -8976,15 +8905,13 @@ "resolved": "https://registry.npmjs.org/obuf/-/obuf-1.1.2.tgz", "integrity": "sha512-PX1wu0AmAdPqOL1mWhqmlOd8kOIZQwGZw6rh7uby9fTc5lhaOWFLX3I6R1hrF9k3zUY40e6igsLGkDXK92LJNg==", "license": "MIT", - "optional": true, - "peer": true + "optional": true }, "node_modules/appium-geckodriver/node_modules/on-finished": { "version": "2.4.1", "resolved": "https://registry.npmjs.org/on-finished/-/on-finished-2.4.1.tgz", "integrity": "sha512-oVlzkg3ENAhCk2zdv7IJwd/QUD4z2RxRwpkcGY8psCVcCYZNq4wYnVWALHM+brtuJjePWiYF/ClmuDr8Ch5+kg==", "license": "MIT", - "peer": true, "dependencies": { "ee-first": "1.1.1" }, @@ -8997,7 +8924,6 @@ "resolved": "https://registry.npmjs.org/on-headers/-/on-headers-1.1.0.tgz", "integrity": "sha512-737ZY3yNnXy37FHkQxPzt4UZ2UWPWiCZWLvFZ4fu5cueciegX0zGPnrlY6bwRg4FdQOe9YU8MkmJwGhoMybl8A==", "license": "MIT", - "peer": true, "engines": { "node": ">= 0.8" } @@ -9016,7 +8942,6 @@ "resolved": "https://registry.npmjs.org/one-time/-/one-time-1.0.0.tgz", "integrity": "sha512-5DXOiRKwuSEcQ/l0kGCF6Q3jcADFv5tSmRaJck/OqkVFcOzutB134KRSfF0xDrL39MNnqxbHBbUUcjZIhTgb2g==", "license": "MIT", - "peer": true, "dependencies": { "fn.name": "1.x.x" } @@ -9026,7 +8951,6 @@ "resolved": "https://registry.npmjs.org/onetime/-/onetime-5.1.2.tgz", "integrity": "sha512-kbpaSSGJTWdAY5KPVeMOKXSrPtr8C8C7wodJbcsd51jRnmD+GZu8Y0VoU6Dm5Z4vWr0Ig/1NKuWRKf7j5aaYSg==", "license": "MIT", - "peer": true, "dependencies": { "mimic-fn": "^2.1.0" }, @@ -9042,7 +8966,6 @@ "resolved": "https://registry.npmjs.org/ora/-/ora-5.4.1.tgz", "integrity": "sha512-5b6Y85tPxZZ7QytO+BQzysW31HJku27cRIlkbAXaNx+BdcVi+LlRFmVXzeF6a7JCwJpyw5c4b+YSVImQIrBpuQ==", "license": "MIT", - "peer": true, "dependencies": { "bl": "^4.1.0", "chalk": "^4.1.0", @@ -9096,7 +9019,6 @@ "resolved": "https://registry.npmjs.org/package-changed/-/package-changed-3.0.0.tgz", "integrity": "sha512-HSRbrO+Ab5AuqqYGSevtKJ1Yt96jW1VKV7wrp8K4SKj5tyDp/7D96uPCQyCPiNtWTEH/7nA3hZ4z2slbc9yFxg==", "license": "ISC", - "peer": true, "dependencies": { "commander": "^6.2.0" }, @@ -9141,7 +9063,6 @@ "resolved": "https://registry.npmjs.org/parseurl/-/parseurl-1.3.3.tgz", "integrity": "sha512-CiyeOxFT/JZyN5m0z9PfXw4SCBJ6Sygz1Dpl0wqjlhDEGGBP1GnsUVEL0p63hoG1fcj3fHynXi9NYO4nWOL+qQ==", "license": "MIT", - "peer": true, "engines": { "node": ">= 0.8" } @@ -9191,7 +9112,6 @@ "resolved": "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-8.3.0.tgz", "integrity": "sha512-7jdwVIRtsP8MYpdXSwOS0YdD0Du+qOoF/AEPIt88PcCFrZCzx41oxku1jD88hZBwbNUIEfpqvuhjFaMAqMTWnA==", "license": "MIT", - "peer": true, "funding": { "type": "opencollective", "url": "https://opencollective.com/express" @@ -9287,7 +9207,6 @@ "resolved": "https://registry.npmjs.org/proxy-addr/-/proxy-addr-2.0.7.tgz", "integrity": "sha512-llQsMLSUDUPT44jdrU/O37qlnifitDP+ZwrmmZcoSKyLKvtZxpyV0n2/bD/N4tBAAZ/gJEdZU7KMraoK1+XYAg==", "license": "MIT", - "peer": true, "dependencies": { "forwarded": "0.2.0", "ipaddr.js": "1.9.1" @@ -9307,7 +9226,6 @@ "resolved": "https://registry.npmjs.org/qs/-/qs-6.14.0.tgz", "integrity": "sha512-YWWTjgABSKcvs/nWBi9PycY/JiPJqOD4JA6o9Sej2AtvSGarXxKC3OQSk4pAarbdQlKAh5D4FCQkJNkW+GAn3w==", "license": "BSD-3-Clause", - "peer": true, "dependencies": { "side-channel": "^1.1.0" }, @@ -9323,7 +9241,6 @@ "resolved": "https://registry.npmjs.org/range-parser/-/range-parser-1.2.1.tgz", "integrity": "sha512-Hrgsx+orqoygnmhFbKaHE6c296J+HTAQXoxEF6gNupROmmGJRoyzfG3ccAveqCBrwr/2yxQ5BVd/GTl5agOwSg==", "license": "MIT", - "peer": true, "engines": { "node": ">= 0.6" } @@ -9333,7 +9250,6 @@ "resolved": "https://registry.npmjs.org/raw-body/-/raw-body-3.0.2.tgz", "integrity": "sha512-K5zQjDllxWkf7Z5xJdV0/B0WTNqx6vxG70zJE4N0kBs4LovmEYWJzQGxC9bS9RAKu3bgM40lrd5zoLJ12MQ5BA==", "license": "MIT", - "peer": true, "dependencies": { "bytes": "~3.1.2", "http-errors": "~2.0.1", @@ -9482,7 +9398,6 @@ "resolved": "https://registry.npmjs.org/restore-cursor/-/restore-cursor-3.1.0.tgz", "integrity": "sha512-l+sSefzHpj5qimhFSE5a8nufZYAM3sBSVMAPtYkmC+4EH2anSGaEMXSD0izRQbu9nfyQ9y5JrVmp7E8oZrUjvA==", "license": "MIT", - "peer": true, "dependencies": { "onetime": "^5.1.0", "signal-exit": "^3.0.2" @@ -9496,7 +9411,6 @@ "resolved": "https://registry.npmjs.org/router/-/router-2.2.0.tgz", "integrity": "sha512-nLTrUKm2UyiL7rlhapu/Zl45FwNgkZGaCpZbIHajDYgwlJCOzLSk+cIPAnsEqV955GjILJnKbdQC1nVPz+gAYQ==", "license": "MIT", - "peer": true, "dependencies": { "debug": "^4.4.0", "depd": "^2.0.0", @@ -9519,7 +9433,6 @@ "resolved": "https://registry.npmjs.org/safe-stable-stringify/-/safe-stable-stringify-2.5.0.tgz", "integrity": "sha512-b3rppTKm9T+PsVCBEOUR46GWI7fdOs00VKZ1+9c1EWDaDMvjQc6tUwuFyIprgGgTcWoVHSKrU8H31ZHA2e0RHA==", "license": "MIT", - "peer": true, "engines": { "node": ">=10" } @@ -9528,8 +9441,7 @@ "version": "2.1.2", "resolved": "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz", "integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==", - "license": "MIT", - "peer": true + "license": "MIT" }, "node_modules/appium-geckodriver/node_modules/sanitize-filename": { "version": "1.6.3", @@ -9545,8 +9457,7 @@ "resolved": "https://registry.npmjs.org/select-hose/-/select-hose-2.0.0.tgz", "integrity": "sha512-mEugaLK+YfkijB4fx0e6kImuJdCIt2LxCRcbEYPqRGCs4F2ogyfZU5IAZRdjCP8JPq2AtdNoC/Dux63d9Kiryg==", "license": "MIT", - "optional": true, - "peer": true + "optional": true }, "node_modules/appium-geckodriver/node_modules/semver": { "version": "7.7.3", @@ -9565,7 +9476,6 @@ "resolved": "https://registry.npmjs.org/send/-/send-1.2.0.tgz", "integrity": "sha512-uaW0WwXKpL9blXE2o0bRhoL2EGXIrZxQ2ZQ4mgcfoBxdFmQold+qWsD2jLrfZ0trjKL6vOw0j//eAwcALFjKSw==", "license": "MIT", - "peer": true, "dependencies": { "debug": "^4.3.5", "encodeurl": "^2.0.0", @@ -9588,7 +9498,6 @@ "resolved": "https://registry.npmjs.org/serve-favicon/-/serve-favicon-2.5.1.tgz", "integrity": "sha512-JndLBslCLA/ebr7rS3d+/EKkzTsTi1jI2T9l+vHfAaGJ7A7NhtDpSZ0lx81HCNWnnE0yHncG+SSnVf9IMxOwXQ==", "license": "MIT", - "peer": true, "dependencies": { "etag": "~1.8.1", "fresh": "~0.5.2", @@ -9605,7 +9514,6 @@ "resolved": "https://registry.npmjs.org/fresh/-/fresh-0.5.2.tgz", "integrity": "sha512-zJ2mQYM18rEFOudeV4GShTGIQ7RbzA7ozbU9I/XBpm7kqgMywgmylMwXHxZJmkVoYkna9d2pVXVXPdYTP9ej8Q==", "license": "MIT", - "peer": true, "engines": { "node": ">= 0.6" } @@ -9628,15 +9536,13 @@ "url": "https://feross.org/support" } ], - "license": "MIT", - "peer": true + "license": "MIT" }, "node_modules/appium-geckodriver/node_modules/serve-static": { "version": "2.2.0", "resolved": "https://registry.npmjs.org/serve-static/-/serve-static-2.2.0.tgz", "integrity": "sha512-61g9pCh0Vnh7IutZjtLGGpTA355+OPn2TyDv/6ivP2h/AdAVX9azsoxmg2/M6nZeQZNYBEwIcsne1mJd9oQItQ==", "license": "MIT", - "peer": true, "dependencies": { "encodeurl": "^2.0.0", "escape-html": "^1.0.3", @@ -9657,8 +9563,7 @@ "version": "1.2.0", "resolved": "https://registry.npmjs.org/setprototypeof/-/setprototypeof-1.2.0.tgz", "integrity": "sha512-E5LDX7Wrp85Kil5bhZv46j8jOeboKq5JMmYM3gVGdGH8xFpPWXUMsNrlODCrkoxMEeNi/XZIwuRvY4XNwYMJpw==", - "license": "ISC", - "peer": true + "license": "ISC" }, "node_modules/appium-geckodriver/node_modules/sharp": { "version": "0.34.5", @@ -9743,7 +9648,6 @@ "resolved": "https://registry.npmjs.org/side-channel/-/side-channel-1.1.0.tgz", "integrity": "sha512-ZX99e6tRweoUXqR+VBrslhda51Nh5MTQwou5tnUDgbtyM0dBgmhEDtWGP/xbKn6hqfPRHujUNwz5fy/wbbhnpw==", "license": "MIT", - "peer": true, "dependencies": { "es-errors": "^1.3.0", "object-inspect": "^1.13.3", @@ -9763,7 +9667,6 @@ "resolved": "https://registry.npmjs.org/side-channel-list/-/side-channel-list-1.0.0.tgz", "integrity": "sha512-FCLHtRD/gnpCiCHEiJLOwdmFP+wzCmDEkc9y7NsYxeF4u7Btsn1ZuwgwJGxImImHicJArLP4R0yX4c2KCrMrTA==", "license": "MIT", - "peer": true, "dependencies": { "es-errors": "^1.3.0", "object-inspect": "^1.13.3" @@ -9780,7 +9683,6 @@ "resolved": "https://registry.npmjs.org/side-channel-map/-/side-channel-map-1.0.1.tgz", "integrity": "sha512-VCjCNfgMsby3tTdo02nbjtM/ewra6jPHmpThenkTYh8pG9ucZ/1P8So4u4FGBek/BjpOVsDCMoLA/iuBKIFXRA==", "license": "MIT", - "peer": true, "dependencies": { "call-bound": "^1.0.2", "es-errors": "^1.3.0", @@ -9799,7 +9701,6 @@ "resolved": "https://registry.npmjs.org/side-channel-weakmap/-/side-channel-weakmap-1.0.2.tgz", "integrity": "sha512-WPS/HvHQTYnHisLo9McqBHOJk2FkHO/tlpvldyrnem4aeQp4hai3gythswg6p01oSoTl58rcpiFAjF2br2Ak2A==", "license": "MIT", - "peer": true, "dependencies": { "call-bound": "^1.0.2", "es-errors": "^1.3.0", @@ -9877,7 +9778,6 @@ "integrity": "sha512-r46gZQZQV+Kl9oItvl1JZZqJKGr+oEkB08A6BzkiR7593/7IbtuncXHd2YoYeTsG4157ZssMu9KYvUHLcjcDoA==", "license": "MIT", "optional": true, - "peer": true, "dependencies": { "debug": "^4.1.0", "handle-thing": "^2.0.0", @@ -9895,7 +9795,6 @@ "integrity": "sha512-hsLVFE5SjA6TCisWeJXFKniGGOpBgMLmerfO2aCyCU5s7nJ/rpAepqmFifv/GCbSbueEeAJJnmSQ2rKC/g8Fcw==", "license": "MIT", "optional": true, - "peer": true, "dependencies": { "debug": "^4.1.0", "detect-node": "^2.0.4", @@ -9911,7 +9810,6 @@ "integrity": "sha512-9u/sniCrY3D5WdsERHzHE4G2YCXqoG5FTHUiCC4SIbr6XcLZBY05ya9EKjYek9O5xOAwjGq+1JdGBAS7Q9ScoA==", "license": "MIT", "optional": true, - "peer": true, "dependencies": { "inherits": "^2.0.3", "string_decoder": "^1.1.1", @@ -9926,7 +9824,6 @@ "resolved": "https://registry.npmjs.org/stack-trace/-/stack-trace-0.0.10.tgz", "integrity": "sha512-KGzahc7puUKkzyMt+IqAep+TVNbKP+k2Lmwhub39m1AsTSkaDutx56aDCo+HLDzf/D26BIHTJWNiTG1KAJiQCg==", "license": "MIT", - "peer": true, "engines": { "node": "*" } @@ -9936,7 +9833,6 @@ "resolved": "https://registry.npmjs.org/statuses/-/statuses-2.0.2.tgz", "integrity": "sha512-DvEy55V3DB7uknRo+4iOGT5fP1slR8wQohVdknigZPMpMstaKJQWhwiYBACJE3Ul2pTnATihhBYnRhZQHGBiRw==", "license": "MIT", - "peer": true, "engines": { "node": ">= 0.8" } @@ -10150,8 +10046,7 @@ "version": "1.0.0", "resolved": "https://registry.npmjs.org/text-hex/-/text-hex-1.0.0.tgz", "integrity": "sha512-uuVGNWzgJ4yhRaNSiubPY7OjISw4sw4E5Uv0wbjp+OzcbmVU/rsT8ujgcXJhn9ypzsgr5vlzpPqP+MBBKcGvbg==", - "license": "MIT", - "peer": true + "license": "MIT" }, "node_modules/appium-geckodriver/node_modules/through": { "version": "2.3.8", @@ -10164,7 +10059,6 @@ "resolved": "https://registry.npmjs.org/toidentifier/-/toidentifier-1.0.1.tgz", "integrity": "sha512-o5sSPKEkg/DIQNmH43V0/uerLrpzVedkUh8tGNvaeXpfpuwjKenlSox/2O/BTlZUtEe+JG7s5YhEz608PlAHRA==", "license": "MIT", - "peer": true, "engines": { "node": ">=0.6" } @@ -10174,7 +10068,6 @@ "resolved": "https://registry.npmjs.org/triple-beam/-/triple-beam-1.4.1.tgz", "integrity": "sha512-aZbgViZrg1QNcG+LULa7nhZpJTZSLm/mXnHXnbAbjmN5aSa0y7V+wvv6+4WaBtpISJzThKy+PIPxc1Nq1EJ9mg==", "license": "MIT", - "peer": true, "engines": { "node": ">= 14.0.0" } @@ -10215,7 +10108,6 @@ "resolved": "https://registry.npmjs.org/type-is/-/type-is-2.0.1.tgz", "integrity": "sha512-OZs6gsjF4vMp32qrCbiVSkrFmXtG/AZhY3t0iAMrMBiAZyV9oALtXO8hsrHbMXF9x6L3grlFuwW2oAz7cav+Gw==", "license": "MIT", - "peer": true, "dependencies": { "content-type": "^1.0.5", "media-typer": "^1.1.0", @@ -10239,7 +10131,6 @@ "resolved": "https://registry.npmjs.org/unpipe/-/unpipe-1.0.0.tgz", "integrity": "sha512-pjy2bYhSsufwWlKwPc+l3cN7+wuJlK6uz0YdJEOlQDbl6jo/YlPi4mb8agUkVC8BF7V8NuzeyPNqRksA3hztKQ==", "license": "MIT", - "peer": true, "engines": { "node": ">= 0.8" } @@ -10284,7 +10175,6 @@ "resolved": "https://registry.npmjs.org/vary/-/vary-1.1.2.tgz", "integrity": "sha512-BNGbWLfd0eUPabhkXUVm0j8uuvREyTh5ovRa/dyow/BqAbZJyC+5fU+IzQOzmAKzYqYRAISoRhdQr3eIZ/PXqg==", "license": "MIT", - "peer": true, "engines": { "node": ">= 0.8" } @@ -10295,7 +10185,6 @@ "integrity": "sha512-O84QOnr0icsbFGLS0O3bI5FswxzRr8/gHwWkDlQFskhSPryQXvrTMxjxGP4+iWYoauLoBvfDpkrOauZ+0iZpDA==", "license": "MIT", "optional": true, - "peer": true, "dependencies": { "minimalistic-assert": "^1.0.0" } @@ -10305,7 +10194,6 @@ "resolved": "https://registry.npmjs.org/wcwidth/-/wcwidth-1.0.1.tgz", "integrity": "sha512-XHPEwS0q6TaxcvG85+8EYkbiCux2XtWG2mkc47Ng2A77BQu9+DqIOJldST4HgPkuea7dvKSj5VgX3P1d4rW8Tg==", "license": "MIT", - "peer": true, "dependencies": { "defaults": "^1.0.3" } @@ -10330,7 +10218,6 @@ "resolved": "https://registry.npmjs.org/winston/-/winston-3.18.3.tgz", "integrity": "sha512-NoBZauFNNWENgsnC9YpgyYwOVrl2m58PpQ8lNHjV3kosGs7KJ7Npk9pCUE+WJlawVSe8mykWDKWFSVfs3QO9ww==", "license": "MIT", - "peer": true, "dependencies": { "@colors/colors": "^1.6.0", "@dabh/diagnostics": "^2.0.8", @@ -10353,7 +10240,6 @@ "resolved": "https://registry.npmjs.org/winston-transport/-/winston-transport-4.9.0.tgz", "integrity": "sha512-8drMJ4rkgaPo1Me4zD/3WLfI/zPdA9o2IipKODunnGDcuqbHwjsbB79ylv04LCGGzU0xQ6vTznOMpQGaLhhm6A==", "license": "MIT", - "peer": true, "dependencies": { "logform": "^2.7.0", "readable-stream": "^3.6.2", @@ -10368,7 +10254,6 @@ "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.2.tgz", "integrity": "sha512-9u/sniCrY3D5WdsERHzHE4G2YCXqoG5FTHUiCC4SIbr6XcLZBY05ya9EKjYek9O5xOAwjGq+1JdGBAS7Q9ScoA==", "license": "MIT", - "peer": true, "dependencies": { "inherits": "^2.0.3", "string_decoder": "^1.1.1", @@ -10383,7 +10268,6 @@ "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.2.tgz", "integrity": "sha512-9u/sniCrY3D5WdsERHzHE4G2YCXqoG5FTHUiCC4SIbr6XcLZBY05ya9EKjYek9O5xOAwjGq+1JdGBAS7Q9ScoA==", "license": "MIT", - "peer": true, "dependencies": { "inherits": "^2.0.3", "string_decoder": "^1.1.1", @@ -10398,7 +10282,6 @@ "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-7.0.0.tgz", "integrity": "sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==", "license": "MIT", - "peer": true, "dependencies": { "ansi-styles": "^4.0.0", "string-width": "^4.1.0", @@ -10440,7 +10323,6 @@ "resolved": "https://registry.npmjs.org/ws/-/ws-8.18.3.tgz", "integrity": "sha512-PEIGCY5tSlUt50cqyMXfCzX+oOPqN0vuGqWzbcJ2xvnkzkq46oOpz7dQaTDBdfICb4N14+GARUDw2XV2N4tvzg==", "license": "MIT", - "peer": true, "engines": { "node": ">=10.0.0" }, @@ -10471,7 +10353,6 @@ "resolved": "https://registry.npmjs.org/y18n/-/y18n-5.0.8.tgz", "integrity": "sha512-0pfFzegeDWJHJIAmTLRP2DwHjdF5s7jo9tuztdQxAhINCdvS+3nGINqPd00AphqJR/0LhANUS6/+7SCb98YOfA==", "license": "ISC", - "peer": true, "engines": { "node": ">=10" } @@ -10481,7 +10362,6 @@ "resolved": "https://registry.npmjs.org/yaml/-/yaml-2.8.2.tgz", "integrity": "sha512-mplynKqc1C2hTVYxd0PU2xQAc22TI1vShAYGksCCfxbn/dFwnHTNi1bvYsBTkhdUNtGIf5xNOg938rrSSYvS9A==", "license": "ISC", - "peer": true, "bin": { "yaml": "bin.mjs" }, @@ -10497,7 +10377,6 @@ "resolved": "https://registry.npmjs.org/yargs/-/yargs-18.0.0.tgz", "integrity": "sha512-4UEqdc2RYGHZc7Doyqkrqiln3p9X2DZVxaGbwhn2pi7MrRagKaOcIKe8L3OxYcbhXLgLFUS3zAYuQjKBQgmuNg==", "license": "MIT", - "peer": true, "dependencies": { "cliui": "^9.0.1", "escalade": "^3.1.1", @@ -10515,7 +10394,6 @@ "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-22.0.0.tgz", "integrity": "sha512-rwu/ClNdSMpkSrUb+d6BRsSkLUq1fmfsY6TOpYzTwvwkg1/NRG85KBy3kq++A8LKQwX6lsu+aWad+2khvuXrqw==", "license": "ISC", - "peer": true, "engines": { "node": "^20.19.0 || ^22.12.0 || >=23" } @@ -10524,15 +10402,13 @@ "version": "10.6.0", "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-10.6.0.tgz", "integrity": "sha512-toUI84YS5YmxW219erniWD0CIVOo46xGKColeNQRgOzDorgBi1v4D71/OFzgD9GO2UGKIv1C3Sp8DAn0+j5w7A==", - "license": "MIT", - "peer": true + "license": "MIT" }, "node_modules/appium-geckodriver/node_modules/yargs/node_modules/string-width": { "version": "7.2.0", "resolved": "https://registry.npmjs.org/string-width/-/string-width-7.2.0.tgz", "integrity": "sha512-tsaTIkKW9b4N+AEj+SVA+WhJzV7/zMhcSu78mLKWSk7cXMOSHsBKFWUs0fWwq8QyK3MgJBQRX6Gbi4kYbdvGkQ==", "license": "MIT", - "peer": true, "dependencies": { "emoji-regex": "^10.3.0", "get-east-asian-width": "^1.0.0", @@ -10550,7 +10426,6 @@ "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-7.1.2.tgz", "integrity": "sha512-gmBGslpoQJtgnMAvOVqGZpEz9dyoKTCzy2nfz/n8aIFhN/jCE/rCmcxabB6jOOHV+0WNnylOxaxBQPSvcWklhA==", "license": "MIT", - "peer": true, "dependencies": { "ansi-regex": "^6.0.1" }, @@ -10636,7 +10511,6 @@ "resolved": "https://registry.npmjs.org/@appium/base-driver/-/base-driver-10.1.2.tgz", "integrity": "sha512-AxCYznylRw4xpOx30dAIQ8m5GsVM9ob/MPwc/KyiKhtofLNxQQlFLvLs7SeX7s8iwvwr0puMasOqlWrWy3gVbA==", "license": "Apache-2.0", - "peer": true, "dependencies": { "@appium/support": "^7.0.4", "@appium/types": "^1.1.2", @@ -10671,7 +10545,6 @@ "resolved": "https://registry.npmjs.org/@appium/base-plugin/-/base-plugin-3.0.5.tgz", "integrity": "sha512-w27EqXQ3zY7xKp61IizbzhZGlxQvFr8uKxeELP5TU/+YxnjU8MyVYmWCG7RXp0dh9n7mZen/WPjZtvqdiBOsMQ==", "license": "Apache-2.0", - "peer": true, "dependencies": { "@appium/base-driver": "^10.1.2", "@appium/support": "^7.0.4" @@ -10686,7 +10559,6 @@ "resolved": "https://registry.npmjs.org/@appium/docutils/-/docutils-2.2.0.tgz", "integrity": "sha512-bwZIShYLRnWCRdGEgjBX+POXyI0X8fbZ3FNHWDlNzYjCBodYckiMw8X48WDwMRd0AeP5mzjBbHSpH7DKfebuFg==", "license": "Apache-2.0", - "peer": true, "dependencies": { "@appium/support": "^7.0.4", "chalk": "4.1.2", @@ -10716,7 +10588,6 @@ "resolved": "https://registry.npmjs.org/teen_process/-/teen_process-3.0.4.tgz", "integrity": "sha512-NQA/5PdJWEAxuYoBRW7RajnAyWmfh5iGMY1kEXiAzobtv0ztERcfDnfszpUTuvhFXrvh3E4GvHt9yWbS/EndzQ==", "license": "Apache-2.0", - "peer": true, "dependencies": { "bluebird": "^3.7.2", "lodash": "^4.17.21", @@ -10749,7 +10620,6 @@ "resolved": "https://registry.npmjs.org/@appium/schema/-/schema-1.0.0.tgz", "integrity": "sha512-eowz+sV6YxuHdsuRizEhG+AGeeMsUiS9ryWLkdFSqQlsNB+uDudehpYQiRkrrtaGOBzq7a3GDUB7zjc6eR80QA==", "license": "Apache-2.0", - "peer": true, "dependencies": { "json-schema": "0.4.0", "source-map-support": "0.5.21" @@ -10764,7 +10634,6 @@ "resolved": "https://registry.npmjs.org/@appium/support/-/support-7.0.4.tgz", "integrity": "sha512-xIK7cFzouZJLIG6RMmg50M+EsILSeO9e9sSkR4xNSaJajaop7LtpkbMfO5JpTgdNiIUYyIsr/3TusQhxnpPNvw==", "license": "Apache-2.0", - "peer": true, "dependencies": { "@appium/logger": "^2.0.3", "@appium/tsconfig": "^1.1.1", @@ -10815,7 +10684,6 @@ "resolved": "https://registry.npmjs.org/teen_process/-/teen_process-3.0.4.tgz", "integrity": "sha512-NQA/5PdJWEAxuYoBRW7RajnAyWmfh5iGMY1kEXiAzobtv0ztERcfDnfszpUTuvhFXrvh3E4GvHt9yWbS/EndzQ==", "license": "Apache-2.0", - "peer": true, "dependencies": { "bluebird": "^3.7.2", "lodash": "^4.17.21", @@ -10832,7 +10700,6 @@ "resolved": "https://registry.npmjs.org/@appium/tsconfig/-/tsconfig-1.1.1.tgz", "integrity": "sha512-ikjo037sWgY2Oy0HRPGnrKHnOdUh9JyzstD7E6HlFqcZu8hvOP1hDQmKdoBTz8gkmSbZWcMRZmWaL3Yqaz2pLw==", "license": "Apache-2.0", - "peer": true, "dependencies": { "@tsconfig/node20": "20.1.8" }, @@ -10846,7 +10713,6 @@ "resolved": "https://registry.npmjs.org/@appium/types/-/types-1.1.2.tgz", "integrity": "sha512-BDyX99GCXWqsfeDxsqsvb6EIfQD7SLTXcCbmcI1PKDTK2wg9znKOtE0YLzXgI6TFQV3+40Xs6za6La/Mv8/rVQ==", "license": "Apache-2.0", - "peer": true, "dependencies": { "@appium/logger": "^2.0.3", "@appium/schema": "^1.0.0", @@ -10863,7 +10729,6 @@ "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.27.1.tgz", "integrity": "sha512-cjQ7ZlQ0Mv3b47hABuTevyTuYN4i+loJKGeV9flcCgIK37cCXRh+L1bd3iBHlynerhQ7BhCkn2BPbQUL+rGqFg==", "license": "MIT", - "peer": true, "dependencies": { "@babel/helper-validator-identifier": "^7.27.1", "js-tokens": "^4.0.0", @@ -10878,7 +10743,6 @@ "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.28.5.tgz", "integrity": "sha512-qSs4ifwzKJSV39ucNjsvc6WVHs6b7S03sOh2OcHF9UHfVPqWWALUsNUVzhSBiItjRZoLHx7nIarVjqKVusUZ1Q==", "license": "MIT", - "peer": true, "engines": { "node": ">=6.9.0" } @@ -10888,7 +10752,6 @@ "resolved": "https://registry.npmjs.org/@colors/colors/-/colors-1.6.0.tgz", "integrity": "sha512-Ir+AOibqzrIsL6ajt3Rz3LskB7OiMVHqltZmspbW/TJuTVuyOMirVqAkjfY6JISiLHgyNqicAC8AyHHGzNd/dA==", "license": "MIT", - "peer": true, "engines": { "node": ">=0.1.90" } @@ -10898,7 +10761,6 @@ "resolved": "https://registry.npmjs.org/@dabh/diagnostics/-/diagnostics-2.0.8.tgz", "integrity": "sha512-R4MSXTVnuMzGD7bzHdW2ZhhdPC/igELENcq5IjEverBvq5hn1SXCWcsi6eSsdWP0/Ur+SItRRjAktmdoX/8R/Q==", "license": "MIT", - "peer": true, "dependencies": { "@so-ric/colorspace": "^1.1.6", "enabled": "2.0.x", @@ -10921,7 +10783,6 @@ "integrity": "sha512-A5P/LfWGFSl6nsckYtjw9da+19jB8hkJ6ACTGcDfEJ0aE+l2n2El7dsVM7UVHZQ9s2lmYMWlrS21YLy2IR1LUw==", "license": "MIT", "optional": true, - "peer": true, "engines": { "node": ">=18" } @@ -10938,7 +10799,6 @@ "os": [ "darwin" ], - "peer": true, "engines": { "node": "^18.17.0 || ^20.3.0 || >=21.0.0" }, @@ -10961,7 +10821,6 @@ "os": [ "darwin" ], - "peer": true, "funding": { "url": "https://opencollective.com/libvips" } @@ -10992,7 +10851,6 @@ "resolved": "https://registry.npmjs.org/@isaacs/cliui/-/cliui-8.0.2.tgz", "integrity": "sha512-O8jcjabXaleOG9DQ0+ARXWZBTfnP4WNAqzuiJK7ll44AmxGKv/J2M4TPjxjY3znBCfvBXFzucm1twdyFybFqEA==", "license": "ISC", - "peer": true, "dependencies": { "string-width": "^5.1.2", "string-width-cjs": "npm:string-width@^4.2.0", @@ -11010,7 +10868,6 @@ "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-6.2.3.tgz", "integrity": "sha512-4Dj6M28JB+oAH8kFkTLUo+a2jwOFkuqb3yucU0CANcRRUbxS0cP0nZYCGjcc3BNXwRIsUVmDGgzawme7zvJHvg==", "license": "MIT", - "peer": true, "engines": { "node": ">=12" }, @@ -11022,15 +10879,13 @@ "version": "9.2.2", "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-9.2.2.tgz", "integrity": "sha512-L18DaJsXSUk2+42pv8mLs5jJT2hqFkFE4j21wOmgbUqsZ2hL72NsUU785g9RXgo3s0ZNgVl42TiHp3ZtOv/Vyg==", - "license": "MIT", - "peer": true + "license": "MIT" }, "node_modules/appium-safari-driver/node_modules/@isaacs/cliui/node_modules/string-width": { "version": "5.1.2", "resolved": "https://registry.npmjs.org/string-width/-/string-width-5.1.2.tgz", "integrity": "sha512-HnLOCR3vjcY8beoNLtcjZ5/nxn2afmME6lhrDrebokqMap+XbeW8n9TXpPDOqdGK5qcI3oT0GKTW6wC7EMiVqA==", "license": "MIT", - "peer": true, "dependencies": { "eastasianwidth": "^0.2.0", "emoji-regex": "^9.2.2", @@ -11048,7 +10903,6 @@ "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-7.1.2.tgz", "integrity": "sha512-gmBGslpoQJtgnMAvOVqGZpEz9dyoKTCzy2nfz/n8aIFhN/jCE/rCmcxabB6jOOHV+0WNnylOxaxBQPSvcWklhA==", "license": "MIT", - "peer": true, "dependencies": { "ansi-regex": "^6.0.1" }, @@ -11064,7 +10918,6 @@ "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-8.1.0.tgz", "integrity": "sha512-si7QWI6zUMq56bESFvagtmzMdGOtoxfR+Sez11Mobfc7tm+VkUckk9bW2UeffTGVUbOksxmSw0AA2gs8g71NCQ==", "license": "MIT", - "peer": true, "dependencies": { "ansi-styles": "^6.1.0", "string-width": "^5.0.1", @@ -11083,7 +10936,6 @@ "integrity": "sha512-+1VkjdD0QBLPodGrJUeqarH8VAIvQODIbwh9XpP5Syisf7YoQgsJKPNFoqqLQlu+VQ/tVSshMR6loPMn8U+dPg==", "license": "MIT", "optional": true, - "peer": true, "engines": { "node": ">=14" } @@ -11093,7 +10945,6 @@ "resolved": "https://registry.npmjs.org/@sidvind/better-ajv-errors/-/better-ajv-errors-4.0.1.tgz", "integrity": "sha512-6arF1ssKxItxgitPYXafUoLmsVBA6K7m9+ZGj6hLDoBl7nWpJ33EInwQUdHTle2METeWGxgQiqSex20KZRykew==", "license": "Apache-2.0", - "peer": true, "dependencies": { "kleur": "^4.1.0" }, @@ -11109,7 +10960,6 @@ "resolved": "https://registry.npmjs.org/@so-ric/colorspace/-/colorspace-1.1.6.tgz", "integrity": "sha512-/KiKkpHNOBgkFJwu9sh48LkHSMYGyuTcSFK/qMBdnOAlrRJzRSXAOFB5qwzaVQuDl8wAvHVMkaASQDReTahxuw==", "license": "MIT", - "peer": true, "dependencies": { "color": "^5.0.2", "text-hex": "1.0.x" @@ -11119,29 +10969,25 @@ "version": "20.1.8", "resolved": "https://registry.npmjs.org/@tsconfig/node20/-/node20-20.1.8.tgz", "integrity": "sha512-Em+IdPfByIzWRRpqWL4Z7ArLHZGxmc36BxE3jCz9nBFSm+5aLaPMZyjwu4yetvyKXeogWcxik4L1jB5JTWfw7A==", - "license": "MIT", - "peer": true + "license": "MIT" }, "node_modules/appium-safari-driver/node_modules/@types/normalize-package-data": { "version": "2.4.4", "resolved": "https://registry.npmjs.org/@types/normalize-package-data/-/normalize-package-data-2.4.4.tgz", "integrity": "sha512-37i+OaWTh9qeK4LSHPsyRC7NahnGotNuZvjLSgcPzblpHB3rrCJxAOgI5gCdKm7coonsaX1Of0ILiTcnZjbfxA==", - "license": "MIT", - "peer": true + "license": "MIT" }, "node_modules/appium-safari-driver/node_modules/@types/triple-beam": { "version": "1.3.5", "resolved": "https://registry.npmjs.org/@types/triple-beam/-/triple-beam-1.3.5.tgz", "integrity": "sha512-6WaYesThRMCl19iryMYP7/x2OVgCtbIVflDGFpWnb9irXI3UjYE4AzmYuiUKY1AJstGijoY+MgUszMgRxIYTYw==", - "license": "MIT", - "peer": true + "license": "MIT" }, "node_modules/appium-safari-driver/node_modules/@xmldom/xmldom": { "version": "0.8.11", "resolved": "https://registry.npmjs.org/@xmldom/xmldom/-/xmldom-0.8.11.tgz", "integrity": "sha512-cQzWCtO6C8TQiYl1ruKNn2U6Ao4o4WBBcbL61yJl84x+j5sOWWFU9X7DpND8XZG3daDppSsigMdfAIl2upQBRw==", "license": "MIT", - "peer": true, "engines": { "node": ">=10.0.0" } @@ -11151,7 +10997,6 @@ "resolved": "https://registry.npmjs.org/abort-controller/-/abort-controller-3.0.0.tgz", "integrity": "sha512-h8lQ8tacZYnR3vNQTgibj+tODHI5/+l06Au2Pcriv/Gmet0eaj4TwWH41sO9wnHDiQsEj19q0drzdWdeAHtweg==", "license": "MIT", - "peer": true, "dependencies": { "event-target-shim": "^5.0.0" }, @@ -11164,7 +11009,6 @@ "resolved": "https://registry.npmjs.org/accepts/-/accepts-2.0.0.tgz", "integrity": "sha512-5cvg6CtKwfgdmVqY1WIiXKc3Q1bkRqGLi+2W/6ao+6Y7gu/RCwRuAhGEzh5B4KlszSuTLgZYuqFqo5bImjNKng==", "license": "MIT", - "peer": true, "dependencies": { "mime-types": "^3.0.0", "negotiator": "^1.0.0" @@ -11178,7 +11022,6 @@ "resolved": "https://registry.npmjs.org/ajv-formats/-/ajv-formats-3.0.1.tgz", "integrity": "sha512-8iUql50EUR+uUcdRQ3HDqa6EVyo3docL8g5WJ3FNcWmu62IbkGUue/pEyLBW8VGKKucTPgqeks4fIU1DA4yowQ==", "license": "MIT", - "peer": true, "dependencies": { "ajv": "^8.0.0" }, @@ -11196,7 +11039,6 @@ "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-6.2.2.tgz", "integrity": "sha512-Bq3SmSpyFHaWjPk8If9yc6svM8c56dB5BAtW4Qbw5jHTwwXXcTLoRMkpDJp6VL0XzlWaCHTXrkFURMYmD0sLqg==", "license": "MIT", - "peer": true, "engines": { "node": ">=12" }, @@ -11209,7 +11051,6 @@ "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", "license": "MIT", - "peer": true, "dependencies": { "color-convert": "^2.0.1" }, @@ -11226,7 +11067,6 @@ "integrity": "sha512-MIifVZdSLdFBRY084PaaQyU8ilG+fgGoVdzGkRLj9Q8hZ2x/ENwjiOveyWLxcjsWMYYwUtm3TTKRvWGrJvX3Iw==", "hasInstallScript": true, "license": "Apache-2.0", - "peer": true, "dependencies": { "@appium/base-driver": "^10.1.2", "@appium/base-plugin": "^3.0.5", @@ -11271,7 +11111,6 @@ "resolved": "https://registry.npmjs.org/teen_process/-/teen_process-3.0.4.tgz", "integrity": "sha512-NQA/5PdJWEAxuYoBRW7RajnAyWmfh5iGMY1kEXiAzobtv0ztERcfDnfszpUTuvhFXrvh3E4GvHt9yWbS/EndzQ==", "license": "Apache-2.0", - "peer": true, "dependencies": { "bluebird": "^3.7.2", "lodash": "^4.17.21", @@ -11288,7 +11127,6 @@ "resolved": "https://registry.npmjs.org/archiver/-/archiver-7.0.1.tgz", "integrity": "sha512-ZcbTaIqJOfCc03QwD468Unz/5Ir8ATtvAHsK+FdXbDIbGfihqh9mrvdcYunQzqn4HrvWWaFyaxJhGZagaJJpPQ==", "license": "MIT", - "peer": true, "dependencies": { "archiver-utils": "^5.0.2", "async": "^3.2.4", @@ -11307,7 +11145,6 @@ "resolved": "https://registry.npmjs.org/archiver-utils/-/archiver-utils-5.0.2.tgz", "integrity": "sha512-wuLJMmIBQYCsGZgYLTy5FIB2pF6Lfb6cXMSF8Qywwk3t20zWnAi7zLcQFdKQmIB8wyZpY5ER38x08GbwtR2cLA==", "license": "MIT", - "peer": true, "dependencies": { "glob": "^10.0.0", "graceful-fs": "^4.2.0", @@ -11326,7 +11163,6 @@ "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.2.tgz", "integrity": "sha512-Jt0vHyM+jmUBqojB7E1NIYadt0vI0Qxjxd2TErW94wDz+E2LAm5vKMXXwg6ZZBTHPuUlDgQHKXvjGBdfcF1ZDQ==", "license": "MIT", - "peer": true, "dependencies": { "balanced-match": "^1.0.0" } @@ -11336,7 +11172,6 @@ "resolved": "https://registry.npmjs.org/glob/-/glob-10.5.0.tgz", "integrity": "sha512-DfXN8DfhJ7NH3Oe7cFmu3NCu1wKbkReJ8TorzSAFbSKrlNaQSKfIzqYqVY8zlbs2NLBbWpRiU52GX2PbaBVNkg==", "license": "ISC", - "peer": true, "dependencies": { "foreground-child": "^3.1.0", "jackspeak": "^3.1.2", @@ -11356,15 +11191,13 @@ "version": "10.4.3", "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-10.4.3.tgz", "integrity": "sha512-JNAzZcXrCt42VGLuYz0zfAzDfAvJWW6AfYlDBQyDV5DClI2m5sAmK+OIO7s59XfsRsWHp02jAJrRadPRGTt6SQ==", - "license": "ISC", - "peer": true + "license": "ISC" }, "node_modules/appium-safari-driver/node_modules/archiver-utils/node_modules/minimatch": { "version": "9.0.5", "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-9.0.5.tgz", "integrity": "sha512-G6T0ZX48xgozx7587koeX9Ys2NYy6Gmv//P89sEte9V9whIapMNF4idKxnW2QtCcLiTWlb/wfCabAtAFWhhBow==", "license": "ISC", - "peer": true, "dependencies": { "brace-expansion": "^2.0.1" }, @@ -11380,7 +11213,6 @@ "resolved": "https://registry.npmjs.org/path-scurry/-/path-scurry-1.11.1.tgz", "integrity": "sha512-Xa4Nw17FS9ApQFJ9umLiJS4orGjm7ZzwUrwamcGQuHSzDyth9boKDaycYdDcZDuqYATXw4HFXgaqWTctW/v1HA==", "license": "BlueOak-1.0.0", - "peer": true, "dependencies": { "lru-cache": "^10.2.0", "minipass": "^5.0.0 || ^6.0.2 || ^7.0.0" @@ -11396,22 +11228,19 @@ "version": "2.0.1", "resolved": "https://registry.npmjs.org/argparse/-/argparse-2.0.1.tgz", "integrity": "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==", - "license": "Python-2.0", - "peer": true + "license": "Python-2.0" }, "node_modules/appium-safari-driver/node_modules/async": { "version": "3.2.6", "resolved": "https://registry.npmjs.org/async/-/async-3.2.6.tgz", "integrity": "sha512-htCUDlxyyCLMgaM3xXg0C0LW2xqfuQ6p05pCEIsXuyQ+a1koYKTuBMzRNwmybfLgvJDMd0r1LTn4+E0Ti6C2AA==", - "license": "MIT", - "peer": true + "license": "MIT" }, "node_modules/appium-safari-driver/node_modules/async-lock": { "version": "1.4.1", "resolved": "https://registry.npmjs.org/async-lock/-/async-lock-1.4.1.tgz", "integrity": "sha512-Az2ZTpuytrtqENulXwO3GGv1Bztugx6TT37NIo7imr/Qo0gsYiGtSdBa2B6fsXhTpVZDNfu1Qn3pk531e3q+nQ==", - "license": "MIT", - "peer": true + "license": "MIT" }, "node_modules/appium-safari-driver/node_modules/asyncbox": { "version": "3.0.0", @@ -11431,15 +11260,13 @@ "version": "0.4.0", "resolved": "https://registry.npmjs.org/asynckit/-/asynckit-0.4.0.tgz", "integrity": "sha512-Oei9OH4tRh0YqU3GxhX79dM/mwVgvbZJaSNaRk+bshkj0S5cfHcgYakreBjrHwatXKbz+IoIdYLxrKim2MjW0Q==", - "license": "MIT", - "peer": true + "license": "MIT" }, "node_modules/appium-safari-driver/node_modules/axios": { "version": "1.13.2", "resolved": "https://registry.npmjs.org/axios/-/axios-1.13.2.tgz", "integrity": "sha512-VPk9ebNqPcy5lRGuSlKx752IlDatOjT9paPlm8A7yOuW2Fbvp4X3JznJtT4f0GzGLLiWE9W8onz51SqLYwzGaA==", "license": "MIT", - "peer": true, "dependencies": { "follow-redirects": "^1.15.6", "form-data": "^4.0.4", @@ -11451,7 +11278,6 @@ "resolved": "https://registry.npmjs.org/b4a/-/b4a-1.7.3.tgz", "integrity": "sha512-5Q2mfq2WfGuFp3uS//0s6baOJLMoVduPYVeNmDYxu5OUA1/cBfvr2RIS7vi62LdNj/urk1hfmj867I3qt6uZ7Q==", "license": "Apache-2.0", - "peer": true, "peerDependencies": { "react-native-b4a": "*" }, @@ -11465,15 +11291,13 @@ "version": "1.0.2", "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz", "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==", - "license": "MIT", - "peer": true + "license": "MIT" }, "node_modules/appium-safari-driver/node_modules/bare-events": { "version": "2.8.2", "resolved": "https://registry.npmjs.org/bare-events/-/bare-events-2.8.2.tgz", "integrity": "sha512-riJjyv1/mHLIPX4RwiK+oW9/4c3TEUeORHKefKAKnZ5kyslbN+HXowtbaVEqt4IMUB7OXlfixcs6gsFeo/jhiQ==", "license": "Apache-2.0", - "peer": true, "peerDependencies": { "bare-abort-controller": "*" }, @@ -11501,22 +11325,19 @@ "url": "https://feross.org/support" } ], - "license": "MIT", - "peer": true + "license": "MIT" }, "node_modules/appium-safari-driver/node_modules/base64-stream": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/base64-stream/-/base64-stream-1.0.0.tgz", "integrity": "sha512-BQQZftaO48FcE1Kof9CmXMFaAdqkcNorgc8CxesZv9nMbbTF1EFyQe89UOuh//QMmdtfUDXyO8rgUalemL5ODA==", - "license": "MIT", - "peer": true + "license": "MIT" }, "node_modules/appium-safari-driver/node_modules/basic-auth": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/basic-auth/-/basic-auth-2.0.1.tgz", "integrity": "sha512-NF+epuEdnUYVlGuhaxbbq+dvJttwLnGY+YixlXlME5KpQ5W3CnXA5cVTneY3SPbPDRkcjMbifrwmFYcClgOZeg==", "license": "MIT", - "peer": true, "dependencies": { "safe-buffer": "5.1.2" }, @@ -11529,7 +11350,6 @@ "resolved": "https://registry.npmjs.org/big-integer/-/big-integer-1.6.52.tgz", "integrity": "sha512-QxD8cf2eVqJOOz63z6JIN9BzvVs/dlySa5HGSBH5xtR8dPteIRQnBxxKqkNTiT6jbDTF6jAfrd4oMcND9RGbQg==", "license": "Unlicense", - "peer": true, "engines": { "node": ">=0.6" } @@ -11539,7 +11359,6 @@ "resolved": "https://registry.npmjs.org/bl/-/bl-4.1.0.tgz", "integrity": "sha512-1W07cM9gS6DcLperZfFSj+bWLtaPGSOHWhPiGzXmvVJbRLdG82sH/Kn8EtW1VqWVA54AKf2h5k5BbnIbwF3h6w==", "license": "MIT", - "peer": true, "dependencies": { "buffer": "^5.5.0", "inherits": "^2.0.4", @@ -11551,7 +11370,6 @@ "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.2.tgz", "integrity": "sha512-9u/sniCrY3D5WdsERHzHE4G2YCXqoG5FTHUiCC4SIbr6XcLZBY05ya9EKjYek9O5xOAwjGq+1JdGBAS7Q9ScoA==", "license": "MIT", - "peer": true, "dependencies": { "inherits": "^2.0.3", "string_decoder": "^1.1.1", @@ -11572,7 +11390,6 @@ "resolved": "https://registry.npmjs.org/body-parser/-/body-parser-2.2.1.tgz", "integrity": "sha512-nfDwkulwiZYQIGwxdy0RUmowMhKcFVcYXUU7m4QlKYim1rUtg83xm2yjZ40QjDuc291AJjjeSc9b++AWHSgSHw==", "license": "MIT", - "peer": true, "dependencies": { "bytes": "^3.1.2", "content-type": "^1.0.5", @@ -11597,7 +11414,6 @@ "resolved": "https://registry.npmjs.org/bplist-creator/-/bplist-creator-0.1.1.tgz", "integrity": "sha512-Ese7052fdWrxp/vqSJkydgx/1MdBnNOCV2XVfbmdGWD2H6EYza+Q4pyYSuVSnCUD22hfI/BFI4jHaC3NLXLlJQ==", "license": "MIT", - "peer": true, "dependencies": { "stream-buffers": "2.2.x" } @@ -11607,7 +11423,6 @@ "resolved": "https://registry.npmjs.org/bplist-parser/-/bplist-parser-0.3.2.tgz", "integrity": "sha512-apC2+fspHGI3mMKj+dGevkGo/tCqVB8jMb6i+OX+E29p0Iposz07fABkRIfVUPNd5A5VbuOz1bZbnmkKLYF+wQ==", "license": "MIT", - "peer": true, "dependencies": { "big-integer": "1.6.x" }, @@ -11634,7 +11449,6 @@ } ], "license": "MIT", - "peer": true, "dependencies": { "base64-js": "^1.3.1", "ieee754": "^1.1.13" @@ -11645,7 +11459,6 @@ "resolved": "https://registry.npmjs.org/buffer-crc32/-/buffer-crc32-1.0.0.tgz", "integrity": "sha512-Db1SbgBS/fg/392AblrMJk97KggmvYhr4pB5ZIMTWtaivCPMWLkmb7m21cJvpvgK+J3nsU2CmmixNBZx4vFj/w==", "license": "MIT", - "peer": true, "engines": { "node": ">=8.0.0" } @@ -11661,7 +11474,6 @@ "resolved": "https://registry.npmjs.org/bytes/-/bytes-3.1.2.tgz", "integrity": "sha512-/Nf7TyzTx6S3yRJObOAV7956r8cr2+Oj8AC5dt8wSP3BQAoeX58NoHyCU8P8zGkNXStjTSi6fzO6F0pBdcYbEg==", "license": "MIT", - "peer": true, "engines": { "node": ">= 0.8" } @@ -11671,7 +11483,6 @@ "resolved": "https://registry.npmjs.org/call-bind-apply-helpers/-/call-bind-apply-helpers-1.0.2.tgz", "integrity": "sha512-Sp1ablJ0ivDkSzjcaJdxEunN5/XvksFJ2sMBFfq6x0ryhQV/2b/KwFe21cMpmHtPOSij8K99/wSfoEuTObmuMQ==", "license": "MIT", - "peer": true, "dependencies": { "es-errors": "^1.3.0", "function-bind": "^1.1.2" @@ -11685,7 +11496,6 @@ "resolved": "https://registry.npmjs.org/call-bound/-/call-bound-1.0.4.tgz", "integrity": "sha512-+ys997U96po4Kx/ABpBCqhA9EuxJaQWDQg7295H4hBphv3IZg0boBKuwYpt4YXp6MZ5AmZQnU/tyMTlRpaSejg==", "license": "MIT", - "peer": true, "dependencies": { "call-bind-apply-helpers": "^1.0.2", "get-intrinsic": "^1.3.0" @@ -11702,7 +11512,6 @@ "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", "license": "MIT", - "peer": true, "dependencies": { "ansi-styles": "^4.1.0", "supports-color": "^7.1.0" @@ -11719,7 +11528,6 @@ "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", "license": "MIT", - "peer": true, "dependencies": { "has-flag": "^4.0.0" }, @@ -11732,7 +11540,6 @@ "resolved": "https://registry.npmjs.org/cli-cursor/-/cli-cursor-3.1.0.tgz", "integrity": "sha512-I/zHAwsKf9FqGoXM4WWRACob9+SNukZTd94DWF57E4toouRulbCxcUh6RKUEOQlYTHJnzkPMySvPNaaSLNfLZw==", "license": "MIT", - "peer": true, "dependencies": { "restore-cursor": "^3.1.0" }, @@ -11745,7 +11552,6 @@ "resolved": "https://registry.npmjs.org/cli-spinners/-/cli-spinners-2.9.2.tgz", "integrity": "sha512-ywqV+5MmyL4E7ybXgKys4DugZbX0FC6LnwrhjuykIjnK9k8OQacQ7axGKnjDXWNhns0xot3bZI5h55H8yo9cJg==", "license": "MIT", - "peer": true, "engines": { "node": ">=6" }, @@ -11758,7 +11564,6 @@ "resolved": "https://registry.npmjs.org/cliui/-/cliui-9.0.1.tgz", "integrity": "sha512-k7ndgKhwoQveBL+/1tqGJYNz097I7WOvwbmmU2AR5+magtbjPWQTS1C5vzGkBC8Ym8UWRzfKUzUUqFLypY4Q+w==", "license": "ISC", - "peer": true, "dependencies": { "string-width": "^7.2.0", "strip-ansi": "^7.1.0", @@ -11773,7 +11578,6 @@ "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-6.2.3.tgz", "integrity": "sha512-4Dj6M28JB+oAH8kFkTLUo+a2jwOFkuqb3yucU0CANcRRUbxS0cP0nZYCGjcc3BNXwRIsUVmDGgzawme7zvJHvg==", "license": "MIT", - "peer": true, "engines": { "node": ">=12" }, @@ -11785,15 +11589,13 @@ "version": "10.6.0", "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-10.6.0.tgz", "integrity": "sha512-toUI84YS5YmxW219erniWD0CIVOo46xGKColeNQRgOzDorgBi1v4D71/OFzgD9GO2UGKIv1C3Sp8DAn0+j5w7A==", - "license": "MIT", - "peer": true + "license": "MIT" }, "node_modules/appium-safari-driver/node_modules/cliui/node_modules/string-width": { "version": "7.2.0", "resolved": "https://registry.npmjs.org/string-width/-/string-width-7.2.0.tgz", "integrity": "sha512-tsaTIkKW9b4N+AEj+SVA+WhJzV7/zMhcSu78mLKWSk7cXMOSHsBKFWUs0fWwq8QyK3MgJBQRX6Gbi4kYbdvGkQ==", "license": "MIT", - "peer": true, "dependencies": { "emoji-regex": "^10.3.0", "get-east-asian-width": "^1.0.0", @@ -11811,7 +11613,6 @@ "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-7.1.2.tgz", "integrity": "sha512-gmBGslpoQJtgnMAvOVqGZpEz9dyoKTCzy2nfz/n8aIFhN/jCE/rCmcxabB6jOOHV+0WNnylOxaxBQPSvcWklhA==", "license": "MIT", - "peer": true, "dependencies": { "ansi-regex": "^6.0.1" }, @@ -11827,7 +11628,6 @@ "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-9.0.2.tgz", "integrity": "sha512-42AtmgqjV+X1VpdOfyTGOYRi0/zsoLqtXQckTmqTeybT+BDIbM/Guxo7x3pE2vtpr1ok6xRqM9OpBe+Jyoqyww==", "license": "MIT", - "peer": true, "dependencies": { "ansi-styles": "^6.2.1", "string-width": "^7.0.0", @@ -11845,7 +11645,6 @@ "resolved": "https://registry.npmjs.org/clone/-/clone-1.0.4.tgz", "integrity": "sha512-JQHZ2QMW6l3aH/j6xCqQThY/9OH4D/9ls34cgkUBiEeocRTU04tHfKPBsUK1PqZCUQM7GiA0IIXJSuXHI64Kbg==", "license": "MIT", - "peer": true, "engines": { "node": ">=0.8" } @@ -11855,7 +11654,6 @@ "resolved": "https://registry.npmjs.org/color/-/color-5.0.3.tgz", "integrity": "sha512-ezmVcLR3xAVp8kYOm4GS45ZLLgIE6SPAFoduLr6hTDajwb3KZ2F46gulK3XpcwRFb5KKGCSezCBAY4Dw4HsyXA==", "license": "MIT", - "peer": true, "dependencies": { "color-convert": "^3.1.3", "color-string": "^2.1.3" @@ -11869,7 +11667,6 @@ "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", "license": "MIT", - "peer": true, "dependencies": { "color-name": "~1.1.4" }, @@ -11881,15 +11678,13 @@ "version": "1.1.4", "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", - "license": "MIT", - "peer": true + "license": "MIT" }, "node_modules/appium-safari-driver/node_modules/color-string": { "version": "2.1.4", "resolved": "https://registry.npmjs.org/color-string/-/color-string-2.1.4.tgz", "integrity": "sha512-Bb6Cq8oq0IjDOe8wJmi4JeNn763Xs9cfrBcaylK1tPypWzyoy2G3l90v9k64kjphl/ZJjPIShFztenRomi8WTg==", "license": "MIT", - "peer": true, "dependencies": { "color-name": "^2.0.0" }, @@ -11902,7 +11697,6 @@ "resolved": "https://registry.npmjs.org/color-name/-/color-name-2.1.0.tgz", "integrity": "sha512-1bPaDNFm0axzE4MEAzKPuqKWeRaT43U/hyxKPBdqTfmPF+d6n7FSoTFxLVULUJOmiLp01KjhIPPH+HrXZJN4Rg==", "license": "MIT", - "peer": true, "engines": { "node": ">=12.20" } @@ -11912,7 +11706,6 @@ "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-3.1.3.tgz", "integrity": "sha512-fasDH2ont2GqF5HpyO4w0+BcewlhHEZOFn9c1ckZdHpJ56Qb7MHhH/IcJZbBGgvdtwdwNbLvxiBEdg336iA9Sg==", "license": "MIT", - "peer": true, "dependencies": { "color-name": "^2.0.0" }, @@ -11925,7 +11718,6 @@ "resolved": "https://registry.npmjs.org/color-name/-/color-name-2.1.0.tgz", "integrity": "sha512-1bPaDNFm0axzE4MEAzKPuqKWeRaT43U/hyxKPBdqTfmPF+d6n7FSoTFxLVULUJOmiLp01KjhIPPH+HrXZJN4Rg==", "license": "MIT", - "peer": true, "engines": { "node": ">=12.20" } @@ -11935,7 +11727,6 @@ "resolved": "https://registry.npmjs.org/combined-stream/-/combined-stream-1.0.8.tgz", "integrity": "sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg==", "license": "MIT", - "peer": true, "dependencies": { "delayed-stream": "~1.0.0" }, @@ -11948,7 +11739,6 @@ "resolved": "https://registry.npmjs.org/commander/-/commander-6.2.1.tgz", "integrity": "sha512-U7VdrJFnJgo4xjrHpTzu0yrHPGImdsmD95ZlgYSEajAn2JKzDhDTPG9kBTefmObL2w/ngeZnilk+OV9CG3d7UA==", "license": "MIT", - "peer": true, "engines": { "node": ">= 6" } @@ -11958,7 +11748,6 @@ "resolved": "https://registry.npmjs.org/compress-commons/-/compress-commons-6.0.2.tgz", "integrity": "sha512-6FqVXeETqWPoGcfzrXb37E50NP0LXT8kAMu5ooZayhWWdgEY4lBEEcbQNXtkuKQsGduxiIcI4gOTsxTmuq/bSg==", "license": "MIT", - "peer": true, "dependencies": { "crc-32": "^1.2.0", "crc32-stream": "^6.0.0", @@ -11975,7 +11764,6 @@ "resolved": "https://registry.npmjs.org/consola/-/consola-3.4.2.tgz", "integrity": "sha512-5IKcdX0nnYavi6G7TtOhwkYzyjfJlatbjMjuLSfE2kYT5pMDOilZ4OvMhi637CcDICTmz3wARPoyhqyX1Y+XvA==", "license": "MIT", - "peer": true, "engines": { "node": "^14.18.0 || >=16.10.0" } @@ -11991,7 +11779,6 @@ "resolved": "https://registry.npmjs.org/content-disposition/-/content-disposition-1.0.1.tgz", "integrity": "sha512-oIXISMynqSqm241k6kcQ5UwttDILMK4BiurCfGEREw6+X9jkkpEe5T9FZaApyLGGOnFuyMWZpdolTXMtvEJ08Q==", "license": "MIT", - "peer": true, "engines": { "node": ">=18" }, @@ -12005,7 +11792,6 @@ "resolved": "https://registry.npmjs.org/content-type/-/content-type-1.0.5.tgz", "integrity": "sha512-nTjqfcBFEipKdXCv4YDQWCfmcLZKm81ldF0pAopTvyrFGVbcR6P/VAAd5G7N+0tTr8QqiU0tFadD6FK4NtJwOA==", "license": "MIT", - "peer": true, "engines": { "node": ">= 0.6" } @@ -12015,7 +11801,6 @@ "resolved": "https://registry.npmjs.org/cookie/-/cookie-0.7.2.tgz", "integrity": "sha512-yki5XnKuf750l50uGTllt6kKILY4nQ1eNIQatoXEByZ5dWgnKqbnqmTrBE5B4N7lrMJKQ2ytWMiTO2o0v6Ew/w==", "license": "MIT", - "peer": true, "engines": { "node": ">= 0.6" } @@ -12025,7 +11810,6 @@ "resolved": "https://registry.npmjs.org/cookie-signature/-/cookie-signature-1.2.2.tgz", "integrity": "sha512-D76uU73ulSXrD1UXF4KE2TMxVVwhsnCgfAyTg9k8P6KGZjlXKrOLe4dJQKI3Bxi5wjesZoFXJWElNWBjPZMbhg==", "license": "MIT", - "peer": true, "engines": { "node": ">=6.6.0" } @@ -12034,15 +11818,13 @@ "version": "1.0.3", "resolved": "https://registry.npmjs.org/core-util-is/-/core-util-is-1.0.3.tgz", "integrity": "sha512-ZQBvi1DcpJ4GDqanjucZ2Hj3wEO5pZDS89BWbkcrvdxksJorwUDDZamX9ldFkp9aw2lmBDLgkObEA4DWNJ9FYQ==", - "license": "MIT", - "peer": true + "license": "MIT" }, "node_modules/appium-safari-driver/node_modules/crc-32": { "version": "1.2.2", "resolved": "https://registry.npmjs.org/crc-32/-/crc-32-1.2.2.tgz", "integrity": "sha512-ROmzCKrTnOwybPcJApAA6WBWij23HVfGVNKqqrZpuyZOHqK2CwHSvpGuyt/UNNvaIjEd8X5IFGp4Mh+Ie1IHJQ==", "license": "Apache-2.0", - "peer": true, "bin": { "crc32": "bin/crc32.njs" }, @@ -12055,7 +11837,6 @@ "resolved": "https://registry.npmjs.org/crc32-stream/-/crc32-stream-6.0.0.tgz", "integrity": "sha512-piICUB6ei4IlTv1+653yq5+KoqfBYmj9bw6LqXoOneTMDXk5nM1qt12mFW1caG3LlJXEKW1Bp0WggEmIfQB34g==", "license": "MIT", - "peer": true, "dependencies": { "crc-32": "^1.2.0", "readable-stream": "^4.0.0" @@ -12069,7 +11850,6 @@ "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.6.tgz", "integrity": "sha512-uV2QOWP2nWzsy2aMp8aRibhi9dlzF5Hgh5SHaB9OiTGEyDTiJJyx0uy51QXdyWbtAHNua4XJzUKca3OzKUd3vA==", "license": "MIT", - "peer": true, "dependencies": { "path-key": "^3.1.0", "shebang-command": "^2.0.0", @@ -12083,15 +11863,13 @@ "version": "2.0.0", "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz", "integrity": "sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==", - "license": "ISC", - "peer": true + "license": "ISC" }, "node_modules/appium-safari-driver/node_modules/cross-spawn/node_modules/which": { "version": "2.0.2", "resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz", "integrity": "sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==", "license": "ISC", - "peer": true, "dependencies": { "isexe": "^2.0.0" }, @@ -12107,7 +11885,6 @@ "resolved": "https://registry.npmjs.org/debug/-/debug-4.4.3.tgz", "integrity": "sha512-RGwwWnwQvkVfavKVt22FGLw+xYSdzARwm0ru6DhTVA3umU5hZc28V3kO4stgYryrTlLpuvgI9GiijltAjNbcqA==", "license": "MIT", - "peer": true, "dependencies": { "ms": "^2.1.3" }, @@ -12125,7 +11902,6 @@ "resolved": "https://registry.npmjs.org/defaults/-/defaults-1.0.4.tgz", "integrity": "sha512-eFuaLoy/Rxalv2kr+lqMlUnrDWV+3j4pljOIJgLIhI058IQfWJ7vXhyEIHu+HtC738klGALYxOKDO0bQP3tg8A==", "license": "MIT", - "peer": true, "dependencies": { "clone": "^1.0.2" }, @@ -12138,7 +11914,6 @@ "resolved": "https://registry.npmjs.org/delayed-stream/-/delayed-stream-1.0.0.tgz", "integrity": "sha512-ZySD7Nf91aLB0RxL4KGrKHBXl7Eds1DAmEdcoVawXnLD7SDhpNgtuII2aAkg7a7QS41jxPSZ17p4VdGnMHk3MQ==", "license": "MIT", - "peer": true, "engines": { "node": ">=0.4.0" } @@ -12148,7 +11923,6 @@ "resolved": "https://registry.npmjs.org/depd/-/depd-2.0.0.tgz", "integrity": "sha512-g7nH6P6dyDioJogAAGprGpCtVImJhpPk/roCzdb3fIh61/s/nPsfR6onyMwkCAR/OlC3yBC0lESvUoQEAssIrw==", "license": "MIT", - "peer": true, "engines": { "node": ">= 0.8" } @@ -12159,7 +11933,6 @@ "integrity": "sha512-Btj2BOOO83o3WyH59e8MgXsxEQVcarkUOpEYrubB0urwnN10yQ364rsiByU11nZlqWYZm05i/of7io4mzihBtQ==", "license": "Apache-2.0", "optional": true, - "peer": true, "engines": { "node": ">=8" } @@ -12169,15 +11942,13 @@ "resolved": "https://registry.npmjs.org/detect-node/-/detect-node-2.1.0.tgz", "integrity": "sha512-T0NIuQpnTvFDATNuHN5roPwSBG83rFsuO+MXXH9/3N1eFbn4wcPjttvjMLEPWJ0RGUYgQE7cGgS3tNxbqCGM7g==", "license": "MIT", - "optional": true, - "peer": true + "optional": true }, "node_modules/appium-safari-driver/node_modules/diff": { "version": "8.0.2", "resolved": "https://registry.npmjs.org/diff/-/diff-8.0.2.tgz", "integrity": "sha512-sSuxWU5j5SR9QQji/o2qMvqRNYRDOcBTgsJ/DeCf4iSN4gW+gNMXM7wFIP+fdXZxoNiAnHUTGjCr+TSWXdRDKg==", "license": "BSD-3-Clause", - "peer": true, "engines": { "node": ">=0.3.1" } @@ -12187,7 +11958,6 @@ "resolved": "https://registry.npmjs.org/dunder-proto/-/dunder-proto-1.0.1.tgz", "integrity": "sha512-KIN/nDJBQRcXw0MLVhZE9iQHmG68qAVIBg9CqmUYjmQIhgij9U5MFvrqkUL5FbtyyzZuOeOt0zdeRe4UY7ct+A==", "license": "MIT", - "peer": true, "dependencies": { "call-bind-apply-helpers": "^1.0.1", "es-errors": "^1.3.0", @@ -12201,43 +11971,37 @@ "version": "0.1.2", "resolved": "https://registry.npmjs.org/duplexer/-/duplexer-0.1.2.tgz", "integrity": "sha512-jtD6YG370ZCIi/9GTaJKQxWTZD045+4R4hTk/x1UyoqadyJ9x9CgSi1RlVDQF8U2sxLLSnFkCaMihqljHIWgMg==", - "license": "MIT", - "peer": true + "license": "MIT" }, "node_modules/appium-safari-driver/node_modules/eastasianwidth": { "version": "0.2.0", "resolved": "https://registry.npmjs.org/eastasianwidth/-/eastasianwidth-0.2.0.tgz", "integrity": "sha512-I88TYZWc9XiYHRQ4/3c5rjjfgkjhLyW2luGIheGERbNQ6OY7yTybanSpDXZa8y7VUP9YmDcYa+eyq4ca7iLqWA==", - "license": "MIT", - "peer": true + "license": "MIT" }, "node_modules/appium-safari-driver/node_modules/ee-first": { "version": "1.1.1", "resolved": "https://registry.npmjs.org/ee-first/-/ee-first-1.1.1.tgz", "integrity": "sha512-WMwm9LhRUo+WUaRN+vRuETqG89IgZphVSNkdFgeb6sS/E4OrDIN7t48CAewSHXc6C8lefD8KKfr5vY61brQlow==", - "license": "MIT", - "peer": true + "license": "MIT" }, "node_modules/appium-safari-driver/node_modules/emoji-regex": { "version": "8.0.0", "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz", "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==", - "license": "MIT", - "peer": true + "license": "MIT" }, "node_modules/appium-safari-driver/node_modules/enabled": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/enabled/-/enabled-2.0.0.tgz", "integrity": "sha512-AKrN98kuwOzMIdAizXGI86UFBoo26CL21UM763y1h/GMSJ4/OHU9k2YlsmBpyScFo/wbLzWQJBMCW4+IO3/+OQ==", - "license": "MIT", - "peer": true + "license": "MIT" }, "node_modules/appium-safari-driver/node_modules/encodeurl": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/encodeurl/-/encodeurl-2.0.0.tgz", "integrity": "sha512-Q0n9HRi4m6JuGIV1eFlmvJB7ZEVxu93IrMyiMsGC0lrMJMWzRgx6WGquyfQgZVb31vhGgXnfmPNNXmxnOkRBrg==", "license": "MIT", - "peer": true, "engines": { "node": ">= 0.8" } @@ -12247,7 +12011,6 @@ "resolved": "https://registry.npmjs.org/error-ex/-/error-ex-1.3.4.tgz", "integrity": "sha512-sqQamAnR14VgCr1A618A3sGrygcpK+HEbenA/HiEAkkUwcZIIB/tgWqHFxWgOyDh4nB4JCRimh79dR5Ywc9MDQ==", "license": "MIT", - "peer": true, "dependencies": { "is-arrayish": "^0.2.1" } @@ -12257,7 +12020,6 @@ "resolved": "https://registry.npmjs.org/es-define-property/-/es-define-property-1.0.1.tgz", "integrity": "sha512-e3nRfgfUZ4rNGL232gUgX06QNyyez04KdjFrF+LTRoOXmrOgFKDg4BCdsjW8EnT69eqdYGmRpJwiPVYNrCaW3g==", "license": "MIT", - "peer": true, "engines": { "node": ">= 0.4" } @@ -12267,7 +12029,6 @@ "resolved": "https://registry.npmjs.org/es-errors/-/es-errors-1.3.0.tgz", "integrity": "sha512-Zf5H2Kxt2xjTvbJvP2ZWLEICxA6j+hAmMzIlypy4xcBg1vKVnx89Wy0GbS+kf5cwCVFFzdCFh2XSCFNULS6csw==", "license": "MIT", - "peer": true, "engines": { "node": ">= 0.4" } @@ -12277,7 +12038,6 @@ "resolved": "https://registry.npmjs.org/es-object-atoms/-/es-object-atoms-1.1.1.tgz", "integrity": "sha512-FGgH2h8zKNim9ljj7dankFPcICIK9Cp5bm+c2gQSYePhpaG5+esrLODihIorn+Pe6FGJzWhXQotPv73jTaldXA==", "license": "MIT", - "peer": true, "dependencies": { "es-errors": "^1.3.0" }, @@ -12290,7 +12050,6 @@ "resolved": "https://registry.npmjs.org/es-set-tostringtag/-/es-set-tostringtag-2.1.0.tgz", "integrity": "sha512-j6vWzfrGVfyXxge+O0x5sh6cvxAog0a/4Rdd2K36zCMV5eJ+/+tOAngRO8cODMNWbVRdVlmGZQL2YS3yR8bIUA==", "license": "MIT", - "peer": true, "dependencies": { "es-errors": "^1.3.0", "get-intrinsic": "^1.2.6", @@ -12306,7 +12065,6 @@ "resolved": "https://registry.npmjs.org/escalade/-/escalade-3.2.0.tgz", "integrity": "sha512-WUj2qlxaQtO4g6Pq5c29GTcWGDyd8itL8zTlipgECz3JesAiiOKotd8JU6otB3PACgG6xkJUyVhboMS+bje/jA==", "license": "MIT", - "peer": true, "engines": { "node": ">=6" } @@ -12315,15 +12073,13 @@ "version": "1.0.3", "resolved": "https://registry.npmjs.org/escape-html/-/escape-html-1.0.3.tgz", "integrity": "sha512-NiSupZ4OeuGwr68lGIeym/ksIZMJodUGOSCZ/FSnTxcrekbvqrgdUxlJOMpijaKZVjAJrWrGs/6Jy8OMuyj9ow==", - "license": "MIT", - "peer": true + "license": "MIT" }, "node_modules/appium-safari-driver/node_modules/etag": { "version": "1.8.1", "resolved": "https://registry.npmjs.org/etag/-/etag-1.8.1.tgz", "integrity": "sha512-aIL5Fx7mawVa300al2BnEE4iNvo1qETxLrPI/o05L7z6go7fCw1J6EQmbK4FmJ2AS7kgVF/KEZWufBfdClMcPg==", "license": "MIT", - "peer": true, "engines": { "node": ">= 0.6" } @@ -12333,7 +12089,6 @@ "resolved": "https://registry.npmjs.org/event-target-shim/-/event-target-shim-5.0.1.tgz", "integrity": "sha512-i/2XbnSz/uxRCU6+NdVJgKWDTM427+MqYbkQzD321DuCQJUqOuJKIA0IM2+W2xtYHdKOmZ4dR6fExsd4SXL+WQ==", "license": "MIT", - "peer": true, "engines": { "node": ">=6" } @@ -12343,7 +12098,6 @@ "resolved": "https://registry.npmjs.org/events/-/events-3.3.0.tgz", "integrity": "sha512-mQw+2fkQbALzQ7V0MY0IqdnXNOeTtP4r0lN9z7AAawCXgqea7bDii20AYrIBrFd/Hx0M2Ocz6S111CaFkUcb0Q==", "license": "MIT", - "peer": true, "engines": { "node": ">=0.8.x" } @@ -12353,7 +12107,6 @@ "resolved": "https://registry.npmjs.org/events-universal/-/events-universal-1.0.1.tgz", "integrity": "sha512-LUd5euvbMLpwOF8m6ivPCbhQeSiYVNb8Vs0fQ8QjXo0JTkEHpz8pxdQf0gStltaPpw0Cca8b39KxvK9cfKRiAw==", "license": "Apache-2.0", - "peer": true, "dependencies": { "bare-events": "^2.7.0" } @@ -12363,7 +12116,6 @@ "resolved": "https://registry.npmjs.org/express/-/express-5.2.1.tgz", "integrity": "sha512-hIS4idWWai69NezIdRt2xFVofaF4j+6INOpJlVOLDO8zXGpUVEVzIYk12UUi2JzjEzWL3IOAxcTubgz9Po0yXw==", "license": "MIT", - "peer": true, "dependencies": { "accepts": "^2.0.0", "body-parser": "^2.2.1", @@ -12413,8 +12165,7 @@ "version": "1.3.2", "resolved": "https://registry.npmjs.org/fast-fifo/-/fast-fifo-1.3.2.tgz", "integrity": "sha512-/d9sfos4yxzpwkDkuN7k2SqFKtYNmCTzgfEpz82x34IM9/zc8KGxQoXg1liNC/izpRM/MBdt44Nmx41ZWqk+FQ==", - "license": "MIT", - "peer": true + "license": "MIT" }, "node_modules/appium-safari-driver/node_modules/fast-uri": { "version": "3.1.0", @@ -12438,7 +12189,6 @@ "resolved": "https://registry.npmjs.org/fastest-levenshtein/-/fastest-levenshtein-1.0.16.tgz", "integrity": "sha512-eRnCtTTtGZFpQCwhJiUOuxPQWRXVKYDn0b2PeHfXL6/Zi53SLAzAHfVhVWK2AryC/WH05kGfxhFIPvTF0SXQzg==", "license": "MIT", - "peer": true, "engines": { "node": ">= 4.9.1" } @@ -12447,15 +12197,13 @@ "version": "4.2.3", "resolved": "https://registry.npmjs.org/fecha/-/fecha-4.2.3.tgz", "integrity": "sha512-OP2IUU6HeYKJi3i0z4A19kHMQoLVs4Hc+DPqqxI2h/DPZHTm/vjsfC6P0b4jCMy14XizLBqvndQ+UilD7707Jw==", - "license": "MIT", - "peer": true + "license": "MIT" }, "node_modules/appium-safari-driver/node_modules/finalhandler": { "version": "2.1.1", "resolved": "https://registry.npmjs.org/finalhandler/-/finalhandler-2.1.1.tgz", "integrity": "sha512-S8KoZgRZN+a5rNwqTxlZZePjT/4cnm0ROV70LedRHZ0p8u9fRID0hJUZQpkKLzro8LfmC8sx23bY6tVNxv8pQA==", "license": "MIT", - "peer": true, "dependencies": { "debug": "^4.4.0", "encodeurl": "^2.0.0", @@ -12477,7 +12225,6 @@ "resolved": "https://registry.npmjs.org/find-up/-/find-up-5.0.0.tgz", "integrity": "sha512-78/PXT1wlLLDgTzDs7sjq9hzz0vXD+zn+7wypEe4fXQxCmdmqfGsEPQxmiCSQI3ajFV91bVSsvNtrJRiW6nGng==", "license": "MIT", - "peer": true, "dependencies": { "locate-path": "^6.0.0", "path-exists": "^4.0.0" @@ -12493,8 +12240,7 @@ "version": "1.1.0", "resolved": "https://registry.npmjs.org/fn.name/-/fn.name-1.1.0.tgz", "integrity": "sha512-GRnmB5gPyJpAhTQdSZTSp9uaPSvl09KoYcMQtsB9rQoOmzs9dH6ffeccH+Z+cv6P68Hu5bC6JjRh4Ah/mHSNRw==", - "license": "MIT", - "peer": true + "license": "MIT" }, "node_modules/appium-safari-driver/node_modules/follow-redirects": { "version": "1.15.11", @@ -12507,7 +12253,6 @@ } ], "license": "MIT", - "peer": true, "engines": { "node": ">=4.0" }, @@ -12522,7 +12267,6 @@ "resolved": "https://registry.npmjs.org/foreground-child/-/foreground-child-3.3.1.tgz", "integrity": "sha512-gIXjKqtFuWEgzFRJA9WCQeSJLZDjgJUOMCMzxtvFq/37KojM1BFGufqsCy0r4qSQmYLsZYMeyRqzIWOMup03sw==", "license": "ISC", - "peer": true, "dependencies": { "cross-spawn": "^7.0.6", "signal-exit": "^4.0.1" @@ -12539,7 +12283,6 @@ "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-4.1.0.tgz", "integrity": "sha512-bzyZ1e88w9O1iNJbKnOlvYTrWPDl46O1bG0D3XInv+9tkPrxrN8jUUTiFlDkkmKWgn1M6CfIA13SuGqOa9Korw==", "license": "ISC", - "peer": true, "engines": { "node": ">=14" }, @@ -12552,7 +12295,6 @@ "resolved": "https://registry.npmjs.org/form-data/-/form-data-4.0.5.tgz", "integrity": "sha512-8RipRLol37bNs2bhoV67fiTEvdTrbMUYcFTiy3+wuuOnUog2QBHCZWXDRijWQfAkhBj2Uf5UnVaiWwA5vdd82w==", "license": "MIT", - "peer": true, "dependencies": { "asynckit": "^0.4.0", "combined-stream": "^1.0.8", @@ -12569,7 +12311,6 @@ "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.52.0.tgz", "integrity": "sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg==", "license": "MIT", - "peer": true, "engines": { "node": ">= 0.6" } @@ -12579,7 +12320,6 @@ "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.35.tgz", "integrity": "sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw==", "license": "MIT", - "peer": true, "dependencies": { "mime-db": "1.52.0" }, @@ -12592,7 +12332,6 @@ "resolved": "https://registry.npmjs.org/forwarded/-/forwarded-0.2.0.tgz", "integrity": "sha512-buRG0fpBtRHSTCOASe6hD258tEubFoRLb4ZNA6NxMVHNw2gOcwHo9wyablzMzOA5z9xA9L1KNjk/Nt6MT9aYow==", "license": "MIT", - "peer": true, "engines": { "node": ">= 0.6" } @@ -12602,7 +12341,6 @@ "resolved": "https://registry.npmjs.org/fresh/-/fresh-2.0.0.tgz", "integrity": "sha512-Rx/WycZ60HOaqLKAi6cHRKKI7zxWbJ31MhntmtwMoaTeF7XFH9hhBp8vITaMidfljRQ6eYWCKkaTK+ykVJHP2A==", "license": "MIT", - "peer": true, "engines": { "node": ">= 0.8" } @@ -12611,7 +12349,6 @@ "version": "1.0.1", "resolved": "https://registry.npmjs.org/ftp-response-parser/-/ftp-response-parser-1.0.1.tgz", "integrity": "sha512-++Ahlo2hs/IC7UVQzjcSAfeUpCwTTzs4uvG5XfGnsinIFkWUYF4xWwPd5qZuK8MJrmUIxFMuHcfqaosCDjvIWw==", - "peer": true, "dependencies": { "readable-stream": "^1.0.31" }, @@ -12623,15 +12360,13 @@ "version": "0.0.1", "resolved": "https://registry.npmjs.org/isarray/-/isarray-0.0.1.tgz", "integrity": "sha512-D2S+3GLxWH+uhrNEcoh/fnmYeP8E8/zHl644d/jdA0g2uyXvy3sb0qxotE+ne0LtccHknQzWwZEzhak7oJ0COQ==", - "license": "MIT", - "peer": true + "license": "MIT" }, "node_modules/appium-safari-driver/node_modules/ftp-response-parser/node_modules/readable-stream": { "version": "1.1.14", "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-1.1.14.tgz", "integrity": "sha512-+MeVjFf4L44XUkhM1eYbD8fyEsxcV81pqMSR5gblfcLCHfZvbrqy4/qYHE+/R5HoBUT11WV5O08Cr1n3YXkWVQ==", "license": "MIT", - "peer": true, "dependencies": { "core-util-is": "~1.0.0", "inherits": "~2.0.1", @@ -12643,15 +12378,13 @@ "version": "0.10.31", "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-0.10.31.tgz", "integrity": "sha512-ev2QzSzWPYmy9GuqfIVildA4OdcGLeFZQrq5ys6RtiuF+RQQiZWr8TZNyAcuVXyQRYfEO+MsoB/1BuQVhOJuoQ==", - "license": "MIT", - "peer": true + "license": "MIT" }, "node_modules/appium-safari-driver/node_modules/function-bind": { "version": "1.1.2", "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.2.tgz", "integrity": "sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA==", "license": "MIT", - "peer": true, "funding": { "url": "https://github.com/sponsors/ljharb" } @@ -12661,7 +12394,6 @@ "resolved": "https://registry.npmjs.org/get-caller-file/-/get-caller-file-2.0.5.tgz", "integrity": "sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg==", "license": "ISC", - "peer": true, "engines": { "node": "6.* || 8.* || >= 10.*" } @@ -12671,7 +12403,6 @@ "resolved": "https://registry.npmjs.org/get-east-asian-width/-/get-east-asian-width-1.4.0.tgz", "integrity": "sha512-QZjmEOC+IT1uk6Rx0sX22V6uHWVwbdbxf1faPqJ1QhLdGgsRGCZoyaQBm/piRdJy/D2um6hM1UP7ZEeQ4EkP+Q==", "license": "MIT", - "peer": true, "engines": { "node": ">=18" }, @@ -12684,7 +12415,6 @@ "resolved": "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.3.0.tgz", "integrity": "sha512-9fSjSaos/fRIVIp+xSJlE6lfwhES7LNtKaCBIamHsjr2na1BiABJPo0mOjjz8GJDURarmCPGqaiVg5mfjb98CQ==", "license": "MIT", - "peer": true, "dependencies": { "call-bind-apply-helpers": "^1.0.2", "es-define-property": "^1.0.1", @@ -12709,7 +12439,6 @@ "resolved": "https://registry.npmjs.org/get-proto/-/get-proto-1.0.1.tgz", "integrity": "sha512-sTSfBjoXBp89JvIKIefqw7U2CCebsc74kiY6awiGogKtoSGbgjYE/G/+l9sF3MWFPNc9IcoOC4ODfKHfxFmp0g==", "license": "MIT", - "peer": true, "dependencies": { "dunder-proto": "^1.0.1", "es-object-atoms": "^1.0.0" @@ -12723,7 +12452,6 @@ "resolved": "https://registry.npmjs.org/get-stream/-/get-stream-6.0.1.tgz", "integrity": "sha512-ts6Wi+2j3jQjqi70w5AlN8DFnkSwC+MqmxEzdEALB2qXZYV3X/b1CTfgPLGJNMeAWxdPfU8FO1ms3NUfaHCPYg==", "license": "MIT", - "peer": true, "engines": { "node": ">=10" }, @@ -12768,7 +12496,6 @@ "resolved": "https://registry.npmjs.org/gopd/-/gopd-1.2.0.tgz", "integrity": "sha512-ZUKRh6/kUFoAiTAtTYPZJ3hw9wNxx+BIBOijnlG9PnrJsCcSjs1wyyD6vJpaYtgnzDrKYRSqf3OO6Rfa93xsRg==", "license": "MIT", - "peer": true, "engines": { "node": ">= 0.4" }, @@ -12780,23 +12507,20 @@ "version": "4.2.11", "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.11.tgz", "integrity": "sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ==", - "license": "ISC", - "peer": true + "license": "ISC" }, "node_modules/appium-safari-driver/node_modules/handle-thing": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/handle-thing/-/handle-thing-2.0.1.tgz", "integrity": "sha512-9Qn4yBxelxoh2Ow62nP+Ka/kMnOXRi8BXnRaUwezLNhqelnN49xKz4F/dPP8OYLxLxq6JDtZb2i9XznUQbNPTg==", "license": "MIT", - "optional": true, - "peer": true + "optional": true }, "node_modules/appium-safari-driver/node_modules/has-flag": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", "license": "MIT", - "peer": true, "engines": { "node": ">=8" } @@ -12806,7 +12530,6 @@ "resolved": "https://registry.npmjs.org/has-symbols/-/has-symbols-1.1.0.tgz", "integrity": "sha512-1cDNdwJ2Jaohmb3sg4OmKaMBwuC48sYni5HUw2DvsC8LjGTLK9h+eb1X6RyuOHe4hT0ULCW68iomhjUoKUqlPQ==", "license": "MIT", - "peer": true, "engines": { "node": ">= 0.4" }, @@ -12819,7 +12542,6 @@ "resolved": "https://registry.npmjs.org/has-tostringtag/-/has-tostringtag-1.0.2.tgz", "integrity": "sha512-NqADB8VjPFLM2V0VvHUewwwsw0ZWBaIdgo+ieHtK3hasLz4qeCRjYcqfB6AQrBggRKppKF8L52/VqdVsO47Dlw==", "license": "MIT", - "peer": true, "dependencies": { "has-symbols": "^1.0.3" }, @@ -12835,7 +12557,6 @@ "resolved": "https://registry.npmjs.org/hasown/-/hasown-2.0.2.tgz", "integrity": "sha512-0hJU9SCPvmMzIBdZFqNPXWa6dqh7WdH0cII9y+CyS8rG3nL48Bclra9HmKhVVUHyPWNH5Y7xDwAB7bfgSjkUMQ==", "license": "MIT", - "peer": true, "dependencies": { "function-bind": "^1.1.2" }, @@ -12847,8 +12568,7 @@ "version": "2.8.9", "resolved": "https://registry.npmjs.org/hosted-git-info/-/hosted-git-info-2.8.9.tgz", "integrity": "sha512-mxIDAb9Lsm6DoOJ7xH+5+X4y1LU/4Hi50L9C5sIswK3JzULS4bwk1FvjdBgvYR4bzT4tuUQiC15FE2f5HbLvYw==", - "license": "ISC", - "peer": true + "license": "ISC" }, "node_modules/appium-safari-driver/node_modules/hpack.js": { "version": "2.1.6", @@ -12856,7 +12576,6 @@ "integrity": "sha512-zJxVehUdMGIKsRaNt7apO2Gqp0BdqW5yaiGHXXmbpvxgBYVZnAql+BJb4RO5ad2MgpbZKn5G6nMnegrH1FcNYQ==", "license": "MIT", "optional": true, - "peer": true, "dependencies": { "inherits": "^2.0.1", "obuf": "^1.0.0", @@ -12869,8 +12588,7 @@ "resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz", "integrity": "sha512-VLghIWNM6ELQzo7zwmcg0NmTVyWKYjvIeM83yjp0wRDTmUnrM678fQbcKBo6n2CJEF0szoG//ytg+TKla89ALQ==", "license": "MIT", - "optional": true, - "peer": true + "optional": true }, "node_modules/appium-safari-driver/node_modules/hpack.js/node_modules/readable-stream": { "version": "2.3.8", @@ -12878,7 +12596,6 @@ "integrity": "sha512-8p0AUk4XODgIewSi0l8Epjs+EVnWiK7NoDIEGU0HhE7+ZyY8D1IMY7odu5lRrFXGg71L15KG8QrPmum45RTtdA==", "license": "MIT", "optional": true, - "peer": true, "dependencies": { "core-util-is": "~1.0.0", "inherits": "~2.0.3", @@ -12895,7 +12612,6 @@ "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==", "license": "MIT", "optional": true, - "peer": true, "dependencies": { "safe-buffer": "~5.1.0" } @@ -12905,15 +12621,13 @@ "resolved": "https://registry.npmjs.org/http-deceiver/-/http-deceiver-1.2.7.tgz", "integrity": "sha512-LmpOGxTfbpgtGVxJrj5k7asXHCgNZp5nLfp+hWc8QQRqtb7fUy6kRY3BO1h9ddF6yIPYUARgxGOwB42DnxIaNw==", "license": "MIT", - "optional": true, - "peer": true + "optional": true }, "node_modules/appium-safari-driver/node_modules/http-errors": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/http-errors/-/http-errors-2.0.1.tgz", "integrity": "sha512-4FbRdAX+bSdmo4AUFuS0WNiPz8NgFt+r8ThgNWmlrjQjt1Q7ZR9+zTlce2859x4KSXrwIsaeTqDoKQmtP8pLmQ==", "license": "MIT", - "peer": true, "dependencies": { "depd": "~2.0.0", "inherits": "~2.0.4", @@ -12933,15 +12647,13 @@ "version": "2.3.0", "resolved": "https://registry.npmjs.org/http-status-codes/-/http-status-codes-2.3.0.tgz", "integrity": "sha512-RJ8XvFvpPM/Dmc5SV+dC4y5PCeOhT3x1Hq0NU3rjGeg5a/CqlhZ7uudknPwZFz4aeAXDcbAyaeP7GAo9lvngtA==", - "license": "MIT", - "peer": true + "license": "MIT" }, "node_modules/appium-safari-driver/node_modules/iconv-lite": { "version": "0.7.1", "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.7.1.tgz", "integrity": "sha512-2Tth85cXwGFHfvRgZWszZSvdo+0Xsqmw8k8ZwxScfcBneNUraK+dxRxRm24nszx80Y0TVio8kKLt5sLE7ZCLlw==", "license": "MIT", - "peer": true, "dependencies": { "safer-buffer": ">= 2.1.2 < 3.0.0" }, @@ -12971,22 +12683,19 @@ "url": "https://feross.org/support" } ], - "license": "BSD-3-Clause", - "peer": true + "license": "BSD-3-Clause" }, "node_modules/appium-safari-driver/node_modules/inherits": { "version": "2.0.4", "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz", "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==", - "license": "ISC", - "peer": true + "license": "ISC" }, "node_modules/appium-safari-driver/node_modules/ipaddr.js": { "version": "1.9.1", "resolved": "https://registry.npmjs.org/ipaddr.js/-/ipaddr.js-1.9.1.tgz", "integrity": "sha512-0KI/607xoxSToH7GjN1FfSbLoU0+btTicjsQSWQlh/hZykN8KpmMf7uYwPW3R+akZ6R/w18ZlXSHBYXiYUPO3g==", "license": "MIT", - "peer": true, "engines": { "node": ">= 0.10" } @@ -12995,15 +12704,13 @@ "version": "0.2.1", "resolved": "https://registry.npmjs.org/is-arrayish/-/is-arrayish-0.2.1.tgz", "integrity": "sha512-zz06S8t0ozoDXMG+ube26zeCTNXcKIPJZJi8hBrF4idCLms4CG9QtK7qBl1boi5ODzFpjswb5JPmHCbMpjaYzg==", - "license": "MIT", - "peer": true + "license": "MIT" }, "node_modules/appium-safari-driver/node_modules/is-core-module": { "version": "2.16.1", "resolved": "https://registry.npmjs.org/is-core-module/-/is-core-module-2.16.1.tgz", "integrity": "sha512-UfoeMA6fIJ8wTYFEUjelnaGI67v6+N7qXJEvQuIGa99l4xsCruSYOVSQ0uPANn4dAzm8lkYPaKLrrijLq7x23w==", "license": "MIT", - "peer": true, "dependencies": { "hasown": "^2.0.2" }, @@ -13019,7 +12726,6 @@ "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz", "integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==", "license": "MIT", - "peer": true, "engines": { "node": ">=8" } @@ -13029,7 +12735,6 @@ "resolved": "https://registry.npmjs.org/is-interactive/-/is-interactive-1.0.0.tgz", "integrity": "sha512-2HvIEKRoqS62guEC+qBjpvRubdX910WCMuJTZ+I9yvqKU2/12eSL549HMwtabb4oupdj2sMP50k+XJfB/8JE6w==", "license": "MIT", - "peer": true, "engines": { "node": ">=8" } @@ -13047,15 +12752,13 @@ "version": "4.0.0", "resolved": "https://registry.npmjs.org/is-promise/-/is-promise-4.0.0.tgz", "integrity": "sha512-hvpoI6korhJMnej285dSg6nu1+e6uxs7zG3BYAm5byqDsgJNWwxzM6z6iZiAgQR4TJ30JmBTOwqZUw3WlyH3AQ==", - "license": "MIT", - "peer": true + "license": "MIT" }, "node_modules/appium-safari-driver/node_modules/is-stream": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/is-stream/-/is-stream-2.0.1.tgz", "integrity": "sha512-hFoiJiTl63nn+kstHGBtewWSKnQLpyb155KHheA1l39uvtO9nWIop1p3udqPcUd/xbF1VLMO4n7OI6p7RbngDg==", "license": "MIT", - "peer": true, "engines": { "node": ">=8" }, @@ -13068,7 +12771,6 @@ "resolved": "https://registry.npmjs.org/is-unicode-supported/-/is-unicode-supported-0.1.0.tgz", "integrity": "sha512-knxG2q4UC3u8stRGyAVJCOdxFmv5DZiRcdlIaAQXAbSfJya+OhopNotLQrstBhququ4ZpuKbDc/8S6mgXgPFPw==", "license": "MIT", - "peer": true, "engines": { "node": ">=10" }, @@ -13090,7 +12792,6 @@ "resolved": "https://registry.npmjs.org/jackspeak/-/jackspeak-3.4.3.tgz", "integrity": "sha512-OGlZQpz2yfahA/Rd1Y8Cd9SIEsqvXkLVoSw/cgwhnhFMDbsQFeZYoJJ7bIZBS9BcamUW96asq/npPWugM+RQBw==", "license": "BlueOak-1.0.0", - "peer": true, "dependencies": { "@isaacs/cliui": "^8.0.2" }, @@ -13105,15 +12806,13 @@ "version": "4.0.0", "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz", "integrity": "sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==", - "license": "MIT", - "peer": true + "license": "MIT" }, "node_modules/appium-safari-driver/node_modules/jsftp": { "version": "2.1.3", "resolved": "https://registry.npmjs.org/jsftp/-/jsftp-2.1.3.tgz", "integrity": "sha512-r79EVB8jaNAZbq8hvanL8e8JGu2ZNr2bXdHC4ZdQhRImpSPpnWwm5DYVzQ5QxJmtGtKhNNuvqGgbNaFl604fEQ==", "license": "MIT", - "peer": true, "dependencies": { "debug": "^3.1.0", "ftp-response-parser": "^1.0.1", @@ -13131,7 +12830,6 @@ "resolved": "https://registry.npmjs.org/debug/-/debug-3.2.7.tgz", "integrity": "sha512-CFjzYYAi4ThfiQvizrFQevTTXHtnCqWfe7x1AhgEscTz6ZbLbfoLRLPugTQyBth6f8ZERVUSyWHFD/7Wu4t1XQ==", "license": "MIT", - "peer": true, "dependencies": { "ms": "^2.1.1" } @@ -13140,15 +12838,13 @@ "version": "2.3.1", "resolved": "https://registry.npmjs.org/json-parse-even-better-errors/-/json-parse-even-better-errors-2.3.1.tgz", "integrity": "sha512-xyFwyhro/JEof6Ghe2iz2NcXoj2sloNsWr/XsERDK/oiPCfaNhl5ONfp+jQdAZRQQ0IJWNzH9zIZF7li91kh2w==", - "license": "MIT", - "peer": true + "license": "MIT" }, "node_modules/appium-safari-driver/node_modules/json-schema": { "version": "0.4.0", "resolved": "https://registry.npmjs.org/json-schema/-/json-schema-0.4.0.tgz", "integrity": "sha512-es94M3nTIfsEPisRafak+HDLfHXnKBhV3vU5eqPcS3flIWqcxJWgXHXiey3YrpaNsanY5ei1VoYEbOzijuq9BA==", - "license": "(AFL-2.1 OR BSD-3-Clause)", - "peer": true + "license": "(AFL-2.1 OR BSD-3-Clause)" }, "node_modules/appium-safari-driver/node_modules/json-schema-traverse": { "version": "1.0.0", @@ -13162,7 +12858,6 @@ "resolved": "https://registry.npmjs.org/klaw/-/klaw-4.1.0.tgz", "integrity": "sha512-1zGZ9MF9H22UnkpVeuaGKOjfA2t6WrfdrJmGjy16ykcjnKQDmHVX+KI477rpbGevz/5FD4MC3xf1oxylBgcaQw==", "license": "MIT", - "peer": true, "engines": { "node": ">=14.14.0" } @@ -13172,7 +12867,6 @@ "resolved": "https://registry.npmjs.org/kleur/-/kleur-4.1.5.tgz", "integrity": "sha512-o+NO+8WrRiQEE4/7nwRJhN1HWpVmJm511pBHUxPLtp0BUISzlBplORYSmTclCnJvQq2tKu/sgl3xVpkc7ZWuQQ==", "license": "MIT", - "peer": true, "engines": { "node": ">=6" } @@ -13181,15 +12875,13 @@ "version": "2.0.0", "resolved": "https://registry.npmjs.org/kuler/-/kuler-2.0.0.tgz", "integrity": "sha512-Xq9nH7KlWZmXAtodXDDRE7vs6DU1gTU8zYDHDiWLSip45Egwq3plLHzPn27NgvzL2r1LMPC1vdqh98sQxtqj4A==", - "license": "MIT", - "peer": true + "license": "MIT" }, "node_modules/appium-safari-driver/node_modules/lazystream": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/lazystream/-/lazystream-1.0.1.tgz", "integrity": "sha512-b94GiNHQNy6JNTrt5w6zNyffMrNkXZb3KTkCZJb2V1xaEGCk093vkZ2jk3tpaeP33/OiXC+WvK9AxUebnf5nbw==", "license": "MIT", - "peer": true, "dependencies": { "readable-stream": "^2.0.5" }, @@ -13201,15 +12893,13 @@ "version": "1.0.0", "resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz", "integrity": "sha512-VLghIWNM6ELQzo7zwmcg0NmTVyWKYjvIeM83yjp0wRDTmUnrM678fQbcKBo6n2CJEF0szoG//ytg+TKla89ALQ==", - "license": "MIT", - "peer": true + "license": "MIT" }, "node_modules/appium-safari-driver/node_modules/lazystream/node_modules/readable-stream": { "version": "2.3.8", "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.8.tgz", "integrity": "sha512-8p0AUk4XODgIewSi0l8Epjs+EVnWiK7NoDIEGU0HhE7+ZyY8D1IMY7odu5lRrFXGg71L15KG8QrPmum45RTtdA==", "license": "MIT", - "peer": true, "dependencies": { "core-util-is": "~1.0.0", "inherits": "~2.0.3", @@ -13225,7 +12915,6 @@ "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz", "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==", "license": "MIT", - "peer": true, "dependencies": { "safe-buffer": "~5.1.0" } @@ -13235,7 +12924,6 @@ "resolved": "https://registry.npmjs.org/lilconfig/-/lilconfig-3.1.3.tgz", "integrity": "sha512-/vlFKAoH5Cgt3Ie+JLhRbwOsCQePABiU3tJ1egGvyQ+33R/vcwM2Zl2QR/LzjsBeItPt3oSVXapn+m4nQDvpzw==", "license": "MIT", - "peer": true, "engines": { "node": ">=14" }, @@ -13247,15 +12935,13 @@ "version": "1.2.4", "resolved": "https://registry.npmjs.org/lines-and-columns/-/lines-and-columns-1.2.4.tgz", "integrity": "sha512-7ylylesZQ/PV29jhEDl3Ufjo6ZX7gCqJr5F7PKrqc93v7fzSymt1BpwEU8nAUXs8qzzvqhbjhK5QZg6Mt/HkBg==", - "license": "MIT", - "peer": true + "license": "MIT" }, "node_modules/appium-safari-driver/node_modules/locate-path": { "version": "6.0.0", "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-6.0.0.tgz", "integrity": "sha512-iPZK6eYjbxRu3uB4/WZ3EsEIMJFMqAoopl3R+zuq0UjcAm/MO6KCweDgPfP3elTztoKP3KtnVHxTn2NHBSDVUw==", "license": "MIT", - "peer": true, "dependencies": { "p-locate": "^5.0.0" }, @@ -13271,7 +12957,6 @@ "resolved": "https://registry.npmjs.org/lockfile/-/lockfile-1.0.4.tgz", "integrity": "sha512-cvbTwETRfsFh4nHsL1eGWapU1XFi5Ot9E85sWAwia7Y7EgB7vfqcZhTKZ+l7hCGxSPoushMv5GKhT5PdLv03WA==", "license": "ISC", - "peer": true, "dependencies": { "signal-exit": "^3.0.2" } @@ -13293,7 +12978,6 @@ "resolved": "https://registry.npmjs.org/log-symbols/-/log-symbols-4.1.0.tgz", "integrity": "sha512-8XPvpAA8uyhfteu8pIvQxpJZ7SYYdpUivZpGy6sFsBuKRY/7rQGavedeB8aK+Zkyq6upMFVL/9AW6vOYzfRyLg==", "license": "MIT", - "peer": true, "dependencies": { "chalk": "^4.1.0", "is-unicode-supported": "^0.1.0" @@ -13310,7 +12994,6 @@ "resolved": "https://registry.npmjs.org/logform/-/logform-2.7.0.tgz", "integrity": "sha512-TFYA4jnP7PVbmlBIfhlSe+WKxs9dklXMTEGcBCIvLhE/Tn3H6Gk1norupVW7m5Cnd4bLcr08AytbyV/xj7f/kQ==", "license": "MIT", - "peer": true, "dependencies": { "@colors/colors": "1.6.0", "@types/triple-beam": "^1.3.2", @@ -13337,7 +13020,6 @@ "resolved": "https://registry.npmjs.org/math-intrinsics/-/math-intrinsics-1.1.0.tgz", "integrity": "sha512-/IXtbwEk5HTPyEwyKX6hGkYXxM9nbj64B+ilVJnC/R6B0pH5G4V3b0pVbL7DBj4tkhBAppbQUlf6F6Xl9LHu1g==", "license": "MIT", - "peer": true, "engines": { "node": ">= 0.4" } @@ -13347,7 +13029,6 @@ "resolved": "https://registry.npmjs.org/media-typer/-/media-typer-1.1.0.tgz", "integrity": "sha512-aisnrDP4GNe06UcKFnV5bfMNPBUw4jsLGaWwWfnH3v02GnBuXX2MCVn5RbrWo0j3pczUilYblq7fQ7Nw2t5XKw==", "license": "MIT", - "peer": true, "engines": { "node": ">= 0.8" } @@ -13357,7 +13038,6 @@ "resolved": "https://registry.npmjs.org/merge-descriptors/-/merge-descriptors-2.0.0.tgz", "integrity": "sha512-Snk314V5ayFLhp3fkUREub6WtjBfPdCPY1Ln8/8munuLuiYhsABgBVWsozAG+MWMbVEvcdcpbi9R7ww22l9Q3g==", "license": "MIT", - "peer": true, "engines": { "node": ">=18" }, @@ -13370,7 +13050,6 @@ "resolved": "https://registry.npmjs.org/method-override/-/method-override-3.0.0.tgz", "integrity": "sha512-IJ2NNN/mSl9w3kzWB92rcdHpz+HjkxhDJWNDBqSlas+zQdP8wBiJzITPg08M/k2uVvMow7Sk41atndNtt/PHSA==", "license": "MIT", - "peer": true, "dependencies": { "debug": "3.1.0", "methods": "~1.1.2", @@ -13386,7 +13065,6 @@ "resolved": "https://registry.npmjs.org/debug/-/debug-3.1.0.tgz", "integrity": "sha512-OX8XqP7/1a9cqkxYw2yXss15f26NKWBpDXQd0/uK/KPqdQhxbPa994hnzjcE2VqQpDslf55723cKPUOGSmMY3g==", "license": "MIT", - "peer": true, "dependencies": { "ms": "2.0.0" } @@ -13395,15 +13073,13 @@ "version": "2.0.0", "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==", - "license": "MIT", - "peer": true + "license": "MIT" }, "node_modules/appium-safari-driver/node_modules/methods": { "version": "1.1.2", "resolved": "https://registry.npmjs.org/methods/-/methods-1.1.2.tgz", "integrity": "sha512-iclAHeNqNm68zFtnZ0e+1L2yUIdvzNoauKU4WBA3VvH/vPFieF7qfRlwUZU+DA9P9bPXIS90ulxoUoCH23sV2w==", "license": "MIT", - "peer": true, "engines": { "node": ">= 0.6" } @@ -13413,7 +13089,6 @@ "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.54.0.tgz", "integrity": "sha512-aU5EJuIN2WDemCcAp2vFBfp/m4EAhWJnUNSSw0ixs7/kXbd6Pg64EmwJkNdFhB8aWt1sH2CTXrLxo/iAGV3oPQ==", "license": "MIT", - "peer": true, "engines": { "node": ">= 0.6" } @@ -13423,7 +13098,6 @@ "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-3.0.2.tgz", "integrity": "sha512-Lbgzdk0h4juoQ9fCKXW4by0UJqj+nOOrI9MJ1sSj4nI8aI2eo1qmvQEie4VD1glsS250n15LsWsYtCugiStS5A==", "license": "MIT", - "peer": true, "dependencies": { "mime-db": "^1.54.0" }, @@ -13440,7 +13114,6 @@ "resolved": "https://registry.npmjs.org/mimic-fn/-/mimic-fn-2.1.0.tgz", "integrity": "sha512-OqbOk5oEQeAZ8WXWydlu9HJjz9WVdEIvamMCcXmuqUYjTknH/sqsWvhQ3vgwKFRR1HpjvNBKQ37nbJgYzGqGcg==", "license": "MIT", - "peer": true, "engines": { "node": ">=6" } @@ -13450,8 +13123,7 @@ "resolved": "https://registry.npmjs.org/minimalistic-assert/-/minimalistic-assert-1.0.1.tgz", "integrity": "sha512-UtJcAD4yEaGtjPezWuO9wC4nwUnVH/8/Im3yEHQP4b67cXlD/Qr9hdITCU1xDbSEXg2XKNaP8jsReV7vQd00/A==", "license": "ISC", - "optional": true, - "peer": true + "optional": true }, "node_modules/appium-safari-driver/node_modules/minipass": { "version": "7.1.2", @@ -13467,7 +13139,6 @@ "resolved": "https://registry.npmjs.org/moment/-/moment-2.30.1.tgz", "integrity": "sha512-uEmtNhbDOrWPFS+hdjFCBfy9f2YoyzRpwcl+DqpC6taX21FzsTLQVbMV/W7PzNSX6x/bhC1zA3c2UQ5NzH6how==", "license": "MIT", - "peer": true, "engines": { "node": "*" } @@ -13477,7 +13148,6 @@ "resolved": "https://registry.npmjs.org/morgan/-/morgan-1.10.1.tgz", "integrity": "sha512-223dMRJtI/l25dJKWpgij2cMtywuG/WiUKXdvwfbhGKBhy1puASqXwFzmWZ7+K73vUPoR7SS2Qz2cI/g9MKw0A==", "license": "MIT", - "peer": true, "dependencies": { "basic-auth": "~2.0.1", "debug": "2.6.9", @@ -13494,7 +13164,6 @@ "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", "license": "MIT", - "peer": true, "dependencies": { "ms": "2.0.0" } @@ -13503,15 +13172,13 @@ "version": "2.0.0", "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==", - "license": "MIT", - "peer": true + "license": "MIT" }, "node_modules/appium-safari-driver/node_modules/morgan/node_modules/on-finished": { "version": "2.3.0", "resolved": "https://registry.npmjs.org/on-finished/-/on-finished-2.3.0.tgz", "integrity": "sha512-ikqdkGAAyf/X/gPhXGvfgAytDZtDbr+bkNUJ0N9h5MI/dmdgCs3l6hoHrcUv41sRKew3jIwrp4qQDXiK99Utww==", "license": "MIT", - "peer": true, "dependencies": { "ee-first": "1.1.1" }, @@ -13523,15 +13190,13 @@ "version": "2.1.3", "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==", - "license": "MIT", - "peer": true + "license": "MIT" }, "node_modules/appium-safari-driver/node_modules/ncp": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/ncp/-/ncp-2.0.0.tgz", "integrity": "sha512-zIdGUrPRFTUELUvr3Gmc7KZ2Sw/h1PiVM0Af/oHB6zgnV1ikqSfRk+TOufi79aHYCW3NiOXmr1BP5nWbzojLaA==", "license": "MIT", - "peer": true, "bin": { "ncp": "bin/ncp" } @@ -13541,7 +13206,6 @@ "resolved": "https://registry.npmjs.org/negotiator/-/negotiator-1.0.0.tgz", "integrity": "sha512-8Ofs/AUQh8MaEcrlq5xOX0CQ9ypTF5dl78mjlMNfOK08fzpgTHQRQPBxcPlEtIw0yRpws+Zo/3r+5WRby7u3Gg==", "license": "MIT", - "peer": true, "engines": { "node": ">= 0.6" } @@ -13572,7 +13236,6 @@ "resolved": "https://registry.npmjs.org/normalize-package-data/-/normalize-package-data-2.5.0.tgz", "integrity": "sha512-/5CMN3T0R4XTj4DcGaexo+roZSdSFW/0AOOTROrjxzCG1wrWXEsGbRKevjlIL+ZDE4sZlJr5ED4YW0yqmkK+eA==", "license": "BSD-2-Clause", - "peer": true, "dependencies": { "hosted-git-info": "^2.1.4", "resolve": "^1.10.0", @@ -13585,7 +13248,6 @@ "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.2.tgz", "integrity": "sha512-cBznnQ9KjJqU67B52RMC65CMarK2600WFnbkcaiwWq3xy/5haFJlshgnpjovMVJ+Hff49d8GEn0b87C5pDQ10g==", "license": "ISC", - "peer": true, "bin": { "semver": "bin/semver" } @@ -13595,7 +13257,6 @@ "resolved": "https://registry.npmjs.org/normalize-path/-/normalize-path-3.0.0.tgz", "integrity": "sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==", "license": "MIT", - "peer": true, "engines": { "node": ">=0.10.0" } @@ -13605,7 +13266,6 @@ "resolved": "https://registry.npmjs.org/object-inspect/-/object-inspect-1.13.4.tgz", "integrity": "sha512-W67iLl4J2EXEGTbfeHCffrjDfitvLANg0UlX3wFUUSTx92KXRFegMHUVgSqE+wvhAbi4WqjGg9czysTV2Epbew==", "license": "MIT", - "peer": true, "engines": { "node": ">= 0.4" }, @@ -13618,15 +13278,13 @@ "resolved": "https://registry.npmjs.org/obuf/-/obuf-1.1.2.tgz", "integrity": "sha512-PX1wu0AmAdPqOL1mWhqmlOd8kOIZQwGZw6rh7uby9fTc5lhaOWFLX3I6R1hrF9k3zUY40e6igsLGkDXK92LJNg==", "license": "MIT", - "optional": true, - "peer": true + "optional": true }, "node_modules/appium-safari-driver/node_modules/on-finished": { "version": "2.4.1", "resolved": "https://registry.npmjs.org/on-finished/-/on-finished-2.4.1.tgz", "integrity": "sha512-oVlzkg3ENAhCk2zdv7IJwd/QUD4z2RxRwpkcGY8psCVcCYZNq4wYnVWALHM+brtuJjePWiYF/ClmuDr8Ch5+kg==", "license": "MIT", - "peer": true, "dependencies": { "ee-first": "1.1.1" }, @@ -13639,7 +13297,6 @@ "resolved": "https://registry.npmjs.org/on-headers/-/on-headers-1.1.0.tgz", "integrity": "sha512-737ZY3yNnXy37FHkQxPzt4UZ2UWPWiCZWLvFZ4fu5cueciegX0zGPnrlY6bwRg4FdQOe9YU8MkmJwGhoMybl8A==", "license": "MIT", - "peer": true, "engines": { "node": ">= 0.8" } @@ -13649,7 +13306,6 @@ "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", "integrity": "sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w==", "license": "ISC", - "peer": true, "dependencies": { "wrappy": "1" } @@ -13659,7 +13315,6 @@ "resolved": "https://registry.npmjs.org/one-time/-/one-time-1.0.0.tgz", "integrity": "sha512-5DXOiRKwuSEcQ/l0kGCF6Q3jcADFv5tSmRaJck/OqkVFcOzutB134KRSfF0xDrL39MNnqxbHBbUUcjZIhTgb2g==", "license": "MIT", - "peer": true, "dependencies": { "fn.name": "1.x.x" } @@ -13669,7 +13324,6 @@ "resolved": "https://registry.npmjs.org/onetime/-/onetime-5.1.2.tgz", "integrity": "sha512-kbpaSSGJTWdAY5KPVeMOKXSrPtr8C8C7wodJbcsd51jRnmD+GZu8Y0VoU6Dm5Z4vWr0Ig/1NKuWRKf7j5aaYSg==", "license": "MIT", - "peer": true, "dependencies": { "mimic-fn": "^2.1.0" }, @@ -13685,7 +13339,6 @@ "resolved": "https://registry.npmjs.org/ora/-/ora-5.4.1.tgz", "integrity": "sha512-5b6Y85tPxZZ7QytO+BQzysW31HJku27cRIlkbAXaNx+BdcVi+LlRFmVXzeF6a7JCwJpyw5c4b+YSVImQIrBpuQ==", "license": "MIT", - "peer": true, "dependencies": { "bl": "^4.1.0", "chalk": "^4.1.0", @@ -13709,7 +13362,6 @@ "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-3.1.0.tgz", "integrity": "sha512-TYOanM3wGwNGsZN2cVTYPArw454xnXj5qmWF1bEoAc4+cU/ol7GVh7odevjp1FNHduHc3KZMcFduxU5Xc6uJRQ==", "license": "MIT", - "peer": true, "dependencies": { "yocto-queue": "^0.1.0" }, @@ -13725,7 +13377,6 @@ "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-5.0.0.tgz", "integrity": "sha512-LaNjtRWUBY++zB5nE/NwcaoMylSPk+S+ZHNB1TzdbMJMny6dynpAGt7X/tl/QYq3TIeE6nxHppbo2LGymrG5Pw==", "license": "MIT", - "peer": true, "dependencies": { "p-limit": "^3.0.2" }, @@ -13741,7 +13392,6 @@ "resolved": "https://registry.npmjs.org/package-changed/-/package-changed-3.0.0.tgz", "integrity": "sha512-HSRbrO+Ab5AuqqYGSevtKJ1Yt96jW1VKV7wrp8K4SKj5tyDp/7D96uPCQyCPiNtWTEH/7nA3hZ4z2slbc9yFxg==", "license": "ISC", - "peer": true, "dependencies": { "commander": "^6.2.0" }, @@ -13760,7 +13410,6 @@ "resolved": "https://registry.npmjs.org/parse-json/-/parse-json-5.2.0.tgz", "integrity": "sha512-ayCKvm/phCGxOkYRSCM82iDwct8/EonSEgCSxWxD7ve6jHggsFl4fZVQBPRNgQoKiuV/odhFrGzQXZwbifC8Rg==", "license": "MIT", - "peer": true, "dependencies": { "@babel/code-frame": "^7.0.0", "error-ex": "^1.3.1", @@ -13778,7 +13427,6 @@ "version": "1.1.3", "resolved": "https://registry.npmjs.org/parse-listing/-/parse-listing-1.1.3.tgz", "integrity": "sha512-a1p1i+9Qyc8pJNwdrSvW1g5TPxRH0sywVi6OzVvYHRo6xwF9bDWBxtH0KkxeOOvhUE8vAMtiSfsYQFOuK901eA==", - "peer": true, "engines": { "node": ">=0.6.21" } @@ -13788,7 +13436,6 @@ "resolved": "https://registry.npmjs.org/parseurl/-/parseurl-1.3.3.tgz", "integrity": "sha512-CiyeOxFT/JZyN5m0z9PfXw4SCBJ6Sygz1Dpl0wqjlhDEGGBP1GnsUVEL0p63hoG1fcj3fHynXi9NYO4nWOL+qQ==", "license": "MIT", - "peer": true, "engines": { "node": ">= 0.8" } @@ -13798,7 +13445,6 @@ "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-4.0.0.tgz", "integrity": "sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w==", "license": "MIT", - "peer": true, "engines": { "node": ">=8" } @@ -13808,7 +13454,6 @@ "resolved": "https://registry.npmjs.org/path-key/-/path-key-3.1.1.tgz", "integrity": "sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==", "license": "MIT", - "peer": true, "engines": { "node": ">=8" } @@ -13817,8 +13462,7 @@ "version": "1.0.7", "resolved": "https://registry.npmjs.org/path-parse/-/path-parse-1.0.7.tgz", "integrity": "sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw==", - "license": "MIT", - "peer": true + "license": "MIT" }, "node_modules/appium-safari-driver/node_modules/path-scurry": { "version": "2.0.1", @@ -13841,7 +13485,6 @@ "resolved": "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-8.3.0.tgz", "integrity": "sha512-7jdwVIRtsP8MYpdXSwOS0YdD0Du+qOoF/AEPIt88PcCFrZCzx41oxku1jD88hZBwbNUIEfpqvuhjFaMAqMTWnA==", "license": "MIT", - "peer": true, "funding": { "type": "opencollective", "url": "https://opencollective.com/express" @@ -13851,22 +13494,19 @@ "version": "1.2.0", "resolved": "https://registry.npmjs.org/pend/-/pend-1.2.0.tgz", "integrity": "sha512-F3asv42UuXchdzt+xXqfW1OGlVBe+mxa2mqI0pg5yAHZPvFmY3Y6drSf/GQ1A86WgWEN9Kzh/WrgKa6iGcHXLg==", - "license": "MIT", - "peer": true + "license": "MIT" }, "node_modules/appium-safari-driver/node_modules/picocolors": { "version": "1.1.1", "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.1.1.tgz", "integrity": "sha512-xceH2snhtb5M9liqDsmEw56le376mTZkEX/jEb/RxNFyegNul7eNslCXP9FDj/Lcu0X8KEyMceP2ntpaHrDEVA==", - "license": "ISC", - "peer": true + "license": "ISC" }, "node_modules/appium-safari-driver/node_modules/pkg-dir": { "version": "5.0.0", "resolved": "https://registry.npmjs.org/pkg-dir/-/pkg-dir-5.0.0.tgz", "integrity": "sha512-NPE8TDbzl/3YQYY7CSS228s3g2ollTFnc+Qi3tqmqJp9Vg2ovUpixcJEo2HJScN2Ez+kEaal6y70c0ehqJBJeA==", "license": "MIT", - "peer": true, "dependencies": { "find-up": "^5.0.0" }, @@ -13879,7 +13519,6 @@ "resolved": "https://registry.npmjs.org/plist/-/plist-3.1.0.tgz", "integrity": "sha512-uysumyrvkUX0rX/dEVqt8gC3sTBzd4zoWfLeS29nb53imdaXVvLINYXTI2GNqzaMuvacNx4uJQ8+b3zXR0pkgQ==", "license": "MIT", - "peer": true, "dependencies": { "@xmldom/xmldom": "^0.8.8", "base64-js": "^1.5.1", @@ -13894,7 +13533,6 @@ "resolved": "https://registry.npmjs.org/pluralize/-/pluralize-8.0.0.tgz", "integrity": "sha512-Nc3IT5yHzflTfbjgqWcCPpo7DaKy4FnpB0l/zCAW0Tc7jxAiuqSxHasntB3D7887LSrA93kDJ9IXovxJYxyLCA==", "license": "MIT", - "peer": true, "engines": { "node": ">=4" } @@ -13927,7 +13565,6 @@ "resolved": "https://registry.npmjs.org/process/-/process-0.11.10.tgz", "integrity": "sha512-cdGef/drWFoydD1JsMzuFf8100nZl+GT+yacc2bEced5f9Rjk4z+WtFUTBu9PhOi9j/jfmBPu0mMEY4wIdAF8A==", "license": "MIT", - "peer": true, "engines": { "node": ">= 0.6.0" } @@ -13936,15 +13573,13 @@ "version": "2.0.1", "resolved": "https://registry.npmjs.org/process-nextick-args/-/process-nextick-args-2.0.1.tgz", "integrity": "sha512-3ouUOpQhtgrbOa17J7+uxOTpITYWaGP7/AhoR3+A+/1e9skrzelGi/dXzEYyvbxubEF6Wn2ypscTKiKJFFn1ag==", - "license": "MIT", - "peer": true + "license": "MIT" }, "node_modules/appium-safari-driver/node_modules/proxy-addr": { "version": "2.0.7", "resolved": "https://registry.npmjs.org/proxy-addr/-/proxy-addr-2.0.7.tgz", "integrity": "sha512-llQsMLSUDUPT44jdrU/O37qlnifitDP+ZwrmmZcoSKyLKvtZxpyV0n2/bD/N4tBAAZ/gJEdZU7KMraoK1+XYAg==", "license": "MIT", - "peer": true, "dependencies": { "forwarded": "0.2.0", "ipaddr.js": "1.9.1" @@ -13957,15 +13592,13 @@ "version": "1.1.0", "resolved": "https://registry.npmjs.org/proxy-from-env/-/proxy-from-env-1.1.0.tgz", "integrity": "sha512-D+zkORCbA9f1tdWRK0RaCR3GPv50cMxcrz4X8k5LTSUD1Dkw47mKJEZQNunItRTkWwgtaUSo1RVFRIG9ZXiFYg==", - "license": "MIT", - "peer": true + "license": "MIT" }, "node_modules/appium-safari-driver/node_modules/qs": { "version": "6.14.0", "resolved": "https://registry.npmjs.org/qs/-/qs-6.14.0.tgz", "integrity": "sha512-YWWTjgABSKcvs/nWBi9PycY/JiPJqOD4JA6o9Sej2AtvSGarXxKC3OQSk4pAarbdQlKAh5D4FCQkJNkW+GAn3w==", "license": "BSD-3-Clause", - "peer": true, "dependencies": { "side-channel": "^1.1.0" }, @@ -13981,7 +13614,6 @@ "resolved": "https://registry.npmjs.org/range-parser/-/range-parser-1.2.1.tgz", "integrity": "sha512-Hrgsx+orqoygnmhFbKaHE6c296J+HTAQXoxEF6gNupROmmGJRoyzfG3ccAveqCBrwr/2yxQ5BVd/GTl5agOwSg==", "license": "MIT", - "peer": true, "engines": { "node": ">= 0.6" } @@ -13991,7 +13623,6 @@ "resolved": "https://registry.npmjs.org/raw-body/-/raw-body-3.0.2.tgz", "integrity": "sha512-K5zQjDllxWkf7Z5xJdV0/B0WTNqx6vxG70zJE4N0kBs4LovmEYWJzQGxC9bS9RAKu3bgM40lrd5zoLJ12MQ5BA==", "license": "MIT", - "peer": true, "dependencies": { "bytes": "~3.1.2", "http-errors": "~2.0.1", @@ -14007,7 +13638,6 @@ "resolved": "https://registry.npmjs.org/read-pkg/-/read-pkg-5.2.0.tgz", "integrity": "sha512-Ug69mNOpfvKDAc2Q8DRpMjjzdtrnv9HcSMX+4VsZxD1aZ6ZzrIE7rlzXBtWTyhULSMKg076AW6WR5iZpD0JiOg==", "license": "MIT", - "peer": true, "dependencies": { "@types/normalize-package-data": "^2.4.0", "normalize-package-data": "^2.5.0", @@ -14023,7 +13653,6 @@ "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.6.0.tgz", "integrity": "sha512-q+MB8nYR1KDLrgr4G5yemftpMC7/QLqVndBmEEdqzmNj5dcFOO4Oo8qlwZE3ULT3+Zim1F8Kq4cBnikNhlCMlg==", "license": "(MIT OR CC0-1.0)", - "peer": true, "engines": { "node": ">=8" } @@ -14033,7 +13662,6 @@ "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-4.7.0.tgz", "integrity": "sha512-oIGGmcpTLwPga8Bn6/Z75SVaH1z5dUut2ibSyAMVhmUggWpmDn2dapB0n7f8nwaSiRtepAsfJyfXIO5DCVAODg==", "license": "MIT", - "peer": true, "dependencies": { "abort-controller": "^3.0.0", "buffer": "^6.0.3", @@ -14064,7 +13692,6 @@ } ], "license": "MIT", - "peer": true, "dependencies": { "base64-js": "^1.3.1", "ieee754": "^1.2.1" @@ -14075,7 +13702,6 @@ "resolved": "https://registry.npmjs.org/readdir-glob/-/readdir-glob-1.1.3.tgz", "integrity": "sha512-v05I2k7xN8zXvPD9N+z/uhXPaj0sUFCe2rcWZIpBsqxfP7xXFQ0tipAd/wjj1YxWyWtUS5IDJpOG82JKt2EAVA==", "license": "Apache-2.0", - "peer": true, "dependencies": { "minimatch": "^5.1.0" } @@ -14085,7 +13711,6 @@ "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.2.tgz", "integrity": "sha512-Jt0vHyM+jmUBqojB7E1NIYadt0vI0Qxjxd2TErW94wDz+E2LAm5vKMXXwg6ZZBTHPuUlDgQHKXvjGBdfcF1ZDQ==", "license": "MIT", - "peer": true, "dependencies": { "balanced-match": "^1.0.0" } @@ -14095,7 +13720,6 @@ "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-5.1.6.tgz", "integrity": "sha512-lKwV/1brpG6mBUFHtb7NUmtABCb2WZZmm2wNiOA5hAb8VdCS4B3dtMWyvcoViccwAW/COERjXLt0zP1zXUN26g==", "license": "ISC", - "peer": true, "dependencies": { "brace-expansion": "^2.0.1" }, @@ -14118,7 +13742,6 @@ "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.22.11.tgz", "integrity": "sha512-RfqAvLnMl313r7c9oclB1HhUEAezcpLjz95wFH4LVuhk9JF/r22qmVP9AMmOU4vMX7Q8pN8jwNg/CSpdFnMjTQ==", "license": "MIT", - "peer": true, "dependencies": { "is-core-module": "^2.16.1", "path-parse": "^1.0.7", @@ -14139,7 +13762,6 @@ "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-5.0.0.tgz", "integrity": "sha512-qYg9KP24dD5qka9J47d0aVky0N+b4fTU89LN9iDnjB5waksiC49rvMB0PrUJQGoTmH50XPiqOvAjDfaijGxYZw==", "license": "MIT", - "peer": true, "engines": { "node": ">=8" } @@ -14149,7 +13771,6 @@ "resolved": "https://registry.npmjs.org/restore-cursor/-/restore-cursor-3.1.0.tgz", "integrity": "sha512-l+sSefzHpj5qimhFSE5a8nufZYAM3sBSVMAPtYkmC+4EH2anSGaEMXSD0izRQbu9nfyQ9y5JrVmp7E8oZrUjvA==", "license": "MIT", - "peer": true, "dependencies": { "onetime": "^5.1.0", "signal-exit": "^3.0.2" @@ -14182,7 +13803,6 @@ "resolved": "https://registry.npmjs.org/router/-/router-2.2.0.tgz", "integrity": "sha512-nLTrUKm2UyiL7rlhapu/Zl45FwNgkZGaCpZbIHajDYgwlJCOzLSk+cIPAnsEqV955GjILJnKbdQC1nVPz+gAYQ==", "license": "MIT", - "peer": true, "dependencies": { "debug": "^4.4.0", "depd": "^2.0.0", @@ -14198,15 +13818,13 @@ "version": "5.1.2", "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==", - "license": "MIT", - "peer": true + "license": "MIT" }, "node_modules/appium-safari-driver/node_modules/safe-stable-stringify": { "version": "2.5.0", "resolved": "https://registry.npmjs.org/safe-stable-stringify/-/safe-stable-stringify-2.5.0.tgz", "integrity": "sha512-b3rppTKm9T+PsVCBEOUR46GWI7fdOs00VKZ1+9c1EWDaDMvjQc6tUwuFyIprgGgTcWoVHSKrU8H31ZHA2e0RHA==", "license": "MIT", - "peer": true, "engines": { "node": ">=10" } @@ -14215,15 +13833,13 @@ "version": "2.1.2", "resolved": "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz", "integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==", - "license": "MIT", - "peer": true + "license": "MIT" }, "node_modules/appium-safari-driver/node_modules/sanitize-filename": { "version": "1.6.3", "resolved": "https://registry.npmjs.org/sanitize-filename/-/sanitize-filename-1.6.3.tgz", "integrity": "sha512-y/52Mcy7aw3gRm7IrcGDFx/bCk4AhRh2eI9luHOQM86nZsqwiRkkq2GekHXBBD+SmPidc8i2PqtYZl+pWJ8Oeg==", "license": "WTFPL OR ISC", - "peer": true, "dependencies": { "truncate-utf8-bytes": "^1.0.0" } @@ -14233,8 +13849,7 @@ "resolved": "https://registry.npmjs.org/select-hose/-/select-hose-2.0.0.tgz", "integrity": "sha512-mEugaLK+YfkijB4fx0e6kImuJdCIt2LxCRcbEYPqRGCs4F2ogyfZU5IAZRdjCP8JPq2AtdNoC/Dux63d9Kiryg==", "license": "MIT", - "optional": true, - "peer": true + "optional": true }, "node_modules/appium-safari-driver/node_modules/semver": { "version": "7.7.3", @@ -14253,7 +13868,6 @@ "resolved": "https://registry.npmjs.org/send/-/send-1.2.0.tgz", "integrity": "sha512-uaW0WwXKpL9blXE2o0bRhoL2EGXIrZxQ2ZQ4mgcfoBxdFmQold+qWsD2jLrfZ0trjKL6vOw0j//eAwcALFjKSw==", "license": "MIT", - "peer": true, "dependencies": { "debug": "^4.3.5", "encodeurl": "^2.0.0", @@ -14276,7 +13890,6 @@ "resolved": "https://registry.npmjs.org/serve-favicon/-/serve-favicon-2.5.1.tgz", "integrity": "sha512-JndLBslCLA/ebr7rS3d+/EKkzTsTi1jI2T9l+vHfAaGJ7A7NhtDpSZ0lx81HCNWnnE0yHncG+SSnVf9IMxOwXQ==", "license": "MIT", - "peer": true, "dependencies": { "etag": "~1.8.1", "fresh": "~0.5.2", @@ -14293,7 +13906,6 @@ "resolved": "https://registry.npmjs.org/fresh/-/fresh-0.5.2.tgz", "integrity": "sha512-zJ2mQYM18rEFOudeV4GShTGIQ7RbzA7ozbU9I/XBpm7kqgMywgmylMwXHxZJmkVoYkna9d2pVXVXPdYTP9ej8Q==", "license": "MIT", - "peer": true, "engines": { "node": ">= 0.6" } @@ -14316,15 +13928,13 @@ "url": "https://feross.org/support" } ], - "license": "MIT", - "peer": true + "license": "MIT" }, "node_modules/appium-safari-driver/node_modules/serve-static": { "version": "2.2.0", "resolved": "https://registry.npmjs.org/serve-static/-/serve-static-2.2.0.tgz", "integrity": "sha512-61g9pCh0Vnh7IutZjtLGGpTA355+OPn2TyDv/6ivP2h/AdAVX9azsoxmg2/M6nZeQZNYBEwIcsne1mJd9oQItQ==", "license": "MIT", - "peer": true, "dependencies": { "encodeurl": "^2.0.0", "escape-html": "^1.0.3", @@ -14345,8 +13955,7 @@ "version": "1.2.0", "resolved": "https://registry.npmjs.org/setprototypeof/-/setprototypeof-1.2.0.tgz", "integrity": "sha512-E5LDX7Wrp85Kil5bhZv46j8jOeboKq5JMmYM3gVGdGH8xFpPWXUMsNrlODCrkoxMEeNi/XZIwuRvY4XNwYMJpw==", - "license": "ISC", - "peer": true + "license": "ISC" }, "node_modules/appium-safari-driver/node_modules/sharp": { "version": "0.34.5", @@ -14355,7 +13964,6 @@ "hasInstallScript": true, "license": "Apache-2.0", "optional": true, - "peer": true, "dependencies": { "@img/colour": "^1.0.0", "detect-libc": "^2.1.2", @@ -14399,7 +14007,6 @@ "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-2.0.0.tgz", "integrity": "sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==", "license": "MIT", - "peer": true, "dependencies": { "shebang-regex": "^3.0.0" }, @@ -14412,7 +14019,6 @@ "resolved": "https://registry.npmjs.org/shebang-regex/-/shebang-regex-3.0.0.tgz", "integrity": "sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==", "license": "MIT", - "peer": true, "engines": { "node": ">=8" } @@ -14434,7 +14040,6 @@ "resolved": "https://registry.npmjs.org/side-channel/-/side-channel-1.1.0.tgz", "integrity": "sha512-ZX99e6tRweoUXqR+VBrslhda51Nh5MTQwou5tnUDgbtyM0dBgmhEDtWGP/xbKn6hqfPRHujUNwz5fy/wbbhnpw==", "license": "MIT", - "peer": true, "dependencies": { "es-errors": "^1.3.0", "object-inspect": "^1.13.3", @@ -14454,7 +14059,6 @@ "resolved": "https://registry.npmjs.org/side-channel-list/-/side-channel-list-1.0.0.tgz", "integrity": "sha512-FCLHtRD/gnpCiCHEiJLOwdmFP+wzCmDEkc9y7NsYxeF4u7Btsn1ZuwgwJGxImImHicJArLP4R0yX4c2KCrMrTA==", "license": "MIT", - "peer": true, "dependencies": { "es-errors": "^1.3.0", "object-inspect": "^1.13.3" @@ -14471,7 +14075,6 @@ "resolved": "https://registry.npmjs.org/side-channel-map/-/side-channel-map-1.0.1.tgz", "integrity": "sha512-VCjCNfgMsby3tTdo02nbjtM/ewra6jPHmpThenkTYh8pG9ucZ/1P8So4u4FGBek/BjpOVsDCMoLA/iuBKIFXRA==", "license": "MIT", - "peer": true, "dependencies": { "call-bound": "^1.0.2", "es-errors": "^1.3.0", @@ -14490,7 +14093,6 @@ "resolved": "https://registry.npmjs.org/side-channel-weakmap/-/side-channel-weakmap-1.0.2.tgz", "integrity": "sha512-WPS/HvHQTYnHisLo9McqBHOJk2FkHO/tlpvldyrnem4aeQp4hai3gythswg6p01oSoTl58rcpiFAjF2br2Ak2A==", "license": "MIT", - "peer": true, "dependencies": { "call-bound": "^1.0.2", "es-errors": "^1.3.0", @@ -14509,8 +14111,7 @@ "version": "3.0.7", "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-3.0.7.tgz", "integrity": "sha512-wnD2ZE+l+SPC/uoS0vXeE9L1+0wuaMqKlfz9AMUo38JsyLSBWSFcHR1Rri62LZc12vLr1gb3jl7iwQhgwpAbGQ==", - "license": "ISC", - "peer": true + "license": "ISC" }, "node_modules/appium-safari-driver/node_modules/source-map": { "version": "0.6.1", @@ -14536,7 +14137,6 @@ "resolved": "https://registry.npmjs.org/spdx-correct/-/spdx-correct-3.2.0.tgz", "integrity": "sha512-kN9dJbvnySHULIluDHy32WHRUu3Og7B9sbY7tsFLctQkIqnMh3hErYgdMjTYuqmcXX+lK5T1lnUt3G7zNswmZA==", "license": "Apache-2.0", - "peer": true, "dependencies": { "spdx-expression-parse": "^3.0.0", "spdx-license-ids": "^3.0.0" @@ -14546,15 +14146,13 @@ "version": "2.5.0", "resolved": "https://registry.npmjs.org/spdx-exceptions/-/spdx-exceptions-2.5.0.tgz", "integrity": "sha512-PiU42r+xO4UbUS1buo3LPJkjlO7430Xn5SVAhdpzzsPHsjbYVflnnFdATgabnLude+Cqu25p6N+g2lw/PFsa4w==", - "license": "CC-BY-3.0", - "peer": true + "license": "CC-BY-3.0" }, "node_modules/appium-safari-driver/node_modules/spdx-expression-parse": { "version": "3.0.1", "resolved": "https://registry.npmjs.org/spdx-expression-parse/-/spdx-expression-parse-3.0.1.tgz", "integrity": "sha512-cbqHunsQWnJNE6KhVSMsMeH5H/L9EpymbzqTQ3uLwNCLZ1Q481oWaofqH7nO6V07xlXwY6PhQdQ2IedWx/ZK4Q==", "license": "MIT", - "peer": true, "dependencies": { "spdx-exceptions": "^2.1.0", "spdx-license-ids": "^3.0.0" @@ -14564,8 +14162,7 @@ "version": "3.0.22", "resolved": "https://registry.npmjs.org/spdx-license-ids/-/spdx-license-ids-3.0.22.tgz", "integrity": "sha512-4PRT4nh1EImPbt2jASOKHX7PB7I+e4IWNLvkKFDxNhJlfjbYlleYQh285Z/3mPTHSAK/AvdMmw5BNNuYH8ShgQ==", - "license": "CC0-1.0", - "peer": true + "license": "CC0-1.0" }, "node_modules/appium-safari-driver/node_modules/spdy": { "version": "4.0.2", @@ -14573,7 +14170,6 @@ "integrity": "sha512-r46gZQZQV+Kl9oItvl1JZZqJKGr+oEkB08A6BzkiR7593/7IbtuncXHd2YoYeTsG4157ZssMu9KYvUHLcjcDoA==", "license": "MIT", "optional": true, - "peer": true, "dependencies": { "debug": "^4.1.0", "handle-thing": "^2.0.0", @@ -14591,7 +14187,6 @@ "integrity": "sha512-hsLVFE5SjA6TCisWeJXFKniGGOpBgMLmerfO2aCyCU5s7nJ/rpAepqmFifv/GCbSbueEeAJJnmSQ2rKC/g8Fcw==", "license": "MIT", "optional": true, - "peer": true, "dependencies": { "debug": "^4.1.0", "detect-node": "^2.0.4", @@ -14607,7 +14202,6 @@ "integrity": "sha512-9u/sniCrY3D5WdsERHzHE4G2YCXqoG5FTHUiCC4SIbr6XcLZBY05ya9EKjYek9O5xOAwjGq+1JdGBAS7Q9ScoA==", "license": "MIT", "optional": true, - "peer": true, "dependencies": { "inherits": "^2.0.3", "string_decoder": "^1.1.1", @@ -14622,7 +14216,6 @@ "resolved": "https://registry.npmjs.org/stack-trace/-/stack-trace-0.0.10.tgz", "integrity": "sha512-KGzahc7puUKkzyMt+IqAep+TVNbKP+k2Lmwhub39m1AsTSkaDutx56aDCo+HLDzf/D26BIHTJWNiTG1KAJiQCg==", "license": "MIT", - "peer": true, "engines": { "node": "*" } @@ -14632,7 +14225,6 @@ "resolved": "https://registry.npmjs.org/statuses/-/statuses-2.0.2.tgz", "integrity": "sha512-DvEy55V3DB7uknRo+4iOGT5fP1slR8wQohVdknigZPMpMstaKJQWhwiYBACJE3Ul2pTnATihhBYnRhZQHGBiRw==", "license": "MIT", - "peer": true, "engines": { "node": ">= 0.8" } @@ -14642,7 +14234,6 @@ "resolved": "https://registry.npmjs.org/stream-buffers/-/stream-buffers-2.2.0.tgz", "integrity": "sha512-uyQK/mx5QjHun80FLJTfaWE7JtwfRMKBLkMne6udYOmvH0CawotVa7TfgYHzAnpphn4+TweIx1QKMnRIbipmUg==", "license": "Unlicense", - "peer": true, "engines": { "node": ">= 0.10.0" } @@ -14652,7 +14243,6 @@ "resolved": "https://registry.npmjs.org/stream-combiner/-/stream-combiner-0.2.2.tgz", "integrity": "sha512-6yHMqgLYDzQDcAkL+tjJDC5nSNuNIx0vZtRZeiPh7Saef7VHX9H5Ijn9l2VIol2zaNYlYEX6KyuT/237A58qEQ==", "license": "MIT", - "peer": true, "dependencies": { "duplexer": "~0.1.1", "through": "~2.3.4" @@ -14663,7 +14253,6 @@ "resolved": "https://registry.npmjs.org/streamx/-/streamx-2.23.0.tgz", "integrity": "sha512-kn+e44esVfn2Fa/O0CPFcex27fjIL6MkVae0Mm6q+E6f0hWv578YCERbv+4m02cjxvDsPKLnmxral/rR6lBMAg==", "license": "MIT", - "peer": true, "dependencies": { "events-universal": "^1.0.0", "fast-fifo": "^1.3.2", @@ -14675,7 +14264,6 @@ "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.3.0.tgz", "integrity": "sha512-hkRX8U1WjJFd8LsDJ2yQ/wWWxaopEsABU1XfkM8A+j0+85JAGppt16cr1Whg6KIbb4okU6Mql6BOj+uup/wKeA==", "license": "MIT", - "peer": true, "dependencies": { "safe-buffer": "~5.2.0" } @@ -14698,15 +14286,13 @@ "url": "https://feross.org/support" } ], - "license": "MIT", - "peer": true + "license": "MIT" }, "node_modules/appium-safari-driver/node_modules/string-width": { "version": "4.2.3", "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz", "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==", "license": "MIT", - "peer": true, "dependencies": { "emoji-regex": "^8.0.0", "is-fullwidth-code-point": "^3.0.0", @@ -14722,7 +14308,6 @@ "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz", "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==", "license": "MIT", - "peer": true, "dependencies": { "emoji-regex": "^8.0.0", "is-fullwidth-code-point": "^3.0.0", @@ -14737,7 +14322,6 @@ "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", "license": "MIT", - "peer": true, "dependencies": { "ansi-regex": "^5.0.1" }, @@ -14751,7 +14335,6 @@ "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", "license": "MIT", - "peer": true, "dependencies": { "ansi-regex": "^5.0.1" }, @@ -14764,7 +14347,6 @@ "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==", "license": "MIT", - "peer": true, "engines": { "node": ">=8" } @@ -14774,7 +14356,6 @@ "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==", "license": "MIT", - "peer": true, "engines": { "node": ">=8" } @@ -14784,7 +14365,6 @@ "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-8.1.1.tgz", "integrity": "sha512-MpUEN2OodtUzxvKQl72cUF7RQ5EiHsGvSsVG0ia9c5RbWGL2CI4C7EpPS8UTBIplnlzZiNuV56w+FuNxy3ty2Q==", "license": "MIT", - "peer": true, "dependencies": { "has-flag": "^4.0.0" }, @@ -14800,7 +14380,6 @@ "resolved": "https://registry.npmjs.org/supports-preserve-symlinks-flag/-/supports-preserve-symlinks-flag-1.0.0.tgz", "integrity": "sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w==", "license": "MIT", - "peer": true, "engines": { "node": ">= 0.4" }, @@ -14813,7 +14392,6 @@ "resolved": "https://registry.npmjs.org/tagged-tag/-/tagged-tag-1.0.0.tgz", "integrity": "sha512-yEFYrVhod+hdNyx7g5Bnkkb0G6si8HJurOoOEgC8B/O0uXLHlaey/65KRv6cuWBNhBgHKAROVpc7QyYqE5gFng==", "license": "MIT", - "peer": true, "engines": { "node": ">=20" }, @@ -14826,7 +14404,6 @@ "resolved": "https://registry.npmjs.org/tar-stream/-/tar-stream-3.1.7.tgz", "integrity": "sha512-qJj60CXt7IU1Ffyc3NJMjh6EkuCFej46zUqJ4J7pqYlThyd9bO0XBTmcOIhSzZJVWfsLks0+nle/j538YAW9RQ==", "license": "MIT", - "peer": true, "dependencies": { "b4a": "^1.6.4", "fast-fifo": "^1.2.0", @@ -14853,7 +14430,6 @@ "resolved": "https://registry.npmjs.org/text-decoder/-/text-decoder-1.2.3.tgz", "integrity": "sha512-3/o9z3X0X0fTupwsYvR03pJ/DjWuqqrfwBgTQzdWDiQSm9KitAyz/9WqsT2JQW7KV2m+bC2ol/zqpW37NHxLaA==", "license": "Apache-2.0", - "peer": true, "dependencies": { "b4a": "^1.6.4" } @@ -14862,22 +14438,19 @@ "version": "1.0.0", "resolved": "https://registry.npmjs.org/text-hex/-/text-hex-1.0.0.tgz", "integrity": "sha512-uuVGNWzgJ4yhRaNSiubPY7OjISw4sw4E5Uv0wbjp+OzcbmVU/rsT8ujgcXJhn9ypzsgr5vlzpPqP+MBBKcGvbg==", - "license": "MIT", - "peer": true + "license": "MIT" }, "node_modules/appium-safari-driver/node_modules/through": { "version": "2.3.8", "resolved": "https://registry.npmjs.org/through/-/through-2.3.8.tgz", "integrity": "sha512-w89qg7PI8wAdvX60bMDP+bFoD5Dvhm9oLheFp5O4a2QF0cSBGsBX4qZmadPMvVqlLJBBci+WqGGOAPvcDeNSVg==", - "license": "MIT", - "peer": true + "license": "MIT" }, "node_modules/appium-safari-driver/node_modules/toidentifier": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/toidentifier/-/toidentifier-1.0.1.tgz", "integrity": "sha512-o5sSPKEkg/DIQNmH43V0/uerLrpzVedkUh8tGNvaeXpfpuwjKenlSox/2O/BTlZUtEe+JG7s5YhEz608PlAHRA==", "license": "MIT", - "peer": true, "engines": { "node": ">=0.6" } @@ -14887,7 +14460,6 @@ "resolved": "https://registry.npmjs.org/triple-beam/-/triple-beam-1.4.1.tgz", "integrity": "sha512-aZbgViZrg1QNcG+LULa7nhZpJTZSLm/mXnHXnbAbjmN5aSa0y7V+wvv6+4WaBtpISJzThKy+PIPxc1Nq1EJ9mg==", "license": "MIT", - "peer": true, "engines": { "node": ">= 14.0.0" } @@ -14897,7 +14469,6 @@ "resolved": "https://registry.npmjs.org/truncate-utf8-bytes/-/truncate-utf8-bytes-1.0.2.tgz", "integrity": "sha512-95Pu1QXQvruGEhv62XCMO3Mm90GscOCClvrIUwCM0PYOXK3kaF3l3sIHxx71ThJfcbM2O5Au6SO3AWCSEfW4mQ==", "license": "WTFPL", - "peer": true, "dependencies": { "utf8-byte-length": "^1.0.1" } @@ -14914,7 +14485,6 @@ "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-5.3.0.tgz", "integrity": "sha512-d9CwU93nN0IA1QL+GSNDdwLAu1Ew5ZjTwupvedwg3WdfoH6pIDvYQ2hV0Uc2nKBLPq7NB5apCx57MLS5qlmO5g==", "license": "(MIT OR CC0-1.0)", - "peer": true, "dependencies": { "tagged-tag": "^1.0.0" }, @@ -14930,7 +14500,6 @@ "resolved": "https://registry.npmjs.org/type-is/-/type-is-2.0.1.tgz", "integrity": "sha512-OZs6gsjF4vMp32qrCbiVSkrFmXtG/AZhY3t0iAMrMBiAZyV9oALtXO8hsrHbMXF9x6L3grlFuwW2oAz7cav+Gw==", "license": "MIT", - "peer": true, "dependencies": { "content-type": "^1.0.5", "media-typer": "^1.1.0", @@ -14945,7 +14514,6 @@ "resolved": "https://registry.npmjs.org/unorm/-/unorm-1.6.0.tgz", "integrity": "sha512-b2/KCUlYZUeA7JFUuRJZPUtr4gZvBh7tavtv4fvk4+KV9pfGiR6CQAQAWl49ZpR3ts2dk4FYkP7EIgDJoiOLDA==", "license": "MIT or GPL-2.0", - "peer": true, "engines": { "node": ">= 0.4.0" } @@ -14955,7 +14523,6 @@ "resolved": "https://registry.npmjs.org/unpipe/-/unpipe-1.0.0.tgz", "integrity": "sha512-pjy2bYhSsufwWlKwPc+l3cN7+wuJlK6uz0YdJEOlQDbl6jo/YlPi4mb8agUkVC8BF7V8NuzeyPNqRksA3hztKQ==", "license": "MIT", - "peer": true, "engines": { "node": ">= 0.8" } @@ -14964,15 +14531,13 @@ "version": "1.0.5", "resolved": "https://registry.npmjs.org/utf8-byte-length/-/utf8-byte-length-1.0.5.tgz", "integrity": "sha512-Xn0w3MtiQ6zoz2vFyUVruaCL53O/DwUvkEeOvj+uulMm0BkUGYWmBYVyElqZaSLhY6ZD0ulfU3aBra2aVT4xfA==", - "license": "(WTFPL OR MIT)", - "peer": true + "license": "(WTFPL OR MIT)" }, "node_modules/appium-safari-driver/node_modules/util-deprecate": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz", "integrity": "sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw==", - "license": "MIT", - "peer": true + "license": "MIT" }, "node_modules/appium-safari-driver/node_modules/uuid": { "version": "13.0.0", @@ -14992,7 +14557,6 @@ "resolved": "https://registry.npmjs.org/validate-npm-package-license/-/validate-npm-package-license-3.0.4.tgz", "integrity": "sha512-DpKm2Ui/xN7/HQKCtpZxoRWBhZ9Z0kqtygG8XCgNQ8ZlDnxuQmWhj566j8fN4Cu3/JmbhsDo7fcAJq4s9h27Ew==", "license": "Apache-2.0", - "peer": true, "dependencies": { "spdx-correct": "^3.0.0", "spdx-expression-parse": "^3.0.0" @@ -15003,7 +14567,6 @@ "resolved": "https://registry.npmjs.org/vary/-/vary-1.1.2.tgz", "integrity": "sha512-BNGbWLfd0eUPabhkXUVm0j8uuvREyTh5ovRa/dyow/BqAbZJyC+5fU+IzQOzmAKzYqYRAISoRhdQr3eIZ/PXqg==", "license": "MIT", - "peer": true, "engines": { "node": ">= 0.8" } @@ -15014,7 +14577,6 @@ "integrity": "sha512-O84QOnr0icsbFGLS0O3bI5FswxzRr8/gHwWkDlQFskhSPryQXvrTMxjxGP4+iWYoauLoBvfDpkrOauZ+0iZpDA==", "license": "MIT", "optional": true, - "peer": true, "dependencies": { "minimalistic-assert": "^1.0.0" } @@ -15024,7 +14586,6 @@ "resolved": "https://registry.npmjs.org/wcwidth/-/wcwidth-1.0.1.tgz", "integrity": "sha512-XHPEwS0q6TaxcvG85+8EYkbiCux2XtWG2mkc47Ng2A77BQu9+DqIOJldST4HgPkuea7dvKSj5VgX3P1d4rW8Tg==", "license": "MIT", - "peer": true, "dependencies": { "defaults": "^1.0.3" } @@ -15049,7 +14610,6 @@ "resolved": "https://registry.npmjs.org/winston/-/winston-3.18.3.tgz", "integrity": "sha512-NoBZauFNNWENgsnC9YpgyYwOVrl2m58PpQ8lNHjV3kosGs7KJ7Npk9pCUE+WJlawVSe8mykWDKWFSVfs3QO9ww==", "license": "MIT", - "peer": true, "dependencies": { "@colors/colors": "^1.6.0", "@dabh/diagnostics": "^2.0.8", @@ -15072,7 +14632,6 @@ "resolved": "https://registry.npmjs.org/winston-transport/-/winston-transport-4.9.0.tgz", "integrity": "sha512-8drMJ4rkgaPo1Me4zD/3WLfI/zPdA9o2IipKODunnGDcuqbHwjsbB79ylv04LCGGzU0xQ6vTznOMpQGaLhhm6A==", "license": "MIT", - "peer": true, "dependencies": { "logform": "^2.7.0", "readable-stream": "^3.6.2", @@ -15087,7 +14646,6 @@ "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.2.tgz", "integrity": "sha512-9u/sniCrY3D5WdsERHzHE4G2YCXqoG5FTHUiCC4SIbr6XcLZBY05ya9EKjYek9O5xOAwjGq+1JdGBAS7Q9ScoA==", "license": "MIT", - "peer": true, "dependencies": { "inherits": "^2.0.3", "string_decoder": "^1.1.1", @@ -15102,7 +14660,6 @@ "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.2.tgz", "integrity": "sha512-9u/sniCrY3D5WdsERHzHE4G2YCXqoG5FTHUiCC4SIbr6XcLZBY05ya9EKjYek9O5xOAwjGq+1JdGBAS7Q9ScoA==", "license": "MIT", - "peer": true, "dependencies": { "inherits": "^2.0.3", "string_decoder": "^1.1.1", @@ -15117,7 +14674,6 @@ "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-7.0.0.tgz", "integrity": "sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==", "license": "MIT", - "peer": true, "dependencies": { "ansi-styles": "^4.0.0", "string-width": "^4.1.0", @@ -15136,7 +14692,6 @@ "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-7.0.0.tgz", "integrity": "sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==", "license": "MIT", - "peer": true, "dependencies": { "ansi-styles": "^4.0.0", "string-width": "^4.1.0", @@ -15153,15 +14708,13 @@ "version": "1.0.2", "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", "integrity": "sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==", - "license": "ISC", - "peer": true + "license": "ISC" }, "node_modules/appium-safari-driver/node_modules/ws": { "version": "8.18.3", "resolved": "https://registry.npmjs.org/ws/-/ws-8.18.3.tgz", "integrity": "sha512-PEIGCY5tSlUt50cqyMXfCzX+oOPqN0vuGqWzbcJ2xvnkzkq46oOpz7dQaTDBdfICb4N14+GARUDw2XV2N4tvzg==", "license": "MIT", - "peer": true, "engines": { "node": ">=10.0.0" }, @@ -15183,7 +14736,6 @@ "resolved": "https://registry.npmjs.org/xmlbuilder/-/xmlbuilder-15.1.1.tgz", "integrity": "sha512-yMqGBqtXyeN1e3TGYvgNgDVZ3j84W4cwkOXQswghol6APgZWaff9lnbvN7MHYJOiXsvGPXtjTYJEiC9J2wv9Eg==", "license": "MIT", - "peer": true, "engines": { "node": ">=8.0" } @@ -15193,7 +14745,6 @@ "resolved": "https://registry.npmjs.org/y18n/-/y18n-5.0.8.tgz", "integrity": "sha512-0pfFzegeDWJHJIAmTLRP2DwHjdF5s7jo9tuztdQxAhINCdvS+3nGINqPd00AphqJR/0LhANUS6/+7SCb98YOfA==", "license": "ISC", - "peer": true, "engines": { "node": ">=10" } @@ -15203,7 +14754,6 @@ "resolved": "https://registry.npmjs.org/yaml/-/yaml-2.8.2.tgz", "integrity": "sha512-mplynKqc1C2hTVYxd0PU2xQAc22TI1vShAYGksCCfxbn/dFwnHTNi1bvYsBTkhdUNtGIf5xNOg938rrSSYvS9A==", "license": "ISC", - "peer": true, "bin": { "yaml": "bin.mjs" }, @@ -15219,7 +14769,6 @@ "resolved": "https://registry.npmjs.org/yargs/-/yargs-18.0.0.tgz", "integrity": "sha512-4UEqdc2RYGHZc7Doyqkrqiln3p9X2DZVxaGbwhn2pi7MrRagKaOcIKe8L3OxYcbhXLgLFUS3zAYuQjKBQgmuNg==", "license": "MIT", - "peer": true, "dependencies": { "cliui": "^9.0.1", "escalade": "^3.1.1", @@ -15237,7 +14786,6 @@ "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-22.0.0.tgz", "integrity": "sha512-rwu/ClNdSMpkSrUb+d6BRsSkLUq1fmfsY6TOpYzTwvwkg1/NRG85KBy3kq++A8LKQwX6lsu+aWad+2khvuXrqw==", "license": "ISC", - "peer": true, "engines": { "node": "^20.19.0 || ^22.12.0 || >=23" } @@ -15246,15 +14794,13 @@ "version": "10.6.0", "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-10.6.0.tgz", "integrity": "sha512-toUI84YS5YmxW219erniWD0CIVOo46xGKColeNQRgOzDorgBi1v4D71/OFzgD9GO2UGKIv1C3Sp8DAn0+j5w7A==", - "license": "MIT", - "peer": true + "license": "MIT" }, "node_modules/appium-safari-driver/node_modules/yargs/node_modules/string-width": { "version": "7.2.0", "resolved": "https://registry.npmjs.org/string-width/-/string-width-7.2.0.tgz", "integrity": "sha512-tsaTIkKW9b4N+AEj+SVA+WhJzV7/zMhcSu78mLKWSk7cXMOSHsBKFWUs0fWwq8QyK3MgJBQRX6Gbi4kYbdvGkQ==", "license": "MIT", - "peer": true, "dependencies": { "emoji-regex": "^10.3.0", "get-east-asian-width": "^1.0.0", @@ -15272,7 +14818,6 @@ "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-7.1.2.tgz", "integrity": "sha512-gmBGslpoQJtgnMAvOVqGZpEz9dyoKTCzy2nfz/n8aIFhN/jCE/rCmcxabB6jOOHV+0WNnylOxaxBQPSvcWklhA==", "license": "MIT", - "peer": true, "dependencies": { "ansi-regex": "^6.0.1" }, @@ -15288,7 +14833,6 @@ "resolved": "https://registry.npmjs.org/yauzl/-/yauzl-3.2.0.tgz", "integrity": "sha512-Ow9nuGZE+qp1u4JIPvg+uCiUr7xGQWdff7JQSk5VGYTAZMDe2q8lxJ10ygv10qmSj031Ty/6FNJpLO4o1Sgc+w==", "license": "MIT", - "peer": true, "dependencies": { "buffer-crc32": "~0.2.3", "pend": "~1.2.0" @@ -15302,7 +14846,6 @@ "resolved": "https://registry.npmjs.org/buffer-crc32/-/buffer-crc32-0.2.13.tgz", "integrity": "sha512-VO9Ht/+p3SN7SKWqcrgEzjGbRSJYTx+Q1pTQC0wrWqHx0vpJraQ6GtHx8tvcg1rlK1byhU5gccxgOgj7B0TDkQ==", "license": "MIT", - "peer": true, "engines": { "node": "*" } @@ -15312,7 +14855,6 @@ "resolved": "https://registry.npmjs.org/yocto-queue/-/yocto-queue-0.1.0.tgz", "integrity": "sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q==", "license": "MIT", - "peer": true, "engines": { "node": ">=10" }, @@ -15325,7 +14867,6 @@ "resolved": "https://registry.npmjs.org/zip-stream/-/zip-stream-6.0.1.tgz", "integrity": "sha512-zK7YHHz4ZXpW89AHXUPbQVGKI7uvkd3hzusTdotCg1UxyaVtg0zFJSTfW/Dq5f7OBBVnq6cZIaC8Ti4hb6dtCA==", "license": "MIT", - "peer": true, "dependencies": { "archiver-utils": "^5.0.0", "compress-commons": "^6.0.2", @@ -16502,35 +16043,12 @@ } }, "node_modules/doc-detective-common": { - "version": "3.6.0-dev.1", - "resolved": "https://registry.npmjs.org/doc-detective-common/-/doc-detective-common-3.6.0-dev.1.tgz", - "integrity": "sha512-e+3FNyqjhPUZRq+4A1t7G+au07RZockzCHdQ6LDaQQySPtAiNSO42v48ylbHIu4ZOn06SO933rVJe/b+e1GVdw==", - "license": "AGPL-3.0-only", - "dependencies": { - "@apidevtools/json-schema-ref-parser": "^15.1.3", - "ajv": "^8.17.1", - "ajv-errors": "^3.0.0", - "ajv-formats": "^3.0.1", - "ajv-keywords": "^5.1.0", - "axios": "^1.13.2", - "yaml": "^2.8.2" - } + "resolved": "../common", + "link": true }, "node_modules/doc-detective-resolver": { - "version": "3.6.1-dev.1", - "resolved": "https://registry.npmjs.org/doc-detective-resolver/-/doc-detective-resolver-3.6.1-dev.1.tgz", - "integrity": "sha512-3jjr/hRuBAnMiMJsQmdA0APkXv0zlQzoPtpKCTFo5MPBxbN7C5MV76ReEPYUlHOpDFTaqo1CTbCXLNMEgiGQ+g==", - "license": "AGPL-3.0-only", - "dependencies": { - "@apidevtools/json-schema-ref-parser": "^15.1.3", - "adm-zip": "^0.5.16", - "ajv": "^8.17.1", - "axios": "^1.13.2", - "doc-detective-common": "3.6.0-dev.1", - "dotenv": "^17.2.3", - "json-schema-faker": "^0.5.9", - "posthog-node": "^5.17.2" - } + "resolved": "../resolver", + "link": true }, "node_modules/dom-serializer": { "version": "2.0.0", @@ -17811,6 +17329,7 @@ "node_modules/jsep": { "version": "1.4.0", "license": "MIT", + "peer": true, "engines": { "node": ">= 10.16.0" } diff --git a/package.json b/package.json index aefb6a2..e04c212 100644 --- a/package.json +++ b/package.json @@ -36,8 +36,8 @@ "appium-geckodriver": "^2.1.4", "appium-safari-driver": "^4.1.4", "axios": "^1.13.2", - "doc-detective-common": "3.6.0-dev.1", - "doc-detective-resolver": "3.6.1-dev.1", + "doc-detective-common": "file:../common", + "doc-detective-resolver": "file:../resolver", "dotenv": "^17.2.3", "geckodriver": "^6.1.0", "jq-web": "^0.6.2", diff --git a/src/integrations/heretto.js b/src/integrations/heretto.js index 3393590..bf00176 100644 --- a/src/integrations/heretto.js +++ b/src/integrations/heretto.js @@ -43,32 +43,124 @@ class HerettoUploader { return result; } - if (!integrationConfig.apiBaseUrl || !integrationConfig.apiToken) { - result.description = "Heretto integration missing apiBaseUrl or apiToken"; + if (!integrationConfig.organizationId || !integrationConfig.apiToken) { + result.description = "Heretto integration missing organizationId or apiToken"; return result; } - // Resolve the file ID + // Construct the API base URL from organizationId + const apiBaseUrl = `https://${integrationConfig.organizationId}.heretto.com`; + + // Resolve the file ID using resource dependencies map let fileId = sourceIntegration.fileId; + let parentFolderId = sourceIntegration.parentFolderId; + const filename = path.basename(sourceIntegration.filePath); + const relativeFilePath = sourceIntegration.filePath; + + // Try to resolve from resource dependencies map first (most accurate) + if (!fileId && integrationConfig.resourceDependencies) { + const resolvedFile = this.resolveFromDependencies({ + resourceDependencies: integrationConfig.resourceDependencies, + filePath: relativeFilePath, + filename, + log: (level, msg) => log(config, level, msg), + }); + + if (resolvedFile) { + fileId = resolvedFile.uuid; + if (!parentFolderId && resolvedFile.parentFolderId) { + parentFolderId = resolvedFile.parentFolderId; + } + log(config, "debug", `Resolved from dependencies: ${relativeFilePath} -> ${fileId}`); + } + } if (!fileId) { log(config, "debug", `No fileId found, searching for file by path: ${sourceIntegration.filePath}`); try { fileId = await this.searchFileByName({ - apiBaseUrl: integrationConfig.apiBaseUrl, + apiBaseUrl, apiToken: integrationConfig.apiToken, username: integrationConfig.username || "", - filename: path.basename(sourceIntegration.filePath), + filename, log: (level, msg) => log(config, level, msg), }); + // If file not found, try to create it in the parent folder if (!fileId) { - result.description = `Could not find file in Heretto: ${sourceIntegration.filePath}`; - return result; + // Try to find parent folder from resource dependencies + if (!parentFolderId && integrationConfig.resourceDependencies) { + parentFolderId = this.findParentFolderFromDependencies({ + resourceDependencies: integrationConfig.resourceDependencies, + filePath: relativeFilePath, + log: (level, msg) => log(config, level, msg), + }); + } + + // Fall back to folder search if not found in dependencies + if (!parentFolderId && relativeFilePath) { + const parentDirPath = path.dirname(relativeFilePath); + if (parentDirPath && parentDirPath !== ".") { + const folderName = path.basename(parentDirPath); + log(config, "debug", `File not found, searching for parent folder: ${folderName}`); + + parentFolderId = await this.searchFolderByName({ + apiBaseUrl, + apiToken: integrationConfig.apiToken, + username: integrationConfig.username || "", + folderName, + log: (level, msg) => log(config, level, msg), + }); + } + } + + if (parentFolderId) { + log(config, "debug", `Creating new document in folder: ${parentFolderId}`); + + const mimeType = this.getContentType(localFilePath); + const createResult = await this.createDocument({ + apiBaseUrl, + apiToken: integrationConfig.apiToken, + username: integrationConfig.username || "", + parentFolderId, + filename, + mimeType, + log: (level, msg) => log(config, level, msg), + }); + + if (createResult.created) { + fileId = createResult.documentId; + log(config, "info", `Created new document in Heretto with ID: ${fileId}`); + } else if (createResult.existsInFolder) { + // File already exists in folder - get its ID + log(config, "debug", `File already exists in folder, searching for its ID`); + fileId = await this.getFileInFolder({ + apiBaseUrl, + apiToken: integrationConfig.apiToken, + username: integrationConfig.username || "", + folderId: parentFolderId, + filename, + log: (level, msg) => log(config, level, msg), + }); + + if (fileId) { + log(config, "info", `Found existing document in folder with ID: ${fileId}`); + } else { + result.description = `File exists in folder but could not get its ID: ${filename}`; + return result; + } + } else { + result.description = `Failed to create document in Heretto: ${filename}`; + return result; + } + } else { + result.description = `Could not find file or parent folder in Heretto: ${sourceIntegration.filePath}`; + return result; + } } } catch (error) { - result.description = `Error searching for file: ${error.message}`; + result.description = `Error searching/creating file: ${error.message}`; return result; } } @@ -85,7 +177,7 @@ class HerettoUploader { // Upload to Heretto try { await this.uploadFile({ - apiBaseUrl: integrationConfig.apiBaseUrl, + apiBaseUrl, apiToken: integrationConfig.apiToken, username: integrationConfig.username || "", documentId: fileId, @@ -103,6 +195,356 @@ class HerettoUploader { return result; } + /** + * Resolves a file path to its UUID using the resource dependencies map. + * @param {Object} options - Resolution options + * @returns {Object|null} File info with uuid and parentFolderId, or null if not found + */ + resolveFromDependencies({ resourceDependencies, filePath, filename, log }) { + if (!resourceDependencies) return null; + + // Normalize the file path for comparison + const normalizedPath = filePath.replace(/\\/g, "/").replace(/^\.\//, "").replace(/^\.\.\//, ""); + + // Try exact path match first + for (const [depPath, info] of Object.entries(resourceDependencies)) { + if (depPath.startsWith("_")) continue; // Skip internal keys + + const normalizedDepPath = depPath.replace(/\\/g, "/"); + + // Check if paths match (accounting for relative path variations) + if (normalizedDepPath === normalizedPath || + normalizedDepPath.endsWith("/" + normalizedPath) || + normalizedDepPath.endsWith(normalizedPath)) { + log("debug", `Found exact path match in dependencies: ${depPath}`); + return info; + } + } + + // Try filename match with parent folder context + const parentDir = path.dirname(normalizedPath); + const parentFolderName = path.basename(parentDir); + + for (const [depPath, info] of Object.entries(resourceDependencies)) { + if (depPath.startsWith("_")) continue; + + const depFilename = path.basename(depPath); + const depParentDir = path.dirname(depPath); + const depParentFolderName = path.basename(depParentDir); + + // Match by filename and parent folder name + if (depFilename === filename && depParentFolderName === parentFolderName) { + log("debug", `Found filename+folder match in dependencies: ${depPath}`); + return info; + } + } + + // Try filename-only match as last resort + for (const [depPath, info] of Object.entries(resourceDependencies)) { + if (depPath.startsWith("_")) continue; + + const depFilename = path.basename(depPath); + if (depFilename === filename) { + log("debug", `Found filename match in dependencies: ${depPath}`); + return info; + } + } + + log("debug", `No match found in dependencies for: ${filePath}`); + return null; + } + + /** + * Finds the parent folder ID for a file path using resource dependencies. + * @param {Object} options - Resolution options + * @returns {string|null} Parent folder UUID or null if not found + */ + findParentFolderFromDependencies({ resourceDependencies, filePath, log }) { + if (!resourceDependencies) return null; + + // Normalize path and get parent directory + const normalizedPath = filePath.replace(/\\/g, "/").replace(/^\.\//, "").replace(/^\.\.\//, ""); + const parentDir = path.dirname(normalizedPath); + const targetFolderName = path.basename(parentDir); + + log("debug", `Looking for parent folder '${targetFolderName}' in dependencies`); + + // Find a sibling file in the same folder to get the parent folder ID + for (const [depPath, info] of Object.entries(resourceDependencies)) { + if (depPath.startsWith("_")) continue; + + const depParentDir = path.dirname(depPath); + const depFolderName = path.basename(depParentDir); + + // If we find a file in the same folder, use its parent folder ID + if (depFolderName === targetFolderName && info.parentFolderId) { + log("debug", `Found sibling file ${depPath} with parent folder ID: ${info.parentFolderId}`); + return info.parentFolderId; + } + } + + // Alternative: look for folder paths in the dependencies + for (const [depPath, info] of Object.entries(resourceDependencies)) { + if (depPath.startsWith("_")) continue; + + // Check if this is the folder itself (ends with folder name) + if (depPath.endsWith("/" + targetFolderName) || depPath === targetFolderName) { + log("debug", `Found folder ${depPath} with ID: ${info.uuid}`); + return info.uuid; + } + } + + // Fallback: use the ditamap's parent folder ID if available + // This is useful when the target folder doesn't exist yet - we can create it + // as a sibling to the ditamap + if (resourceDependencies._ditamapParentFolderId) { + log("debug", `Using ditamap parent folder as fallback: ${resourceDependencies._ditamapParentFolderId}`); + return resourceDependencies._ditamapParentFolderId; + } + + log("debug", `Could not find parent folder '${targetFolderName}' in dependencies`); + return null; + } + + /** + * Creates a new document in Heretto. + * @param {Object} options - Creation options + * @returns {Promise} Result with created: boolean, documentId: string (if successful or already exists) + */ + async createDocument({ apiBaseUrl, apiToken, username, parentFolderId, filename, mimeType, log }) { + const createUrl = new URL(`/rest/all-files/${parentFolderId}`, apiBaseUrl); + + const createBody = `${this.escapeXml(filename)}${mimeType}`; + + return new Promise((resolve, reject) => { + const protocol = createUrl.protocol === "https:" ? https : http; + const authString = Buffer.from(`${username}:${apiToken}`).toString("base64"); + + const options = { + hostname: createUrl.hostname, + port: createUrl.port || (createUrl.protocol === "https:" ? 443 : 80), + path: createUrl.pathname, + method: "POST", + headers: { + "Content-Type": "application/xml", + "Authorization": `Basic ${authString}`, + "Content-Length": Buffer.byteLength(createBody), + }, + }; + + log("debug", `Creating document at ${createUrl.toString()}`); + + const req = protocol.request(options, (res) => { + let data = ""; + + res.on("data", (chunk) => { + data += chunk; + }); + + res.on("end", () => { + if (res.statusCode === 200 || res.statusCode === 201) { + try { + // Parse the XML response to extract the document ID + // Response format: ... + const idMatch = data.match(/id="([^"]+)"/); + if (idMatch && idMatch[1]) { + log("debug", `Document created successfully with ID: ${idMatch[1]}`); + resolve({ created: true, documentId: idMatch[1] }); + } else { + log("warning", `Document created but could not parse ID from response: ${data}`); + reject(new Error("Could not parse document ID from create response")); + } + } catch (parseError) { + reject(new Error(`Failed to parse create response: ${parseError.message}`)); + } + } else if (res.statusCode === 400 && data.includes("already exists")) { + // File already exists in this folder - we need to find its ID + log("debug", `Document already exists in folder, will search for existing file`); + resolve({ created: false, existsInFolder: true, parentFolderId }); + } else { + reject(new Error(`Create document failed with status ${res.statusCode}: ${data}`)); + } + }); + }); + + req.on("error", (error) => { + reject(new Error(`Create document request error: ${error.message}`)); + }); + + req.write(createBody); + req.end(); + }); + } + + /** + * Gets file information from a specific folder. + * @param {Object} options - Options + * @returns {Promise} File ID if found, null otherwise + */ + async getFileInFolder({ apiBaseUrl, apiToken, username, folderId, filename, log }) { + const folderUrl = new URL(`/rest/all-files/${folderId}`, apiBaseUrl); + + return new Promise((resolve, reject) => { + const protocol = folderUrl.protocol === "https:" ? https : http; + const authString = Buffer.from(`${username}:${apiToken}`).toString("base64"); + + const options = { + hostname: folderUrl.hostname, + port: folderUrl.port || (folderUrl.protocol === "https:" ? 443 : 80), + path: folderUrl.pathname, + method: "GET", + headers: { + "Authorization": `Basic ${authString}`, + "Accept": "application/xml", + }, + }; + + log("debug", `Getting folder contents: ${folderUrl.toString()}`); + + const req = protocol.request(options, (res) => { + let data = ""; + + res.on("data", (chunk) => { + data += chunk; + }); + + res.on("end", () => { + if (res.statusCode === 200) { + try { + // Parse XML to find the file by name + // Looking for child resources with matching name + // Example: ... + const escapedFilename = filename.replace(/[.*+?^${}()|[\]\\]/g, '\\$&'); + const nameIdMatch = data.match(new RegExp(`id="([^"]+)"[^>]*name="${escapedFilename}"`, 'i')); + const idNameMatch = data.match(new RegExp(`name="${escapedFilename}"[^>]*id="([^"]+)"`, 'i')); + + const match = nameIdMatch || idNameMatch; + if (match && match[1]) { + log("debug", `Found file ${filename} with ID: ${match[1]}`); + resolve(match[1]); + } else { + log("debug", `File ${filename} not found in folder ${folderId}`); + resolve(null); + } + } catch (parseError) { + log("debug", `Error parsing folder contents: ${parseError.message}`); + resolve(null); + } + } else { + log("debug", `Failed to get folder contents: ${res.statusCode}`); + resolve(null); + } + }); + }); + + req.on("error", (error) => { + log("debug", `Error getting folder contents: ${error.message}`); + resolve(null); + }); + + req.end(); + }); + } + + /** + * Escapes special characters for XML. + * @param {string} str - String to escape + * @returns {string} Escaped string + */ + escapeXml(str) { + return str + .replace(/&/g, "&") + .replace(//g, ">") + .replace(/"/g, """) + .replace(/'/g, "'"); + } + + /** + * Searches for a folder in Heretto by name. + * @param {Object} options - Search options + * @returns {Promise} Folder ID if found, null otherwise + */ + async searchFolderByName({ apiBaseUrl, apiToken, username, folderName, log }) { + const searchUrl = new URL("/ezdnxtgen/api/search", apiBaseUrl); + + const searchBody = JSON.stringify({ + queryString: folderName, + searchResultType: "FOLDERS_ONLY", + }); + + return new Promise((resolve, reject) => { + const protocol = searchUrl.protocol === "https:" ? https : http; + const authString = Buffer.from(`${username}:${apiToken}`).toString("base64"); + + const options = { + hostname: searchUrl.hostname, + port: searchUrl.port || (searchUrl.protocol === "https:" ? 443 : 80), + path: searchUrl.pathname, + method: "POST", + headers: { + "Content-Type": "application/json", + "Authorization": `Basic ${authString}`, + "Content-Length": Buffer.byteLength(searchBody), + }, + }; + + log("debug", `Searching for folder: ${folderName}`); + + const req = protocol.request(options, (res) => { + let data = ""; + + res.on("data", (chunk) => { + data += chunk; + }); + + res.on("end", () => { + if (res.statusCode >= 200 && res.statusCode < 300) { + try { + // Handle empty response body (no results) + if (!data || data.trim() === "") { + log("debug", "Folder search returned empty response - no results found"); + resolve(null); + return; + } + + const result = JSON.parse(data); + // Find the matching folder in results + if (result.searchResults && result.searchResults.length > 0) { + // Look for exact folder name match + const match = result.searchResults.find( + (r) => r.name === folderName || r.title === folderName + ); + if (match) { + log("debug", `Found folder: ${folderName} with ID: ${match.uuid || match.id}`); + resolve(match.uuid || match.id); + } else { + // Take first result as fallback + log("debug", `Exact folder match not found, using first result: ${result.searchResults[0].uuid || result.searchResults[0].id}`); + resolve(result.searchResults[0].uuid || result.searchResults[0].id); + } + } else { + log("debug", `No folders found matching: ${folderName}`); + resolve(null); + } + } catch (parseError) { + reject(new Error(`Failed to parse folder search response: ${parseError.message}`)); + } + } else { + reject(new Error(`Folder search request failed with status ${res.statusCode}: ${data}`)); + } + }); + }); + + req.on("error", (error) => { + reject(new Error(`Folder search request error: ${error.message}`)); + }); + + req.write(searchBody); + req.end(); + }); + } + /** * Searches for a file in Heretto by filename. * @param {Object} options - Search options @@ -113,7 +555,7 @@ class HerettoUploader { const searchBody = JSON.stringify({ queryString: filename, - searchResultType: "FILES", + searchResultType: "FILES_ONLY", }); return new Promise((resolve, reject) => { @@ -142,6 +584,13 @@ class HerettoUploader { res.on("end", () => { if (res.statusCode >= 200 && res.statusCode < 300) { try { + // Handle empty response body (no results) + if (!data || data.trim() === "") { + log("debug", "Search returned empty response - no results found"); + resolve(null); + return; + } + const result = JSON.parse(data); // Find the matching file in results if (result.searchResults && result.searchResults.length > 0) { diff --git a/src/tests/saveScreenshot.js b/src/tests/saveScreenshot.js index fa55e7e..44f5258 100644 --- a/src/tests/saveScreenshot.js +++ b/src/tests/saveScreenshot.js @@ -390,6 +390,8 @@ async function saveScreenshot({ config, step, driver }) { // Set output path for new screenshots if (!result.outputs.screenshotPath) { result.outputs.screenshotPath = filePath; + // Mark new screenshots as changed so they can be uploaded + result.outputs.changed = true; // Preserve sourceIntegration metadata if (step.screenshot.sourceIntegration) { result.outputs.sourceIntegration = step.screenshot.sourceIntegration; diff --git a/test/screenshot.test.js b/test/screenshot.test.js new file mode 100644 index 0000000..72069f9 --- /dev/null +++ b/test/screenshot.test.js @@ -0,0 +1,273 @@ +const fs = require("fs"); +const path = require("path"); +const assert = require("assert").strict; +const { runTests } = require("../src"); +const { createServer } = require("./server"); + +// Create a server for screenshot tests +const server = createServer({ + port: 8093, + staticDir: "./test/server/public", +}); + +// Start the server before tests +before(async () => { + try { + await server.start(); + } catch (error) { + console.error(`Failed to start test server: ${error.message}`); + throw error; + } +}); + +// Stop the server after tests +after(async () => { + try { + await server.stop(); + } catch (error) { + console.error(`Failed to stop test server: ${error.message}`); + } +}); + +describe("Screenshot sourceIntegration preservation", function () { + this.timeout(0); + + const tempDir = path.resolve("./test/temp-screenshot-tests"); + + beforeEach(function () { + if (!fs.existsSync(tempDir)) { + fs.mkdirSync(tempDir, { recursive: true }); + } + }); + + afterEach(function () { + // Cleanup temp files + if (fs.existsSync(tempDir)) { + const files = fs.readdirSync(tempDir); + for (const file of files) { + fs.unlinkSync(path.join(tempDir, file)); + } + fs.rmdirSync(tempDir); + } + }); + + it("preserves sourceIntegration for new screenshots", async function () { + const screenshotPath = path.join(tempDir, "new-screenshot.png"); + + const testSpec = { + tests: [ + { + steps: [ + { + goTo: "http://localhost:8093", + }, + { + screenshot: { + path: screenshotPath, + sourceIntegration: { + type: "heretto", + integrationName: "test-integration", + filePath: "new-screenshot.png", + contentPath: "/content/topic.dita", + }, + }, + }, + ], + }, + ], + }; + + const tempFilePath = path.join(tempDir, "test-spec.json"); + fs.writeFileSync(tempFilePath, JSON.stringify(testSpec, null, 2)); + + const result = await runTests({ input: tempFilePath, logLevel: "silent" }); + + // Find the screenshot step + const screenshotStep = result.specs[0].tests[0].contexts[0].steps[1]; + + // Verify sourceIntegration is preserved + assert.ok(screenshotStep.outputs.sourceIntegration, "sourceIntegration should be present"); + assert.equal(screenshotStep.outputs.sourceIntegration.type, "heretto"); + assert.equal(screenshotStep.outputs.sourceIntegration.integrationName, "test-integration"); + assert.equal(screenshotStep.outputs.sourceIntegration.filePath, "new-screenshot.png"); + assert.equal(screenshotStep.outputs.sourceIntegration.contentPath, "/content/topic.dita"); + + // Verify changed is true for new screenshots + assert.equal(screenshotStep.outputs.changed, true, "changed should be true for new screenshots"); + }); + + it("preserves sourceIntegration when variation exceeds threshold", async function () { + const screenshotPath = path.join(tempDir, "variation-screenshot.png"); + + // First, create an initial screenshot + const initialSpec = { + tests: [ + { + steps: [ + { + goTo: "http://localhost:8093", + }, + { + screenshot: { + path: screenshotPath, + maxVariation: 0.05, + overwrite: "false", + }, + }, + ], + }, + ], + }; + + const initialFilePath = path.join(tempDir, "initial-spec.json"); + fs.writeFileSync(initialFilePath, JSON.stringify(initialSpec, null, 2)); + await runTests({ input: initialFilePath, logLevel: "silent" }); + + // Now run with a different page to trigger variation warning + const variationSpec = { + tests: [ + { + steps: [ + { + goTo: "http://localhost:8093/drag-drop-test.html", // Different page + }, + { + screenshot: { + path: screenshotPath, + maxVariation: 0.05, + overwrite: "aboveVariation", + sourceIntegration: { + type: "heretto", + integrationName: "variation-test", + filePath: "variation-screenshot.png", + contentPath: "/content/variation-topic.dita", + }, + }, + }, + ], + }, + ], + }; + + const variationFilePath = path.join(tempDir, "variation-spec.json"); + fs.writeFileSync(variationFilePath, JSON.stringify(variationSpec, null, 2)); + + const result = await runTests({ input: variationFilePath, logLevel: "silent" }); + + const screenshotStep = result.specs[0].tests[0].contexts[0].steps[1]; + + // Verify the step is a WARNING (variation exceeded) + assert.equal(screenshotStep.result, "WARNING"); + + // Verify sourceIntegration is preserved + assert.ok(screenshotStep.outputs.sourceIntegration, "sourceIntegration should be present"); + assert.equal(screenshotStep.outputs.sourceIntegration.type, "heretto"); + assert.equal(screenshotStep.outputs.sourceIntegration.integrationName, "variation-test"); + + // Verify changed is true + assert.equal(screenshotStep.outputs.changed, true, "changed should be true when variation exceeds threshold"); + }); + + it("preserves sourceIntegration when screenshot is within variation", async function () { + const screenshotPath = path.join(tempDir, "same-screenshot.png"); + + // First, create an initial screenshot + const initialSpec = { + tests: [ + { + steps: [ + { + goTo: "http://localhost:8093", + }, + { + screenshot: { + path: screenshotPath, + maxVariation: 0.05, + overwrite: "false", + }, + }, + ], + }, + ], + }; + + const initialFilePath = path.join(tempDir, "initial-spec.json"); + fs.writeFileSync(initialFilePath, JSON.stringify(initialSpec, null, 2)); + await runTests({ input: initialFilePath, logLevel: "silent" }); + + // Now run with the same page (should be within variation) + const samePageSpec = { + tests: [ + { + steps: [ + { + goTo: "http://localhost:8093", // Same page + }, + { + screenshot: { + path: screenshotPath, + maxVariation: 0.95, // High threshold to ensure within variation + overwrite: "aboveVariation", + sourceIntegration: { + type: "heretto", + integrationName: "same-page-test", + filePath: "same-screenshot.png", + contentPath: "/content/same-topic.dita", + }, + }, + }, + ], + }, + ], + }; + + const sameFilePath = path.join(tempDir, "same-spec.json"); + fs.writeFileSync(sameFilePath, JSON.stringify(samePageSpec, null, 2)); + + const result = await runTests({ input: sameFilePath, logLevel: "silent" }); + + const screenshotStep = result.specs[0].tests[0].contexts[0].steps[1]; + + // Verify the step passed (within variation) + assert.equal(screenshotStep.result, "PASS"); + + // Verify sourceIntegration is preserved + assert.ok(screenshotStep.outputs.sourceIntegration, "sourceIntegration should be present"); + assert.equal(screenshotStep.outputs.sourceIntegration.type, "heretto"); + assert.equal(screenshotStep.outputs.sourceIntegration.integrationName, "same-page-test"); + + // Verify changed is false (within variation, no update) + assert.equal(screenshotStep.outputs.changed, false, "changed should be false when within variation"); + }); + + it("does not set sourceIntegration when not provided", async function () { + const screenshotPath = path.join(tempDir, "no-integration-screenshot.png"); + + const testSpec = { + tests: [ + { + steps: [ + { + goTo: "http://localhost:8093", + }, + { + screenshot: { + path: screenshotPath, + }, + }, + ], + }, + ], + }; + + const tempFilePath = path.join(tempDir, "test-spec.json"); + fs.writeFileSync(tempFilePath, JSON.stringify(testSpec, null, 2)); + + const result = await runTests({ input: tempFilePath, logLevel: "silent" }); + + const screenshotStep = result.specs[0].tests[0].contexts[0].steps[1]; + + // Verify sourceIntegration is NOT set + assert.equal(screenshotStep.outputs.sourceIntegration, undefined, "sourceIntegration should not be set when not provided"); + }); +}); diff --git a/test/upload.test.js b/test/upload.test.js new file mode 100644 index 0000000..bf2500f --- /dev/null +++ b/test/upload.test.js @@ -0,0 +1,641 @@ +const assert = require("assert").strict; +const { + collectChangedFiles, + getIntegrationConfig, + getUploader, +} = require("../src/integrations"); + +describe("Upload module", function () { + describe("collectChangedFiles", function () { + it("returns empty array for null report", function () { + const result = collectChangedFiles(null); + assert.deepEqual(result, []); + }); + + it("returns empty array for report without specs", function () { + const result = collectChangedFiles({}); + assert.deepEqual(result, []); + }); + + it("returns empty array for report with empty specs", function () { + const result = collectChangedFiles({ specs: [] }); + assert.deepEqual(result, []); + }); + + it("extracts file when changed is true and sourceIntegration present", function () { + const report = { + specs: [ + { + specId: "spec-1", + tests: [ + { + testId: "test-1", + contexts: [ + { + steps: [ + { + stepId: "step-1", + screenshot: { path: "test.png" }, + outputs: { + changed: true, + screenshotPath: "/path/to/test.png", + sourceIntegration: { + type: "heretto", + integrationName: "example", + filePath: "test.png", + contentPath: "/content/topic.dita", + }, + }, + }, + ], + }, + ], + }, + ], + }, + ], + }; + + const result = collectChangedFiles(report); + + assert.equal(result.length, 1); + assert.equal(result[0].localPath, "/path/to/test.png"); + assert.equal(result[0].sourceIntegration.type, "heretto"); + assert.equal(result[0].sourceIntegration.integrationName, "example"); + assert.equal(result[0].stepId, "step-1"); + assert.equal(result[0].testId, "test-1"); + assert.equal(result[0].specId, "spec-1"); + }); + + it("ignores step when changed is false", function () { + const report = { + specs: [ + { + specId: "spec-1", + tests: [ + { + testId: "test-1", + contexts: [ + { + steps: [ + { + stepId: "step-1", + screenshot: { path: "test.png" }, + outputs: { + changed: false, + screenshotPath: "/path/to/test.png", + sourceIntegration: { + type: "heretto", + integrationName: "example", + }, + }, + }, + ], + }, + ], + }, + ], + }, + ], + }; + + const result = collectChangedFiles(report); + assert.equal(result.length, 0); + }); + + it("ignores step when sourceIntegration is missing", function () { + const report = { + specs: [ + { + specId: "spec-1", + tests: [ + { + testId: "test-1", + contexts: [ + { + steps: [ + { + stepId: "step-1", + screenshot: { path: "test.png" }, + outputs: { + changed: true, + screenshotPath: "/path/to/test.png", + }, + }, + ], + }, + ], + }, + ], + }, + ], + }; + + const result = collectChangedFiles(report); + assert.equal(result.length, 0); + }); + + it("ignores step without screenshot property", function () { + const report = { + specs: [ + { + specId: "spec-1", + tests: [ + { + testId: "test-1", + contexts: [ + { + steps: [ + { + stepId: "step-1", + goTo: "http://example.com", + outputs: { + changed: true, + sourceIntegration: { + type: "heretto", + integrationName: "example", + }, + }, + }, + ], + }, + ], + }, + ], + }, + ], + }; + + const result = collectChangedFiles(report); + assert.equal(result.length, 0); + }); + + it("collects multiple changed files from different tests", function () { + const report = { + specs: [ + { + specId: "spec-1", + tests: [ + { + testId: "test-1", + contexts: [ + { + steps: [ + { + stepId: "step-1", + screenshot: { path: "screenshot1.png" }, + outputs: { + changed: true, + screenshotPath: "/path/to/screenshot1.png", + sourceIntegration: { + type: "heretto", + integrationName: "example", + }, + }, + }, + ], + }, + ], + }, + { + testId: "test-2", + contexts: [ + { + steps: [ + { + stepId: "step-2", + screenshot: { path: "screenshot2.png" }, + outputs: { + changed: true, + screenshotPath: "/path/to/screenshot2.png", + sourceIntegration: { + type: "heretto", + integrationName: "another", + }, + }, + }, + ], + }, + ], + }, + ], + }, + ], + }; + + const result = collectChangedFiles(report); + + assert.equal(result.length, 2); + assert.equal(result[0].localPath, "/path/to/screenshot1.png"); + assert.equal(result[1].localPath, "/path/to/screenshot2.png"); + }); + }); + + describe("getIntegrationConfig", function () { + it("returns null for missing sourceIntegration type", function () { + const config = { integrations: { heretto: [{ name: "example" }] } }; + const result = getIntegrationConfig(config, { integrationName: "example" }); + assert.equal(result, null); + }); + + it("returns null for missing integrationName", function () { + const config = { integrations: { heretto: [{ name: "example" }] } }; + const result = getIntegrationConfig(config, { type: "heretto" }); + assert.equal(result, null); + }); + + it("returns heretto config when found", function () { + const herettoConfig = { + name: "example", + organizationId: "test-org", + username: "user", + apiToken: "token", + }; + const config = { integrations: { heretto: [herettoConfig] } }; + const sourceIntegration = { type: "heretto", integrationName: "example" }; + + const result = getIntegrationConfig(config, sourceIntegration); + + assert.deepEqual(result, herettoConfig); + }); + + it("returns null when heretto config not found by name", function () { + const config = { + integrations: { + heretto: [{ name: "other", organizationId: "org" }], + }, + }; + const sourceIntegration = { type: "heretto", integrationName: "example" }; + + const result = getIntegrationConfig(config, sourceIntegration); + assert.equal(result, undefined); + }); + + it("returns null for unknown integration type", function () { + const config = { integrations: { heretto: [{ name: "example" }] } }; + const sourceIntegration = { type: "unknown", integrationName: "example" }; + + const result = getIntegrationConfig(config, sourceIntegration); + assert.equal(result, null); + }); + }); + + describe("getUploader", function () { + it("returns null for null sourceIntegration", function () { + const result = getUploader(null); + assert.equal(result, null); + }); + + it("returns null for sourceIntegration without type", function () { + const result = getUploader({ integrationName: "example" }); + assert.equal(result, null); + }); + + it("returns HerettoUploader for heretto type", function () { + const result = getUploader({ type: "heretto" }); + assert.notEqual(result, null); + assert.equal(typeof result.canHandle, "function"); + assert.equal(typeof result.upload, "function"); + assert.equal(result.canHandle({ type: "heretto" }), true); + }); + + it("returns null for unknown type", function () { + const result = getUploader({ type: "unknown-cms" }); + assert.equal(result, null); + }); + }); + + describe("HerettoUploader", function () { + const HerettoUploader = getUploader({ type: "heretto" }); + + describe("resolveFromDependencies", function () { + const mockLog = () => {}; + + it("returns null when resourceDependencies is null", function () { + const result = HerettoUploader.resolveFromDependencies({ + resourceDependencies: null, + filePath: "test.png", + filename: "test.png", + log: mockLog, + }); + assert.equal(result, null); + }); + + it("returns null when resourceDependencies is undefined", function () { + const result = HerettoUploader.resolveFromDependencies({ + resourceDependencies: undefined, + filePath: "test.png", + filename: "test.png", + log: mockLog, + }); + assert.equal(result, null); + }); + + it("finds exact path match in dependencies", function () { + const resourceDependencies = { + "content/media/test.png": { uuid: "file-uuid-123", parentFolderId: "folder-uuid-456" }, + }; + const result = HerettoUploader.resolveFromDependencies({ + resourceDependencies, + filePath: "content/media/test.png", + filename: "test.png", + log: mockLog, + }); + assert.deepEqual(result, { uuid: "file-uuid-123", parentFolderId: "folder-uuid-456" }); + }); + + it("finds path match with leading relative path removed", function () { + const resourceDependencies = { + "content/_media/screenshot.png": { uuid: "uuid-1", parentFolderId: "parent-1" }, + }; + const result = HerettoUploader.resolveFromDependencies({ + resourceDependencies, + filePath: "../_media/screenshot.png", + filename: "screenshot.png", + log: mockLog, + }); + // Should match via filename + folder name + assert.notEqual(result, null); + }); + + it("finds filename+folder match when exact path does not match", function () { + const resourceDependencies = { + "master/content/images/logo.png": { uuid: "uuid-logo", parentFolderId: "images-folder" }, + }; + const result = HerettoUploader.resolveFromDependencies({ + resourceDependencies, + filePath: "images/logo.png", + filename: "logo.png", + log: mockLog, + }); + assert.deepEqual(result, { uuid: "uuid-logo", parentFolderId: "images-folder" }); + }); + + it("finds filename-only match as last resort", function () { + const resourceDependencies = { + "totally/different/path/unique-file.png": { uuid: "uuid-unique", parentFolderId: "some-folder" }, + }; + const result = HerettoUploader.resolveFromDependencies({ + resourceDependencies, + filePath: "other/path/unique-file.png", + filename: "unique-file.png", + log: mockLog, + }); + assert.deepEqual(result, { uuid: "uuid-unique", parentFolderId: "some-folder" }); + }); + + it("skips internal keys starting with underscore", function () { + const resourceDependencies = { + "_ditamapParentFolderId": "internal-folder-id", + "_ditamapPath": "some/path.ditamap", + "real/file.png": { uuid: "real-uuid", parentFolderId: "real-folder" }, + }; + const result = HerettoUploader.resolveFromDependencies({ + resourceDependencies, + filePath: "_ditamapParentFolderId", + filename: "_ditamapParentFolderId", + log: mockLog, + }); + // Should not match the internal key + assert.equal(result, null); + }); + + it("returns null when no match found", function () { + const resourceDependencies = { + "path/to/other-file.png": { uuid: "uuid-other", parentFolderId: "folder-other" }, + }; + const result = HerettoUploader.resolveFromDependencies({ + resourceDependencies, + filePath: "completely/different/nonexistent.png", + filename: "nonexistent.png", + log: mockLog, + }); + assert.equal(result, null); + }); + + it("normalizes Windows backslashes to forward slashes", function () { + const resourceDependencies = { + "content/_media/image.png": { uuid: "uuid-win", parentFolderId: "folder-win" }, + }; + const result = HerettoUploader.resolveFromDependencies({ + resourceDependencies, + filePath: "content\\_media\\image.png", + filename: "image.png", + log: mockLog, + }); + assert.deepEqual(result, { uuid: "uuid-win", parentFolderId: "folder-win" }); + }); + }); + + describe("findParentFolderFromDependencies", function () { + const mockLog = () => {}; + + it("returns null when resourceDependencies is null", function () { + const result = HerettoUploader.findParentFolderFromDependencies({ + resourceDependencies: null, + filePath: "_media/test.png", + log: mockLog, + }); + assert.equal(result, null); + }); + + it("finds parent folder from sibling file", function () { + const resourceDependencies = { + "content/_media/existing-image.png": { uuid: "sibling-uuid", parentFolderId: "media-folder-uuid" }, + }; + const result = HerettoUploader.findParentFolderFromDependencies({ + resourceDependencies, + filePath: "_media/new-image.png", + log: mockLog, + }); + assert.equal(result, "media-folder-uuid"); + }); + + it("finds folder by direct path match", function () { + const resourceDependencies = { + "content/_media": { uuid: "direct-folder-uuid" }, + }; + const result = HerettoUploader.findParentFolderFromDependencies({ + resourceDependencies, + filePath: "_media/new-file.png", + log: mockLog, + }); + assert.equal(result, "direct-folder-uuid"); + }); + + it("uses ditamap parent folder as fallback", function () { + const resourceDependencies = { + "_ditamapParentFolderId": "ditamap-parent-folder-uuid", + "other/path/file.dita": { uuid: "other-uuid", parentFolderId: "other-folder" }, + }; + const result = HerettoUploader.findParentFolderFromDependencies({ + resourceDependencies, + filePath: "_nonexistent_folder/new-file.png", + log: mockLog, + }); + assert.equal(result, "ditamap-parent-folder-uuid"); + }); + + it("prefers sibling file match over ditamap fallback", function () { + const resourceDependencies = { + "_ditamapParentFolderId": "ditamap-parent-folder-uuid", + "content/_media/sibling.png": { uuid: "sibling-uuid", parentFolderId: "correct-media-folder" }, + }; + const result = HerettoUploader.findParentFolderFromDependencies({ + resourceDependencies, + filePath: "_media/new-file.png", + log: mockLog, + }); + assert.equal(result, "correct-media-folder"); + }); + + it("returns null when no folder found and no ditamap fallback", function () { + const resourceDependencies = { + "completely/different/path/file.png": { uuid: "some-uuid", parentFolderId: "some-folder" }, + }; + const result = HerettoUploader.findParentFolderFromDependencies({ + resourceDependencies, + filePath: "_unknown_folder/file.png", + log: mockLog, + }); + assert.equal(result, null); + }); + + it("normalizes relative path prefixes", function () { + const resourceDependencies = { + "content/_media/file.png": { uuid: "uuid", parentFolderId: "media-folder" }, + }; + const result = HerettoUploader.findParentFolderFromDependencies({ + resourceDependencies, + filePath: "../_media/new-file.png", + log: mockLog, + }); + assert.equal(result, "media-folder"); + }); + }); + + describe("canHandle", function () { + it("returns true for heretto type", function () { + assert.equal(HerettoUploader.canHandle({ type: "heretto" }), true); + }); + + it("returns false for other types", function () { + assert.equal(HerettoUploader.canHandle({ type: "other" }), false); + assert.equal(HerettoUploader.canHandle({ type: "github" }), false); + }); + + it("returns false for null", function () { + assert.equal(HerettoUploader.canHandle(null), false); + }); + + it("returns false for undefined", function () { + assert.equal(HerettoUploader.canHandle(undefined), false); + }); + }); + + describe("getContentType", function () { + it("returns image/png for .png files", function () { + assert.equal(HerettoUploader.getContentType("test.png"), "image/png"); + assert.equal(HerettoUploader.getContentType("/path/to/image.PNG"), "image/png"); + }); + + it("returns image/jpeg for .jpg files", function () { + assert.equal(HerettoUploader.getContentType("photo.jpg"), "image/jpeg"); + assert.equal(HerettoUploader.getContentType("photo.JPG"), "image/jpeg"); + }); + + it("returns image/jpeg for .jpeg files", function () { + assert.equal(HerettoUploader.getContentType("photo.jpeg"), "image/jpeg"); + }); + + it("returns image/gif for .gif files", function () { + assert.equal(HerettoUploader.getContentType("animation.gif"), "image/gif"); + }); + + it("returns image/svg+xml for .svg files", function () { + assert.equal(HerettoUploader.getContentType("icon.svg"), "image/svg+xml"); + }); + + it("returns image/webp for .webp files", function () { + assert.equal(HerettoUploader.getContentType("modern.webp"), "image/webp"); + }); + + it("returns application/octet-stream for unknown extensions", function () { + assert.equal(HerettoUploader.getContentType("file.unknown"), "application/octet-stream"); + assert.equal(HerettoUploader.getContentType("noextension"), "application/octet-stream"); + }); + }); + + describe("escapeXml", function () { + it("escapes ampersand", function () { + assert.equal(HerettoUploader.escapeXml("a & b"), "a & b"); + }); + + it("escapes less than", function () { + assert.equal(HerettoUploader.escapeXml("a < b"), "a < b"); + }); + + it("escapes greater than", function () { + assert.equal(HerettoUploader.escapeXml("a > b"), "a > b"); + }); + + it("escapes double quotes", function () { + assert.equal(HerettoUploader.escapeXml('name="value"'), "name="value""); + }); + + it("escapes single quotes", function () { + assert.equal(HerettoUploader.escapeXml("it's"), "it's"); + }); + + it("handles multiple special characters", function () { + assert.equal(HerettoUploader.escapeXml('a & b'), "<tag attr="val">a & b</tag>"); + }); + + it("returns empty string for empty input", function () { + assert.equal(HerettoUploader.escapeXml(""), ""); + }); + + it("returns string unchanged when no special characters", function () { + assert.equal(HerettoUploader.escapeXml("normal text 123"), "normal text 123"); + }); + }); + + describe("upload validation", function () { + it("returns error for missing integrationConfig", async function () { + const result = await HerettoUploader.upload({ + config: {}, + integrationConfig: null, + localFilePath: "/path/to/file.png", + sourceIntegration: { type: "heretto", filePath: "file.png" }, + log: () => {}, + }); + assert.equal(result.status, "FAIL"); + assert.equal(result.description, "No Heretto integration configuration found"); + }); + + it("returns error for missing organizationId", async function () { + const result = await HerettoUploader.upload({ + config: {}, + integrationConfig: { apiToken: "token" }, + localFilePath: "/path/to/file.png", + sourceIntegration: { type: "heretto", filePath: "file.png" }, + log: () => {}, + }); + assert.equal(result.status, "FAIL"); + assert.equal(result.description, "Heretto integration missing organizationId or apiToken"); + }); + + it("returns error for missing apiToken", async function () { + const result = await HerettoUploader.upload({ + config: {}, + integrationConfig: { organizationId: "org" }, + localFilePath: "/path/to/file.png", + sourceIntegration: { type: "heretto", filePath: "file.png" }, + log: () => {}, + }); + assert.equal(result.status, "FAIL"); + assert.equal(result.description, "Heretto integration missing organizationId or apiToken"); + }); + }); + }); +}); From 40885238e44ba02db7bd70347b4490e0f3c1d8c5 Mon Sep 17 00:00:00 2001 From: hawkeyexl Date: Mon, 29 Dec 2025 19:25:38 -0800 Subject: [PATCH 3/9] feat: Enhance HerettoUploader with improved folder resolution and add integration tests - Refactor folder resolution logic to ensure correct target folder is identified before file upload. - Implement integration tests for Heretto upload functionality, covering document retrieval and upload processes. - Update existing tests to reflect changes in folder resolution behavior. --- src/integrations/heretto.js | 341 +++++++++++++++++++++++----- test/heretto-upload.test.js | 438 ++++++++++++++++++++++++++++++++++++ test/upload.test.js | 29 ++- 3 files changed, 744 insertions(+), 64 deletions(-) create mode 100644 test/heretto-upload.test.js diff --git a/src/integrations/heretto.js b/src/integrations/heretto.js index bf00176..382d7d2 100644 --- a/src/integrations/heretto.js +++ b/src/integrations/heretto.js @@ -76,47 +76,69 @@ class HerettoUploader { } if (!fileId) { - log(config, "debug", `No fileId found, searching for file by path: ${sourceIntegration.filePath}`); + log(config, "debug", `No fileId found, resolving correct folder for: ${sourceIntegration.filePath}`); try { - fileId = await this.searchFileByName({ - apiBaseUrl, - apiToken: integrationConfig.apiToken, - username: integrationConfig.username || "", - filename, - log: (level, msg) => log(config, level, msg), - }); - - // If file not found, try to create it in the parent folder - if (!fileId) { - // Try to find parent folder from resource dependencies - if (!parentFolderId && integrationConfig.resourceDependencies) { - parentFolderId = this.findParentFolderFromDependencies({ - resourceDependencies: integrationConfig.resourceDependencies, - filePath: relativeFilePath, + // STEP 1: Resolve the correct target folder first + // This ensures we upload to the right location, not just any file with the same name + if (!parentFolderId && integrationConfig.resourceDependencies) { + const folderResolution = this.findParentFolderFromDependencies({ + resourceDependencies: integrationConfig.resourceDependencies, + filePath: relativeFilePath, + log: (level, msg) => log(config, level, msg), + }); + + parentFolderId = folderResolution.folderId; + + // If not found in dependencies, try to find the target folder as a child + // of the ditamap's parent folder via API + if (!parentFolderId && folderResolution.ditamapParentFolderId && folderResolution.targetFolderName) { + log(config, "debug", `Searching for folder '${folderResolution.targetFolderName}' in ditamap's parent folder`); + parentFolderId = await this.getChildFolderByName({ + apiBaseUrl, + apiToken: integrationConfig.apiToken, + username: integrationConfig.username || "", + parentFolderId: folderResolution.ditamapParentFolderId, + folderName: folderResolution.targetFolderName, log: (level, msg) => log(config, level, msg), }); } - - // Fall back to folder search if not found in dependencies - if (!parentFolderId && relativeFilePath) { - const parentDirPath = path.dirname(relativeFilePath); - if (parentDirPath && parentDirPath !== ".") { - const folderName = path.basename(parentDirPath); - log(config, "debug", `File not found, searching for parent folder: ${folderName}`); - - parentFolderId = await this.searchFolderByName({ - apiBaseUrl, - apiToken: integrationConfig.apiToken, - username: integrationConfig.username || "", - folderName, - log: (level, msg) => log(config, level, msg), - }); - } + } + + // Fall back to folder search if not found in dependencies + if (!parentFolderId && relativeFilePath) { + const parentDirPath = path.dirname(relativeFilePath); + if (parentDirPath && parentDirPath !== ".") { + const folderName = path.basename(parentDirPath); + log(config, "debug", `Searching for parent folder by name: ${folderName}`); + + parentFolderId = await this.searchFolderByName({ + apiBaseUrl, + apiToken: integrationConfig.apiToken, + username: integrationConfig.username || "", + folderName, + log: (level, msg) => log(config, level, msg), + }); } + } - if (parentFolderId) { - log(config, "debug", `Creating new document in folder: ${parentFolderId}`); + // STEP 2: Look for the file in the correct folder + if (parentFolderId) { + log(config, "debug", `Looking for file '${filename}' in target folder ${parentFolderId}`); + fileId = await this.getFileInFolder({ + apiBaseUrl, + apiToken: integrationConfig.apiToken, + username: integrationConfig.username || "", + folderId: parentFolderId, + filename, + log: (level, msg) => log(config, level, msg), + }); + + if (fileId) { + log(config, "debug", `Found existing file in target folder with ID: ${fileId}`); + } else { + // STEP 3: File doesn't exist in target folder - create it + log(config, "debug", `File not in target folder, creating new document`); const mimeType = this.getContentType(localFilePath); const createResult = await this.createDocument({ @@ -133,8 +155,8 @@ class HerettoUploader { fileId = createResult.documentId; log(config, "info", `Created new document in Heretto with ID: ${fileId}`); } else if (createResult.existsInFolder) { - // File already exists in folder - get its ID - log(config, "debug", `File already exists in folder, searching for its ID`); + // This shouldn't happen since we just checked, but handle it anyway + log(config, "debug", `File exists in folder (race condition), searching for its ID`); fileId = await this.getFileInFolder({ apiBaseUrl, apiToken: integrationConfig.apiToken, @@ -144,9 +166,7 @@ class HerettoUploader { log: (level, msg) => log(config, level, msg), }); - if (fileId) { - log(config, "info", `Found existing document in folder with ID: ${fileId}`); - } else { + if (!fileId) { result.description = `File exists in folder but could not get its ID: ${filename}`; return result; } @@ -154,7 +174,19 @@ class HerettoUploader { result.description = `Failed to create document in Heretto: ${filename}`; return result; } - } else { + } + } else { + // Last resort: search globally by filename (may find file in wrong folder) + log(config, "debug", `No target folder found, searching globally for file: ${filename}`); + fileId = await this.searchFileByName({ + apiBaseUrl, + apiToken: integrationConfig.apiToken, + username: integrationConfig.username || "", + filename, + log: (level, msg) => log(config, level, msg), + }); + + if (!fileId) { result.description = `Could not find file or parent folder in Heretto: ${sourceIntegration.filePath}`; return result; } @@ -256,17 +288,27 @@ class HerettoUploader { /** * Finds the parent folder ID for a file path using resource dependencies. + * Returns the target folder name for API lookup if not found in dependencies. * @param {Object} options - Resolution options - * @returns {string|null} Parent folder UUID or null if not found + * @returns {Object} { folderId, targetFolderName, ditamapParentFolderId } */ findParentFolderFromDependencies({ resourceDependencies, filePath, log }) { - if (!resourceDependencies) return null; + const result = { + folderId: null, + targetFolderName: null, + ditamapParentFolderId: null, + }; + + if (!resourceDependencies) return result; // Normalize path and get parent directory const normalizedPath = filePath.replace(/\\/g, "/").replace(/^\.\//, "").replace(/^\.\.\//, ""); const parentDir = path.dirname(normalizedPath); const targetFolderName = path.basename(parentDir); + result.targetFolderName = targetFolderName; + result.ditamapParentFolderId = resourceDependencies._ditamapParentFolderId || null; + log("debug", `Looking for parent folder '${targetFolderName}' in dependencies`); // Find a sibling file in the same folder to get the parent folder ID @@ -279,7 +321,8 @@ class HerettoUploader { // If we find a file in the same folder, use its parent folder ID if (depFolderName === targetFolderName && info.parentFolderId) { log("debug", `Found sibling file ${depPath} with parent folder ID: ${info.parentFolderId}`); - return info.parentFolderId; + result.folderId = info.parentFolderId; + return result; } } @@ -290,20 +333,80 @@ class HerettoUploader { // Check if this is the folder itself (ends with folder name) if (depPath.endsWith("/" + targetFolderName) || depPath === targetFolderName) { log("debug", `Found folder ${depPath} with ID: ${info.uuid}`); - return info.uuid; + result.folderId = info.uuid; + return result; } } - // Fallback: use the ditamap's parent folder ID if available - // This is useful when the target folder doesn't exist yet - we can create it - // as a sibling to the ditamap - if (resourceDependencies._ditamapParentFolderId) { - log("debug", `Using ditamap parent folder as fallback: ${resourceDependencies._ditamapParentFolderId}`); - return resourceDependencies._ditamapParentFolderId; - } - - log("debug", `Could not find parent folder '${targetFolderName}' in dependencies`); - return null; + log("debug", `Could not find parent folder '${targetFolderName}' in dependencies, will search via API`); + return result; + } + + /** + * Gets a child folder within a parent folder by name. + * @param {Object} options - Search options + * @returns {Promise} Child folder ID if found, null otherwise + */ + async getChildFolderByName({ apiBaseUrl, apiToken, username, parentFolderId, folderName, log }) { + const folderUrl = new URL(`/rest/all-files/${parentFolderId}`, apiBaseUrl); + + return new Promise((resolve, reject) => { + const protocol = folderUrl.protocol === "https:" ? https : http; + const authString = Buffer.from(`${username}:${apiToken}`).toString("base64"); + + const options = { + hostname: folderUrl.hostname, + port: folderUrl.port || (folderUrl.protocol === "https:" ? 443 : 80), + path: folderUrl.pathname, + method: "GET", + headers: { + "Authorization": `Basic ${authString}`, + "Accept": "application/xml", + }, + }; + + log("debug", `Looking for child folder '${folderName}' in parent ${parentFolderId}`); + + const req = protocol.request(options, (res) => { + let data = ""; + + res.on("data", (chunk) => { + data += chunk; + }); + + res.on("end", () => { + if (res.statusCode === 200) { + try { + // Parse XML to find the folder by name in children + // Looking for: + const escapedFolderName = folderName.replace(/[.*+?^${}()|[\]\\]/g, '\\$&'); + const folderMatch = data.match(new RegExp(` { + log("debug", `Error getting folder contents: ${error.message}`); + resolve(null); + }); + + req.end(); + }); } /** @@ -677,6 +780,136 @@ class HerettoUploader { }); } + /** + * Gets document information from Heretto. + * @param {Object} options - Options + * @returns {Promise} Document info including id, name, mimeType, folderUuid, uri + */ + async getDocumentInfo({ apiBaseUrl, apiToken, username, documentId, log }) { + const docUrl = new URL(`/rest/all-files/${documentId}`, apiBaseUrl); + + return new Promise((resolve, reject) => { + const protocol = docUrl.protocol === "https:" ? https : http; + const authString = Buffer.from(`${username}:${apiToken}`).toString("base64"); + + const options = { + hostname: docUrl.hostname, + port: docUrl.port || (docUrl.protocol === "https:" ? 443 : 80), + path: docUrl.pathname, + method: "GET", + headers: { + "Authorization": `Basic ${authString}`, + "Accept": "application/xml", + }, + }; + + log("debug", `Getting document info: ${docUrl.toString()}`); + + const req = protocol.request(options, (res) => { + let data = ""; + + res.on("data", (chunk) => { + data += chunk; + }); + + res.on("end", () => { + if (res.statusCode === 200) { + try { + // Parse XML response to extract document info + // The tag has id and folder-uuid as ATTRIBUTES + // But , , are CHILD ELEMENTS + + // Extract attributes from the opening tag + const resourceMatch = data.match(/]+)>/); + let id = null; + let folderUuid = null; + + if (resourceMatch) { + const attrs = resourceMatch[1]; + const idMatch = attrs.match(/\bid="([^"]+)"/); + const folderMatch = attrs.match(/\bfolder-uuid="([^"]+)"/); + id = idMatch ? idMatch[1] : null; + folderUuid = folderMatch ? folderMatch[1] : null; + } + + // Extract child elements + const nameMatch = data.match(/([^<]+)<\/name>/); + const mimeMatch = data.match(/([^<]+)<\/mime-type>/); + const uriMatch = data.match(/([^<]+)<\/xmldb-uri>/); + + resolve({ + id, + name: nameMatch ? nameMatch[1] : null, + mimeType: mimeMatch ? mimeMatch[1] : null, + folderUuid, + uri: uriMatch ? uriMatch[1] : null, + rawXml: data, + }); + } catch (parseError) { + reject(new Error(`Failed to parse document info: ${parseError.message}`)); + } + } else { + reject(new Error(`Get document info failed with status ${res.statusCode}: ${data}`)); + } + }); + }); + + req.on("error", (error) => { + reject(new Error(`Get document info request error: ${error.message}`)); + }); + + req.end(); + }); + } + + /** + * Gets document content from Heretto. + * @param {Object} options - Options + * @returns {Promise} Document content as buffer + */ + async getDocumentContent({ apiBaseUrl, apiToken, username, documentId, log }) { + const contentUrl = new URL(`/rest/all-files/${documentId}/content`, apiBaseUrl); + + return new Promise((resolve, reject) => { + const protocol = contentUrl.protocol === "https:" ? https : http; + const authString = Buffer.from(`${username}:${apiToken}`).toString("base64"); + + const options = { + hostname: contentUrl.hostname, + port: contentUrl.port || (contentUrl.protocol === "https:" ? 443 : 80), + path: contentUrl.pathname, + method: "GET", + headers: { + "Authorization": `Basic ${authString}`, + }, + }; + + log("debug", `Getting document content: ${contentUrl.toString()}`); + + const req = protocol.request(options, (res) => { + const chunks = []; + + res.on("data", (chunk) => { + chunks.push(chunk); + }); + + res.on("end", () => { + if (res.statusCode === 200) { + resolve(Buffer.concat(chunks)); + } else { + reject(new Error(`Get document content failed with status ${res.statusCode}`)); + } + }); + }); + + req.on("error", (error) => { + reject(new Error(`Get document content request error: ${error.message}`)); + }); + + req.end(); + }); + } + /** * Determines the content type based on file extension. * @param {string} filePath - File path diff --git a/test/heretto-upload.test.js b/test/heretto-upload.test.js new file mode 100644 index 0000000..99bbdc6 --- /dev/null +++ b/test/heretto-upload.test.js @@ -0,0 +1,438 @@ +const fs = require("fs"); +const path = require("path"); +const assert = require("assert").strict; +const { HerettoUploader } = require("../src/integrations/heretto"); + +/** + * Integration tests for Heretto upload functionality. + * These tests require valid Heretto credentials and perform actual API calls. + * + * Required environment variables: + * - HERETTO_ORG_ID: Heretto organization ID + * - HERETTO_USERNAME: Heretto username + * - HERETTO_TOKEN: Heretto API token + */ +describe("Heretto Upload Integration", function () { + this.timeout(60000); // 60 second timeout for API calls + + const herettoUploader = new HerettoUploader(); + + // Get credentials from environment + const orgId = process.env.HERETTO_ORG_ID; + const username = process.env.HERETTO_USERNAME; + const apiToken = process.env.HERETTO_TOKEN; + + // Skip tests if credentials are not available + const hasCredentials = orgId && username && apiToken; + + // Known UUIDs from the E2E tests + const KNOWN_DITAMAP_ID = "265fa972-253f-4e6c-8b17-cdd4838111ea"; + const KNOWN_COFFEE_GUIDE_FOLDER_ID = "6acdcac0-ef31-4873-a40c-2345c75c0a14"; + + // Test document tracking + let testDocumentId = null; + const testFilename = `test-upload-${Date.now()}.png`; + + const apiBaseUrl = hasCredentials ? `https://${orgId}.heretto.com` : null; + + const mockLog = (level, msg) => { + if (process.env.DEBUG_HERETTO) { + console.log(`[${level}] ${msg}`); + } + }; + + before(function () { + if (!hasCredentials) { + console.log(" Skipping Heretto integration tests - credentials not available"); + console.log(" Set HERETTO_ORG_ID, HERETTO_USERNAME, and HERETTO_TOKEN to run these tests"); + this.skip(); + } + }); + + describe("getDocumentInfo", function () { + it("retrieves document information for known ditamap", async function () { + if (!hasCredentials) this.skip(); + + const docInfo = await herettoUploader.getDocumentInfo({ + apiBaseUrl, + apiToken, + username, + documentId: KNOWN_DITAMAP_ID, + log: mockLog, + }); + + // Log raw XML for debugging + if (process.env.DEBUG_HERETTO) { + console.log("Raw XML (first 500 chars):", docInfo.rawXml?.substring(0, 500)); + } + + assert.ok(docInfo, "Should return document info"); + assert.equal(docInfo.id, KNOWN_DITAMAP_ID, "Document ID should match"); + assert.equal(docInfo.name, "heretto_coffee_brewing_guide.ditamap", "Document name should match"); + assert.ok(docInfo.folderUuid, "Should have folder UUID"); + assert.ok(docInfo.uri, "Should have URI"); + + // Verify we get the Coffee_Guide folder + assert.equal(docInfo.folderUuid, KNOWN_COFFEE_GUIDE_FOLDER_ID, "Should be in Coffee_Guide folder"); + }); + + it("returns document mime type", async function () { + if (!hasCredentials) this.skip(); + + const docInfo = await herettoUploader.getDocumentInfo({ + apiBaseUrl, + apiToken, + username, + documentId: KNOWN_DITAMAP_ID, + log: mockLog, + }); + + assert.ok(docInfo.mimeType, "Should have mime type"); + }); + }); + + describe("getFileInFolder", function () { + it("finds file in known folder", async function () { + if (!hasCredentials) this.skip(); + + // The ditamap should be in the Coffee_Guide folder + const fileId = await herettoUploader.getFileInFolder({ + apiBaseUrl, + apiToken, + username, + folderId: KNOWN_COFFEE_GUIDE_FOLDER_ID, + filename: "heretto_coffee_brewing_guide.ditamap", + log: mockLog, + }); + + assert.ok(fileId, "Should find the ditamap in the folder"); + assert.equal(fileId, KNOWN_DITAMAP_ID, "File ID should match known ditamap ID"); + }); + + it("returns null for non-existent file in folder", async function () { + if (!hasCredentials) this.skip(); + + const fileId = await herettoUploader.getFileInFolder({ + apiBaseUrl, + apiToken, + username, + folderId: KNOWN_COFFEE_GUIDE_FOLDER_ID, + filename: "definitely-does-not-exist-xyz123.png", + log: mockLog, + }); + + assert.equal(fileId, null, "Should return null for non-existent file"); + }); + }); + + describe("createDocument and upload flow", function () { + it("creates a new document in known folder", async function () { + if (!hasCredentials) this.skip(); + + const createResult = await herettoUploader.createDocument({ + apiBaseUrl, + apiToken, + username, + parentFolderId: KNOWN_COFFEE_GUIDE_FOLDER_ID, + filename: testFilename, + mimeType: "image/png", + log: mockLog, + }); + + assert.ok(createResult, "Should return create result"); + + if (createResult.created) { + assert.ok(createResult.documentId, "Should have document ID when created"); + testDocumentId = createResult.documentId; + } else if (createResult.existsInFolder) { + // File already exists, get its ID + const existingId = await herettoUploader.getFileInFolder({ + apiBaseUrl, + apiToken, + username, + folderId: KNOWN_COFFEE_GUIDE_FOLDER_ID, + filename: testFilename, + log: mockLog, + }); + assert.ok(existingId, "Should find existing file ID"); + testDocumentId = existingId; + } + + assert.ok(testDocumentId, "Should have a document ID"); + }); + + it("uploads content to the created document", async function () { + if (!hasCredentials) this.skip(); + if (!testDocumentId) this.skip(); + + // Create a simple test PNG (1x1 red pixel) + const pngContent = Buffer.from([ + 0x89, 0x50, 0x4E, 0x47, 0x0D, 0x0A, 0x1A, 0x0A, // PNG signature + 0x00, 0x00, 0x00, 0x0D, 0x49, 0x48, 0x44, 0x52, // IHDR chunk + 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x01, + 0x08, 0x02, 0x00, 0x00, 0x00, 0x90, 0x77, 0x53, + 0xDE, 0x00, 0x00, 0x00, 0x0C, 0x49, 0x44, 0x41, // IDAT chunk + 0x54, 0x08, 0xD7, 0x63, 0xF8, 0xCF, 0xC0, 0x00, + 0x00, 0x00, 0x03, 0x00, 0x01, 0x00, 0x05, 0xFE, + 0xD4, 0xA4, 0x00, 0x00, 0x00, 0x00, 0x49, 0x45, // IEND chunk + 0x4E, 0x44, 0xAE, 0x42, 0x60, 0x82 + ]); + + await herettoUploader.uploadFile({ + apiBaseUrl, + apiToken, + username, + documentId: testDocumentId, + content: pngContent, + contentType: "image/png", + log: mockLog, + }); + + // If we get here without throwing, upload succeeded + assert.ok(true, "Upload should succeed"); + }); + + it("verifies uploaded document location and content", async function () { + if (!hasCredentials) this.skip(); + if (!testDocumentId) this.skip(); + + // Get document info to verify location + const docInfo = await herettoUploader.getDocumentInfo({ + apiBaseUrl, + apiToken, + username, + documentId: testDocumentId, + log: mockLog, + }); + + assert.ok(docInfo, "Should get document info"); + assert.equal(docInfo.id, testDocumentId, "Document ID should match"); + assert.equal(docInfo.name, testFilename, "Filename should match"); + assert.equal(docInfo.folderUuid, KNOWN_COFFEE_GUIDE_FOLDER_ID, "Should be in the correct folder"); + assert.equal(docInfo.mimeType, "image/png", "MIME type should be image/png"); + + // Get document content to verify it was uploaded + const content = await herettoUploader.getDocumentContent({ + apiBaseUrl, + apiToken, + username, + documentId: testDocumentId, + log: mockLog, + }); + + assert.ok(content, "Should get document content"); + assert.ok(Buffer.isBuffer(content), "Content should be a Buffer"); + assert.ok(content.length > 0, "Content should not be empty"); + + // Verify PNG signature + assert.equal(content[0], 0x89, "Should start with PNG signature"); + assert.equal(content[1], 0x50, "Second byte of PNG signature"); + assert.equal(content[2], 0x4E, "Third byte of PNG signature"); + assert.equal(content[3], 0x47, "Fourth byte of PNG signature"); + }); + + it("can update existing document content", async function () { + if (!hasCredentials) this.skip(); + if (!testDocumentId) this.skip(); + + // Create a different PNG (1x1 blue pixel - different content) + const newPngContent = Buffer.from([ + 0x89, 0x50, 0x4E, 0x47, 0x0D, 0x0A, 0x1A, 0x0A, + 0x00, 0x00, 0x00, 0x0D, 0x49, 0x48, 0x44, 0x52, + 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x01, + 0x08, 0x02, 0x00, 0x00, 0x00, 0x90, 0x77, 0x53, + 0xDE, 0x00, 0x00, 0x00, 0x0C, 0x49, 0x44, 0x41, + 0x54, 0x08, 0xD7, 0x63, 0xF8, 0x0F, 0xC0, 0x00, // Different color + 0x00, 0x00, 0x03, 0x00, 0x01, 0x00, 0x05, 0xFE, + 0xD4, 0xA4, 0x00, 0x00, 0x00, 0x00, 0x49, 0x45, + 0x4E, 0x44, 0xAE, 0x42, 0x60, 0x82 + ]); + + // Upload the new content + await herettoUploader.uploadFile({ + apiBaseUrl, + apiToken, + username, + documentId: testDocumentId, + content: newPngContent, + contentType: "image/png", + log: mockLog, + }); + + // Verify the content was updated + const content = await herettoUploader.getDocumentContent({ + apiBaseUrl, + apiToken, + username, + documentId: testDocumentId, + log: mockLog, + }); + + assert.ok(content, "Should get updated content"); + assert.ok(Buffer.isBuffer(content), "Content should be a Buffer"); + + // Content should match what we uploaded + assert.deepEqual(content, newPngContent, "Content should match uploaded content"); + }); + }); + + describe("full upload method with ditamap fallback", function () { + it("uploads a file using ditamap parent folder fallback", async function () { + if (!hasCredentials) this.skip(); + + // Create a temp file to upload + const tempDir = path.resolve("./test/temp-heretto-upload"); + if (!fs.existsSync(tempDir)) { + fs.mkdirSync(tempDir, { recursive: true }); + } + + const localFilename = `integration-test-${Date.now()}.png`; + const localFilePath = path.join(tempDir, localFilename); + + // Create a simple PNG file + const pngContent = Buffer.from([ + 0x89, 0x50, 0x4E, 0x47, 0x0D, 0x0A, 0x1A, 0x0A, + 0x00, 0x00, 0x00, 0x0D, 0x49, 0x48, 0x44, 0x52, + 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x01, + 0x08, 0x02, 0x00, 0x00, 0x00, 0x90, 0x77, 0x53, + 0xDE, 0x00, 0x00, 0x00, 0x0C, 0x49, 0x44, 0x41, + 0x54, 0x08, 0xD7, 0x63, 0xF8, 0xCF, 0xC0, 0x00, + 0x00, 0x00, 0x03, 0x00, 0x01, 0x00, 0x05, 0xFE, + 0xD4, 0xA4, 0x00, 0x00, 0x00, 0x00, 0x49, 0x45, + 0x4E, 0x44, 0xAE, 0x42, 0x60, 0x82 + ]); + + fs.writeFileSync(localFilePath, pngContent); + + // The _media folder ID inside Coffee_Guide + const KNOWN_MEDIA_FOLDER_ID = "afa9ac13-f700-4a6b-8c28-9ea32786ab20"; + + try { + // Use the full upload method with resourceDependencies (ditamap parent folder) + // The fix now correctly resolves the target folder (_media) from the filePath + // and finds it by name within the ditamap parent folder + const result = await herettoUploader.upload({ + config: {}, + integrationConfig: { + organizationId: orgId, + username, + apiToken, + resourceDependencies: { + "_ditamapParentFolderId": KNOWN_COFFEE_GUIDE_FOLDER_ID, + }, + }, + localFilePath, + sourceIntegration: { + type: "heretto", + integrationName: "test", + filePath: `_media/${localFilename}`, + contentPath: "/content/topic.dita", + }, + log: mockLog, + }); + + assert.equal(result.status, "PASS", `Upload should succeed: ${result.description}`); + assert.ok(result.description.includes("Successfully uploaded"), "Should have success message"); + + // Extract document ID from result + const docIdMatch = result.description.match(/document ID: ([a-f0-9-]+)/i); + assert.ok(docIdMatch, "Should have document ID in result"); + + const uploadedDocId = docIdMatch[1]; + + // Verify the upload by getting document info + const docInfo = await herettoUploader.getDocumentInfo({ + apiBaseUrl, + apiToken, + username, + documentId: uploadedDocId, + log: mockLog, + }); + + assert.ok(docInfo, "Should get document info"); + assert.equal(docInfo.name, localFilename, "Filename should match"); + // The fix now correctly places files in the _media folder, not the ditamap parent + assert.equal(docInfo.folderUuid, KNOWN_MEDIA_FOLDER_ID, "Should be in _media folder (correct behavior)"); + + // Verify content + const uploadedContent = await herettoUploader.getDocumentContent({ + apiBaseUrl, + apiToken, + username, + documentId: uploadedDocId, + log: mockLog, + }); + + assert.deepEqual(uploadedContent, pngContent, "Uploaded content should match"); + + } finally { + // Cleanup + if (fs.existsSync(localFilePath)) { + fs.unlinkSync(localFilePath); + } + if (fs.existsSync(tempDir)) { + fs.rmdirSync(tempDir); + } + } + }); + + it("uploads and verifies existing file update", async function () { + if (!hasCredentials) this.skip(); + + // Use the known screenshot file from the E2E test + const knownScreenshotId = "411d629b-cee0-4960-8f92-6b1cf54302d4"; + + // Create new content to upload + const newContent = Buffer.from([ + 0x89, 0x50, 0x4E, 0x47, 0x0D, 0x0A, 0x1A, 0x0A, + 0x00, 0x00, 0x00, 0x0D, 0x49, 0x48, 0x44, 0x52, + 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x02, // 2x2 instead of 1x1 + 0x08, 0x02, 0x00, 0x00, 0x00, 0xFD, 0xD4, 0x9A, + 0x73, 0x00, 0x00, 0x00, 0x12, 0x49, 0x44, 0x41, + 0x54, 0x08, 0xD7, 0x63, 0xF8, 0xCF, 0xC0, 0xF0, + 0x9F, 0x81, 0xE1, 0x3F, 0x03, 0x00, 0x06, 0xB0, + 0x02, 0x01, 0x89, 0xC7, 0xF4, 0x27, 0x00, 0x00, + 0x00, 0x00, 0x49, 0x45, 0x4E, 0x44, 0xAE, 0x42, + 0x60, 0x82 + ]); + + // Upload to existing document + await herettoUploader.uploadFile({ + apiBaseUrl, + apiToken, + username, + documentId: knownScreenshotId, + content: newContent, + contentType: "image/png", + log: mockLog, + }); + + // Verify the document info + const docInfo = await herettoUploader.getDocumentInfo({ + apiBaseUrl, + apiToken, + username, + documentId: knownScreenshotId, + log: mockLog, + }); + + assert.ok(docInfo, "Should get document info"); + assert.equal(docInfo.name, "la_pavoni_screenshot.png", "Filename should be la_pavoni_screenshot.png"); + + // Verify content was updated + const content = await herettoUploader.getDocumentContent({ + apiBaseUrl, + apiToken, + username, + documentId: knownScreenshotId, + log: mockLog, + }); + + assert.ok(content, "Should get content"); + assert.ok(Buffer.isBuffer(content), "Content should be buffer"); + // Content length will differ from what we uploaded due to re-encoding + // Just verify it's a valid PNG + assert.equal(content[0], 0x89, "Should be PNG"); + }); + }); +}); diff --git a/test/upload.test.js b/test/upload.test.js index bf2500f..23401f3 100644 --- a/test/upload.test.js +++ b/test/upload.test.js @@ -430,13 +430,13 @@ describe("Upload module", function () { describe("findParentFolderFromDependencies", function () { const mockLog = () => {}; - it("returns null when resourceDependencies is null", function () { + it("returns empty result when resourceDependencies is null", function () { const result = HerettoUploader.findParentFolderFromDependencies({ resourceDependencies: null, filePath: "_media/test.png", log: mockLog, }); - assert.equal(result, null); + assert.deepEqual(result, { folderId: null, targetFolderName: null, ditamapParentFolderId: null }); }); it("finds parent folder from sibling file", function () { @@ -448,7 +448,8 @@ describe("Upload module", function () { filePath: "_media/new-image.png", log: mockLog, }); - assert.equal(result, "media-folder-uuid"); + assert.equal(result.folderId, "media-folder-uuid"); + assert.equal(result.targetFolderName, "_media"); }); it("finds folder by direct path match", function () { @@ -460,10 +461,11 @@ describe("Upload module", function () { filePath: "_media/new-file.png", log: mockLog, }); - assert.equal(result, "direct-folder-uuid"); + assert.equal(result.folderId, "direct-folder-uuid"); + assert.equal(result.targetFolderName, "_media"); }); - it("uses ditamap parent folder as fallback", function () { + it("returns ditamap parent folder info when folder not found", function () { const resourceDependencies = { "_ditamapParentFolderId": "ditamap-parent-folder-uuid", "other/path/file.dita": { uuid: "other-uuid", parentFolderId: "other-folder" }, @@ -473,7 +475,10 @@ describe("Upload module", function () { filePath: "_nonexistent_folder/new-file.png", log: mockLog, }); - assert.equal(result, "ditamap-parent-folder-uuid"); + // folderId should be null (not found), but ditamapParentFolderId should be set for API lookup + assert.equal(result.folderId, null); + assert.equal(result.ditamapParentFolderId, "ditamap-parent-folder-uuid"); + assert.equal(result.targetFolderName, "_nonexistent_folder"); }); it("prefers sibling file match over ditamap fallback", function () { @@ -486,10 +491,11 @@ describe("Upload module", function () { filePath: "_media/new-file.png", log: mockLog, }); - assert.equal(result, "correct-media-folder"); + assert.equal(result.folderId, "correct-media-folder"); + assert.equal(result.targetFolderName, "_media"); }); - it("returns null when no folder found and no ditamap fallback", function () { + it("returns null folderId when no folder found and no ditamap fallback", function () { const resourceDependencies = { "completely/different/path/file.png": { uuid: "some-uuid", parentFolderId: "some-folder" }, }; @@ -498,7 +504,9 @@ describe("Upload module", function () { filePath: "_unknown_folder/file.png", log: mockLog, }); - assert.equal(result, null); + assert.equal(result.folderId, null); + assert.equal(result.ditamapParentFolderId, null); + assert.equal(result.targetFolderName, "_unknown_folder"); }); it("normalizes relative path prefixes", function () { @@ -510,7 +518,8 @@ describe("Upload module", function () { filePath: "../_media/new-file.png", log: mockLog, }); - assert.equal(result, "media-folder"); + assert.equal(result.folderId, "media-folder"); + assert.equal(result.targetFolderName, "_media"); }); }); From 3117a09a98fa3db9780522bb09fddd1824f0e62c Mon Sep 17 00:00:00 2001 From: hawkeyexl Date: Tue, 30 Dec 2025 13:40:18 -0800 Subject: [PATCH 4/9] feat: Enhance saveScreenshot function to include additional output details - Add screenshotPath to outputs when overwriting existing files - Set changed flag to true when a file is overwritten - Preserve sourceIntegration metadata in outputs if provided --- src/tests/saveScreenshot.js | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/src/tests/saveScreenshot.js b/src/tests/saveScreenshot.js index 44f5258..f8bc3d6 100644 --- a/src/tests/saveScreenshot.js +++ b/src/tests/saveScreenshot.js @@ -293,6 +293,12 @@ async function saveScreenshot({ config, step, driver }) { // Replace old file with new file result.description += ` Overwrote existing file.`; fs.renameSync(filePath, existFilePath); + result.outputs.screenshotPath = existFilePath; + result.outputs.changed = true; + // Preserve sourceIntegration metadata + if (step.screenshot.sourceIntegration) { + result.outputs.sourceIntegration = step.screenshot.sourceIntegration; + } return result; } let fractionalDiff; From 41ad41259a920df0b61f3db70ea4ff38ae8a240f Mon Sep 17 00:00:00 2001 From: hawkeyexl Date: Sat, 3 Jan 2026 19:29:51 -0800 Subject: [PATCH 5/9] Update dependencies in package.json - Bump appium-chromium-driver to version 2.1.0 - Bump appium-geckodriver to version 2.1.6 - Bump appium-safari-driver to version 4.1.6 - Update doc-detective-common to version 3.6.0-dev.2 - Update doc-detective-resolver to version 3.6.1-dev.2 - Upgrade posthog-node to version 5.18.1 - Upgrade webdriverio to version 9.23.0 --- package-lock.json | 599 ++++++++++++++++++++++++++++++---------------- package.json | 14 +- 2 files changed, 400 insertions(+), 213 deletions(-) diff --git a/package-lock.json b/package-lock.json index 3b71400..d879aeb 100644 --- a/package-lock.json +++ b/package-lock.json @@ -15,21 +15,21 @@ "@puppeteer/browsers": "^2.11.0", "ajv": "^8.17.1", "appium": "^3.1.2", - "appium-chromium-driver": "^2.0.5", - "appium-geckodriver": "^2.1.4", - "appium-safari-driver": "^4.1.4", + "appium-chromium-driver": "^2.1.0", + "appium-geckodriver": "^2.1.6", + "appium-safari-driver": "^4.1.6", "axios": "^1.13.2", - "doc-detective-common": "file:../common", - "doc-detective-resolver": "file:../resolver", + "doc-detective-common": "^3.6.0-dev.2", + "doc-detective-resolver": "^3.6.1-dev.2", "dotenv": "^17.2.3", "geckodriver": "^6.1.0", "jq-web": "^0.6.2", "json-schema-faker": "^0.5.9", "pixelmatch": "^7.1.0", "pngjs": "^7.0.0", - "posthog-node": "^5.17.3", + "posthog-node": "^5.18.1", "tree-kill": "^1.2.2", - "webdriverio": "^9.21.0" + "webdriverio": "^9.23.0" }, "devDependencies": { "depcheck": "^1.4.7", @@ -72,51 +72,6 @@ "@img/sharp-win32-x64": "^0.34.5" } }, - "../common": { - "name": "doc-detective-common", - "version": "3.6.0-dev.1", - "license": "AGPL-3.0-only", - "dependencies": { - "@apidevtools/json-schema-ref-parser": "^15.1.3", - "ajv": "^8.17.1", - "ajv-errors": "^3.0.0", - "ajv-formats": "^3.0.1", - "ajv-keywords": "^5.1.0", - "axios": "^1.13.2", - "yaml": "^2.8.2" - }, - "devDependencies": { - "chai": "^6.2.1", - "mocha": "^11.7.5", - "sinon": "^21.0.0" - } - }, - "../resolver": { - "name": "doc-detective-resolver", - "version": "3.6.1-dev.1", - "license": "AGPL-3.0-only", - "dependencies": { - "@apidevtools/json-schema-ref-parser": "^15.1.3", - "adm-zip": "^0.5.16", - "ajv": "^8.17.1", - "axios": "^1.13.2", - "doc-detective-common": "file:../common", - "dotenv": "^17.2.3", - "fast-xml-parser": "^5.3.3", - "json-schema-faker": "^0.5.9", - "posthog-node": "^5.17.2" - }, - "devDependencies": { - "body-parser": "^2.2.1", - "chai": "^6.2.1", - "express": "^5.2.1", - "mocha": "^11.7.5", - "proxyquire": "^2.1.3", - "semver": "^7.7.3", - "sinon": "^21.0.0", - "yaml": "^2.8.2" - } - }, "node_modules/@apidevtools/json-schema-ref-parser": { "version": "15.1.3", "license": "MIT", @@ -1234,9 +1189,9 @@ } }, "node_modules/@posthog/core": { - "version": "1.8.0", - "resolved": "https://registry.npmjs.org/@posthog/core/-/core-1.8.0.tgz", - "integrity": "sha512-SfmG1EdbR+2zpQccgBUxM/snCROB9WGkY7VH1r9iaoTNqoaN9IkmIEA/07cZLY4DxVP8jt6Vdfe3s84xksac1g==", + "version": "1.9.0", + "resolved": "https://registry.npmjs.org/@posthog/core/-/core-1.9.0.tgz", + "integrity": "sha512-j7KSWxJTUtNyKynLt/p0hfip/3I46dWU2dk+pt7dKRoz2l5CYueHuHK4EO7Wlgno5yo1HO4sc4s30MXMTICHJw==", "license": "MIT", "dependencies": { "cross-spawn": "^7.0.6" @@ -1244,6 +1199,8 @@ }, "node_modules/@promptbook/utils": { "version": "0.69.5", + "resolved": "https://registry.npmjs.org/@promptbook/utils/-/utils-0.69.5.tgz", + "integrity": "sha512-xm5Ti/Hp3o4xHrsK9Yy3MS6KbDxYbq485hDsFvxqaNA7equHLPdo8H8faTitTeb14QCDfLW4iwCxdVYu5sn6YQ==", "funding": [ { "type": "individual", @@ -1349,10 +1306,14 @@ }, "node_modules/@types/which": { "version": "2.0.2", + "resolved": "https://registry.npmjs.org/@types/which/-/which-2.0.2.tgz", + "integrity": "sha512-113D3mDkZDjo+EeUEHCFy0qniNc1ZpecGiAU7WSo7YDoSzolZIQKpYFHrPpjkB2nuyahcKfrmLXeQlh7gqJYdw==", "license": "MIT" }, "node_modules/@types/ws": { "version": "8.18.1", + "resolved": "https://registry.npmjs.org/@types/ws/-/ws-8.18.1.tgz", + "integrity": "sha512-ThVF6DCVhA8kUGy+aazFQ4kXQ7E1Ty7A3ypFOe0IcJV8O/M511G99AW24irKrW56Wt44yG9+ij8FaqoBGkuBXg==", "license": "MIT", "dependencies": { "@types/node": "*" @@ -1418,12 +1379,14 @@ "license": "MIT" }, "node_modules/@wdio/config": { - "version": "9.21.0", + "version": "9.23.0", + "resolved": "https://registry.npmjs.org/@wdio/config/-/config-9.23.0.tgz", + "integrity": "sha512-hhtngUG2uCxYmScSEor+k22EVlsTW3ARXgke8NPVeQA4p1+GC2CvRZi4P7nmhRTZubgLrENYYsveFcYR+1UXhQ==", "license": "MIT", "dependencies": { "@wdio/logger": "9.18.0", "@wdio/types": "9.20.0", - "@wdio/utils": "9.21.0", + "@wdio/utils": "9.23.0", "deepmerge-ts": "^7.0.3", "glob": "^10.2.2", "import-meta-resolve": "^4.0.0" @@ -1434,6 +1397,8 @@ }, "node_modules/@wdio/config/node_modules/glob": { "version": "10.5.0", + "resolved": "https://registry.npmjs.org/glob/-/glob-10.5.0.tgz", + "integrity": "sha512-DfXN8DfhJ7NH3Oe7cFmu3NCu1wKbkReJ8TorzSAFbSKrlNaQSKfIzqYqVY8zlbs2NLBbWpRiU52GX2PbaBVNkg==", "license": "ISC", "dependencies": { "foreground-child": "^3.1.0", @@ -1450,25 +1415,16 @@ "url": "https://github.com/sponsors/isaacs" } }, - "node_modules/@wdio/config/node_modules/jackspeak": { - "version": "3.4.3", - "license": "BlueOak-1.0.0", - "dependencies": { - "@isaacs/cliui": "^8.0.2" - }, - "funding": { - "url": "https://github.com/sponsors/isaacs" - }, - "optionalDependencies": { - "@pkgjs/parseargs": "^0.11.0" - } - }, "node_modules/@wdio/config/node_modules/lru-cache": { "version": "10.4.3", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-10.4.3.tgz", + "integrity": "sha512-JNAzZcXrCt42VGLuYz0zfAzDfAvJWW6AfYlDBQyDV5DClI2m5sAmK+OIO7s59XfsRsWHp02jAJrRadPRGTt6SQ==", "license": "ISC" }, "node_modules/@wdio/config/node_modules/minimatch": { "version": "9.0.5", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-9.0.5.tgz", + "integrity": "sha512-G6T0ZX48xgozx7587koeX9Ys2NYy6Gmv//P89sEte9V9whIapMNF4idKxnW2QtCcLiTWlb/wfCabAtAFWhhBow==", "license": "ISC", "dependencies": { "brace-expansion": "^2.0.1" @@ -1482,6 +1438,8 @@ }, "node_modules/@wdio/config/node_modules/path-scurry": { "version": "1.11.1", + "resolved": "https://registry.npmjs.org/path-scurry/-/path-scurry-1.11.1.tgz", + "integrity": "sha512-Xa4Nw17FS9ApQFJ9umLiJS4orGjm7ZzwUrwamcGQuHSzDyth9boKDaycYdDcZDuqYATXw4HFXgaqWTctW/v1HA==", "license": "BlueOak-1.0.0", "dependencies": { "lru-cache": "^10.2.0", @@ -1520,6 +1478,8 @@ }, "node_modules/@wdio/protocols": { "version": "9.16.2", + "resolved": "https://registry.npmjs.org/@wdio/protocols/-/protocols-9.16.2.tgz", + "integrity": "sha512-h3k97/lzmyw5MowqceAuY3HX/wGJojXHkiPXA3WlhGPCaa2h4+GovV2nJtRvknCKsE7UHA1xB5SWeI8MzloBew==", "license": "MIT" }, "node_modules/@wdio/repl": { @@ -1545,6 +1505,8 @@ }, "node_modules/@wdio/types": { "version": "9.20.0", + "resolved": "https://registry.npmjs.org/@wdio/types/-/types-9.20.0.tgz", + "integrity": "sha512-zMmAtse2UMCSOW76mvK3OejauAdcFGuKopNRH7crI0gwKTZtvV89yXWRziz9cVXpFgfmJCjf9edxKFWdhuF5yw==", "license": "MIT", "dependencies": { "@types/node": "^20.1.0" @@ -1554,7 +1516,9 @@ } }, "node_modules/@wdio/types/node_modules/@types/node": { - "version": "20.19.25", + "version": "20.19.27", + "resolved": "https://registry.npmjs.org/@types/node/-/node-20.19.27.tgz", + "integrity": "sha512-N2clP5pJhB2YnZJ3PIHFk5RkygRX5WO/5f0WC08tp0wd+sv0rsJk3MqWn3CbNmT2J505a5336jaQj4ph1AdMug==", "license": "MIT", "dependencies": { "undici-types": "~6.21.0" @@ -1562,10 +1526,14 @@ }, "node_modules/@wdio/types/node_modules/undici-types": { "version": "6.21.0", + "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-6.21.0.tgz", + "integrity": "sha512-iwDZqg0QAGrg9Rav5H4n0M64c3mkR59cJ6wQp+7C4nI0gsmExaedaYLNO44eT4AtBBwjbTiGPMlt2Md0T9H9JQ==", "license": "MIT" }, "node_modules/@wdio/utils": { - "version": "9.21.0", + "version": "9.23.0", + "resolved": "https://registry.npmjs.org/@wdio/utils/-/utils-9.23.0.tgz", + "integrity": "sha512-WhXuVSxEvPw/i34bL1aCHAOi+4g29kRkIMyBShNSxH+Shxh2G91RJYsXm4IAiPMGcC4H6G8T2VcbZ32qnGPm5Q==", "license": "MIT", "dependencies": { "@puppeteer/browsers": "^2.2.0", @@ -1624,6 +1592,15 @@ "node": ">= 0.6" } }, + "node_modules/adm-zip": { + "version": "0.5.16", + "resolved": "https://registry.npmjs.org/adm-zip/-/adm-zip-0.5.16.tgz", + "integrity": "sha512-TGw5yVi4saajsSEgz25grObGHEUaDrniwvA2qwSC060KfqGPdglhvPMA2lPIoxs3PQIItj2iag35fONcQqgUaQ==", + "license": "MIT", + "engines": { + "node": ">=12.0" + } + }, "node_modules/agent-base": { "version": "7.1.4", "license": "MIT", @@ -1646,6 +1623,15 @@ "url": "https://github.com/sponsors/epoberezkin" } }, + "node_modules/ajv-errors": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/ajv-errors/-/ajv-errors-3.0.0.tgz", + "integrity": "sha512-V3wD15YHfHz6y0KdhYFjyy9vWtEVALT9UrxfN3zqlI6dMioHnJrqOYfyPKol3oqrnCM9uwkcdCwkJ0WUcbLMTQ==", + "license": "MIT", + "peerDependencies": { + "ajv": "^8.0.1" + } + }, "node_modules/ajv-formats": { "version": "3.0.1", "license": "MIT", @@ -1661,6 +1647,18 @@ } } }, + "node_modules/ajv-keywords": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/ajv-keywords/-/ajv-keywords-5.1.0.tgz", + "integrity": "sha512-YCS/JNFAUyr5vAuhk1DWm1CBxRHW9LbJ2ozWeemrIqpbsqKjHVxYPyi5GC0rjZIT5JxJ3virVTS8wk4i/Z+krw==", + "license": "MIT", + "dependencies": { + "fast-deep-equal": "^3.1.3" + }, + "peerDependencies": { + "ajv": "^8.8.2" + } + }, "node_modules/ansi-regex": { "version": "6.2.2", "license": "MIT", @@ -1731,15 +1729,13 @@ } }, "node_modules/appium-chromium-driver": { - "version": "2.0.5", - "resolved": "https://registry.npmjs.org/appium-chromium-driver/-/appium-chromium-driver-2.0.5.tgz", - "integrity": "sha512-S7FZjy7MT2gJbq8K2Uux58Xinqink5fmKqajMsy89znjMEsTQUzBSSt4IROpfKEB+cLfQlWy4ONLSQPF7I0t9w==", + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/appium-chromium-driver/-/appium-chromium-driver-2.1.0.tgz", + "integrity": "sha512-9a59FoCcrKVSq5jKtbVnOQ/8w8E2jY/YMMz2Wh9oxI57C/rU8hTCjDiFJwFKG9Sx2RDkrIYq10HfpAeX97Cdig==", "hasShrinkwrap": true, "license": "Apache-2.0", "dependencies": { - "appium-chromedriver": "^8.0.0", - "bluebird": "^3.7.2", - "lodash": "^4.17.21" + "appium-chromedriver": "^8.0.0" }, "engines": { "node": "^20.19.0 || ^22.12.0 || >=24.0.0", @@ -2280,14 +2276,14 @@ } }, "node_modules/appium-chromium-driver/node_modules/appium-adb": { - "version": "14.1.5", - "resolved": "https://registry.npmjs.org/appium-adb/-/appium-adb-14.1.5.tgz", - "integrity": "sha512-pR7HPfnm58rxWvxywowjeDt89KHglZvnQbDFLk2aMcrnQIli++fHqV3E9FuDp5w/34VuguX6GTjYMfnGTaYkhA==", + "version": "14.1.7", + "resolved": "https://registry.npmjs.org/appium-adb/-/appium-adb-14.1.7.tgz", + "integrity": "sha512-/06TJ7maIJ4RzKmXdnqVNBhBZqoxAwoDeYBEaRm8Dbsa803Io16CJ94R3ncpQwlD5r5bsj4YMmwdZtVZKMjsLw==", "license": "Apache-2.0", "dependencies": { "@appium/support": "^7.0.0-rc.1", "async-lock": "^1.0.0", - "asyncbox": "^3.0.0", + "asyncbox": "^4.0.1", "bluebird": "^3.4.7", "ini": "^6.0.0", "lodash": "^4.0.0", @@ -2300,17 +2296,31 @@ "npm": ">=10" } }, + "node_modules/appium-chromium-driver/node_modules/appium-adb/node_modules/asyncbox": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/asyncbox/-/asyncbox-4.0.1.tgz", + "integrity": "sha512-JtbRZ6JWq1eT0mq/Eg2yObjnX9+80QcYQXDYyLxeNcbu2jHjbV18De2eyn69GTWbbLvDm52Pp/4SFDtte3q/bQ==", + "license": "Apache-2.0", + "dependencies": { + "bluebird": "^3.5.1", + "lodash": "^4.17.4" + }, + "engines": { + "node": "^20.19.0 || ^22.12.0 || >=24.0.0", + "npm": ">=10" + } + }, "node_modules/appium-chromium-driver/node_modules/appium-chromedriver": { - "version": "8.0.27", - "resolved": "https://registry.npmjs.org/appium-chromedriver/-/appium-chromedriver-8.0.27.tgz", - "integrity": "sha512-4GaoxCghx8zxmvcj1adXPsD6Eqk0VXQyZN/TTfVvKpbInpuRZbkLJJgnRE7gVwlRe2JnzzXtzzNEbmAWUBxaFQ==", + "version": "8.0.29", + "resolved": "https://registry.npmjs.org/appium-chromedriver/-/appium-chromedriver-8.0.29.tgz", + "integrity": "sha512-WQGTcqIUbXhgZLhdlP7vv4bqYJTZYdPiaW5RXpYoMEZ0qX2GHw7jLAzEk+mhl6AY/uheAruX6x9XGF3EPerYEQ==", "license": "Apache-2.0", "dependencies": { "@appium/base-driver": "^10.0.0-rc.2", "@appium/support": "^7.0.0-rc.1", "@xmldom/xmldom": "^0.x", "appium-adb": "^14.0.0", - "asyncbox": "^3.0.0", + "asyncbox": "^4.0.1", "axios": "^1.6.5", "bluebird": "^3.5.1", "compare-versions": "^6.0.0", @@ -2324,6 +2334,20 @@ "npm": ">=10" } }, + "node_modules/appium-chromium-driver/node_modules/appium-chromedriver/node_modules/asyncbox": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/asyncbox/-/asyncbox-4.0.1.tgz", + "integrity": "sha512-JtbRZ6JWq1eT0mq/Eg2yObjnX9+80QcYQXDYyLxeNcbu2jHjbV18De2eyn69GTWbbLvDm52Pp/4SFDtte3q/bQ==", + "license": "Apache-2.0", + "dependencies": { + "bluebird": "^3.5.1", + "lodash": "^4.17.4" + }, + "engines": { + "node": "^20.19.0 || ^22.12.0 || >=24.0.0", + "npm": ">=10" + } + }, "node_modules/appium-chromium-driver/node_modules/archiver": { "version": "7.0.1", "resolved": "https://registry.npmjs.org/archiver/-/archiver-7.0.1.tgz", @@ -5043,25 +5067,29 @@ } }, "node_modules/appium-chromium-driver/node_modules/send": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/send/-/send-1.2.0.tgz", - "integrity": "sha512-uaW0WwXKpL9blXE2o0bRhoL2EGXIrZxQ2ZQ4mgcfoBxdFmQold+qWsD2jLrfZ0trjKL6vOw0j//eAwcALFjKSw==", + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/send/-/send-1.2.1.tgz", + "integrity": "sha512-1gnZf7DFcoIcajTjTwjwuDjzuz4PPcY2StKPlsGAQ1+YH20IRVrBaXSWmdjowTJ6u8Rc01PoYOGHXfP1mYcZNQ==", "license": "MIT", "dependencies": { - "debug": "^4.3.5", + "debug": "^4.4.3", "encodeurl": "^2.0.0", "escape-html": "^1.0.3", "etag": "^1.8.1", "fresh": "^2.0.0", - "http-errors": "^2.0.0", - "mime-types": "^3.0.1", + "http-errors": "^2.0.1", + "mime-types": "^3.0.2", "ms": "^2.1.3", "on-finished": "^2.4.1", "range-parser": "^1.2.1", - "statuses": "^2.0.1" + "statuses": "^2.0.2" }, "engines": { "node": ">= 18" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/express" } }, "node_modules/appium-chromium-driver/node_modules/serve-favicon": { @@ -5110,9 +5138,9 @@ "license": "MIT" }, "node_modules/appium-chromium-driver/node_modules/serve-static": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/serve-static/-/serve-static-2.2.0.tgz", - "integrity": "sha512-61g9pCh0Vnh7IutZjtLGGpTA355+OPn2TyDv/6ivP2h/AdAVX9azsoxmg2/M6nZeQZNYBEwIcsne1mJd9oQItQ==", + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/serve-static/-/serve-static-2.2.1.tgz", + "integrity": "sha512-xRXBn0pPqQTVQiC8wyQrKs2MOlX24zQ0POGaj0kultvoOCstBQM5yvOhAVSUwOMjQtTvsPWoNCHfPGwaaQJhTw==", "license": "MIT", "dependencies": { "encodeurl": "^2.0.0", @@ -5122,6 +5150,10 @@ }, "engines": { "node": ">= 18" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/express" } }, "node_modules/appium-chromium-driver/node_modules/set-blocking": { @@ -6083,21 +6115,21 @@ } }, "node_modules/appium-geckodriver": { - "version": "2.1.4", - "resolved": "https://registry.npmjs.org/appium-geckodriver/-/appium-geckodriver-2.1.4.tgz", - "integrity": "sha512-IkFxnBzwfYCGegbzb5yMVlwi50yAP1kFh5NhvT7j0OrjCiwxQfe7Z9ce7pJy3ez9eomrFHPstEioYpjWg71pNw==", + "version": "2.1.6", + "resolved": "https://registry.npmjs.org/appium-geckodriver/-/appium-geckodriver-2.1.6.tgz", + "integrity": "sha512-UJo6DJ+FqGXdS8RWMWamyhU+C+/EgVMtrfPqecmZirilkubXRWIC43dyL8LkludF20iSfKcFjL+DJce6IuOzJQ==", "hasShrinkwrap": true, "license": "Apache-2.0", "dependencies": { "appium-adb": "^14.0.0", - "asyncbox": "^3.0.0", + "asyncbox": "^4.0.1", "axios": "^1.7.7", "bluebird": "^3.5.1", "lodash": "^4.17.4", "portscanner": "2.2.0", "semver": "^7.6.3", "tar-stream": "^3.1.7", - "teen_process": "^3.0.0" + "teen_process": "^4.0.4" }, "engines": { "node": "^20.19.0 || ^22.12.0 || >=24.0.0", @@ -6141,6 +6173,20 @@ "spdy": "4.0.2" } }, + "node_modules/appium-geckodriver/node_modules/@appium/base-driver/node_modules/asyncbox": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/asyncbox/-/asyncbox-3.0.0.tgz", + "integrity": "sha512-X7U0nedUMKV3nn9c4R0Zgvdvv6cw97tbDlHSZicq1snGPi/oX9DgGmFSURWtxDdnBWd3V0YviKhqAYAVvoWQ/A==", + "license": "Apache-2.0", + "dependencies": { + "bluebird": "^3.5.1", + "lodash": "^4.17.4", + "source-map-support": "^0.x" + }, + "engines": { + "node": ">=16" + } + }, "node_modules/appium-geckodriver/node_modules/@appium/base-plugin": { "version": "3.0.5", "resolved": "https://registry.npmjs.org/@appium/base-plugin/-/base-plugin-3.0.5.tgz", @@ -6725,14 +6771,14 @@ } }, "node_modules/appium-geckodriver/node_modules/appium-adb": { - "version": "14.1.5", - "resolved": "https://registry.npmjs.org/appium-adb/-/appium-adb-14.1.5.tgz", - "integrity": "sha512-pR7HPfnm58rxWvxywowjeDt89KHglZvnQbDFLk2aMcrnQIli++fHqV3E9FuDp5w/34VuguX6GTjYMfnGTaYkhA==", + "version": "14.1.7", + "resolved": "https://registry.npmjs.org/appium-adb/-/appium-adb-14.1.7.tgz", + "integrity": "sha512-/06TJ7maIJ4RzKmXdnqVNBhBZqoxAwoDeYBEaRm8Dbsa803Io16CJ94R3ncpQwlD5r5bsj4YMmwdZtVZKMjsLw==", "license": "Apache-2.0", "dependencies": { "@appium/support": "^7.0.0-rc.1", "async-lock": "^1.0.0", - "asyncbox": "^3.0.0", + "asyncbox": "^4.0.1", "bluebird": "^3.4.7", "ini": "^6.0.0", "lodash": "^4.0.0", @@ -6745,6 +6791,35 @@ "npm": ">=10" } }, + "node_modules/appium-geckodriver/node_modules/appium-adb/node_modules/teen_process": { + "version": "3.0.6", + "resolved": "https://registry.npmjs.org/teen_process/-/teen_process-3.0.6.tgz", + "integrity": "sha512-nUw1B4MogSZzzy67n37IM1vg4doj+bWOZ7VwIFZGfD7MDmO+FRlhQlA2+22xJnTELVDDlOaTAMpKuuMI2vkDtg==", + "license": "Apache-2.0", + "dependencies": { + "bluebird": "^3.7.2", + "lodash": "^4.17.21", + "shell-quote": "^1.8.1" + }, + "engines": { + "node": "^20.19.0 || ^22.12.0 || >=24.0.0", + "npm": ">=10" + } + }, + "node_modules/appium-geckodriver/node_modules/appium/node_modules/asyncbox": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/asyncbox/-/asyncbox-3.0.0.tgz", + "integrity": "sha512-X7U0nedUMKV3nn9c4R0Zgvdvv6cw97tbDlHSZicq1snGPi/oX9DgGmFSURWtxDdnBWd3V0YviKhqAYAVvoWQ/A==", + "license": "Apache-2.0", + "dependencies": { + "bluebird": "^3.5.1", + "lodash": "^4.17.4", + "source-map-support": "^0.x" + }, + "engines": { + "node": ">=16" + } + }, "node_modules/appium-geckodriver/node_modules/appium/node_modules/teen_process": { "version": "3.0.4", "resolved": "https://registry.npmjs.org/teen_process/-/teen_process-3.0.4.tgz", @@ -6882,17 +6957,17 @@ "license": "MIT" }, "node_modules/appium-geckodriver/node_modules/asyncbox": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/asyncbox/-/asyncbox-3.0.0.tgz", - "integrity": "sha512-X7U0nedUMKV3nn9c4R0Zgvdvv6cw97tbDlHSZicq1snGPi/oX9DgGmFSURWtxDdnBWd3V0YviKhqAYAVvoWQ/A==", + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/asyncbox/-/asyncbox-4.0.1.tgz", + "integrity": "sha512-JtbRZ6JWq1eT0mq/Eg2yObjnX9+80QcYQXDYyLxeNcbu2jHjbV18De2eyn69GTWbbLvDm52Pp/4SFDtte3q/bQ==", "license": "Apache-2.0", "dependencies": { "bluebird": "^3.5.1", - "lodash": "^4.17.4", - "source-map-support": "^0.x" + "lodash": "^4.17.4" }, "engines": { - "node": ">=16" + "node": "^20.19.0 || ^22.12.0 || >=24.0.0", + "npm": ">=10" } }, "node_modules/appium-geckodriver/node_modules/asynckit": { @@ -9472,25 +9547,29 @@ } }, "node_modules/appium-geckodriver/node_modules/send": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/send/-/send-1.2.0.tgz", - "integrity": "sha512-uaW0WwXKpL9blXE2o0bRhoL2EGXIrZxQ2ZQ4mgcfoBxdFmQold+qWsD2jLrfZ0trjKL6vOw0j//eAwcALFjKSw==", + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/send/-/send-1.2.1.tgz", + "integrity": "sha512-1gnZf7DFcoIcajTjTwjwuDjzuz4PPcY2StKPlsGAQ1+YH20IRVrBaXSWmdjowTJ6u8Rc01PoYOGHXfP1mYcZNQ==", "license": "MIT", "dependencies": { - "debug": "^4.3.5", + "debug": "^4.4.3", "encodeurl": "^2.0.0", "escape-html": "^1.0.3", "etag": "^1.8.1", "fresh": "^2.0.0", - "http-errors": "^2.0.0", - "mime-types": "^3.0.1", + "http-errors": "^2.0.1", + "mime-types": "^3.0.2", "ms": "^2.1.3", "on-finished": "^2.4.1", "range-parser": "^1.2.1", - "statuses": "^2.0.1" + "statuses": "^2.0.2" }, "engines": { "node": ">= 18" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/express" } }, "node_modules/appium-geckodriver/node_modules/serve-favicon": { @@ -9539,9 +9618,9 @@ "license": "MIT" }, "node_modules/appium-geckodriver/node_modules/serve-static": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/serve-static/-/serve-static-2.2.0.tgz", - "integrity": "sha512-61g9pCh0Vnh7IutZjtLGGpTA355+OPn2TyDv/6ivP2h/AdAVX9azsoxmg2/M6nZeQZNYBEwIcsne1mJd9oQItQ==", + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/serve-static/-/serve-static-2.2.1.tgz", + "integrity": "sha512-xRXBn0pPqQTVQiC8wyQrKs2MOlX24zQ0POGaj0kultvoOCstBQM5yvOhAVSUwOMjQtTvsPWoNCHfPGwaaQJhTw==", "license": "MIT", "dependencies": { "encodeurl": "^2.0.0", @@ -9551,6 +9630,10 @@ }, "engines": { "node": ">= 18" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/express" } }, "node_modules/appium-geckodriver/node_modules/set-blocking": { @@ -10019,9 +10102,9 @@ } }, "node_modules/appium-geckodriver/node_modules/teen_process": { - "version": "3.0.6", - "resolved": "https://registry.npmjs.org/teen_process/-/teen_process-3.0.6.tgz", - "integrity": "sha512-nUw1B4MogSZzzy67n37IM1vg4doj+bWOZ7VwIFZGfD7MDmO+FRlhQlA2+22xJnTELVDDlOaTAMpKuuMI2vkDtg==", + "version": "4.0.4", + "resolved": "https://registry.npmjs.org/teen_process/-/teen_process-4.0.4.tgz", + "integrity": "sha512-aeHqdf0jw2Rx3r1wbwJQrmg1PlU/zLcqSL7YrXChKywnpQob8o4Yhfn2RvViDDsU+0mVYleC4UDzo47Gg4wc8g==", "license": "Apache-2.0", "dependencies": { "bluebird": "^3.7.2", @@ -10485,18 +10568,18 @@ } }, "node_modules/appium-safari-driver": { - "version": "4.1.4", - "resolved": "https://registry.npmjs.org/appium-safari-driver/-/appium-safari-driver-4.1.4.tgz", - "integrity": "sha512-FCbAamlpE5lgJb+OaM+SzhQ7n/Ow0+oHNYoYBo7NhLFg/t6OQKjMwNXtOl46+pG8Len64QlqTjr6HFRPUFzong==", + "version": "4.1.6", + "resolved": "https://registry.npmjs.org/appium-safari-driver/-/appium-safari-driver-4.1.6.tgz", + "integrity": "sha512-cdDbYgcszYzQ4Q9NFHx/+ftXmzzZE9go52zsv7BJuxNBSbUNR5p7k5jAsgAgSBPXS8nbWAi2N/so6ROqtPsT3w==", "hasShrinkwrap": true, "license": "Apache-2.0", "dependencies": { - "asyncbox": "^3.0.0", + "asyncbox": "^4.0.1", "bluebird": "^3.5.1", "lodash": "^4.17.4", "node-simctl": "^8.0.0", "portscanner": "2.2.0", - "teen_process": "^3.0.0" + "teen_process": "^4.0.4" }, "engines": { "node": "^20.19.0 || ^22.12.0 || >=24.0.0", @@ -10540,6 +10623,20 @@ "spdy": "4.0.2" } }, + "node_modules/appium-safari-driver/node_modules/@appium/base-driver/node_modules/asyncbox": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/asyncbox/-/asyncbox-3.0.0.tgz", + "integrity": "sha512-X7U0nedUMKV3nn9c4R0Zgvdvv6cw97tbDlHSZicq1snGPi/oX9DgGmFSURWtxDdnBWd3V0YviKhqAYAVvoWQ/A==", + "license": "Apache-2.0", + "dependencies": { + "bluebird": "^3.5.1", + "lodash": "^4.17.4", + "source-map-support": "^0.x" + }, + "engines": { + "node": ">=16" + } + }, "node_modules/appium-safari-driver/node_modules/@appium/base-plugin": { "version": "3.0.5", "resolved": "https://registry.npmjs.org/@appium/base-plugin/-/base-plugin-3.0.5.tgz", @@ -11106,6 +11203,20 @@ "npm": ">=10" } }, + "node_modules/appium-safari-driver/node_modules/appium/node_modules/asyncbox": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/asyncbox/-/asyncbox-3.0.0.tgz", + "integrity": "sha512-X7U0nedUMKV3nn9c4R0Zgvdvv6cw97tbDlHSZicq1snGPi/oX9DgGmFSURWtxDdnBWd3V0YviKhqAYAVvoWQ/A==", + "license": "Apache-2.0", + "dependencies": { + "bluebird": "^3.5.1", + "lodash": "^4.17.4", + "source-map-support": "^0.x" + }, + "engines": { + "node": ">=16" + } + }, "node_modules/appium-safari-driver/node_modules/appium/node_modules/teen_process": { "version": "3.0.4", "resolved": "https://registry.npmjs.org/teen_process/-/teen_process-3.0.4.tgz", @@ -11243,17 +11354,17 @@ "license": "MIT" }, "node_modules/appium-safari-driver/node_modules/asyncbox": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/asyncbox/-/asyncbox-3.0.0.tgz", - "integrity": "sha512-X7U0nedUMKV3nn9c4R0Zgvdvv6cw97tbDlHSZicq1snGPi/oX9DgGmFSURWtxDdnBWd3V0YviKhqAYAVvoWQ/A==", + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/asyncbox/-/asyncbox-4.0.1.tgz", + "integrity": "sha512-JtbRZ6JWq1eT0mq/Eg2yObjnX9+80QcYQXDYyLxeNcbu2jHjbV18De2eyn69GTWbbLvDm52Pp/4SFDtte3q/bQ==", "license": "Apache-2.0", "dependencies": { "bluebird": "^3.5.1", - "lodash": "^4.17.4", - "source-map-support": "^0.x" + "lodash": "^4.17.4" }, "engines": { - "node": ">=16" + "node": "^20.19.0 || ^22.12.0 || >=24.0.0", + "npm": ">=10" } }, "node_modules/appium-safari-driver/node_modules/asynckit": { @@ -13211,18 +13322,18 @@ } }, "node_modules/appium-safari-driver/node_modules/node-simctl": { - "version": "8.1.1", - "resolved": "https://registry.npmjs.org/node-simctl/-/node-simctl-8.1.1.tgz", - "integrity": "sha512-2uyaczrXXAqqCKVioQmNaCHugehVCnZRzmnobc+QVcy3LntD+YqdRJg+uDEUMydRU8htA/rQhGRho9cUWGcvmA==", + "version": "8.1.3", + "resolved": "https://registry.npmjs.org/node-simctl/-/node-simctl-8.1.3.tgz", + "integrity": "sha512-tt/pYsRUzWmwFtAeOj5flIBAgSXl/tIA276AHj8nN2XErP7i3avpFjZ8oVrJTDCfBVukf4Jin50rlE0CESexfQ==", "license": "Apache-2.0", "dependencies": { "@appium/logger": "^2.0.0-rc.1", - "asyncbox": "^3.0.0", + "asyncbox": "^4.0.1", "bluebird": "^3.5.1", "lodash": "^4.2.1", "rimraf": "^6.0.1", "semver": "^7.0.0", - "teen_process": "^3.0.0", + "teen_process": "^4.0.4", "uuid": "^13.0.0", "which": "^6.0.0" }, @@ -13864,25 +13975,29 @@ } }, "node_modules/appium-safari-driver/node_modules/send": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/send/-/send-1.2.0.tgz", - "integrity": "sha512-uaW0WwXKpL9blXE2o0bRhoL2EGXIrZxQ2ZQ4mgcfoBxdFmQold+qWsD2jLrfZ0trjKL6vOw0j//eAwcALFjKSw==", + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/send/-/send-1.2.1.tgz", + "integrity": "sha512-1gnZf7DFcoIcajTjTwjwuDjzuz4PPcY2StKPlsGAQ1+YH20IRVrBaXSWmdjowTJ6u8Rc01PoYOGHXfP1mYcZNQ==", "license": "MIT", "dependencies": { - "debug": "^4.3.5", + "debug": "^4.4.3", "encodeurl": "^2.0.0", "escape-html": "^1.0.3", "etag": "^1.8.1", "fresh": "^2.0.0", - "http-errors": "^2.0.0", - "mime-types": "^3.0.1", + "http-errors": "^2.0.1", + "mime-types": "^3.0.2", "ms": "^2.1.3", "on-finished": "^2.4.1", "range-parser": "^1.2.1", - "statuses": "^2.0.1" + "statuses": "^2.0.2" }, "engines": { "node": ">= 18" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/express" } }, "node_modules/appium-safari-driver/node_modules/serve-favicon": { @@ -13931,9 +14046,9 @@ "license": "MIT" }, "node_modules/appium-safari-driver/node_modules/serve-static": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/serve-static/-/serve-static-2.2.0.tgz", - "integrity": "sha512-61g9pCh0Vnh7IutZjtLGGpTA355+OPn2TyDv/6ivP2h/AdAVX9azsoxmg2/M6nZeQZNYBEwIcsne1mJd9oQItQ==", + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/serve-static/-/serve-static-2.2.1.tgz", + "integrity": "sha512-xRXBn0pPqQTVQiC8wyQrKs2MOlX24zQ0POGaj0kultvoOCstBQM5yvOhAVSUwOMjQtTvsPWoNCHfPGwaaQJhTw==", "license": "MIT", "dependencies": { "encodeurl": "^2.0.0", @@ -13943,6 +14058,10 @@ }, "engines": { "node": ">= 18" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/express" } }, "node_modules/appium-safari-driver/node_modules/set-blocking": { @@ -14411,9 +14530,9 @@ } }, "node_modules/appium-safari-driver/node_modules/teen_process": { - "version": "3.0.6", - "resolved": "https://registry.npmjs.org/teen_process/-/teen_process-3.0.6.tgz", - "integrity": "sha512-nUw1B4MogSZzzy67n37IM1vg4doj+bWOZ7VwIFZGfD7MDmO+FRlhQlA2+22xJnTELVDDlOaTAMpKuuMI2vkDtg==", + "version": "4.0.4", + "resolved": "https://registry.npmjs.org/teen_process/-/teen_process-4.0.4.tgz", + "integrity": "sha512-aeHqdf0jw2Rx3r1wbwJQrmg1PlU/zLcqSL7YrXChKywnpQob8o4Yhfn2RvViDDsU+0mVYleC4UDzo47Gg4wc8g==", "license": "Apache-2.0", "dependencies": { "bluebird": "^3.7.2", @@ -14909,7 +15028,9 @@ } }, "node_modules/archiver-utils/node_modules/glob": { - "version": "10.4.5", + "version": "10.5.0", + "resolved": "https://registry.npmjs.org/glob/-/glob-10.5.0.tgz", + "integrity": "sha512-DfXN8DfhJ7NH3Oe7cFmu3NCu1wKbkReJ8TorzSAFbSKrlNaQSKfIzqYqVY8zlbs2NLBbWpRiU52GX2PbaBVNkg==", "license": "ISC", "dependencies": { "foreground-child": "^3.1.0", @@ -14926,19 +15047,6 @@ "url": "https://github.com/sponsors/isaacs" } }, - "node_modules/archiver-utils/node_modules/jackspeak": { - "version": "3.4.3", - "license": "BlueOak-1.0.0", - "dependencies": { - "@isaacs/cliui": "^8.0.2" - }, - "funding": { - "url": "https://github.com/sponsors/isaacs" - }, - "optionalDependencies": { - "@pkgjs/parseargs": "^0.11.0" - } - }, "node_modules/archiver-utils/node_modules/lru-cache": { "version": "10.4.3", "license": "ISC" @@ -15838,6 +15946,8 @@ }, "node_modules/deepmerge-ts": { "version": "7.1.5", + "resolved": "https://registry.npmjs.org/deepmerge-ts/-/deepmerge-ts-7.1.5.tgz", + "integrity": "sha512-HOJkrhaYsweh+W+e74Yn7YStZOilkoPb6fycpwNLKzSPtruFs48nYis0zy5yJz1+ktUhHxoRDJ27RQAWLIJVJw==", "license": "BSD-3-Clause", "engines": { "node": ">=16.0.0" @@ -15940,7 +16050,9 @@ "license": "MIT" }, "node_modules/depcheck/node_modules/js-yaml": { - "version": "3.14.1", + "version": "3.14.2", + "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-3.14.2.tgz", + "integrity": "sha512-PMSmkqxr106Xa156c2M265Z+FTrPl+oxd/rgOQy2tijQeK5TxQ43psO1ZCwhVOSdnn+RzkzlRz/eY4BgJBYVpg==", "dev": true, "license": "MIT", "dependencies": { @@ -16043,12 +16155,36 @@ } }, "node_modules/doc-detective-common": { - "resolved": "../common", - "link": true + "version": "3.6.0-dev.2", + "resolved": "https://registry.npmjs.org/doc-detective-common/-/doc-detective-common-3.6.0-dev.2.tgz", + "integrity": "sha512-6wrfWvUSNVh8I1ccqCI7Z0ICxK5j59X2XttLsspcfiSTA42Rsm7jTlFrbMFxQOGBukyVa3mIi44maF9FCTkvdw==", + "license": "AGPL-3.0-only", + "dependencies": { + "@apidevtools/json-schema-ref-parser": "^15.1.3", + "ajv": "^8.17.1", + "ajv-errors": "^3.0.0", + "ajv-formats": "^3.0.1", + "ajv-keywords": "^5.1.0", + "axios": "^1.13.2", + "yaml": "^2.8.2" + } }, "node_modules/doc-detective-resolver": { - "resolved": "../resolver", - "link": true + "version": "3.6.1-dev.2", + "resolved": "https://registry.npmjs.org/doc-detective-resolver/-/doc-detective-resolver-3.6.1-dev.2.tgz", + "integrity": "sha512-BrNPiTMOVOEocGW0w8lG4dLrQP9Hhk5kIvzpOEv3MIc8fgpt2GnjIMiH/adomP8eOhw5o8MBZ0mzalkj0Wg1Jg==", + "license": "AGPL-3.0-only", + "dependencies": { + "@apidevtools/json-schema-ref-parser": "^15.1.3", + "adm-zip": "^0.5.16", + "ajv": "^8.17.1", + "axios": "^1.13.2", + "doc-detective-common": "^3.6.0-dev.2", + "dotenv": "^17.2.3", + "fast-xml-parser": "^5.3.3", + "json-schema-faker": "^0.5.9", + "posthog-node": "^5.18.1" + } }, "node_modules/dom-serializer": { "version": "2.0.0", @@ -16129,6 +16265,8 @@ }, "node_modules/edge-paths": { "version": "3.0.5", + "resolved": "https://registry.npmjs.org/edge-paths/-/edge-paths-3.0.5.tgz", + "integrity": "sha512-sB7vSrDnFa4ezWQk9nZ/n0FdpdUuC6R1EOrlU3DL+bovcNFK28rqu2emmAUjujYEJTWIgQGqgVVWUZXMnc8iWg==", "license": "MIT", "dependencies": { "@types/which": "^2.0.1", @@ -16143,10 +16281,14 @@ }, "node_modules/edge-paths/node_modules/isexe": { "version": "2.0.0", + "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz", + "integrity": "sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==", "license": "ISC" }, "node_modules/edge-paths/node_modules/which": { "version": "2.0.2", + "resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz", + "integrity": "sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==", "license": "ISC", "dependencies": { "isexe": "^2.0.0" @@ -16159,7 +16301,9 @@ } }, "node_modules/edgedriver": { - "version": "6.2.0", + "version": "6.2.1", + "resolved": "https://registry.npmjs.org/edgedriver/-/edgedriver-6.2.1.tgz", + "integrity": "sha512-3R/+lehVRT07HdF8EQKpS8EJ4umd0PVzNBd0oxhCpT9PEicm+j6XgyTOtbfTTV5gGlEw/cXbZhjH72R5Oj0aug==", "hasInstallScript": true, "license": "MIT", "dependencies": { @@ -16167,7 +16311,7 @@ "@zip.js/zip.js": "^2.8.11", "decamelize": "^6.0.1", "edge-paths": "^3.0.5", - "fast-xml-parser": "^5.3.2", + "fast-xml-parser": "^5.3.3", "http-proxy-agent": "^7.0.2", "https-proxy-agent": "^7.0.6", "which": "^6.0.0" @@ -16492,7 +16636,9 @@ "license": "BSD-3-Clause" }, "node_modules/fast-xml-parser": { - "version": "5.3.2", + "version": "5.3.3", + "resolved": "https://registry.npmjs.org/fast-xml-parser/-/fast-xml-parser-5.3.3.tgz", + "integrity": "sha512-2O3dkPAAC6JavuMm8+4+pgTk+5hoAs+CjZ+sWcQLkX9+/tHRuTkQh/Oaifr8qDmZ8iEHb771Ea6G8CdwkrgvYA==", "funding": [ { "type": "github", @@ -16766,6 +16912,8 @@ }, "node_modules/get-port": { "version": "7.1.0", + "resolved": "https://registry.npmjs.org/get-port/-/get-port-7.1.0.tgz", + "integrity": "sha512-QB9NKEeDg3xxVwCCwJQ9+xycaz6pBB6iQ76wiWMl1927n0Kir6alPiP+yuiICLLU4jpMe08dXfpebuQppFA2zw==", "license": "MIT", "engines": { "node": ">=16" @@ -17160,6 +17308,8 @@ }, "node_modules/import-meta-resolve": { "version": "4.2.0", + "resolved": "https://registry.npmjs.org/import-meta-resolve/-/import-meta-resolve-4.2.0.tgz", + "integrity": "sha512-Iqv2fzaTQN28s/FwZAoFq0ZSs/7hMAHJVX+w8PZl3cY19Pxk6jFFalxQoIfW2826i/fDLXv8IiEZRIT0lDuWcg==", "license": "MIT", "funding": { "type": "github", @@ -17308,6 +17458,21 @@ "node": ">=16" } }, + "node_modules/jackspeak": { + "version": "3.4.3", + "resolved": "https://registry.npmjs.org/jackspeak/-/jackspeak-3.4.3.tgz", + "integrity": "sha512-OGlZQpz2yfahA/Rd1Y8Cd9SIEsqvXkLVoSw/cgwhnhFMDbsQFeZYoJJ7bIZBS9BcamUW96asq/npPWugM+RQBw==", + "license": "BlueOak-1.0.0", + "dependencies": { + "@isaacs/cliui": "^8.0.2" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + }, + "optionalDependencies": { + "@pkgjs/parseargs": "^0.11.0" + } + }, "node_modules/jq-web": { "version": "0.6.2", "license": "ISC" @@ -17403,7 +17568,9 @@ } }, "node_modules/json-schema-ref-parser/node_modules/js-yaml": { - "version": "3.14.1", + "version": "3.14.2", + "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-3.14.2.tgz", + "integrity": "sha512-PMSmkqxr106Xa156c2M265Z+FTrPl+oxd/rgOQy2tijQeK5TxQ43psO1ZCwhVOSdnn+RzkzlRz/eY4BgJBYVpg==", "license": "MIT", "dependencies": { "argparse": "^1.0.7", @@ -17565,6 +17732,8 @@ }, "node_modules/locate-app": { "version": "2.5.0", + "resolved": "https://registry.npmjs.org/locate-app/-/locate-app-2.5.0.tgz", + "integrity": "sha512-xIqbzPMBYArJRmPGUZD9CzV9wOqmVtQnaAn3wrj3s6WYW0bQvPI7x+sPYUGmDTYMHefVK//zc6HEYZ1qnxIK+Q==", "funding": [ { "type": "individual", @@ -17584,6 +17753,8 @@ }, "node_modules/locate-app/node_modules/type-fest": { "version": "4.26.0", + "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-4.26.0.tgz", + "integrity": "sha512-OduNjVJsFbifKb57UqZ2EMP1i4u64Xwow3NYXUtBbD4vIwJdQd4+xl8YDou1dlm4DVrtwT/7Ky8z8WyCULVfxw==", "license": "(MIT OR CC0-1.0)", "engines": { "node": ">=16" @@ -17808,6 +17979,8 @@ }, "node_modules/mitt": { "version": "3.0.1", + "resolved": "https://registry.npmjs.org/mitt/-/mitt-3.0.1.tgz", + "integrity": "sha512-vKivATfr97l2/QBCYAkXYDbrIWPM2IIKEl7YPhjCvKlG3kE2gm+uBo6nEXK3M5/Ffh/FLpKExzOQ3JJoJGFKBw==", "license": "MIT" }, "node_modules/mocha": { @@ -17854,7 +18027,9 @@ } }, "node_modules/mocha/node_modules/glob": { - "version": "10.4.5", + "version": "10.5.0", + "resolved": "https://registry.npmjs.org/glob/-/glob-10.5.0.tgz", + "integrity": "sha512-DfXN8DfhJ7NH3Oe7cFmu3NCu1wKbkReJ8TorzSAFbSKrlNaQSKfIzqYqVY8zlbs2NLBbWpRiU52GX2PbaBVNkg==", "dev": true, "license": "ISC", "dependencies": { @@ -17872,20 +18047,6 @@ "url": "https://github.com/sponsors/isaacs" } }, - "node_modules/mocha/node_modules/jackspeak": { - "version": "3.4.3", - "dev": true, - "license": "BlueOak-1.0.0", - "dependencies": { - "@isaacs/cliui": "^8.0.2" - }, - "funding": { - "url": "https://github.com/sponsors/isaacs" - }, - "optionalDependencies": { - "@pkgjs/parseargs": "^0.11.0" - } - }, "node_modules/mocha/node_modules/lru-cache": { "version": "10.4.3", "dev": true, @@ -18507,12 +18668,12 @@ } }, "node_modules/posthog-node": { - "version": "5.17.3", - "resolved": "https://registry.npmjs.org/posthog-node/-/posthog-node-5.17.3.tgz", - "integrity": "sha512-sV7olZNd4RTmqUyfk0FARqy8WRVsqCkgQtuO+P1GkP5oURcqx0VvGqktnByw2zFV63qX5Fa3vdoH4xheahYzKQ==", + "version": "5.18.1", + "resolved": "https://registry.npmjs.org/posthog-node/-/posthog-node-5.18.1.tgz", + "integrity": "sha512-Hi7cRqAlvuEitdiurXJFdMip+BxcwYoX66at5RErMVP91V+Ph9BspGiawC3mJx/4znjwUjF29kAhf8oZQ2uJ5Q==", "license": "MIT", "dependencies": { - "@posthog/core": "1.8.0" + "@posthog/core": "1.9.0" }, "engines": { "node": ">=20" @@ -18584,7 +18745,9 @@ } }, "node_modules/qs": { - "version": "6.14.0", + "version": "6.14.1", + "resolved": "https://registry.npmjs.org/qs/-/qs-6.14.1.tgz", + "integrity": "sha512-4EK3+xJl8Ts67nLYNwqw/dsFVnCf+qR7RgXSK9jEEm9unao3njwMDdmsdvoKBKHzxd7tCYz5e5M+SnMjdtXGQQ==", "license": "BSD-3-Clause", "dependencies": { "side-channel": "^1.1.0" @@ -18834,7 +18997,9 @@ } }, "node_modules/safaridriver": { - "version": "1.0.0", + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/safaridriver/-/safaridriver-1.0.1.tgz", + "integrity": "sha512-jkg4434cYgtrIF2AeY/X0Wmd2W73cK5qIEFE3hDrrQenJH/2SDJIXGvPAigfvQTcE9+H31zkiNHbUqcihEiMRA==", "license": "MIT", "engines": { "node": ">=18.0.0" @@ -19211,6 +19376,8 @@ }, "node_modules/spacetrim": { "version": "0.11.59", + "resolved": "https://registry.npmjs.org/spacetrim/-/spacetrim-0.11.59.tgz", + "integrity": "sha512-lLYsktklSRKprreOm7NXReW8YiX2VBjbgmXYEziOoGf/qsJqAEACaDvoTtUOycwjpaSh+bT8eu0KrJn7UNxiCg==", "funding": [ { "type": "individual", @@ -19290,6 +19457,8 @@ }, "node_modules/split2": { "version": "4.2.0", + "resolved": "https://registry.npmjs.org/split2/-/split2-4.2.0.tgz", + "integrity": "sha512-UcjcJOWknrNkF6PLX83qcHM6KHgVKNkV62Y8a5uYDVv9ydGQVwAHMKqHdJje1VTWpljG0WYpCDhrCdAOYH4TWg==", "license": "ISC", "engines": { "node": ">= 10.x" @@ -19436,7 +19605,9 @@ } }, "node_modules/strnum": { - "version": "2.1.1", + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/strnum/-/strnum-2.1.2.tgz", + "integrity": "sha512-l63NF9y/cLROq/yqKXSLtcMeeyOfnSQlfMSlzFt/K73oIaD8DGaQWd7Z34X9GPiKqP5rbSh84Hl4bOlLcjiSrQ==", "funding": [ { "type": "github", @@ -19633,6 +19804,8 @@ }, "node_modules/userhome": { "version": "1.0.1", + "resolved": "https://registry.npmjs.org/userhome/-/userhome-1.0.1.tgz", + "integrity": "sha512-5cnLm4gseXjAclKowC4IjByaGsjtAoV6PrOQOljplNB54ReUYJP8HdAFq2muHinSDAh09PPX/uXDPfdxRHvuSA==", "license": "MIT", "engines": { "node": ">= 0.8.0" @@ -19674,6 +19847,8 @@ }, "node_modules/wait-port": { "version": "1.1.0", + "resolved": "https://registry.npmjs.org/wait-port/-/wait-port-1.1.0.tgz", + "integrity": "sha512-3e04qkoN3LxTMLakdqeWth8nih8usyg+sf1Bgdf9wwUkp05iuK1eSY/QpLvscT/+F/gA89+LpUmmgBtesbqI2Q==", "license": "MIT", "dependencies": { "chalk": "^4.1.2", @@ -19689,6 +19864,8 @@ }, "node_modules/wait-port/node_modules/commander": { "version": "9.5.0", + "resolved": "https://registry.npmjs.org/commander/-/commander-9.5.0.tgz", + "integrity": "sha512-KRs7WVDKg86PWiuAqhDrAQnTXZKraVcCc6vFdL14qrZ/DcWwuRo7VoiYXalXO7S5GKpqYiVEwCbgFDfxNHKJBQ==", "license": "MIT", "engines": { "node": "^12.20.0 || >=14" @@ -19710,16 +19887,18 @@ } }, "node_modules/webdriver": { - "version": "9.21.0", + "version": "9.23.0", + "resolved": "https://registry.npmjs.org/webdriver/-/webdriver-9.23.0.tgz", + "integrity": "sha512-XkZOhjoBOY7maKI3BhDF2rNiDne4wBD6Gw6VUnt4X9b7j9NtfzcCrThBlT0hnA8W77bWNtMRCSpw9Ajy08HqKg==", "license": "MIT", "dependencies": { "@types/node": "^20.1.0", "@types/ws": "^8.5.3", - "@wdio/config": "9.21.0", + "@wdio/config": "9.23.0", "@wdio/logger": "9.18.0", "@wdio/protocols": "9.16.2", "@wdio/types": "9.20.0", - "@wdio/utils": "9.21.0", + "@wdio/utils": "9.23.0", "deepmerge-ts": "^7.0.3", "https-proxy-agent": "^7.0.6", "undici": "^6.21.3", @@ -19730,7 +19909,9 @@ } }, "node_modules/webdriver/node_modules/@types/node": { - "version": "20.19.25", + "version": "20.19.27", + "resolved": "https://registry.npmjs.org/@types/node/-/node-20.19.27.tgz", + "integrity": "sha512-N2clP5pJhB2YnZJ3PIHFk5RkygRX5WO/5f0WC08tp0wd+sv0rsJk3MqWn3CbNmT2J505a5336jaQj4ph1AdMug==", "license": "MIT", "dependencies": { "undici-types": "~6.21.0" @@ -19738,6 +19919,8 @@ }, "node_modules/webdriver/node_modules/undici": { "version": "6.22.0", + "resolved": "https://registry.npmjs.org/undici/-/undici-6.22.0.tgz", + "integrity": "sha512-hU/10obOIu62MGYjdskASR3CUAiYaFTtC9Pa6vHyf//mAipSvSQg6od2CnJswq7fvzNS3zJhxoRkgNVaHurWKw==", "license": "MIT", "engines": { "node": ">=18.17" @@ -19745,20 +19928,24 @@ }, "node_modules/webdriver/node_modules/undici-types": { "version": "6.21.0", + "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-6.21.0.tgz", + "integrity": "sha512-iwDZqg0QAGrg9Rav5H4n0M64c3mkR59cJ6wQp+7C4nI0gsmExaedaYLNO44eT4AtBBwjbTiGPMlt2Md0T9H9JQ==", "license": "MIT" }, "node_modules/webdriverio": { - "version": "9.21.0", + "version": "9.23.0", + "resolved": "https://registry.npmjs.org/webdriverio/-/webdriverio-9.23.0.tgz", + "integrity": "sha512-Y5y4jpwHvuduUfup+gXTuCU6AROn/k6qOba3st0laFluKHY+q5SHOpQAJdS8acYLwE8caDQ2dXJhmXyxuJrm0Q==", "license": "MIT", "dependencies": { "@types/node": "^20.11.30", "@types/sinonjs__fake-timers": "^8.1.5", - "@wdio/config": "9.21.0", + "@wdio/config": "9.23.0", "@wdio/logger": "9.18.0", "@wdio/protocols": "9.16.2", "@wdio/repl": "9.16.2", "@wdio/types": "9.20.0", - "@wdio/utils": "9.21.0", + "@wdio/utils": "9.23.0", "archiver": "^7.0.1", "aria-query": "^5.3.0", "cheerio": "^1.0.0-rc.12", @@ -19775,7 +19962,7 @@ "rgb2hex": "0.2.5", "serialize-error": "^12.0.0", "urlpattern-polyfill": "^10.0.0", - "webdriver": "9.21.0" + "webdriver": "9.23.0" }, "engines": { "node": ">=18.20.0" diff --git a/package.json b/package.json index ffbad26..31cd6b8 100644 --- a/package.json +++ b/package.json @@ -32,21 +32,21 @@ "@puppeteer/browsers": "^2.11.0", "ajv": "^8.17.1", "appium": "^3.1.2", - "appium-chromium-driver": "^2.0.5", - "appium-geckodriver": "^2.1.4", - "appium-safari-driver": "^4.1.4", + "appium-chromium-driver": "^2.1.0", + "appium-geckodriver": "^2.1.6", + "appium-safari-driver": "^4.1.6", "axios": "^1.13.2", - "doc-detective-common": "file:../common", - "doc-detective-resolver": "file:../resolver", + "doc-detective-common": "^3.6.0-dev.2", + "doc-detective-resolver": "^3.6.1-dev.2", "dotenv": "^17.2.3", "geckodriver": "^6.1.0", "jq-web": "^0.6.2", "json-schema-faker": "^0.5.9", "pixelmatch": "^7.1.0", "pngjs": "^7.0.0", - "posthog-node": "^5.17.3", + "posthog-node": "^5.18.1", "tree-kill": "^1.2.2", - "webdriverio": "^9.21.0" + "webdriverio": "^9.23.0" }, "optionalDependencies": { "@ffmpeg-installer/darwin-arm64": "4.1.5", From 18712c2e1bd8a5148d5d324884aa0b74d36700e5 Mon Sep 17 00:00:00 2001 From: hawkeyexl Date: Sat, 3 Jan 2026 19:30:27 -0800 Subject: [PATCH 6/9] fix: Update package dependencies to remove caret (^) for versioning - Change "doc-detective-common" and "doc-detective-resolver" versions to fixed versions --- package-lock.json | 4 ++-- package.json | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/package-lock.json b/package-lock.json index d879aeb..f3f75e8 100644 --- a/package-lock.json +++ b/package-lock.json @@ -19,8 +19,8 @@ "appium-geckodriver": "^2.1.6", "appium-safari-driver": "^4.1.6", "axios": "^1.13.2", - "doc-detective-common": "^3.6.0-dev.2", - "doc-detective-resolver": "^3.6.1-dev.2", + "doc-detective-common": "3.6.0-dev.2", + "doc-detective-resolver": "3.6.1-dev.2", "dotenv": "^17.2.3", "geckodriver": "^6.1.0", "jq-web": "^0.6.2", diff --git a/package.json b/package.json index 31cd6b8..be5ff19 100644 --- a/package.json +++ b/package.json @@ -36,8 +36,8 @@ "appium-geckodriver": "^2.1.6", "appium-safari-driver": "^4.1.6", "axios": "^1.13.2", - "doc-detective-common": "^3.6.0-dev.2", - "doc-detective-resolver": "^3.6.1-dev.2", + "doc-detective-common": "3.6.0-dev.2", + "doc-detective-resolver": "3.6.1-dev.2", "dotenv": "^17.2.3", "geckodriver": "^6.1.0", "jq-web": "^0.6.2", From 3efc7a6508e3702ccb626f13f12839ff935348a2 Mon Sep 17 00:00:00 2001 From: hawkeyexl Date: Sun, 4 Jan 2026 08:15:03 -0800 Subject: [PATCH 7/9] feat: Add request timeouts and improve integration config handling - Set a 30-second timeout for various requests in HerettoUploader to prevent hanging. - Update getIntegrationConfig to return null instead of undefined for unknown integrations. - Increase timeout for screenshot tests to 60 seconds for better stability. --- src/integrations/heretto.js | 40 +++++++++++++++++++++++++++++++++++++ src/integrations/index.js | 2 +- test/screenshot.test.js | 2 +- test/upload.test.js | 2 +- 4 files changed, 43 insertions(+), 3 deletions(-) diff --git a/src/integrations/heretto.js b/src/integrations/heretto.js index 382d7d2..29f5a54 100644 --- a/src/integrations/heretto.js +++ b/src/integrations/heretto.js @@ -400,6 +400,11 @@ class HerettoUploader { }); }); + // Set a reasonable timeout (30 seconds) + req.setTimeout(30000, () => { + req.destroy(new Error('Request timeout')); + }); + req.on("error", (error) => { log("debug", `Error getting folder contents: ${error.message}`); resolve(null); @@ -474,6 +479,11 @@ class HerettoUploader { reject(new Error(`Create document request error: ${error.message}`)); }); + // Set a reasonable timeout (30 seconds) + req.setTimeout(30000, () => { + req.destroy(new Error('Request timeout')); + }); + req.write(createBody); req.end(); }); @@ -545,6 +555,11 @@ class HerettoUploader { resolve(null); }); + // Set a reasonable timeout (30 seconds) + req.setTimeout(30000, () => { + req.destroy(new Error('Request timeout')); + }); + req.end(); }); } @@ -643,6 +658,11 @@ class HerettoUploader { reject(new Error(`Folder search request error: ${error.message}`)); }); + // Set a reasonable timeout (30 seconds) + req.setTimeout(30000, () => { + req.destroy(new Error('Request timeout')); + }); + req.write(searchBody); req.end(); }); @@ -723,6 +743,11 @@ class HerettoUploader { reject(new Error(`Search request error: ${error.message}`)); }); + // Set a reasonable timeout (30 seconds) + req.setTimeout(30000, () => { + req.destroy(new Error('Request timeout')); + }); + req.write(searchBody); req.end(); }); @@ -775,6 +800,11 @@ class HerettoUploader { reject(new Error(`Upload request error: ${error.message}`)); }); + // Set a reasonable timeout (30 seconds) + req.setTimeout(30000, () => { + req.destroy(new Error('Request timeout')); + }); + req.write(content); req.end(); }); @@ -858,6 +888,11 @@ class HerettoUploader { reject(new Error(`Get document info request error: ${error.message}`)); }); + // Set a reasonable timeout (30 seconds) + req.setTimeout(30000, () => { + req.destroy(new Error('Request timeout')); + }); + req.end(); }); } @@ -906,6 +941,11 @@ class HerettoUploader { reject(new Error(`Get document content request error: ${error.message}`)); }); + // Set a reasonable timeout (30 seconds) + req.setTimeout(30000, () => { + req.destroy(new Error('Request timeout')); + }); + req.end(); }); } diff --git a/src/integrations/index.js b/src/integrations/index.js index 847cc66..545f939 100644 --- a/src/integrations/index.js +++ b/src/integrations/index.js @@ -205,7 +205,7 @@ function getIntegrationConfig(config, sourceIntegration) { case "heretto": return config?.integrations?.heretto?.find( (h) => h.name === sourceIntegration.integrationName - ); + ) ?? null; default: return null; } diff --git a/test/screenshot.test.js b/test/screenshot.test.js index 72069f9..dd242f8 100644 --- a/test/screenshot.test.js +++ b/test/screenshot.test.js @@ -30,7 +30,7 @@ after(async () => { }); describe("Screenshot sourceIntegration preservation", function () { - this.timeout(0); + this.timeout(60000); // 60 seconds const tempDir = path.resolve("./test/temp-screenshot-tests"); diff --git a/test/upload.test.js b/test/upload.test.js index 23401f3..d48238e 100644 --- a/test/upload.test.js +++ b/test/upload.test.js @@ -268,7 +268,7 @@ describe("Upload module", function () { const sourceIntegration = { type: "heretto", integrationName: "example" }; const result = getIntegrationConfig(config, sourceIntegration); - assert.equal(result, undefined); + assert.equal(result, null); }); it("returns null for unknown integration type", function () { From 8abf499b20db6ad6ab8836626bb8e0a30d10d327 Mon Sep 17 00:00:00 2001 From: hawkeyexl Date: Sun, 4 Jan 2026 10:26:06 -0800 Subject: [PATCH 8/9] feat: Enhance Heretto integration and improve test handling - Remove hardcoded input path in main function for flexibility. - Update file path normalization to use posix for cross-platform support. - Expand documentation for resolveFromDependencies and findParentFolderFromDependencies methods. - Add additional properties to collectChangedFiles return type for better clarity. - Implement parallel uploads in uploadChangedFiles for improved performance. - Modify screenshot tests to ensure consistent port usage and cleanup of temporary files. --- dev/index.js | 1 - src/integrations/heretto.js | 21 +++-- src/integrations/index.js | 107 +++++++++++++++++------- src/tests.js | 4 +- test/screenshot.test.js | 158 +++++++++++++++++++++--------------- 5 files changed, 189 insertions(+), 102 deletions(-) diff --git a/dev/index.js b/dev/index.js index 2fc5bd7..35cf370 100644 --- a/dev/index.js +++ b/dev/index.js @@ -8,7 +8,6 @@ require("dotenv").config({ path: path.join(__dirname, ".env") }); async function main() { const json = { input: ["heretto:example"], - // input: ["c:\\Users\\hawkeyexl\\AppData\\Local\\Temp\\doc-detective\\heretto_c96e625d5c1ee50972362046445a5ca4\\ot-output\\dita\\_topics\\espresso.dita"], logLevel: "debug", runOn: [ { diff --git a/src/integrations/heretto.js b/src/integrations/heretto.js index 29f5a54..09c9ae9 100644 --- a/src/integrations/heretto.js +++ b/src/integrations/heretto.js @@ -230,13 +230,17 @@ class HerettoUploader { /** * Resolves a file path to its UUID using the resource dependencies map. * @param {Object} options - Resolution options - * @returns {Object|null} File info with uuid and parentFolderId, or null if not found + * @param {Object.} options.resourceDependencies - Map of resource paths to resource metadata + * @param {string} options.filePath - Original file path to resolve + * @param {string} options.filename - Filename extracted from the file path + * @param {Function} options.log - Logging function + * @returns {{uuid: string, parentFolderId: string}|null} File info with uuid and parentFolderId, or null if not found */ resolveFromDependencies({ resourceDependencies, filePath, filename, log }) { if (!resourceDependencies) return null; - // Normalize the file path for comparison - const normalizedPath = filePath.replace(/\\/g, "/").replace(/^\.\//, "").replace(/^\.\.\//, ""); + // Normalize the file path for comparison using posix normalize for cross-platform support + const normalizedPath = path.posix.normalize(filePath.replace(/\\/g, "/")); // Try exact path match first for (const [depPath, info] of Object.entries(resourceDependencies)) { @@ -290,7 +294,10 @@ class HerettoUploader { * Finds the parent folder ID for a file path using resource dependencies. * Returns the target folder name for API lookup if not found in dependencies. * @param {Object} options - Resolution options - * @returns {Object} { folderId, targetFolderName, ditamapParentFolderId } + * @param {Object.} options.resourceDependencies - Map of resource paths to resource metadata + * @param {string} options.filePath - File path to find parent folder for + * @param {Function} options.log - Logging function + * @returns {{folderId: string|null, targetFolderName: string|null, ditamapParentFolderId: string|null}} Resolution result with folder info */ findParentFolderFromDependencies({ resourceDependencies, filePath, log }) { const result = { @@ -301,8 +308,10 @@ class HerettoUploader { if (!resourceDependencies) return result; - // Normalize path and get parent directory - const normalizedPath = filePath.replace(/\\/g, "/").replace(/^\.\//, "").replace(/^\.\.\//, ""); + // Normalize path and get parent directory using posix normalize for cross-platform support + const normalizedPath = path.posix + .normalize(filePath.replace(/\\/g, "/")) + .replace(/^(\.\/)|(\.\.\/)*/g, ""); const parentDir = path.dirname(normalizedPath); const targetFolderName = path.basename(parentDir); diff --git a/src/integrations/index.js b/src/integrations/index.js index 545f939..1e90d92 100644 --- a/src/integrations/index.js +++ b/src/integrations/index.js @@ -34,7 +34,12 @@ function getUploader(sourceIntegration) { /** * Collects all changed files from a test report that have source integrations. * @param {Object} report - Test execution report - * @returns {Array} Array of { localPath, sourceIntegration } objects + * @returns {Array} Array of objects with properties: + * - localPath: string - Path to the local file + * - sourceIntegration: Object - Source integration metadata + * - stepId: string - ID of the step that produced this file + * - testId: string - ID of the test containing this step + * - specId: string - ID of the spec containing this test */ function collectChangedFiles(report) { const changedFiles = []; @@ -74,7 +79,18 @@ function collectChangedFiles(report) { * @param {Object} options.config - Doc Detective config * @param {Object} options.report - Test execution report * @param {Function} options.log - Logging function - * @returns {Promise} Upload results summary + * @returns {Promise<{ + * total: number, + * successful: number, + * failed: number, + * skipped: number, + * details: Array<{ + * localPath: string, + * status: string, + * description?: string, + * reason?: string + * }> + * }>} Upload results summary */ async function uploadChangedFiles({ config, report, log }) { const results = { @@ -95,6 +111,9 @@ async function uploadChangedFiles({ config, report, log }) { log(config, "info", `Found ${changedFiles.length} changed file(s) to upload.`); + // Prepare upload tasks, filtering out files without valid uploaders or configs + const uploadTasks = []; + for (const file of changedFiles) { const uploader = getUploader(file.sourceIntegration); @@ -134,24 +153,67 @@ async function uploadChangedFiles({ config, report, log }) { continue; } - try { + // Queue this file for parallel upload + uploadTasks.push({ + file, + uploader, + integrationConfig, + }); + } + + // Execute all uploads in parallel using Promise.allSettled + if (uploadTasks.length > 0) { + log(config, "debug", `Executing ${uploadTasks.length} upload(s) in parallel...`); + + const uploadPromises = uploadTasks.map(async ({ file, uploader, integrationConfig }) => { log( config, "info", `Uploading ${file.localPath} to ${file.sourceIntegration.type}...` ); - const uploadResult = await uploader.upload({ - config, - integrationConfig, - localFilePath: file.localPath, - sourceIntegration: file.sourceIntegration, - log, - }); + try { + const uploadResult = await uploader.upload({ + config, + integrationConfig, + localFilePath: file.localPath, + sourceIntegration: file.sourceIntegration, + log, + }); + + return { file, uploadResult, error: null }; + } catch (error) { + // Catch errors within the promise to preserve file reference + return { file, uploadResult: null, error }; + } + }); + + const settledResults = await Promise.allSettled(uploadPromises); + + for (const settled of settledResults) { + // All promises should be fulfilled since we catch errors internally + const { file, uploadResult, error } = settled.value; - if (uploadResult.status === "PASS") { + if (error) { + results.failed++; + log( + config, + "warning", + `Error uploading ${file.localPath}: ${error.message}` + ); + results.details.push({ + localPath: file.localPath, + status: "FAIL", + description: error.message, + }); + } else if (uploadResult.status === "PASS") { results.successful++; log(config, "info", `Successfully uploaded: ${file.localPath}`); + results.details.push({ + localPath: file.localPath, + status: uploadResult.status, + description: uploadResult.description, + }); } else { results.failed++; log( @@ -159,25 +221,12 @@ async function uploadChangedFiles({ config, report, log }) { "warning", `Failed to upload ${file.localPath}: ${uploadResult.description}` ); + results.details.push({ + localPath: file.localPath, + status: uploadResult.status, + description: uploadResult.description, + }); } - - results.details.push({ - localPath: file.localPath, - status: uploadResult.status, - description: uploadResult.description, - }); - } catch (error) { - results.failed++; - log( - config, - "warning", - `Error uploading ${file.localPath}: ${error.message}` - ); - results.details.push({ - localPath: file.localPath, - status: "FAIL", - description: error.message, - }); } } diff --git a/src/tests.js b/src/tests.js index 39eb9c8..be91562 100644 --- a/src/tests.js +++ b/src/tests.js @@ -800,7 +800,9 @@ async function runSpecs({ resolvedTests }) { // Upload changed files back to source integrations (best-effort) // This automatically syncs any changed screenshots back to their source CMS - if (config?.integrations?.heretto?.length > 0) { + // Only upload if uploadOnChange is enabled (defaults to true for backward compatibility) + const uploadOnChange = config?.uploadOnChange ?? true; + if (uploadOnChange && config?.integrations?.heretto?.length > 0) { try { const uploadResults = await uploadChangedFiles({ config, report, log }); report.uploadResults = uploadResults; diff --git a/test/screenshot.test.js b/test/screenshot.test.js index dd242f8..11d36b8 100644 --- a/test/screenshot.test.js +++ b/test/screenshot.test.js @@ -6,7 +6,7 @@ const { createServer } = require("./server"); // Create a server for screenshot tests const server = createServer({ - port: 8093, + port: 8092, staticDir: "./test/server/public", }); @@ -53,13 +53,14 @@ describe("Screenshot sourceIntegration preservation", function () { it("preserves sourceIntegration for new screenshots", async function () { const screenshotPath = path.join(tempDir, "new-screenshot.png"); + const tempFilePath = path.join(tempDir, "test-spec.json"); const testSpec = { tests: [ { steps: [ { - goTo: "http://localhost:8093", + goTo: "http://localhost:8092", }, { screenshot: { @@ -77,27 +78,34 @@ describe("Screenshot sourceIntegration preservation", function () { ], }; - const tempFilePath = path.join(tempDir, "test-spec.json"); - fs.writeFileSync(tempFilePath, JSON.stringify(testSpec, null, 2)); + try { + fs.writeFileSync(tempFilePath, JSON.stringify(testSpec, null, 2)); - const result = await runTests({ input: tempFilePath, logLevel: "silent" }); + const result = await runTests({ input: tempFilePath, logLevel: "silent" }); - // Find the screenshot step - const screenshotStep = result.specs[0].tests[0].contexts[0].steps[1]; + // Find the screenshot step + const screenshotStep = result.specs[0].tests[0].contexts[0].steps[1]; - // Verify sourceIntegration is preserved - assert.ok(screenshotStep.outputs.sourceIntegration, "sourceIntegration should be present"); - assert.equal(screenshotStep.outputs.sourceIntegration.type, "heretto"); - assert.equal(screenshotStep.outputs.sourceIntegration.integrationName, "test-integration"); - assert.equal(screenshotStep.outputs.sourceIntegration.filePath, "new-screenshot.png"); - assert.equal(screenshotStep.outputs.sourceIntegration.contentPath, "/content/topic.dita"); - - // Verify changed is true for new screenshots - assert.equal(screenshotStep.outputs.changed, true, "changed should be true for new screenshots"); + // Verify sourceIntegration is preserved + assert.ok(screenshotStep.outputs.sourceIntegration, "sourceIntegration should be present"); + assert.equal(screenshotStep.outputs.sourceIntegration.type, "heretto"); + assert.equal(screenshotStep.outputs.sourceIntegration.integrationName, "test-integration"); + assert.equal(screenshotStep.outputs.sourceIntegration.filePath, "new-screenshot.png"); + assert.equal(screenshotStep.outputs.sourceIntegration.contentPath, "/content/topic.dita"); + + // Verify changed is true for new screenshots + assert.equal(screenshotStep.outputs.changed, true, "changed should be true for new screenshots"); + } finally { + // Cleanup temp files + if (fs.existsSync(tempFilePath)) fs.unlinkSync(tempFilePath); + if (fs.existsSync(screenshotPath)) fs.unlinkSync(screenshotPath); + } }); it("preserves sourceIntegration when variation exceeds threshold", async function () { const screenshotPath = path.join(tempDir, "variation-screenshot.png"); + const initialFilePath = path.join(tempDir, "initial-spec.json"); + const variationFilePath = path.join(tempDir, "variation-spec.json"); // First, create an initial screenshot const initialSpec = { @@ -105,7 +113,7 @@ describe("Screenshot sourceIntegration preservation", function () { { steps: [ { - goTo: "http://localhost:8093", + goTo: "http://localhost:8092", }, { screenshot: { @@ -119,17 +127,13 @@ describe("Screenshot sourceIntegration preservation", function () { ], }; - const initialFilePath = path.join(tempDir, "initial-spec.json"); - fs.writeFileSync(initialFilePath, JSON.stringify(initialSpec, null, 2)); - await runTests({ input: initialFilePath, logLevel: "silent" }); - - // Now run with a different page to trigger variation warning + // Variation spec to trigger warning const variationSpec = { tests: [ { steps: [ { - goTo: "http://localhost:8093/drag-drop-test.html", // Different page + goTo: "http://localhost:8092/drag-drop-test.html", // Different page }, { screenshot: { @@ -149,27 +153,39 @@ describe("Screenshot sourceIntegration preservation", function () { ], }; - const variationFilePath = path.join(tempDir, "variation-spec.json"); - fs.writeFileSync(variationFilePath, JSON.stringify(variationSpec, null, 2)); + try { + fs.writeFileSync(initialFilePath, JSON.stringify(initialSpec, null, 2)); + await runTests({ input: initialFilePath, logLevel: "silent" }); - const result = await runTests({ input: variationFilePath, logLevel: "silent" }); + // Now run with a different page to trigger variation warning + fs.writeFileSync(variationFilePath, JSON.stringify(variationSpec, null, 2)); - const screenshotStep = result.specs[0].tests[0].contexts[0].steps[1]; + const result = await runTests({ input: variationFilePath, logLevel: "silent" }); - // Verify the step is a WARNING (variation exceeded) - assert.equal(screenshotStep.result, "WARNING"); - - // Verify sourceIntegration is preserved - assert.ok(screenshotStep.outputs.sourceIntegration, "sourceIntegration should be present"); - assert.equal(screenshotStep.outputs.sourceIntegration.type, "heretto"); - assert.equal(screenshotStep.outputs.sourceIntegration.integrationName, "variation-test"); - - // Verify changed is true - assert.equal(screenshotStep.outputs.changed, true, "changed should be true when variation exceeds threshold"); + const screenshotStep = result.specs[0].tests[0].contexts[0].steps[1]; + + // Verify the step is a WARNING (variation exceeded) + assert.equal(screenshotStep.result, "WARNING"); + + // Verify sourceIntegration is preserved + assert.ok(screenshotStep.outputs.sourceIntegration, "sourceIntegration should be present"); + assert.equal(screenshotStep.outputs.sourceIntegration.type, "heretto"); + assert.equal(screenshotStep.outputs.sourceIntegration.integrationName, "variation-test"); + + // Verify changed is true + assert.equal(screenshotStep.outputs.changed, true, "changed should be true when variation exceeds threshold"); + } finally { + // Cleanup temp files + if (fs.existsSync(initialFilePath)) fs.unlinkSync(initialFilePath); + if (fs.existsSync(variationFilePath)) fs.unlinkSync(variationFilePath); + if (fs.existsSync(screenshotPath)) fs.unlinkSync(screenshotPath); + } }); it("preserves sourceIntegration when screenshot is within variation", async function () { const screenshotPath = path.join(tempDir, "same-screenshot.png"); + const initialFilePath = path.join(tempDir, "initial-spec.json"); + const sameFilePath = path.join(tempDir, "same-spec.json"); // First, create an initial screenshot const initialSpec = { @@ -177,7 +193,7 @@ describe("Screenshot sourceIntegration preservation", function () { { steps: [ { - goTo: "http://localhost:8093", + goTo: "http://localhost:8092", }, { screenshot: { @@ -191,17 +207,13 @@ describe("Screenshot sourceIntegration preservation", function () { ], }; - const initialFilePath = path.join(tempDir, "initial-spec.json"); - fs.writeFileSync(initialFilePath, JSON.stringify(initialSpec, null, 2)); - await runTests({ input: initialFilePath, logLevel: "silent" }); - - // Now run with the same page (should be within variation) + // Same page spec to test within variation const samePageSpec = { tests: [ { steps: [ { - goTo: "http://localhost:8093", // Same page + goTo: "http://localhost:8092", // Same page }, { screenshot: { @@ -221,34 +233,45 @@ describe("Screenshot sourceIntegration preservation", function () { ], }; - const sameFilePath = path.join(tempDir, "same-spec.json"); - fs.writeFileSync(sameFilePath, JSON.stringify(samePageSpec, null, 2)); + try { + fs.writeFileSync(initialFilePath, JSON.stringify(initialSpec, null, 2)); + await runTests({ input: initialFilePath, logLevel: "silent" }); - const result = await runTests({ input: sameFilePath, logLevel: "silent" }); + // Now run with the same page (should be within variation) + fs.writeFileSync(sameFilePath, JSON.stringify(samePageSpec, null, 2)); - const screenshotStep = result.specs[0].tests[0].contexts[0].steps[1]; + const result = await runTests({ input: sameFilePath, logLevel: "silent" }); - // Verify the step passed (within variation) - assert.equal(screenshotStep.result, "PASS"); - - // Verify sourceIntegration is preserved - assert.ok(screenshotStep.outputs.sourceIntegration, "sourceIntegration should be present"); - assert.equal(screenshotStep.outputs.sourceIntegration.type, "heretto"); - assert.equal(screenshotStep.outputs.sourceIntegration.integrationName, "same-page-test"); - - // Verify changed is false (within variation, no update) - assert.equal(screenshotStep.outputs.changed, false, "changed should be false when within variation"); + const screenshotStep = result.specs[0].tests[0].contexts[0].steps[1]; + + // Verify the step passed (within variation) + assert.equal(screenshotStep.result, "PASS"); + + // Verify sourceIntegration is preserved + assert.ok(screenshotStep.outputs.sourceIntegration, "sourceIntegration should be present"); + assert.equal(screenshotStep.outputs.sourceIntegration.type, "heretto"); + assert.equal(screenshotStep.outputs.sourceIntegration.integrationName, "same-page-test"); + + // Verify changed is false (within variation, no update) + assert.equal(screenshotStep.outputs.changed, false, "changed should be false when within variation"); + } finally { + // Cleanup temp files + if (fs.existsSync(initialFilePath)) fs.unlinkSync(initialFilePath); + if (fs.existsSync(sameFilePath)) fs.unlinkSync(sameFilePath); + if (fs.existsSync(screenshotPath)) fs.unlinkSync(screenshotPath); + } }); it("does not set sourceIntegration when not provided", async function () { const screenshotPath = path.join(tempDir, "no-integration-screenshot.png"); + const tempFilePath = path.join(tempDir, "test-spec.json"); const testSpec = { tests: [ { steps: [ { - goTo: "http://localhost:8093", + goTo: "http://localhost:8092", }, { screenshot: { @@ -260,14 +283,19 @@ describe("Screenshot sourceIntegration preservation", function () { ], }; - const tempFilePath = path.join(tempDir, "test-spec.json"); - fs.writeFileSync(tempFilePath, JSON.stringify(testSpec, null, 2)); + try { + fs.writeFileSync(tempFilePath, JSON.stringify(testSpec, null, 2)); - const result = await runTests({ input: tempFilePath, logLevel: "silent" }); + const result = await runTests({ input: tempFilePath, logLevel: "silent" }); - const screenshotStep = result.specs[0].tests[0].contexts[0].steps[1]; + const screenshotStep = result.specs[0].tests[0].contexts[0].steps[1]; - // Verify sourceIntegration is NOT set - assert.equal(screenshotStep.outputs.sourceIntegration, undefined, "sourceIntegration should not be set when not provided"); + // Verify sourceIntegration is NOT set + assert.equal(screenshotStep.outputs.sourceIntegration, undefined, "sourceIntegration should not be set when not provided"); + } finally { + // Cleanup temp files + if (fs.existsSync(tempFilePath)) fs.unlinkSync(tempFilePath); + if (fs.existsSync(screenshotPath)) fs.unlinkSync(screenshotPath); + } }); }); From 7e030a3747d63222e2daa6877d8571654356f60c Mon Sep 17 00:00:00 2001 From: hawkeyexl Date: Sun, 4 Jan 2026 13:48:09 -0800 Subject: [PATCH 9/9] feat: Improve Heretto integration and enhance file path handling - Normalize file paths to handle multiple levels of relative references. - Update documentation for resource dependencies and upload functions. - Check both global and per-integration uploadOnChange settings for better control. --- src/integrations/heretto.js | 29 +++++++++++++++++++++-------- src/integrations/index.js | 37 ++++++++++++++++--------------------- src/tests.js | 9 +++++++-- 3 files changed, 44 insertions(+), 31 deletions(-) diff --git a/src/integrations/heretto.js b/src/integrations/heretto.js index 09c9ae9..5660267 100644 --- a/src/integrations/heretto.js +++ b/src/integrations/heretto.js @@ -240,7 +240,11 @@ class HerettoUploader { if (!resourceDependencies) return null; // Normalize the file path for comparison using posix normalize for cross-platform support - const normalizedPath = path.posix.normalize(filePath.replace(/\\/g, "/")); + // Use normalize to handle multiple levels of relative references like ../../folder/file.png + const normalizedPath = path.posix + .normalize(filePath.replace(/\\/g, "/")) + .replace(/^\.\.\/+/g, "") // Remove leading ../ + .replace(/^\.\//, ""); // Remove leading ./ // Try exact path match first for (const [depPath, info] of Object.entries(resourceDependencies)) { @@ -294,10 +298,15 @@ class HerettoUploader { * Finds the parent folder ID for a file path using resource dependencies. * Returns the target folder name for API lookup if not found in dependencies. * @param {Object} options - Resolution options - * @param {Object.} options.resourceDependencies - Map of resource paths to resource metadata - * @param {string} options.filePath - File path to find parent folder for - * @param {Function} options.log - Logging function - * @returns {{folderId: string|null, targetFolderName: string|null, ditamapParentFolderId: string|null}} Resolution result with folder info + * @param {Object.} options.resourceDependencies - Map of resource paths to resource metadata. + * Keys are relative file paths, values are objects with uuid and parentFolderId. + * Special keys starting with '_' (e.g., '_ditamapParentFolderId') store internal metadata. + * @param {string} options.filePath - File path to find parent folder for (can be relative with ../ or ./ prefixes) + * @param {Function} options.log - Logging function with signature (level, message) + * @returns {{folderId: string|null, targetFolderName: string|null, ditamapParentFolderId: string|null}} Resolution result containing: + * - folderId: The parent folder UUID if found in dependencies, null otherwise + * - targetFolderName: The name of the target folder extracted from the file path + * - ditamapParentFolderId: The ditamap's parent folder ID from dependencies (for API fallback lookup) */ findParentFolderFromDependencies({ resourceDependencies, filePath, log }) { const result = { @@ -309,9 +318,11 @@ class HerettoUploader { if (!resourceDependencies) return result; // Normalize path and get parent directory using posix normalize for cross-platform support + // Use a loop/regex pattern to handle multiple levels of relative references like ../../folder/file.png const normalizedPath = path.posix .normalize(filePath.replace(/\\/g, "/")) - .replace(/^(\.\/)|(\.\.\/)*/g, ""); + .replace(/^(\.\.\/)+/g, "") // Remove all leading ../ + .replace(/^\.\//, ""); // Remove leading ./ const parentDir = path.dirname(normalizedPath); const targetFolderName = path.basename(parentDir); @@ -388,7 +399,8 @@ class HerettoUploader { try { // Parse XML to find the folder by name in children // Looking for: - const escapedFolderName = folderName.replace(/[.*+?^${}()|[\]\\]/g, '\\$&'); + // Double-escape backslashes for proper regex character class matching + const escapedFolderName = folderName.replace(/[.*+?^${}()|[\]\\/]/g, '\\$&'); const folderMatch = data.match(new RegExp(`... - const escapedFilename = filename.replace(/[.*+?^${}()|[\]\\]/g, '\\$&'); + // Double-escape backslashes for proper regex character class matching + const escapedFilename = filename.replace(/[.*+?^${}()|[\]\\/]/g, '\\$&'); const nameIdMatch = data.match(new RegExp(`id="([^"]+)"[^>]*name="${escapedFilename}"`, 'i')); const idNameMatch = data.match(new RegExp(`name="${escapedFilename}"[^>]*id="([^"]+)"`, 'i')); diff --git a/src/integrations/index.js b/src/integrations/index.js index 1e90d92..2323b1e 100644 --- a/src/integrations/index.js +++ b/src/integrations/index.js @@ -34,12 +34,12 @@ function getUploader(sourceIntegration) { /** * Collects all changed files from a test report that have source integrations. * @param {Object} report - Test execution report - * @returns {Array} Array of objects with properties: - * - localPath: string - Path to the local file - * - sourceIntegration: Object - Source integration metadata - * - stepId: string - ID of the step that produced this file - * - testId: string - ID of the test containing this step - * - specId: string - ID of the spec containing this test + * @returns {Array<{localPath: string, sourceIntegration: Object, stepId: string, testId: string, specId: string}>} Array of changed file objects containing: + * - localPath: Path to the local file + * - sourceIntegration: Source integration metadata (type, integrationName, filePath, contentPath) + * - stepId: ID of the step that produced this file + * - testId: ID of the test containing this step + * - specId: ID of the spec containing this test */ function collectChangedFiles(report) { const changedFiles = []; @@ -75,22 +75,17 @@ function collectChangedFiles(report) { /** * Uploads all changed files back to their source integrations. * Uses best-effort approach - continues uploading even if individual uploads fail. + * Uploads are executed in parallel using Promise.allSettled for better performance. * @param {Object} options - Upload options - * @param {Object} options.config - Doc Detective config - * @param {Object} options.report - Test execution report - * @param {Function} options.log - Logging function - * @returns {Promise<{ - * total: number, - * successful: number, - * failed: number, - * skipped: number, - * details: Array<{ - * localPath: string, - * status: string, - * description?: string, - * reason?: string - * }> - * }>} Upload results summary + * @param {Object} options.config - Doc Detective config containing integration configurations + * @param {Object} options.report - Test execution report from runSpecs + * @param {Function} options.log - Logging function with signature (config, level, message) + * @returns {Promise<{total: number, successful: number, failed: number, skipped: number, details: Array<{localPath: string, status: string, description?: string, reason?: string}>}>} Upload results summary with: + * - total: Total number of changed files found + * - successful: Number of files successfully uploaded + * - failed: Number of files that failed to upload + * - skipped: Number of files skipped (no uploader or config found) + * - details: Array of per-file results with localPath, status (PASS/FAIL/SKIPPED), and description or reason */ async function uploadChangedFiles({ config, report, log }) { const results = { diff --git a/src/tests.js b/src/tests.js index be91562..6118ebb 100644 --- a/src/tests.js +++ b/src/tests.js @@ -801,8 +801,13 @@ async function runSpecs({ resolvedTests }) { // Upload changed files back to source integrations (best-effort) // This automatically syncs any changed screenshots back to their source CMS // Only upload if uploadOnChange is enabled (defaults to true for backward compatibility) - const uploadOnChange = config?.uploadOnChange ?? true; - if (uploadOnChange && config?.integrations?.heretto?.length > 0) { + // Check both global config.uploadOnChange and per-integration uploadOnChange settings + const herettoConfigs = config?.integrations?.heretto || []; + const hasUploadEnabledIntegration = herettoConfigs.some( + (h) => h.uploadOnChange !== false // Default to true if not explicitly set to false + ); + const globalUploadOnChange = config?.uploadOnChange ?? true; + if (globalUploadOnChange && hasUploadEnabledIntegration && herettoConfigs.length > 0) { try { const uploadResults = await uploadChangedFiles({ config, report, log }); report.uploadResults = uploadResults;