diff --git a/forge.config.ts b/forge.config.ts index 7c712d8..2ec412b 100644 --- a/forge.config.ts +++ b/forge.config.ts @@ -1,26 +1,32 @@ import type { ForgeConfig } from '@electron-forge/shared-types'; -import { MakerSquirrel } from '@electron-forge/maker-squirrel'; +import { MakerDMG } from '@electron-forge/maker-dmg'; import { MakerZIP } from '@electron-forge/maker-zip'; -import { MakerDeb } from '@electron-forge/maker-deb'; -import { MakerRpm } from '@electron-forge/maker-rpm'; import { AutoUnpackNativesPlugin } from '@electron-forge/plugin-auto-unpack-natives'; import { WebpackPlugin } from '@electron-forge/plugin-webpack'; import { FusesPlugin } from '@electron-forge/plugin-fuses'; import { FuseV1Options, FuseVersion } from '@electron/fuses'; -import path from 'path'; import { mainConfig } from './webpack.main.config'; import { rendererConfig } from './webpack.renderer.config'; const config: ForgeConfig = { packagerConfig: { + appBundleId: "com.browserstack.debugging-hub", + appCategoryType: "public.app-category.utilities", + icon: "./images/logo", + osxSign: { + "identity": "Yash Munot" + }, + osxNotarize: { + appleId: process.env.APPLE_ID!, + appleIdPassword: process.env.APPLE_APP_SPECIFIC_PASSWORD!, + teamId: process.env.APPLE_TEAM_ID! + }, asar: true, }, rebuildConfig: {}, makers: [ - new MakerSquirrel({}), + new MakerDMG({}), new MakerZIP({}, ['darwin']), - new MakerRpm({}), - new MakerDeb({}), ], plugins: [ new AutoUnpackNativesPlugin({}), diff --git a/images/icon.icns b/images/icon.icns new file mode 100644 index 0000000..67c51a5 Binary files /dev/null and b/images/icon.icns differ diff --git a/images/icon.png b/images/icon.png new file mode 100644 index 0000000..17c70c8 Binary files /dev/null and b/images/icon.png differ diff --git a/package-lock.json b/package-lock.json index 4e6f206..7ef7d7d 100644 --- a/package-lock.json +++ b/package-lock.json @@ -14,11 +14,13 @@ "copy-webpack-plugin": "^13.0.1", "electron-squirrel-startup": "^1.0.1", "electron-store": "^11.0.2", + "electron-updater": "^6.7.3", "form-data": "^4.0.5", "json-edit-react": "^1.29.0", "lodash": "^4.17.21", "monaco-editor": "^0.55.1", "monaco-types": "^0.1.0", + "papaparse": "^5.5.3", "rc-field-form": "^2.7.0", "react": "^19.2.0", "react-diff-view": "^3.3.2", @@ -30,11 +32,13 @@ "react-virtualized-auto-sizer": "^1.0.26", "react-window": "^2.2.3", "sugar-high": "^0.9.4", + "update-electron-app": "^3.1.2", "zod": "^4.3.5" }, "devDependencies": { "@electron-forge/cli": "^7.10.2", "@electron-forge/maker-deb": "^7.10.2", + "@electron-forge/maker-dmg": "^7.11.1", "@electron-forge/maker-rpm": "^7.10.2", "@electron-forge/maker-squirrel": "^7.10.2", "@electron-forge/maker-zip": "^7.10.2", @@ -43,6 +47,7 @@ "@electron-forge/plugin-webpack": "^7.10.2", "@electron/fuses": "^1.8.0", "@types/diff": "^7.0.2", + "@types/papaparse": "^5.5.2", "@types/pouchdb": "^6.4.2", "@types/react": "^19.2.7", "@types/react-dom": "^19.2.3", @@ -378,6 +383,68 @@ "electron-installer-debian": "^3.2.0" } }, + "node_modules/@electron-forge/maker-dmg": { + "version": "7.11.1", + "resolved": "https://registry.npmjs.org/@electron-forge/maker-dmg/-/maker-dmg-7.11.1.tgz", + "integrity": "sha512-7zs5/Ewz1PcOl4N1102stFgBiFGWxU18+UPFUSd/fgf9MErBl4HBWuVNMIHyeJ/56rdfkcmTxTqE+9TBEYrZcg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@electron-forge/maker-base": "7.11.1", + "@electron-forge/shared-types": "7.11.1", + "fs-extra": "^10.0.0" + }, + "engines": { + "node": ">= 16.4.0" + }, + "optionalDependencies": { + "electron-installer-dmg": "^5.0.1" + } + }, + "node_modules/@electron-forge/maker-dmg/node_modules/@electron-forge/maker-base": { + "version": "7.11.1", + "resolved": "https://registry.npmjs.org/@electron-forge/maker-base/-/maker-base-7.11.1.tgz", + "integrity": "sha512-yhZrCGoN6bDeiB5DHFaueZ1h84AReElEj+f0hl2Ph4UbZnO0cnLpbx+Bs+XfMLAiA+beC8muB5UDK5ysfuT9BQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@electron-forge/shared-types": "7.11.1", + "fs-extra": "^10.0.0", + "which": "^2.0.2" + }, + "engines": { + "node": ">= 16.4.0" + } + }, + "node_modules/@electron-forge/maker-dmg/node_modules/@electron-forge/shared-types": { + "version": "7.11.1", + "resolved": "https://registry.npmjs.org/@electron-forge/shared-types/-/shared-types-7.11.1.tgz", + "integrity": "sha512-vvBWdAEh53UJlDGUevpaJk1+sqDMQibfrbHR+0IPA4MPyQex7/Uhv3vYH9oGHujBVAChQahjAuJt0fG6IJBLZg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@electron-forge/tracer": "7.11.1", + "@electron/packager": "^18.3.5", + "@electron/rebuild": "^3.7.0", + "listr2": "^7.0.2" + }, + "engines": { + "node": ">= 16.4.0" + } + }, + "node_modules/@electron-forge/maker-dmg/node_modules/@electron-forge/tracer": { + "version": "7.11.1", + "resolved": "https://registry.npmjs.org/@electron-forge/tracer/-/tracer-7.11.1.tgz", + "integrity": "sha512-tiB6cglVQFcSw9N8GRwVwZUeB9u0DOx2Mj7aFXBUsFLUYQapvVGv51tUSy/UAW5lvmubGscYIILuVko+II3+NA==", + "dev": true, + "license": "MIT", + "dependencies": { + "chrome-trace-event": "^1.0.3" + }, + "engines": { + "node": ">= 14.17.5" + } + }, "node_modules/@electron-forge/maker-rpm": { "version": "7.10.2", "resolved": "https://registry.npmjs.org/@electron-forge/maker-rpm/-/maker-rpm-7.10.2.tgz", @@ -1697,7 +1764,6 @@ "version": "0.3.11", "resolved": "https://registry.npmjs.org/@jridgewell/source-map/-/source-map-0.3.11.tgz", "integrity": "sha512-ZMp1V8ZFcPG5dIWnQLr3NSI1MiCU7UETdS/A0G8V/XWHvJv3ZsFqutJn1Y5RPmAPX6F3BiE397OqveU/9NCuIA==", - "dev": true, "license": "MIT", "dependencies": { "@jridgewell/gen-mapping": "^0.3.5", @@ -2180,6 +2246,17 @@ "node": ">= 10" } }, + "node_modules/@types/appdmg": { + "version": "0.5.5", + "resolved": "https://registry.npmjs.org/@types/appdmg/-/appdmg-0.5.5.tgz", + "integrity": "sha512-G+n6DgZTZFOteITE30LnWj+HRVIGr7wMlAiLWOO02uJFWVEitaPU9JVXm9wJokkgshBawb2O1OykdcsmkkZfgg==", + "dev": true, + "license": "MIT", + "optional": true, + "dependencies": { + "@types/node": "*" + } + }, "node_modules/@types/body-parser": { "version": "1.19.6", "resolved": "https://registry.npmjs.org/@types/body-parser/-/body-parser-1.19.6.tgz", @@ -2256,7 +2333,6 @@ "version": "9.6.1", "resolved": "https://registry.npmjs.org/@types/eslint/-/eslint-9.6.1.tgz", "integrity": "sha512-FXx2pKgId/WyYo2jXw63kk7/+TY7u7AziEJxJAnSFzHlqTAS3Ync6SvgYAN/k4/PQpnnVuzoMuVnByKK2qp0ag==", - "dev": true, "license": "MIT", "dependencies": { "@types/estree": "*", @@ -2267,7 +2343,6 @@ "version": "3.7.7", "resolved": "https://registry.npmjs.org/@types/eslint-scope/-/eslint-scope-3.7.7.tgz", "integrity": "sha512-MzMFlSLBqNF2gcHWO0G1vP/YQyfvrxZ0bF+u7mzUdZ1/xK4A4sru+nraZz5i3iEIk1l1uyicaDVTB4QbbEkAYg==", - "dev": true, "license": "MIT", "dependencies": { "@types/eslint": "*", @@ -2278,7 +2353,6 @@ "version": "1.0.8", "resolved": "https://registry.npmjs.org/@types/estree/-/estree-1.0.8.tgz", "integrity": "sha512-dWHzHa2WqEXI/O1E9OjrocMTKJl2mSrEolh1Iomrv6U+JuNwaHXsXx9bLu5gG7BUWFIN0skIQJQ/L1rIex4X6w==", - "dev": true, "license": "MIT" }, "node_modules/@types/express": { @@ -2413,7 +2487,6 @@ "version": "24.9.1", "resolved": "https://registry.npmjs.org/@types/node/-/node-24.9.1.tgz", "integrity": "sha512-QoiaXANRkSXK6p0Duvt56W208du4P9Uye9hWLWgGMDTEoKPhuenzNcC4vGUmrNkiOKTlIrBoyNQYNpSwfEZXSg==", - "dev": true, "license": "MIT", "dependencies": { "undici-types": "~7.16.0" @@ -2429,6 +2502,16 @@ "@types/node": "*" } }, + "node_modules/@types/papaparse": { + "version": "5.5.2", + "resolved": "https://registry.npmjs.org/@types/papaparse/-/papaparse-5.5.2.tgz", + "integrity": "sha512-gFnFp/JMzLHCwRf7tQHrNnfhN4eYBVYYI897CGX4MY1tzY9l2aLkVyx2IlKZ/SAqDbB3I1AOZW5gTMGGsqWliA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/node": "*" + } + }, "node_modules/@types/parse-json": { "version": "4.0.2", "resolved": "https://registry.npmjs.org/@types/parse-json/-/parse-json-4.0.2.tgz", @@ -3022,7 +3105,6 @@ "version": "1.14.1", "resolved": "https://registry.npmjs.org/@webassemblyjs/ast/-/ast-1.14.1.tgz", "integrity": "sha512-nuBEDgQfm1ccRp/8bCQrx1frohyufl4JlbMMZ4P1wpeOfDhF6FQkxZJ1b/e+PLwr6X1Nhw6OLme5usuBWYBvuQ==", - "dev": true, "license": "MIT", "dependencies": { "@webassemblyjs/helper-numbers": "1.13.2", @@ -3033,28 +3115,24 @@ "version": "1.13.2", "resolved": "https://registry.npmjs.org/@webassemblyjs/floating-point-hex-parser/-/floating-point-hex-parser-1.13.2.tgz", "integrity": "sha512-6oXyTOzbKxGH4steLbLNOu71Oj+C8Lg34n6CqRvqfS2O71BxY6ByfMDRhBytzknj9yGUPVJ1qIKhRlAwO1AovA==", - "dev": true, "license": "MIT" }, "node_modules/@webassemblyjs/helper-api-error": { "version": "1.13.2", "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-api-error/-/helper-api-error-1.13.2.tgz", "integrity": "sha512-U56GMYxy4ZQCbDZd6JuvvNV/WFildOjsaWD3Tzzvmw/mas3cXzRJPMjP83JqEsgSbyrmaGjBfDtV7KDXV9UzFQ==", - "dev": true, "license": "MIT" }, "node_modules/@webassemblyjs/helper-buffer": { "version": "1.14.1", "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-buffer/-/helper-buffer-1.14.1.tgz", "integrity": "sha512-jyH7wtcHiKssDtFPRB+iQdxlDf96m0E39yb0k5uJVhFGleZFoNw1c4aeIcVUPPbXUVJ94wwnMOAqUHyzoEPVMA==", - "dev": true, "license": "MIT" }, "node_modules/@webassemblyjs/helper-numbers": { "version": "1.13.2", "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-numbers/-/helper-numbers-1.13.2.tgz", "integrity": "sha512-FE8aCmS5Q6eQYcV3gI35O4J789wlQA+7JrqTTpJqn5emA4U2hvwJmvFRC0HODS+3Ye6WioDklgd6scJ3+PLnEA==", - "dev": true, "license": "MIT", "dependencies": { "@webassemblyjs/floating-point-hex-parser": "1.13.2", @@ -3066,14 +3144,12 @@ "version": "1.13.2", "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-wasm-bytecode/-/helper-wasm-bytecode-1.13.2.tgz", "integrity": "sha512-3QbLKy93F0EAIXLh0ogEVR6rOubA9AoZ+WRYhNbFyuB70j3dRdwH9g+qXhLAO0kiYGlg3TxDV+I4rQTr/YNXkA==", - "dev": true, "license": "MIT" }, "node_modules/@webassemblyjs/helper-wasm-section": { "version": "1.14.1", "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-wasm-section/-/helper-wasm-section-1.14.1.tgz", "integrity": "sha512-ds5mXEqTJ6oxRoqjhWDU83OgzAYjwsCV8Lo/N+oRsNDmx/ZDpqalmrtgOMkHwxsG0iI//3BwWAErYRHtgn0dZw==", - "dev": true, "license": "MIT", "dependencies": { "@webassemblyjs/ast": "1.14.1", @@ -3086,7 +3162,6 @@ "version": "1.13.2", "resolved": "https://registry.npmjs.org/@webassemblyjs/ieee754/-/ieee754-1.13.2.tgz", "integrity": "sha512-4LtOzh58S/5lX4ITKxnAK2USuNEvpdVV9AlgGQb8rJDHaLeHciwG4zlGr0j/SNWlr7x3vO1lDEsuePvtcDNCkw==", - "dev": true, "license": "MIT", "dependencies": { "@xtuc/ieee754": "^1.2.0" @@ -3096,7 +3171,6 @@ "version": "1.13.2", "resolved": "https://registry.npmjs.org/@webassemblyjs/leb128/-/leb128-1.13.2.tgz", "integrity": "sha512-Lde1oNoIdzVzdkNEAWZ1dZ5orIbff80YPdHx20mrHwHrVNNTjNr8E3xz9BdpcGqRQbAEa+fkrCb+fRFTl/6sQw==", - "dev": true, "license": "Apache-2.0", "dependencies": { "@xtuc/long": "4.2.2" @@ -3106,14 +3180,12 @@ "version": "1.13.2", "resolved": "https://registry.npmjs.org/@webassemblyjs/utf8/-/utf8-1.13.2.tgz", "integrity": "sha512-3NQWGjKTASY1xV5m7Hr0iPeXD9+RDobLll3T9d2AO+g3my8xy5peVyjSag4I50mR1bBSN/Ct12lo+R9tJk0NZQ==", - "dev": true, "license": "MIT" }, "node_modules/@webassemblyjs/wasm-edit": { "version": "1.14.1", "resolved": "https://registry.npmjs.org/@webassemblyjs/wasm-edit/-/wasm-edit-1.14.1.tgz", "integrity": "sha512-RNJUIQH/J8iA/1NzlE4N7KtyZNHi3w7at7hDjvRNm5rcUXa00z1vRz3glZoULfJ5mpvYhLybmVcwcjGrC1pRrQ==", - "dev": true, "license": "MIT", "dependencies": { "@webassemblyjs/ast": "1.14.1", @@ -3130,7 +3202,6 @@ "version": "1.14.1", "resolved": "https://registry.npmjs.org/@webassemblyjs/wasm-gen/-/wasm-gen-1.14.1.tgz", "integrity": "sha512-AmomSIjP8ZbfGQhumkNvgC33AY7qtMCXnN6bL2u2Js4gVCg8fp735aEiMSBbDR7UQIj90n4wKAFUSEd0QN2Ukg==", - "dev": true, "license": "MIT", "dependencies": { "@webassemblyjs/ast": "1.14.1", @@ -3144,7 +3215,6 @@ "version": "1.14.1", "resolved": "https://registry.npmjs.org/@webassemblyjs/wasm-opt/-/wasm-opt-1.14.1.tgz", "integrity": "sha512-PTcKLUNvBqnY2U6E5bdOQcSM+oVP/PmrDY9NzowJjislEjwP/C4an2303MCVS2Mg9d3AJpIGdUFIQQWbPds0Sw==", - "dev": true, "license": "MIT", "dependencies": { "@webassemblyjs/ast": "1.14.1", @@ -3157,7 +3227,6 @@ "version": "1.14.1", "resolved": "https://registry.npmjs.org/@webassemblyjs/wasm-parser/-/wasm-parser-1.14.1.tgz", "integrity": "sha512-JLBl+KZ0R5qB7mCnud/yyX08jWFw5MsoalJ1pQ4EdFlgj9VdXKGuENGsiCIjegI1W7p91rUlcB/LB5yRJKNTcQ==", - "dev": true, "license": "MIT", "dependencies": { "@webassemblyjs/ast": "1.14.1", @@ -3172,7 +3241,6 @@ "version": "1.14.1", "resolved": "https://registry.npmjs.org/@webassemblyjs/wast-printer/-/wast-printer-1.14.1.tgz", "integrity": "sha512-kPSSXE6De1XOR820C90RIo2ogvZG+c3KiHzqUoO/F34Y2shGzesfqv7o57xrxovZJH/MetF5UjroJ/R/3isoiw==", - "dev": true, "license": "MIT", "dependencies": { "@webassemblyjs/ast": "1.14.1", @@ -3193,14 +3261,12 @@ "version": "1.2.0", "resolved": "https://registry.npmjs.org/@xtuc/ieee754/-/ieee754-1.2.0.tgz", "integrity": "sha512-DX8nKgqcGwsc0eJSqYt5lwP4DH5FlHnmuWWBRy7X0NcaGR0ZtuyeESgMwTYVEtxmsNGY+qit4QYT/MIYTOTPeA==", - "dev": true, "license": "BSD-3-Clause" }, "node_modules/@xtuc/long": { "version": "4.2.2", "resolved": "https://registry.npmjs.org/@xtuc/long/-/long-4.2.2.tgz", "integrity": "sha512-NuHqBY1PB/D8xU6s/thBgOAiAP7HOYDQ32+BFZILJ8ivkUkAHQnWfn6WhL79Owj1qmUnoN/YPhktdIoucipkAQ==", - "dev": true, "license": "Apache-2.0" }, "node_modules/abbrev": { @@ -3228,7 +3294,6 @@ "version": "8.15.0", "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.15.0.tgz", "integrity": "sha512-NZyJarBfL7nWwIq+FDL6Zp/yHEhePMNnnJ0y3qfieCrmNvYct8uvtiV41UvlSe6apAfk0fY1FbWx+NwfmpvtTg==", - "dev": true, "license": "MIT", "bin": { "acorn": "bin/acorn" @@ -3241,7 +3306,6 @@ "version": "1.0.4", "resolved": "https://registry.npmjs.org/acorn-import-phases/-/acorn-import-phases-1.0.4.tgz", "integrity": "sha512-wKmbr/DDiIXzEOiWrTTUcDm24kQ2vGfZQvM2fwg2vXqR5uW6aapr7ObPtj1th32b9u90/Pf4AItvdTh42fBmVQ==", - "dev": true, "license": "MIT", "engines": { "node": ">=10.13.0" @@ -3448,11 +3512,178 @@ "node": ">= 8" } }, + "node_modules/appdmg": { + "version": "0.6.6", + "resolved": "https://registry.npmjs.org/appdmg/-/appdmg-0.6.6.tgz", + "integrity": "sha512-GRmFKlCG+PWbcYF4LUNonTYmy0GjguDy6Jh9WP8mpd0T6j80XIJyXBiWlD0U+MLNhqV9Nhx49Gl9GpVToulpLg==", + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], + "dependencies": { + "async": "^1.4.2", + "ds-store": "^0.1.5", + "execa": "^1.0.0", + "fs-temp": "^1.0.0", + "fs-xattr": "^0.3.0", + "image-size": "^0.7.4", + "is-my-json-valid": "^2.20.0", + "minimist": "^1.1.3", + "parse-color": "^1.0.0", + "path-exists": "^4.0.0", + "repeat-string": "^1.5.4" + }, + "bin": { + "appdmg": "bin/appdmg.js" + }, + "engines": { + "node": ">=8.5" + } + }, + "node_modules/appdmg/node_modules/cross-spawn": { + "version": "6.0.6", + "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-6.0.6.tgz", + "integrity": "sha512-VqCUuhcd1iB+dsv8gxPttb5iZh/D0iubSP21g36KXdEuf6I5JiioesUVjpCdHV9MZRUfVFlvwtIUyPfxo5trtw==", + "dev": true, + "license": "MIT", + "optional": true, + "dependencies": { + "nice-try": "^1.0.4", + "path-key": "^2.0.1", + "semver": "^5.5.0", + "shebang-command": "^1.2.0", + "which": "^1.2.9" + }, + "engines": { + "node": ">=4.8" + } + }, + "node_modules/appdmg/node_modules/execa": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/execa/-/execa-1.0.0.tgz", + "integrity": "sha512-adbxcyWV46qiHyvSp50TKt05tB4tK3HcmF7/nxfAdhnox83seTDbwnaqKO4sXRy7roHAIFqJP/Rw/AuEbX61LA==", + "dev": true, + "license": "MIT", + "optional": true, + "dependencies": { + "cross-spawn": "^6.0.0", + "get-stream": "^4.0.0", + "is-stream": "^1.1.0", + "npm-run-path": "^2.0.0", + "p-finally": "^1.0.0", + "signal-exit": "^3.0.0", + "strip-eof": "^1.0.0" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/appdmg/node_modules/get-stream": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/get-stream/-/get-stream-4.1.0.tgz", + "integrity": "sha512-GMat4EJ5161kIy2HevLlr4luNjBgvmj413KaQA7jt4V8B4RDsfpHk7WQ9GVqfYyyx8OS/L66Kox+rJRNklLK7w==", + "dev": true, + "license": "MIT", + "optional": true, + "dependencies": { + "pump": "^3.0.0" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/appdmg/node_modules/is-stream": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/is-stream/-/is-stream-1.1.0.tgz", + "integrity": "sha512-uQPm8kcs47jx38atAcWTVxyltQYoPT68y9aWYdV6yWXSyW8mzSat0TL6CiWdZeCdF3KrAvpVtnHbTv4RN+rqdQ==", + "dev": true, + "license": "MIT", + "optional": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/appdmg/node_modules/npm-run-path": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/npm-run-path/-/npm-run-path-2.0.2.tgz", + "integrity": "sha512-lJxZYlT4DW/bRUtFh1MQIWqmLwQfAxnqWG4HhEdjMlkrJYnJn0Jrr2u3mgxqaWsdiBc76TYkTG/mhrnYTuzfHw==", + "dev": true, + "license": "MIT", + "optional": true, + "dependencies": { + "path-key": "^2.0.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/appdmg/node_modules/path-key": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/path-key/-/path-key-2.0.1.tgz", + "integrity": "sha512-fEHGKCSmUSDPv4uoj8AlD+joPlq3peND+HRYyxFz4KPw4z926S/b8rIuFs2FYJg3BwsxJf6A9/3eIdLaYC+9Dw==", + "dev": true, + "license": "MIT", + "optional": true, + "engines": { + "node": ">=4" + } + }, + "node_modules/appdmg/node_modules/semver": { + "version": "5.7.2", + "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.2.tgz", + "integrity": "sha512-cBznnQ9KjJqU67B52RMC65CMarK2600WFnbkcaiwWq3xy/5haFJlshgnpjovMVJ+Hff49d8GEn0b87C5pDQ10g==", + "dev": true, + "license": "ISC", + "optional": true, + "bin": { + "semver": "bin/semver" + } + }, + "node_modules/appdmg/node_modules/shebang-command": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-1.2.0.tgz", + "integrity": "sha512-EV3L1+UQWGor21OmnvojK36mhg+TyIKDh3iFBKBohr5xeXIhNBcx8oWdgkTEEQ+BEFFYdLRuqMfd5L84N1V5Vg==", + "dev": true, + "license": "MIT", + "optional": true, + "dependencies": { + "shebang-regex": "^1.0.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/appdmg/node_modules/shebang-regex": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/shebang-regex/-/shebang-regex-1.0.0.tgz", + "integrity": "sha512-wpoSFAxys6b2a2wHZ1XpDSgD7N9iVjg29Ph9uV/uaP9Ex/KXlkTZTeddxDPSYQpgvzKLGJke2UU0AzoGCjNIvQ==", + "dev": true, + "license": "MIT", + "optional": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/appdmg/node_modules/which": { + "version": "1.3.1", + "resolved": "https://registry.npmjs.org/which/-/which-1.3.1.tgz", + "integrity": "sha512-HxJdYWq1MTIQbJ3nw0cqssHoTNU267KlrDuGZ1WYlxDStUtKUhOaJmh112/TZmHxxUfuJqPXSOm7tDyas0OSIQ==", + "dev": true, + "license": "ISC", + "optional": true, + "dependencies": { + "isexe": "^2.0.0" + }, + "bin": { + "which": "bin/which" + } + }, "node_modules/argparse": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/argparse/-/argparse-2.0.1.tgz", "integrity": "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==", - "dev": true, "license": "Python-2.0" }, "node_modules/array-buffer-byte-length": { @@ -3594,6 +3825,14 @@ "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/async": { + "version": "1.5.2", + "resolved": "https://registry.npmjs.org/async/-/async-1.5.2.tgz", + "integrity": "sha512-nSVgobk4rv61R9PUSDtYt7mPVB2olxNR5RWJcAsH676/ef11bUZwvu7+RGYrYauVdDPcO519v68wRhXQtxsV9w==", + "dev": true, + "license": "MIT", + "optional": true + }, "node_modules/async-function": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/async-function/-/async-function-1.0.0.tgz", @@ -3770,6 +4009,17 @@ "dev": true, "license": "MIT" }, + "node_modules/base32-encode": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/base32-encode/-/base32-encode-1.2.0.tgz", + "integrity": "sha512-cHFU8XeRyx0GgmoWi5qHMCVRiqU6J3MHWxVgun7jggCBUpVzm1Ir7M9dYr2whjSNc3tFeXfQ/oZjQu/4u55h9A==", + "dev": true, + "license": "MIT", + "optional": true, + "dependencies": { + "to-data-view": "^1.1.0" + } + }, "node_modules/base64-js": { "version": "1.5.1", "resolved": "https://registry.npmjs.org/base64-js/-/base64-js-1.5.1.tgz", @@ -3795,7 +4045,6 @@ "version": "2.8.19", "resolved": "https://registry.npmjs.org/baseline-browser-mapping/-/baseline-browser-mapping-2.8.19.tgz", "integrity": "sha512-zoKGUdu6vb2jd3YOq0nnhEDQVbPcHhco3UImJrv5dSkvxTc2pl2WjOPsjZXDwPDSl5eghIMuY3R6J9NDKF3KcQ==", - "dev": true, "license": "Apache-2.0", "bin": { "baseline-browser-mapping": "dist/cli.js" @@ -3919,6 +4168,17 @@ "license": "MIT", "optional": true }, + "node_modules/bplist-creator": { + "version": "0.0.8", + "resolved": "https://registry.npmjs.org/bplist-creator/-/bplist-creator-0.0.8.tgz", + "integrity": "sha512-Za9JKzD6fjLC16oX2wsXfc+qBEhJBJB1YPInoAQpMLhDuj5aVOv1baGeIQSq1Fr3OCqzvsoQcSBSwGId/Ja2PA==", + "dev": true, + "license": "MIT", + "optional": true, + "dependencies": { + "stream-buffers": "~2.2.0" + } + }, "node_modules/brace-expansion": { "version": "1.1.12", "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.12.tgz", @@ -3947,7 +4207,6 @@ "version": "4.26.3", "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.26.3.tgz", "integrity": "sha512-lAUU+02RFBuCKQPj/P6NgjlbCnLBMp4UtgTx7vNHd3XSIJF87s9a5rA3aH2yw3GS9DqZAUbOtZdCCiZeVRqt0w==", - "dev": true, "funding": [ { "type": "opencollective", @@ -4016,9 +4275,21 @@ "version": "1.1.2", "resolved": "https://registry.npmjs.org/buffer-from/-/buffer-from-1.1.2.tgz", "integrity": "sha512-E+XQCRwSbaaiChtv6k6Dwgc+bx+Bs6vuKJHHl5kox/BaKbhiXzqQOwK4cO22yElGp2OCmjwVhT3HmxgyPGnJfQ==", - "dev": true, "license": "MIT" }, + "node_modules/builder-util-runtime": { + "version": "9.5.1", + "resolved": "https://registry.npmjs.org/builder-util-runtime/-/builder-util-runtime-9.5.1.tgz", + "integrity": "sha512-qt41tMfgHTllhResqM5DcnHyDIWNgzHvuY2jDcYP9iaGpkWxTUzV6GQjDeLnlR1/DtdlcsWQbA7sByMpmJFTLQ==", + "license": "MIT", + "dependencies": { + "debug": "^4.3.4", + "sax": "^1.2.4" + }, + "engines": { + "node": ">=12.0.0" + } + }, "node_modules/bytes": { "version": "3.1.2", "resolved": "https://registry.npmjs.org/bytes/-/bytes-3.1.2.tgz", @@ -4205,7 +4476,6 @@ "version": "1.0.30001751", "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001751.tgz", "integrity": "sha512-A0QJhug0Ly64Ii3eIqHu5X51ebln3k4yTUkY1j8drqpWHVreg/VLijN48cZ1bYPiqOQuqpkIKnzr/Ul8V+p6Cw==", - "dev": true, "funding": [ { "type": "opencollective", @@ -4298,7 +4568,6 @@ "version": "1.0.4", "resolved": "https://registry.npmjs.org/chrome-trace-event/-/chrome-trace-event-1.0.4.tgz", "integrity": "sha512-rNjApaLzuwaOTjCiT8lSDdGN1APCiqkChLMJxJPWLunPAt5fy8xgU9/jNOchV84wfIxrA0lRQB7oCT8jrn/wrQ==", - "dev": true, "license": "MIT", "engines": { "node": ">=6.0" @@ -5454,6 +5723,19 @@ "url": "https://github.com/sponsors/sindresorhus" } }, + "node_modules/ds-store": { + "version": "0.1.6", + "resolved": "https://registry.npmjs.org/ds-store/-/ds-store-0.1.6.tgz", + "integrity": "sha512-kY21M6Lz+76OS3bnCzjdsJSF7LBpLYGCVfavW8TgQD2XkcqIZ86W0y9qUDZu6fp7SIZzqosMDW2zi7zVFfv4hw==", + "dev": true, + "license": "MIT", + "optional": true, + "dependencies": { + "bplist-creator": "~0.0.3", + "macos-alias": "~0.2.5", + "tn1150": "^0.1.0" + } + }, "node_modules/dunder-proto": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/dunder-proto/-/dunder-proto-1.0.1.tgz", @@ -5734,7 +6016,29 @@ "license": "ISC", "optional": true, "engines": { - "node": ">=10" + "node": ">=10" + } + }, + "node_modules/electron-installer-dmg": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/electron-installer-dmg/-/electron-installer-dmg-5.0.1.tgz", + "integrity": "sha512-qOa1aAQdX57C+vzhDk3549dd/PRlNL4F8y736MTD1a43qptD+PvHY97Bo9gSf+OZ8iUWE7BrYSpk/FgLUe40EA==", + "dev": true, + "license": "Apache-2.0", + "optional": true, + "dependencies": { + "@types/appdmg": "^0.5.5", + "debug": "^4.3.2", + "minimist": "^1.2.7" + }, + "bin": { + "electron-installer-dmg": "dist/electron-installer-dmg-bin.js" + }, + "engines": { + "node": ">= 16" + }, + "optionalDependencies": { + "appdmg": "^0.6.4" } }, "node_modules/electron-installer-redhat": { @@ -5962,9 +6266,24 @@ "version": "1.5.238", "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.5.238.tgz", "integrity": "sha512-khBdc+w/Gv+cS8e/Pbnaw/FXcBUeKrRVik9IxfXtgREOWyJhR4tj43n3amkVogJ/yeQUqzkrZcFhtIxIdqmmcQ==", - "dev": true, "license": "ISC" }, + "node_modules/electron-updater": { + "version": "6.7.3", + "resolved": "https://registry.npmjs.org/electron-updater/-/electron-updater-6.7.3.tgz", + "integrity": "sha512-EgkT8Z9noqXKbwc3u5FkJA+r48jwZ5DTUiOkJMOTEEH//n5Am6wfQGz7nvSFEA2oIAMv9jRzn5JKTyWeSKOPgg==", + "license": "MIT", + "dependencies": { + "builder-util-runtime": "9.5.1", + "fs-extra": "^10.1.0", + "js-yaml": "^4.1.0", + "lazy-val": "^1.0.5", + "lodash.escaperegexp": "^4.1.2", + "lodash.isequal": "^4.5.0", + "semver": "~7.7.3", + "tiny-typed-emitter": "^2.1.0" + } + }, "node_modules/electron-winstaller": { "version": "5.4.0", "resolved": "https://registry.npmjs.org/electron-winstaller/-/electron-winstaller-5.4.0.tgz", @@ -6136,6 +6455,14 @@ "create-emotion": "^10.0.27" } }, + "node_modules/encode-utf8": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/encode-utf8/-/encode-utf8-1.0.3.tgz", + "integrity": "sha512-ucAnuBEhUK4boH2HjVYG5Q2mQyPorvv0u/ocS+zhdw0S8AlHYY+GOFhP1Gio5z4icpP2ivFSvhtFjQi8+T9ppw==", + "dev": true, + "license": "MIT", + "optional": true + }, "node_modules/encodeurl": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/encodeurl/-/encodeurl-2.0.0.tgz", @@ -6321,7 +6648,6 @@ "version": "1.7.0", "resolved": "https://registry.npmjs.org/es-module-lexer/-/es-module-lexer-1.7.0.tgz", "integrity": "sha512-jEQoCwk8hyb2AZziIOLhDqpm5+2ww5uIE6lkO/6jcOCusfk6LhMHpXXfBLXTZ7Ydyt0j4VoUQv6uGNYbdW+kBA==", - "dev": true, "license": "MIT" }, "node_modules/es-object-atoms": { @@ -6394,7 +6720,6 @@ "version": "3.2.0", "resolved": "https://registry.npmjs.org/escalade/-/escalade-3.2.0.tgz", "integrity": "sha512-WUj2qlxaQtO4g6Pq5c29GTcWGDyd8itL8zTlipgECz3JesAiiOKotd8JU6otB3PACgG6xkJUyVhboMS+bje/jA==", - "dev": true, "license": "MIT", "engines": { "node": ">=6" @@ -6598,7 +6923,6 @@ "version": "5.1.1", "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-5.1.1.tgz", "integrity": "sha512-2NxwbF/hZ0KpepYN0cNbo+FN6XoK7GaHlQhgx/hIZl6Va0bF45RQOOwhLIy8lQDbuCiadSLCBnH2CFYquit5bw==", - "dev": true, "license": "BSD-2-Clause", "dependencies": { "esrecurse": "^4.3.0", @@ -6693,7 +7017,6 @@ "version": "4.3.0", "resolved": "https://registry.npmjs.org/esrecurse/-/esrecurse-4.3.0.tgz", "integrity": "sha512-KmfKL3b6G+RXvP8N1vr3Tq1kL/oCFgn2NYXEtqP8/L3pKapUA4G8cFVaoF3SU323CD4XypR/ffioHmkti6/Tag==", - "dev": true, "license": "BSD-2-Clause", "dependencies": { "estraverse": "^5.2.0" @@ -6706,7 +7029,6 @@ "version": "5.3.0", "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-5.3.0.tgz", "integrity": "sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA==", - "dev": true, "license": "BSD-2-Clause", "engines": { "node": ">=4.0" @@ -6716,7 +7038,6 @@ "version": "4.3.0", "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-4.3.0.tgz", "integrity": "sha512-39nnKffWz8xN1BU/2c79n9nB9HDzo0niYUqx6xyqUnyoAnQyyWpOTdZEeiCch8BBu515t4wp9ZmgVfVhn9EBpw==", - "dev": true, "license": "BSD-2-Clause", "engines": { "node": ">=4.0" @@ -6753,7 +7074,6 @@ "version": "3.3.0", "resolved": "https://registry.npmjs.org/events/-/events-3.3.0.tgz", "integrity": "sha512-mQw+2fkQbALzQ7V0MY0IqdnXNOeTtP4r0lN9z7AAawCXgqea7bDii20AYrIBrFd/Hx0M2Ocz6S111CaFkUcb0Q==", - "dev": true, "license": "MIT", "engines": { "node": ">=0.8.x" @@ -7177,6 +7497,17 @@ "node": ">= 12" } }, + "node_modules/fmix": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/fmix/-/fmix-0.1.0.tgz", + "integrity": "sha512-Y6hyofImk9JdzU8k5INtTXX1cu8LDlePWDFU5sftm9H+zKCr5SGrVjdhkvsim646cw5zD0nADj8oHyXMZmCZ9w==", + "dev": true, + "license": "MIT", + "optional": true, + "dependencies": { + "imul": "^1.0.0" + } + }, "node_modules/follow-redirects": { "version": "1.15.11", "resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.15.11.tgz", @@ -7303,7 +7634,6 @@ "version": "10.1.0", "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-10.1.0.tgz", "integrity": "sha512-oRXApq54ETRj4eMiFzGnHWGy+zo5raudjuxN0b8H7s/RU2oW0Wvsx9O0ACRN/kRq9E8Vu/ReskGB5o3ji+FzHQ==", - "dev": true, "license": "MIT", "dependencies": { "graceful-fs": "^4.2.0", @@ -7334,6 +7664,32 @@ "dev": true, "license": "Unlicense" }, + "node_modules/fs-temp": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/fs-temp/-/fs-temp-1.2.1.tgz", + "integrity": "sha512-okTwLB7/Qsq82G6iN5zZJFsOfZtx2/pqrA7Hk/9fvy+c+eJS9CvgGXT2uNxwnI14BDY9L/jQPkaBgSvlKfSW9w==", + "dev": true, + "license": "MIT", + "optional": true, + "dependencies": { + "random-path": "^0.1.0" + } + }, + "node_modules/fs-xattr": { + "version": "0.3.1", + "resolved": "https://registry.npmjs.org/fs-xattr/-/fs-xattr-0.3.1.tgz", + "integrity": "sha512-UVqkrEW0GfDabw4C3HOrFlxKfx0eeigfRne69FxSBdHIP8Qt5Sq6Pu3RM9KmMlkygtC4pPKkj5CiPO5USnj2GA==", + "dev": true, + "hasInstallScript": true, + "license": "MIT", + "optional": true, + "os": [ + "!win32" + ], + "engines": { + "node": ">=8.6.0" + } + }, "node_modules/fs.realpath": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz", @@ -7420,6 +7776,28 @@ "license": "MIT", "optional": true }, + "node_modules/generate-function": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/generate-function/-/generate-function-2.3.1.tgz", + "integrity": "sha512-eeB5GfMNeevm/GRYq20ShmsaGcmI81kIX2K9XQx5miC8KdHaC6Jm0qQ8ZNeGOi7wYB8OsdxKs+Y2oVuTFuVwKQ==", + "dev": true, + "license": "MIT", + "optional": true, + "dependencies": { + "is-property": "^1.0.2" + } + }, + "node_modules/generate-object-property": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/generate-object-property/-/generate-object-property-1.2.0.tgz", + "integrity": "sha512-TuOwZWgJ2VAMEGJvAyPWvpqxSANF0LDpmyHauMjFYzaACvn+QTT/AZomvPCzVBV7yDN3OmwHQ5OvHaeLKre3JQ==", + "dev": true, + "license": "MIT", + "optional": true, + "dependencies": { + "is-property": "^1.0.0" + } + }, "node_modules/generator-function": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/generator-function/-/generator-function-2.0.1.tgz", @@ -7565,6 +7943,15 @@ "integrity": "sha512-YQJnY8aew65id8okGxKCksH3efDCJ9HzV7M9rsvd65habf39Pkh4cgYJ27AaoDMqo1X98pgNJhNMrm/kpV7UVQ==", "license": "MIT" }, + "node_modules/github-url-to-object": { + "version": "4.0.6", + "resolved": "https://registry.npmjs.org/github-url-to-object/-/github-url-to-object-4.0.6.tgz", + "integrity": "sha512-NaqbYHMUAlPcmWFdrAB7bcxrNIiiJWJe8s/2+iOc9vlcHlwHqSGrPk+Yi3nu6ebTwgsZEa7igz+NH2vEq3gYwQ==", + "license": "MIT", + "dependencies": { + "is-url": "^1.1.0" + } + }, "node_modules/glob": { "version": "7.2.3", "resolved": "https://registry.npmjs.org/glob/-/glob-7.2.3.tgz", @@ -7603,7 +7990,6 @@ "version": "0.4.1", "resolved": "https://registry.npmjs.org/glob-to-regexp/-/glob-to-regexp-0.4.1.tgz", "integrity": "sha512-lkX1HJXwyMcprw/5YUZc2s7DrpAiHB21/V+E1rHUrVNokkvB6bqMzT0VfV6/86ZNabt1k14YOIaT7nDvOX3Iiw==", - "dev": true, "license": "BSD-2-Clause" }, "node_modules/global-agent": { @@ -7770,7 +8156,6 @@ "version": "4.0.0", "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", - "dev": true, "license": "MIT", "engines": { "node": ">=8" @@ -8221,6 +8606,20 @@ "node": ">= 4" } }, + "node_modules/image-size": { + "version": "0.7.5", + "resolved": "https://registry.npmjs.org/image-size/-/image-size-0.7.5.tgz", + "integrity": "sha512-Hiyv+mXHfFEP7LzUL/llg9RwFxxY+o9N3JVLIeG5E7iFIFAalxvRU9UZthBdYDEVnzHMgjnKJPPpay5BWf1g9g==", + "dev": true, + "license": "MIT", + "optional": true, + "bin": { + "image-size": "bin/image-size.js" + }, + "engines": { + "node": ">=6.9.0" + } + }, "node_modules/import-fresh": { "version": "3.3.1", "resolved": "https://registry.npmjs.org/import-fresh/-/import-fresh-3.3.1.tgz", @@ -8237,6 +8636,17 @@ "url": "https://github.com/sponsors/sindresorhus" } }, + "node_modules/imul": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/imul/-/imul-1.0.1.tgz", + "integrity": "sha512-WFAgfwPLAjU66EKt6vRdTlKj4nAgIDQzh29JonLa4Bqtl6D8JrIMvWjCnx7xEjVNmP3U0fM5o8ZObk7d0f62bA==", + "dev": true, + "license": "MIT", + "optional": true, + "engines": { + "node": ">=0.10.0" + } + }, "node_modules/imurmurhash": { "version": "0.1.4", "resolved": "https://registry.npmjs.org/imurmurhash/-/imurmurhash-0.1.4.tgz", @@ -8607,6 +9017,29 @@ "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/is-my-ip-valid": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/is-my-ip-valid/-/is-my-ip-valid-1.0.1.tgz", + "integrity": "sha512-jxc8cBcOWbNK2i2aTkCZP6i7wkHF1bqKFrwEHuN5Jtg5BSaZHUZQ/JTOJwoV41YvHnOaRyWWh72T/KvfNz9DJg==", + "dev": true, + "license": "MIT", + "optional": true + }, + "node_modules/is-my-json-valid": { + "version": "2.20.6", + "resolved": "https://registry.npmjs.org/is-my-json-valid/-/is-my-json-valid-2.20.6.tgz", + "integrity": "sha512-1JQwulVNjx8UqkPE/bqDaxtH4PXCe/2VRh/y3p99heOV87HG4Id5/VfDswd+YiAfHcRTfDlWgISycnHuhZq1aw==", + "dev": true, + "license": "MIT", + "optional": true, + "dependencies": { + "generate-function": "^2.0.0", + "generate-object-property": "^1.1.0", + "is-my-ip-valid": "^1.0.0", + "jsonpointer": "^5.0.0", + "xtend": "^4.0.0" + } + }, "node_modules/is-negative-zero": { "version": "2.0.3", "resolved": "https://registry.npmjs.org/is-negative-zero/-/is-negative-zero-2.0.3.tgz", @@ -8683,6 +9116,14 @@ "node": ">=0.10.0" } }, + "node_modules/is-property": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/is-property/-/is-property-1.0.2.tgz", + "integrity": "sha512-Ks/IoX00TtClbGQr4TWXemAnktAQvYB7HzcCxDGqEZU6oCmb2INHuOoKxbtR+HFkmYWBKv/dOZtGRiAjDhj92g==", + "dev": true, + "license": "MIT", + "optional": true + }, "node_modules/is-regex": { "version": "1.2.1", "resolved": "https://registry.npmjs.org/is-regex/-/is-regex-1.2.1.tgz", @@ -8808,6 +9249,12 @@ "url": "https://github.com/sponsors/sindresorhus" } }, + "node_modules/is-url": { + "version": "1.2.4", + "resolved": "https://registry.npmjs.org/is-url/-/is-url-1.2.4.tgz", + "integrity": "sha512-ITvGim8FhRiYe4IQ5uHSkj7pVaPDrCTkNd3yq3cV7iZAcJdHTUMPMEHcqSOy9xZ9qFenQCvi+2wjH9a1nXqHww==", + "license": "MIT" + }, "node_modules/is-weakmap": { "version": "2.0.2", "resolved": "https://registry.npmjs.org/is-weakmap/-/is-weakmap-2.0.2.tgz", @@ -8908,7 +9355,6 @@ "version": "27.5.1", "resolved": "https://registry.npmjs.org/jest-worker/-/jest-worker-27.5.1.tgz", "integrity": "sha512-7vuh85V5cdDofPyxn58nrPjBktZo0u9x1g8WtjQol+jZDaE+fhN+cIvTj11GndBnMnyfrUOG1sZQxCdjKh+DKg==", - "dev": true, "license": "MIT", "dependencies": { "@types/node": "*", @@ -8923,7 +9369,6 @@ "version": "8.1.1", "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-8.1.1.tgz", "integrity": "sha512-MpUEN2OodtUzxvKQl72cUF7RQ5EiHsGvSsVG0ia9c5RbWGL2CI4C7EpPS8UTBIplnlzZiNuV56w+FuNxy3ty2Q==", - "dev": true, "license": "MIT", "dependencies": { "has-flag": "^4.0.0" @@ -8954,7 +9399,6 @@ "version": "4.1.0", "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-4.1.0.tgz", "integrity": "sha512-wpxZs9NoxZaJESJGIZTyDEaYpl0FKSA+FB9aJiyemKhMwkxQg63h4T1KJgUGHpTqPDNRcmmYLugrRjJlBtWvRA==", - "dev": true, "license": "MIT", "dependencies": { "argparse": "^2.0.1" @@ -9046,7 +9490,6 @@ "version": "6.2.0", "resolved": "https://registry.npmjs.org/jsonfile/-/jsonfile-6.2.0.tgz", "integrity": "sha512-FGuPw30AdOIUTRMC2OMRtQV+jkVj2cfPqSeWXv1NEAJ1qZ5zb1X6z1mFhbfOB/iy3ssJCD+3KuZ8r8C3uVFlAg==", - "dev": true, "license": "MIT", "dependencies": { "universalify": "^2.0.0" @@ -9055,6 +9498,17 @@ "graceful-fs": "^4.1.6" } }, + "node_modules/jsonpointer": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/jsonpointer/-/jsonpointer-5.0.1.tgz", + "integrity": "sha512-p/nXbhSEcu3pZRdkW1OfJhpsVtW1gd4Wa1fnQc9YLiTfAjn0312eMKimbdIQzuZl9aa9xUGaRlP9T/CJE/ditQ==", + "dev": true, + "license": "MIT", + "optional": true, + "engines": { + "node": ">=0.10.0" + } + }, "node_modules/junk": { "version": "3.1.0", "resolved": "https://registry.npmjs.org/junk/-/junk-3.1.0.tgz", @@ -9096,6 +9550,12 @@ "shell-quote": "^1.8.3" } }, + "node_modules/lazy-val": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/lazy-val/-/lazy-val-1.0.5.tgz", + "integrity": "sha512-0/BnGCCfyUMkBpeDgWihanIAF9JmZhHBgUhEqzvf+adhNGLoP6TaiI5oF8oyb3I45P+PcnrqihSf01M0l0G5+Q==", + "license": "MIT" + }, "node_modules/levn": { "version": "0.4.1", "resolved": "https://registry.npmjs.org/levn/-/levn-0.4.1.tgz", @@ -9416,7 +9876,6 @@ "version": "4.3.1", "resolved": "https://registry.npmjs.org/loader-runner/-/loader-runner-4.3.1.tgz", "integrity": "sha512-IWqP2SCPhyVFTBtRcgMHdzlf9ul25NwaFx4wCEH/KjAXuuHY4yNjvPXsBokp8jCB936PyWRaPKUNh8NvylLp2Q==", - "dev": true, "license": "MIT", "engines": { "node": ">=6.11.5" @@ -9463,6 +9922,12 @@ "integrity": "sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==", "license": "MIT" }, + "node_modules/lodash.escaperegexp": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/lodash.escaperegexp/-/lodash.escaperegexp-4.1.2.tgz", + "integrity": "sha512-TM9YBvyC84ZxE3rgfefxUWiQKLilstD6k7PTGt6wfbtXF8ixIJLOL3VYyV/z+ZiPLsVxAsKAFVwWlWeb2Y8Yyw==", + "license": "MIT" + }, "node_modules/lodash.get": { "version": "4.4.2", "resolved": "https://registry.npmjs.org/lodash.get/-/lodash.get-4.4.2.tgz", @@ -9471,6 +9936,13 @@ "dev": true, "license": "MIT" }, + "node_modules/lodash.isequal": { + "version": "4.5.0", + "resolved": "https://registry.npmjs.org/lodash.isequal/-/lodash.isequal-4.5.0.tgz", + "integrity": "sha512-pDo3lu8Jhfjqls6GkMgpahsF9kCyayhgykjyLMNFTKWrpVdAQtYyB4muAMWozBB4ig/dtWAmsMxLEI8wuz+DYQ==", + "deprecated": "This package is deprecated. Use require('node:util').isDeepStrictEqual instead.", + "license": "MIT" + }, "node_modules/lodash.merge": { "version": "4.6.2", "resolved": "https://registry.npmjs.org/lodash.merge/-/lodash.merge-4.6.2.tgz", @@ -9586,6 +10058,21 @@ "node": ">=12" } }, + "node_modules/macos-alias": { + "version": "0.2.12", + "resolved": "https://registry.npmjs.org/macos-alias/-/macos-alias-0.2.12.tgz", + "integrity": "sha512-yiLHa7cfJcGRFq4FrR4tMlpNHb4Vy4mWnpajlSSIFM5k4Lv8/7BbbDLzCAVogWNl0LlLhizRp1drXv0hK9h0Yw==", + "dev": true, + "hasInstallScript": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], + "dependencies": { + "nan": "^2.4.0" + } + }, "node_modules/magic-string": { "version": "0.30.19", "resolved": "https://registry.npmjs.org/magic-string/-/magic-string-0.30.19.tgz", @@ -9729,7 +10216,6 @@ "version": "2.0.0", "resolved": "https://registry.npmjs.org/merge-stream/-/merge-stream-2.0.0.tgz", "integrity": "sha512-abv/qOcuPfk3URPfDzmZU1LKmuw8kT+0nIHvKrKgFrwifol/doWcdA4ZqsWQ8ENrFKkd67Mfpo/LovbIUsbt3w==", - "dev": true, "license": "MIT" }, "node_modules/merge2": { @@ -10011,6 +10497,19 @@ "multicast-dns": "cli.js" } }, + "node_modules/murmur-32": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/murmur-32/-/murmur-32-0.2.0.tgz", + "integrity": "sha512-ZkcWZudylwF+ir3Ld1n7gL6bI2mQAzXvSobPwVtu8aYi2sbXeipeSkdcanRLzIofLcM5F53lGaKm2dk7orBi7Q==", + "dev": true, + "license": "MIT", + "optional": true, + "dependencies": { + "encode-utf8": "^1.0.3", + "fmix": "^0.1.0", + "imul": "^1.0.0" + } + }, "node_modules/mute-stream": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/mute-stream/-/mute-stream-1.0.0.tgz", @@ -10021,6 +10520,14 @@ "node": "^14.17.0 || ^16.13.0 || >=18.0.0" } }, + "node_modules/nan": { + "version": "2.25.0", + "resolved": "https://registry.npmjs.org/nan/-/nan-2.25.0.tgz", + "integrity": "sha512-0M90Ag7Xn5KMLLZ7zliPWP3rT90P6PN+IzVFS0VqmnPktBk3700xUVv8Ikm9EUaUE5SDWdp/BIxdENzVznpm1g==", + "dev": true, + "license": "MIT", + "optional": true + }, "node_modules/nanoid": { "version": "3.3.11", "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.11.tgz", @@ -10067,7 +10574,6 @@ "version": "2.6.2", "resolved": "https://registry.npmjs.org/neo-async/-/neo-async-2.6.2.tgz", "integrity": "sha512-Yd3UES5mWCSqR+qNT93S3UoYUkqAZ9lLg8a7g9rimsWmYGK8cVToA4/sF3RrshdyV3sAGMXVUmpMYOw+dLpOuw==", - "dev": true, "license": "MIT" }, "node_modules/nice-try": { @@ -10173,7 +10679,6 @@ "version": "2.0.26", "resolved": "https://registry.npmjs.org/node-releases/-/node-releases-2.0.26.tgz", "integrity": "sha512-S2M9YimhSjBSvYnlr5/+umAnPHE++ODwt5e2Ij6FoX45HA/s4vHdkDx1eax2pAPeAOqu4s9b7ppahsyEFdVqQA==", - "dev": true, "license": "MIT" }, "node_modules/nopt": { @@ -10684,6 +11189,12 @@ "node": ">=4" } }, + "node_modules/papaparse": { + "version": "5.5.3", + "resolved": "https://registry.npmjs.org/papaparse/-/papaparse-5.5.3.tgz", + "integrity": "sha512-5QvjGxYVjxO59MGU2lHVYpRWBBtKHnlIAcSe1uNFCkkptUh63NFRj0FJQm7nR67puEruUci/ZkjmEFrjCAyP4A==", + "license": "MIT" + }, "node_modules/param-case": { "version": "3.0.4", "resolved": "https://registry.npmjs.org/param-case/-/param-case-3.0.4.tgz", @@ -10720,6 +11231,24 @@ "node": ">=0.10.0" } }, + "node_modules/parse-color": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/parse-color/-/parse-color-1.0.0.tgz", + "integrity": "sha512-fuDHYgFHJGbpGMgw9skY/bj3HL/Jrn4l/5rSspy00DoT4RyLnDcRvPxdZ+r6OFwIsgAuhDh4I09tAId4mI12bw==", + "dev": true, + "license": "MIT", + "optional": true, + "dependencies": { + "color-convert": "~0.5.0" + } + }, + "node_modules/parse-color/node_modules/color-convert": { + "version": "0.5.3", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-0.5.3.tgz", + "integrity": "sha512-RwBeO/B/vZR3dfKL1ye/vx8MHZ40ugzpyfeVG5GsiuGnrlMWe2o8wxBbLCpw9CsxV+wHuzYlCiWnybrIA0ling==", + "dev": true, + "optional": true + }, "node_modules/parse-json": { "version": "5.2.0", "resolved": "https://registry.npmjs.org/parse-json/-/parse-json-5.2.0.tgz", @@ -10974,6 +11503,22 @@ } } }, + "node_modules/postcss-loader/node_modules/typescript": { + "version": "5.9.3", + "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.9.3.tgz", + "integrity": "sha512-jl1vZzPDinLr9eUt3J/t7V6FgNEw9QjvBPdysz9KfQDD41fQrC2Y4vKQdiaUpFT4bXlb1RHhLpp8wtm6M5TgSw==", + "dev": true, + "license": "Apache-2.0", + "optional": true, + "peer": true, + "bin": { + "tsc": "bin/tsc", + "tsserver": "bin/tsserver" + }, + "engines": { + "node": ">=14.17" + } + }, "node_modules/postcss-modules-extract-imports": { "version": "3.1.0", "resolved": "https://registry.npmjs.org/postcss-modules-extract-imports/-/postcss-modules-extract-imports-3.1.0.tgz", @@ -11271,6 +11816,18 @@ "url": "https://github.com/sponsors/sindresorhus" } }, + "node_modules/random-path": { + "version": "0.1.2", + "resolved": "https://registry.npmjs.org/random-path/-/random-path-0.1.2.tgz", + "integrity": "sha512-4jY0yoEaQ5v9StCl5kZbNIQlg1QheIDBrdkDn53EynpPb9FgO6//p3X/tgMnrC45XN6QZCzU1Xz/+pSSsJBpRw==", + "dev": true, + "license": "MIT", + "optional": true, + "dependencies": { + "base32-encode": "^0.1.0 || ^1.0.0", + "murmur-32": "^0.1.0 || ^0.2.0" + } + }, "node_modules/randombytes": { "version": "2.1.0", "resolved": "https://registry.npmjs.org/randombytes/-/randombytes-2.1.0.tgz", @@ -11720,6 +12277,17 @@ "strip-ansi": "^6.0.1" } }, + "node_modules/repeat-string": { + "version": "1.6.1", + "resolved": "https://registry.npmjs.org/repeat-string/-/repeat-string-1.6.1.tgz", + "integrity": "sha512-PV0dzCYDNfRi1jCDbJzpW7jNNDRuCOG/jI5ctQcGKt/clZD+YcPS3yIlWuTJMmESC8aevCFmWJy5wjAFgNqN6w==", + "dev": true, + "license": "MIT", + "optional": true, + "engines": { + "node": ">=0.10" + } + }, "node_modules/require-directory": { "version": "2.1.1", "resolved": "https://registry.npmjs.org/require-directory/-/require-directory-2.1.1.tgz", @@ -12000,6 +12568,15 @@ "dev": true, "license": "MIT" }, + "node_modules/sax": { + "version": "1.4.4", + "resolved": "https://registry.npmjs.org/sax/-/sax-1.4.4.tgz", + "integrity": "sha512-1n3r/tGXO6b6VXMdFT54SHzT9ytu9yr7TaELowdYpMqY/Ao7EnlQGmAQ1+RatX7Tkkdm6hONI2owqNx2aZj5Sw==", + "license": "BlueOak-1.0.0", + "engines": { + "node": ">=11.0.0" + } + }, "node_modules/scheduler": { "version": "0.27.0", "resolved": "https://registry.npmjs.org/scheduler/-/scheduler-0.27.0.tgz", @@ -12557,7 +13134,6 @@ "version": "0.6.1", "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", - "dev": true, "license": "BSD-3-Clause", "engines": { "node": ">=0.10.0" @@ -12576,7 +13152,6 @@ "version": "0.5.21", "resolved": "https://registry.npmjs.org/source-map-support/-/source-map-support-0.5.21.tgz", "integrity": "sha512-uBHU3L3czsIyYXKX88fdrGovxdSCoTGDRZ6SYXtSRxLZUzHg5P/66Ht6uoUlHu9EZod+inXhKo3qQgwXUT/y1w==", - "dev": true, "license": "MIT", "dependencies": { "buffer-from": "^1.0.0", @@ -12702,6 +13277,17 @@ "node": ">= 0.4" } }, + "node_modules/stream-buffers": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/stream-buffers/-/stream-buffers-2.2.0.tgz", + "integrity": "sha512-uyQK/mx5QjHun80FLJTfaWE7JtwfRMKBLkMne6udYOmvH0CawotVa7TfgYHzAnpphn4+TweIx1QKMnRIbipmUg==", + "dev": true, + "license": "Unlicense", + "optional": true, + "engines": { + "node": ">= 0.10.0" + } + }, "node_modules/string_decoder": { "version": "1.3.0", "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.3.0.tgz", @@ -13080,7 +13666,6 @@ "version": "5.44.0", "resolved": "https://registry.npmjs.org/terser/-/terser-5.44.0.tgz", "integrity": "sha512-nIVck8DK+GM/0Frwd+nIhZ84pR/BX7rmXMfYwyg+Sri5oGVE99/E3KvXqpC2xHFxyqXyGHTKBSioxxplrO4I4w==", - "dev": true, "license": "BSD-2-Clause", "dependencies": { "@jridgewell/source-map": "^0.3.3", @@ -13099,7 +13684,6 @@ "version": "5.3.14", "resolved": "https://registry.npmjs.org/terser-webpack-plugin/-/terser-webpack-plugin-5.3.14.tgz", "integrity": "sha512-vkZjpUjb6OMS7dhV+tILUW6BhpDR7P2L/aQSAv+Uwk+m8KATX9EccViHTJR2qDtACKPIYndLGCyl3FMo+r2LMw==", - "dev": true, "license": "MIT", "dependencies": { "@jridgewell/trace-mapping": "^0.3.25", @@ -13134,7 +13718,6 @@ "version": "8.17.1", "resolved": "https://registry.npmjs.org/ajv/-/ajv-8.17.1.tgz", "integrity": "sha512-B/gBuNg5SiMTrPkC+A2+cW0RszwxYmn6VYxB/inlBStS5nx6xHIt/ehKRhIMhqusl7a8LjQoZnjCs5vhwxOQ1g==", - "dev": true, "license": "MIT", "dependencies": { "fast-deep-equal": "^3.1.3", @@ -13151,7 +13734,6 @@ "version": "5.1.0", "resolved": "https://registry.npmjs.org/ajv-keywords/-/ajv-keywords-5.1.0.tgz", "integrity": "sha512-YCS/JNFAUyr5vAuhk1DWm1CBxRHW9LbJ2ozWeemrIqpbsqKjHVxYPyi5GC0rjZIT5JxJ3virVTS8wk4i/Z+krw==", - "dev": true, "license": "MIT", "dependencies": { "fast-deep-equal": "^3.1.3" @@ -13164,14 +13746,12 @@ "version": "1.0.0", "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-1.0.0.tgz", "integrity": "sha512-NM8/P9n3XjXhIZn1lLhkFaACTOURQXjWhV4BA/RnOv8xvgqtqpAX9IO4mRQxSx1Rlo4tqzeqb0sOlruaOy3dug==", - "dev": true, "license": "MIT" }, "node_modules/terser-webpack-plugin/node_modules/schema-utils": { "version": "4.3.3", "resolved": "https://registry.npmjs.org/schema-utils/-/schema-utils-4.3.3.tgz", "integrity": "sha512-eflK8wEtyOE6+hsaRVPxvUKYCpRgzLqDTb8krvAsRIwOGlHoSgYLgBXoubGgLd2fT41/OUYdb48v4k4WWHQurA==", - "dev": true, "license": "MIT", "dependencies": { "@types/json-schema": "^7.0.9", @@ -13191,7 +13771,6 @@ "version": "2.20.3", "resolved": "https://registry.npmjs.org/commander/-/commander-2.20.3.tgz", "integrity": "sha512-GpVkmM8vF2vQUkj2LvZmD35JxeJOLCwJ9cUkugyk2nuhbv3+mJvpLYYt+0+USMxE+oj+ey/lJEnhZw75x/OMcQ==", - "dev": true, "license": "MIT" }, "node_modules/text-table": { @@ -13216,6 +13795,12 @@ "license": "MIT", "optional": true }, + "node_modules/tiny-typed-emitter": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/tiny-typed-emitter/-/tiny-typed-emitter-2.1.0.tgz", + "integrity": "sha512-qVtvMxeXbVej0cQWKqVSSAHmKZEHAvxdF8HEUBFWts8h+xEo5m/lEiPakuyZ3BnCBjOD8i24kzNOiOLLgsSxhA==", + "license": "MIT" + }, "node_modules/tinyglobby": { "version": "0.2.15", "resolved": "https://registry.npmjs.org/tinyglobby/-/tinyglobby-0.2.15.tgz", @@ -13296,6 +13881,28 @@ "node": ">=14.14" } }, + "node_modules/tn1150": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/tn1150/-/tn1150-0.1.0.tgz", + "integrity": "sha512-DbplOfQFkqG5IHcDyyrs/lkvSr3mPUVsFf/RbDppOshs22yTPnSJWEe6FkYd1txAwU/zcnR905ar2fi4kwF29w==", + "dev": true, + "license": "MIT", + "optional": true, + "dependencies": { + "unorm": "^1.4.1" + }, + "engines": { + "node": ">=0.12" + } + }, + "node_modules/to-data-view": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/to-data-view/-/to-data-view-1.1.0.tgz", + "integrity": "sha512-1eAdufMg6mwgmlojAx3QeMnzB/BTVp7Tbndi3U7ftcT2zCZadjxkkmLmd97zmaxWi+sgGcgWrokmpEoy0Dn0vQ==", + "dev": true, + "license": "MIT", + "optional": true + }, "node_modules/to-regex-range": { "version": "5.0.1", "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz", @@ -13603,7 +14210,6 @@ "version": "7.16.0", "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-7.16.0.tgz", "integrity": "sha512-Zz+aZWSj8LE6zoxD+xrjh4VfkIG8Ya6LvYkZqtUQGJPZjYl53ypCaUwWqo7eI0x66KBGeRo+mlBEkMSeSZ38Nw==", - "dev": true, "license": "MIT" }, "node_modules/unique-filename": { @@ -13636,12 +14242,22 @@ "version": "2.0.1", "resolved": "https://registry.npmjs.org/universalify/-/universalify-2.0.1.tgz", "integrity": "sha512-gptHNQghINnc/vTGIk0SOFGFNXw7JVrlRUtConJRlvaw6DuX0wO5Jeko9sWrMBhh+PsYAZ7oXAiOnf/UKogyiw==", - "dev": true, "license": "MIT", "engines": { "node": ">= 10.0.0" } }, + "node_modules/unorm": { + "version": "1.6.0", + "resolved": "https://registry.npmjs.org/unorm/-/unorm-1.6.0.tgz", + "integrity": "sha512-b2/KCUlYZUeA7JFUuRJZPUtr4gZvBh7tavtv4fvk4+KV9pfGiR6CQAQAWl49ZpR3ts2dk4FYkP7EIgDJoiOLDA==", + "dev": true, + "license": "MIT or GPL-2.0", + "optional": true, + "engines": { + "node": ">= 0.4.0" + } + }, "node_modules/unpipe": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/unpipe/-/unpipe-1.0.0.tgz", @@ -13656,7 +14272,6 @@ "version": "1.1.3", "resolved": "https://registry.npmjs.org/update-browserslist-db/-/update-browserslist-db-1.1.3.tgz", "integrity": "sha512-UxhIZQ+QInVdunkDAaiazvvT/+fXL5Osr0JZlJulepYu6Jd7qJtDZjlur0emRlT71EN3ScPoE7gvsuIKKNavKw==", - "dev": true, "funding": [ { "type": "opencollective", @@ -13683,6 +14298,16 @@ "browserslist": ">= 4.21.0" } }, + "node_modules/update-electron-app": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/update-electron-app/-/update-electron-app-3.1.2.tgz", + "integrity": "sha512-htLyPJv7mEoCpaSzCg0W3Hxz7ID0GC7BIhhpK32/ITG7McrWak4aOkLEOjJheKAI94AxtBVTjCk4EFIvyttw2w==", + "license": "MIT", + "dependencies": { + "github-url-to-object": "^4.0.4", + "ms": "^2.1.1" + } + }, "node_modules/uri-js": { "version": "4.4.1", "resolved": "https://registry.npmjs.org/uri-js/-/uri-js-4.4.1.tgz", @@ -13903,7 +14528,6 @@ "version": "2.4.4", "resolved": "https://registry.npmjs.org/watchpack/-/watchpack-2.4.4.tgz", "integrity": "sha512-c5EGNOiyxxV5qmTtAB7rbiXxi1ooX1pQKMLX/MIabJjRA0SJBQOjKF+KSVfHkr9U1cADPon0mRiVe/riyaiDUA==", - "dev": true, "license": "MIT", "dependencies": { "glob-to-regexp": "^0.4.1", @@ -13944,7 +14568,6 @@ "version": "5.102.1", "resolved": "https://registry.npmjs.org/webpack/-/webpack-5.102.1.tgz", "integrity": "sha512-7h/weGm9d/ywQ6qzJ+Xy+r9n/3qgp/thalBbpOi5i223dPXKi04IBtqPN9nTd+jBc7QKfvDbaBnFipYp4sJAUQ==", - "dev": true, "license": "MIT", "dependencies": { "@types/eslint-scope": "^3.7.7", @@ -14238,7 +14861,6 @@ "version": "3.3.3", "resolved": "https://registry.npmjs.org/webpack-sources/-/webpack-sources-3.3.3.tgz", "integrity": "sha512-yd1RBzSGanHkitROoPFd6qsrxt+oFhg/129YzheDGqeustzX0vTZJZsSsQjVQC4yzBQ56K55XU8gaNCtIzOnTg==", - "dev": true, "license": "MIT", "engines": { "node": ">=10.13.0" @@ -14248,7 +14870,6 @@ "version": "8.17.1", "resolved": "https://registry.npmjs.org/ajv/-/ajv-8.17.1.tgz", "integrity": "sha512-B/gBuNg5SiMTrPkC+A2+cW0RszwxYmn6VYxB/inlBStS5nx6xHIt/ehKRhIMhqusl7a8LjQoZnjCs5vhwxOQ1g==", - "dev": true, "license": "MIT", "dependencies": { "fast-deep-equal": "^3.1.3", @@ -14265,7 +14886,6 @@ "version": "5.1.0", "resolved": "https://registry.npmjs.org/ajv-keywords/-/ajv-keywords-5.1.0.tgz", "integrity": "sha512-YCS/JNFAUyr5vAuhk1DWm1CBxRHW9LbJ2ozWeemrIqpbsqKjHVxYPyi5GC0rjZIT5JxJ3virVTS8wk4i/Z+krw==", - "dev": true, "license": "MIT", "dependencies": { "fast-deep-equal": "^3.1.3" @@ -14278,14 +14898,12 @@ "version": "1.0.0", "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-1.0.0.tgz", "integrity": "sha512-NM8/P9n3XjXhIZn1lLhkFaACTOURQXjWhV4BA/RnOv8xvgqtqpAX9IO4mRQxSx1Rlo4tqzeqb0sOlruaOy3dug==", - "dev": true, "license": "MIT" }, "node_modules/webpack/node_modules/schema-utils": { "version": "4.3.3", "resolved": "https://registry.npmjs.org/schema-utils/-/schema-utils-4.3.3.tgz", "integrity": "sha512-eflK8wEtyOE6+hsaRVPxvUKYCpRgzLqDTb8krvAsRIwOGlHoSgYLgBXoubGgLd2fT41/OUYdb48v4k4WWHQurA==", - "dev": true, "license": "MIT", "dependencies": { "@types/json-schema": "^7.0.9", @@ -14564,6 +15182,17 @@ "node": ">=8.0" } }, + "node_modules/xtend": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/xtend/-/xtend-4.0.2.tgz", + "integrity": "sha512-LKYU1iAXJXUgAXn9URjiu+MWhyUXHsvfp7mcuYm9dSUKK0/CjtrUwFAxD82/mCWbtLsGjFIad0wIsod4zrTAEQ==", + "dev": true, + "license": "MIT", + "optional": true, + "engines": { + "node": ">=0.4" + } + }, "node_modules/xterm": { "version": "4.19.0", "resolved": "https://registry.npmjs.org/xterm/-/xterm-4.19.0.tgz", diff --git a/package.json b/package.json index f248b80..62141aa 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "debugging-hub", - "productName": "debugging-hub", + "productName": "Debugging Hub", "version": "1.0.0", "description": "Debugging Hub is a desktop application designed as an all-in-one internal tool for CEs and Support teams to streamline and enhance the debugging process.", "main": ".webpack/main", @@ -20,6 +20,7 @@ "devDependencies": { "@electron-forge/cli": "^7.10.2", "@electron-forge/maker-deb": "^7.10.2", + "@electron-forge/maker-dmg": "^7.11.1", "@electron-forge/maker-rpm": "^7.10.2", "@electron-forge/maker-squirrel": "^7.10.2", "@electron-forge/maker-zip": "^7.10.2", @@ -28,6 +29,7 @@ "@electron-forge/plugin-webpack": "^7.10.2", "@electron/fuses": "^1.8.0", "@types/diff": "^7.0.2", + "@types/papaparse": "^5.5.2", "@types/pouchdb": "^6.4.2", "@types/react": "^19.2.7", "@types/react-dom": "^19.2.3", @@ -57,11 +59,13 @@ "copy-webpack-plugin": "^13.0.1", "electron-squirrel-startup": "^1.0.1", "electron-store": "^11.0.2", + "electron-updater": "^6.7.3", "form-data": "^4.0.5", "json-edit-react": "^1.29.0", "lodash": "^4.17.21", "monaco-editor": "^0.55.1", "monaco-types": "^0.1.0", + "papaparse": "^5.5.3", "rc-field-form": "^2.7.0", "react": "^19.2.0", "react-diff-view": "^3.3.2", @@ -73,6 +77,13 @@ "react-virtualized-auto-sizer": "^1.0.26", "react-window": "^2.2.3", "sugar-high": "^0.9.4", + "update-electron-app": "^3.1.2", "zod": "^4.3.5" + }, + "overrides": { + "react-diff-viewer": { + "react": "$react", + "react-dom": "$react-dom" + } } -} +} \ No newline at end of file diff --git a/src/assets/logo.png b/src/assets/logo.png new file mode 100644 index 0000000..17c70c8 Binary files /dev/null and b/src/assets/logo.png differ diff --git a/src/assets/logo.svg b/src/assets/logo.svg deleted file mode 100644 index 365c735..0000000 --- a/src/assets/logo.svg +++ /dev/null @@ -1,36 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/src/channelHandlers/browserstack-api.ts b/src/channelHandlers/browserstack-api.ts index 3bca8d7..94fd067 100644 --- a/src/channelHandlers/browserstack-api.ts +++ b/src/channelHandlers/browserstack-api.ts @@ -40,7 +40,39 @@ export const getAppAutomateSessionDetails: BrowserStackAPI['getAppAutomateSessio } export const getParsedAutomateTextLogs: BrowserStackAPI['getAutomateParsedTextLogs'] = async (session: AutomateSessionResponse) => { - const logs = await download(session.automation_session.logs); + // Check if this is a Playwright session by looking for playwright_logs_url + let logs: string; + let capabilities: any = {}; + + if (session.automation_session.playwright_logs_url) { + // This is a Playwright session + console.log("Detected Playwright session, extracting capabilities from session details"); + // For Playwright, extract capabilities from session details since logs format is different + capabilities = { + browserName: session.automation_session.browser, + browserVersion: session.automation_session.browser_version, + platformName: session.automation_session.os, + platformVersion: session.automation_session.os_version, + deviceName: session.automation_session.device, + projectName: session.automation_session.project_name, + buildName: session.automation_session.build_name, + sessionName: session.automation_session.name, + }; + console.log("Extracted Playwright capabilities:", capabilities); + + try { + logs = await download(session.automation_session.playwright_logs_url); + console.log("Successfully downloaded Playwright logs"); + } catch (error) { + console.warn("Failed to download Playwright logs, falling back to regular logs:", error); + logs = await download(session.automation_session.logs); + } + } else { + // This is a Selenium session, use regular logs + console.log("Detected Selenium session, using regular logs"); + logs = await download(session.automation_session.logs); + } + const lines = logs.split('\n'); const timestampRegex = /^\d{4}-\d{1,2}-\d{1,2} \d{1,2}:\d{1,2}:\d{1,2}:\d{1,3}/; @@ -58,7 +90,15 @@ export const getParsedAutomateTextLogs: BrowserStackAPI['getAutomateParsedTextLo } } - return parseAutomateTextLogs(entries); + const result = parseAutomateTextLogs(entries); + + // For Playwright sessions, override the capabilities with the extracted ones + if (session.automation_session.playwright_logs_url) { + result.capabilities = capabilities; + console.log("Final result capabilities for Playwright:", result.capabilities); + } + + return result; }; export const getAppAutomateParsedTextLogs: BrowserStackAPI['getAppAutomateParsedTextLogs'] = async (session: AutomateSessionResponse) => { diff --git a/src/channelHandlers/credentials-api.ts b/src/channelHandlers/credentials-api.ts index acf53e6..b7a8aec 100644 --- a/src/channelHandlers/credentials-api.ts +++ b/src/channelHandlers/credentials-api.ts @@ -4,16 +4,24 @@ import getStorage from "../storage"; import { safeStorage } from 'electron'; export const setBrowserStackCredentials: CredentialsAPI['setBrowserStackCredentials'] = async (type, username, accessKey) => { + let enccryptedUsername = username + let encryptedAccessKey = accessKey if (safeStorage.isEncryptionAvailable()) { - username = safeStorage.encryptString(username).toString('base64') - accessKey = safeStorage.encryptString(accessKey).toString('base64') + enccryptedUsername = safeStorage.encryptString(username).toString('base64') + encryptedAccessKey = safeStorage.encryptString(accessKey).toString('base64') } getStorage().set(type === 'admin' ? StorageKeys.bstackAdminCredentials : StorageKeys.bstackDemoCredentials, { - username, - accessKey, + username: enccryptedUsername, + accessKey: encryptedAccessKey, }) - CONFIG.adminUsername = username - CONFIG.adminAccessKey = accessKey + + if (type === 'admin') { + CONFIG.adminUsername = username + CONFIG.adminAccessKey = accessKey + } else { + CONFIG.demoUsername = username + CONFIG.demoAccessKey = accessKey + } } export const getBrowserStackCredentials: CredentialsAPI['getBrowserStackCredentials'] = async (type) => { diff --git a/src/global.d.ts b/src/global.d.ts index 5fc2a99..99dee80 100644 --- a/src/global.d.ts +++ b/src/global.d.ts @@ -78,14 +78,16 @@ declare global { created_at: string; // ISO timestamp browser_url: string; public_url: string; - appium_logs_url: string; video_url: string; browser_console_logs_url: string; har_logs_url: string; selenium_logs_url: string; selenium_telemetry_logs_url: string; - appium_logs_url: string, - device_logs_url: string, + playwright_logs_url: string; + session_terminal_logs_url: string; + build_terminal_logs_url: string; + appium_logs_url: string; + device_logs_url: string; app_details: { app_url: string, app_name: string, @@ -104,7 +106,7 @@ declare global { } interface ParsedTextLogsResult { - capabilities: any[]; + capabilities: any; requests: (ParsedTextLogsRequest | string)[]; responses: unknown[]; } diff --git a/src/index.ts b/src/index.ts index cddf23c..83b5eb0 100644 --- a/src/index.ts +++ b/src/index.ts @@ -8,7 +8,19 @@ import CONFIG from './constants/config'; import { mkdirSync } from 'fs' import { executeCommand, getAutomateSessionDetails, getParsedAutomateTextLogs, startBrowserStackSession, stopBrowserStackSession, getAutomateParsedSeleniumLogs, getAutomateParsedSessionLogs, getSeleniumLogs, getHarLogs, getAppAutomateSessionDetails, getAppAutomateParsedTextLogs, getAllUploadedApps, uploadApp, getAppAutomateNetworkLogs, getAppAutomateSessionCapabilities, getScannerSessionIds, getAppAutomateParsedAppiumLogs } from './channelHandlers/browserstack-api'; import { openExternalUrl, openAppPicker } from './channelHandlers/electron-api'; +import { updateElectronApp, UpdateSourceType } from 'update-electron-app'; +updateElectronApp({ + updateSource: { + type: UpdateSourceType.ElectronPublicUpdateService, + repo: 'browserstackce/debugging-hub', + }, + updateInterval: '1 hour', + +}) + +app.setName("Debugging Hub") +app.dock.setIcon(path.join(__dirname, 'assets', 'logo.png')); // This allows TypeScript to pick up the magic constants that's auto-generated by Forge's Webpack // plugin that tells the Electron app where to look for the Webpack-bundled app code (depending on @@ -28,11 +40,13 @@ if (require('electron-squirrel-startup')) { const createWindow = (): void => { // Create the browser window. const mainWindow = new BrowserWindow({ + title: 'Debugging Hub', height: 600, width: 800, webPreferences: { preload: MAIN_WINDOW_PRELOAD_WEBPACK_ENTRY, }, + icon: path.join(__dirname, 'images', 'logo.png'), }); // and load the index.html of the app. diff --git a/src/renderer/components/navbar.tsx b/src/renderer/components/navbar.tsx index c9450cc..640d5ea 100644 --- a/src/renderer/components/navbar.tsx +++ b/src/renderer/components/navbar.tsx @@ -1,7 +1,7 @@ export default function Navbar() { return (
- + Debugging Hub
) diff --git a/src/renderer/components/replay-tool/selenium-tool-page.tsx b/src/renderer/components/replay-tool/selenium-tool-page.tsx index 7ca7084..8e93357 100644 --- a/src/renderer/components/replay-tool/selenium-tool-page.tsx +++ b/src/renderer/components/replay-tool/selenium-tool-page.tsx @@ -95,7 +95,8 @@ type AppAutomateConfigurationFormProps = { } const FormInputValidatorApp = z.object({ - type: z.literal('app').default('app'), + //@ts-ignore + type: z.enum(['app']).default('app'), os: z.string({ error: "OS is required" }).nonempty({ error: "OS is required" }), osVersion: z.string({ error: "OS Version is required" }).nonempty({ error: "OS Version is required" }), device: z.string({ error: "Device is required" }).nonempty({ error: "Device is required" }), @@ -105,7 +106,8 @@ const FormInputValidatorApp = z.object({ }) const FormInpitValidorWeb = z.object({ - type: z.literal('web').default('web'), + //@ts-ignore + type: z.enum(['web']).default('web'), os: z.string({ error: "OS is required" }).nonempty({ error: "OS is required" }), osVersion: z.string({ error: "OS Version is required" }).nonempty({ error: "OS Version is required" }), device: z.string().optional(), diff --git a/src/renderer/products.ts b/src/renderer/products.ts index 8be2370..46b1c1b 100644 --- a/src/renderer/products.ts +++ b/src/renderer/products.ts @@ -6,6 +6,7 @@ import AppAutomateSessionComparison from "./routes/app-automate/tools/session-co import SDKLogsDownloader from "./routes/test-reporting-and-analytics/tools/sdk-logs-downloader"; import SessionFinder from "./routes/website-scanner/tools/session-finder"; import AppLatencyFinder from "./routes/app-automate/tools/latency-finder"; +import CsvImportErrorAnalyser from "./routes/test-management/tools/csv-import-error-analyser"; const Products: { name: string @@ -115,7 +116,7 @@ const Products: { title: "CSV Import Error Analyser", description: "Analyse errors in CSV file imported.", path: "/test-management/csv-import-error-analyser", - component: null, + component: CsvImportErrorAnalyser, }, ], }, diff --git a/src/renderer/routes/automate/tools/session-comparison/components/SessionDiffView.tsx b/src/renderer/routes/automate/tools/session-comparison/components/SessionDiffView.tsx index 69e62bc..bc5b7f0 100644 --- a/src/renderer/routes/automate/tools/session-comparison/components/SessionDiffView.tsx +++ b/src/renderer/routes/automate/tools/session-comparison/components/SessionDiffView.tsx @@ -86,8 +86,8 @@ export default function SessionDiffView({ const infoStrB = createInfoString(sessionB); const nameA = sessionA?.automation_session?.name || "Unnamed Session A"; const nameB = sessionB?.automation_session?.name || "Unnamed Session B"; - const capsStrA = JSON.stringify(logsA?.capabilities?.[0] || {}, null, 2); - const capsStrB = JSON.stringify(logsB?.capabilities?.[0] || {}, null, 2); + const capsStrA = JSON.stringify(logsA?.capabilities || {}, null, 2); + const capsStrB = JSON.stringify(logsB?.capabilities || {}, null, 2); const tabs = [ { id: 'info', label: 'Session Info' }, diff --git a/src/renderer/routes/automate/tools/session-comparison/types.ts b/src/renderer/routes/automate/tools/session-comparison/types.ts index 5d1ceb1..d71f9e8 100644 --- a/src/renderer/routes/automate/tools/session-comparison/types.ts +++ b/src/renderer/routes/automate/tools/session-comparison/types.ts @@ -32,7 +32,7 @@ export interface SessionData { } export interface TextLogsResult { - capabilities: any[]; + capabilities: any; [key: string]: any; } diff --git a/src/renderer/routes/automate/tools/session-comparison/utils/sanitization.ts b/src/renderer/routes/automate/tools/session-comparison/utils/sanitization.ts index b563c51..40f77ad 100644 --- a/src/renderer/routes/automate/tools/session-comparison/utils/sanitization.ts +++ b/src/renderer/routes/automate/tools/session-comparison/utils/sanitization.ts @@ -38,27 +38,38 @@ export function sanitizeTextLogs(textLogsResult: any) { const sanitized = JSON.parse(JSON.stringify(textLogsResult)); - if (Array.isArray(sanitized.capabilities)) { - sanitized.capabilities.forEach((cap: any) => { - if (cap?.[BSTACK_OPTIONS_PATH]?.[ACCESSIBILITY_OPTIONS_PATH]?.[AUTH_TOKEN_KEY]) { - cap[BSTACK_OPTIONS_PATH][ACCESSIBILITY_OPTIONS_PATH][AUTH_TOKEN_KEY] = REDACTED_VALUE; - } + // Handle both array format (Selenium) and object format (Playwright) + const capabilities = sanitized.capabilities; + + if (Array.isArray(capabilities)) { + // Selenium format - array of capability objects + capabilities.forEach((cap: any) => { + sanitizeCapabilityObject(cap); + }); + } else if (typeof capabilities === 'object' && capabilities !== null) { + // Playwright format - single capability object + sanitizeCapabilityObject(capabilities); + } - const alwaysMatch = cap.W3C_capabilities?.alwaysMatch; - if (alwaysMatch?.[BSTACK_OPTIONS_PATH]?.[ACCESSIBILITY_OPTIONS_PATH]?.[AUTH_TOKEN_KEY]) { - alwaysMatch[BSTACK_OPTIONS_PATH][ACCESSIBILITY_OPTIONS_PATH][AUTH_TOKEN_KEY] = REDACTED_VALUE; - } + return sanitized; +} - const firstMatch = cap.W3C_capabilities?.firstMatch; - if (Array.isArray(firstMatch)) { - firstMatch.forEach((match: any) => { - if (match?.[BSTACK_OPTIONS_PATH]?.[ACCESSIBILITY_OPTIONS_PATH]?.[AUTH_TOKEN_KEY]) { - match[BSTACK_OPTIONS_PATH][ACCESSIBILITY_OPTIONS_PATH][AUTH_TOKEN_KEY] = REDACTED_VALUE; - } - }); +function sanitizeCapabilityObject(cap: any) { + if (cap?.[BSTACK_OPTIONS_PATH]?.[ACCESSIBILITY_OPTIONS_PATH]?.[AUTH_TOKEN_KEY]) { + cap[BSTACK_OPTIONS_PATH][ACCESSIBILITY_OPTIONS_PATH][AUTH_TOKEN_KEY] = REDACTED_VALUE; + } + + const alwaysMatch = cap.W3C_capabilities?.alwaysMatch; + if (alwaysMatch?.[BSTACK_OPTIONS_PATH]?.[ACCESSIBILITY_OPTIONS_PATH]?.[AUTH_TOKEN_KEY]) { + alwaysMatch[BSTACK_OPTIONS_PATH][ACCESSIBILITY_OPTIONS_PATH][AUTH_TOKEN_KEY] = REDACTED_VALUE; + } + + const firstMatch = cap.W3C_capabilities?.firstMatch; + if (Array.isArray(firstMatch)) { + firstMatch.forEach((match: any) => { + if (match?.[BSTACK_OPTIONS_PATH]?.[ACCESSIBILITY_OPTIONS_PATH]?.[AUTH_TOKEN_KEY]) { + match[BSTACK_OPTIONS_PATH][ACCESSIBILITY_OPTIONS_PATH][AUTH_TOKEN_KEY] = REDACTED_VALUE; } }); } - - return sanitized; } diff --git a/src/renderer/routes/test-management/index.tsx b/src/renderer/routes/test-management/index.tsx new file mode 100644 index 0000000..0886b73 --- /dev/null +++ b/src/renderer/routes/test-management/index.tsx @@ -0,0 +1,43 @@ +import { NavLink } from "react-router-dom" + +export default function TestManagementPage(props: ProductPageProps) { + const { tools } = props + + return ( +
+
+ {tools.map((tool) => { + const isComingSoon = tool.component === null + + const Card = ( +
+
+

+ {tool.title} +

+

{tool.description}

+
+ {isComingSoon && ( + + Coming soon + + )} +
+
+
+ ) + + return isComingSoon ? ( +
+ {Card} +
+ ) : ( + + {Card} + + ) + })} +
+
+ ) +} diff --git a/src/renderer/routes/test-management/tools/csv-import-error-analyser.tsx b/src/renderer/routes/test-management/tools/csv-import-error-analyser.tsx new file mode 100644 index 0000000..b0ce6b1 --- /dev/null +++ b/src/renderer/routes/test-management/tools/csv-import-error-analyser.tsx @@ -0,0 +1,221 @@ +import { useState } from "react"; +import Papa from "papaparse"; + +type CSVError = { + row?: number; + column?: string; + message: string; +}; + +const SUPPORTED_DELIMITERS = [ + { label: "Comma (,)", value: "," }, + { label: "Semicolon (;)", value: ";" }, + { label: "Colon (:)", value: ":" }, + { label: "Pipe (|)", value: "|" }, + { label: "Tab (\\t)", value: "\t" }, + { label: "Space ( )", value: " " }, +]; + +export default function CsvImportErrorAnalyser() { + const [csvErrors, setCsvErrors] = useState([]); + const [loading, setLoading] = useState(false); + const [fileName, setFileName] = useState(null); + const [selectedDelimiter, setSelectedDelimiter] = useState(","); + const [rawText, setRawText] = useState(null); + + // Stats to help identify if the delimiter is wrong + const [stats, setStats] = useState({ rows: 0, cols: 0 }); + + const validateCSVContent = (csvText: string, delimiter: string): CSVError[] => { + const errors: CSVError[] = []; + + const parsed = Papa.parse>(csvText, { + header: true, + delimiter: delimiter, + skipEmptyLines: true, + }); + + const rows = parsed.data; + const headers = parsed.meta.fields || []; + + // Update stats for the UI logic + setStats({ + rows: rows.length, + cols: headers.length + }); + + if (parsed.errors.length) { + parsed.errors.forEach((e) => + errors.push({ + row: e.row ? e.row + 1 : undefined, + message: `Parse error: ${e.message}`, + }) + ); + } + + if (!headers.length) { + errors.push({ message: "CSV file has no header row or wrong delimiter selected." }); + return errors; + } + + // Column consistency check + rows.forEach((row, i) => { + if (Object.keys(row).length !== headers.length) { + errors.push({ + row: i + 2, + message: "Column count mismatch. Ensure you selected the correct delimiter.", + }); + } + }); + + // Duplicate Test Case ID check + const testCaseIdHeader = headers.find((h) => h.toLowerCase() === "test case id"); + if (testCaseIdHeader) { + const seen = new Set(); + rows.forEach((row, i) => { + const value = row[testCaseIdHeader]; + if (value) { + if (seen.has(value)) { + errors.push({ + row: i + 2, + column: testCaseIdHeader, + message: `Duplicate Test Case ID found: ${value}`, + }); + } + seen.add(value); + } + }); + } + + return errors; + }; + + const handleFileUpload = async (file: File) => { + // FIX: Guard clause to prevent error when user cancels file selection + if (!file) return; + + setLoading(true); + setFileName(file.name); + try { + const text = await file.text(); + setRawText(text); + setCsvErrors(validateCSVContent(text, selectedDelimiter)); + } catch (err) { + console.error("Error reading file:", err); + } finally { + setLoading(false); + } + }; + + const handleDelimiterChange = (newDelimiter: string) => { + setSelectedDelimiter(newDelimiter); + if (rawText) { + setCsvErrors(validateCSVContent(rawText, newDelimiter)); + } + }; + + // Logic to determine if we should show the "Wrong Delimiter" warning + // Triggers if file is parsed but results in only 1 column or 1 row + const showDelimiterWarning = fileName && !loading && (stats.cols <= 1 || stats.rows <= 1); + + return ( +
+

CSV Import Error Analyser

+ +
+ {/* Delimiter Dropdown */} +
+ + +
+ + {/* Upload Button */} +
+ + + { + if (e.target.files && e.target.files.length > 0) { + handleFileUpload(e.target.files[0]); + } + }} + /> +
+
+ + {fileName && ( +
+ File: {fileName} | + Detected: {stats.rows} rows, {stats.cols} columns +
+ )} + + {/* DELIMITER WARNING BOX */} + {showDelimiterWarning && ( +
+
+

+ ⚠️ Possible Delimiter Mismatch +

+

+ The uploaded CSV has just {stats.rows} row(s) and {stats.cols} column(s). + This usually happens when the wrong delimiter is selected. + Please double check that you are using the correct delimiter. +

+
+
+ )} + +
+ + {/* Results Section */} +
+ {loading &&

Analysing CSV…

} + + {!loading && csvErrors.length === 0 && fileName && !showDelimiterWarning && ( +
+ No errors found. The file looks good with the selected delimiter! +
+ )} + + {!loading && csvErrors.length > 0 && ( +
+

+ Found {csvErrors.length} issues +

+
+
    + {csvErrors.map((err, idx) => ( +
  • + {err.row && Row {err.row}} + {err.column && ` [Column: ${err.column}] `} + {": "}{err.message} +
  • + ))} +
+
+
+ )} +
+
+ ); +} \ No newline at end of file diff --git a/src/utils/text-logs-parser.ts b/src/utils/text-logs-parser.ts index a7c68c1..6c64db4 100644 --- a/src/utils/text-logs-parser.ts +++ b/src/utils/text-logs-parser.ts @@ -2,109 +2,123 @@ const buildCapabilities = (line: string[]) => { try { - let caps = JSON.parse(line[1]); - caps = caps.desiredCapabilities ? caps.desiredCapabilities : caps - const keysToRemove = [ - // --- Platform & Environment --- - "os", - "os_version", - "osVersion", - "bstack:options.os", - "bstack:options.osVersion", - "bstack:options.os_version", - "device", - "deviceName", - "appium:deviceName", - "bstack:options.device", - "bstack:options.deviceName", - "platformName", - "bstack:options.platformName", - "appium:platformVersion", - "platformVersion", // Added - - // --- Browser Identification --- - "browserName", - "browser_version", // Added - "browserVersion", // Added - "bstack:options.browser", - "bstack:options.browserName", // Added - "bstack:options.browserVersion", - - // --- App Automation Specifics --- - "app", - "appium:app", - "bstack:options.app", - "appium:appPackage", // Added - "appium:appActivity", // Added - "appium:bundleId", // Added - "appium:automationName", // Added - - // --- BrowserStack Local & Networking --- - "bstack:options.local", - "browserstack.local", // Added - "bstack:options.localIdentifier", - "bstack:options.localIdentifier.app", - "acceptInsecureCerts", // Added - - // --- Metadata & Internal SDK Flags --- - "W3C_capabilities", - "new_bucketing", - "detected_language", - "browserstack.source", - "bstack:options.browserstackSDK", - "browserstack.browserstackSDK", - "bstack:options.hostName", - - // --- Build & Reporting --- - "bstack:options.testhubBuildUuid", - "bstack:options.buildProductMap", - "browserstack.buildProductMap", - "projectName", // Added - "buildName", // Added - "sessionName", // Added - "bstack:options.projectName", // Added - "bstack:options.buildName", // Added - "bstack:options.sessionName", // Added - "browserstack.project", // Added - "browserstack.build", // Added - "browserstack.name", // Added - - // --- Features & Debugging --- - "bstack:options.accessibility", - "bstack:options.accessibilityOptions", - "bstack:options.debug", // Added - "bstack:options.networkLogs", // Added - "bstack:options.video", // Added - "bstack:options.consoleLogs", // Added - "bstack:options.seleniumVersion", // Added - - // --- Security / Credentials --- - "browserstack.user", // Added - "browserstack.key", // Added - "bstack:options.userName", // Added - "bstack:options.accessKey" // Added - ]; - for (const key of keysToRemove) { - // Handle dot notation like "bstack:options.testhubBuildUuid" - if (key.includes(".")) { - const parts = key.split("."); - const parentKey = parts[0]; - const childKey = parts[1]; - - if ( - caps[parentKey] && - typeof caps[parentKey] === "object" - ) { - delete caps[parentKey][childKey]; - } else { - delete caps[key] + // Check if this looks like a Selenium log with JSON after /session + if (line.length > 1 && line[1]) { + try { + let caps = JSON.parse(line[1]); + caps = caps.desiredCapabilities ? caps.desiredCapabilities : caps + const keysToRemove = [ + // --- Platform & Environment --- + "os", + "os_version", + "osVersion", + "bstack:options.os", + "bstack:options.osVersion", + "bstack:options.os_version", + "device", + "deviceName", + "appium:deviceName", + "bstack:options.device", + "bstack:options.deviceName", + "platformName", + "bstack:options.platformName", + "appium:platformVersion", + "platformVersion", // Added + + // --- Browser Identification --- + "browserName", + "browser_version", // Added + "browserVersion", // Added + "bstack:options.browser", + "bstack:options.browserName", // Added + "bstack:options.browserVersion", + + // --- App Automation Specifics --- + "app", + "appium:app", + "bstack:options.app", + "appium:appPackage", // Added + "appium:appActivity", // Added + "appium:bundleId", // Added + "appium:automationName", // Added + + // --- BrowserStack Local & Networking --- + "bstack:options.local", + "browserstack.local", // Added + "bstack:options.localIdentifier", + "bstack:options.localIdentifier.app", + "acceptInsecureCerts", // Added + + // --- Metadata & Internal SDK Flags --- + "W3C_capabilities", + "new_bucketing", + "detected_language", + "browserstack.source", + "bstack:options.browserstackSDK", + "browserstack.browserstackSDK", + "bstack:options.hostName", + + // --- Build & Reporting --- + "bstack:options.testhubBuildUuid", + "bstack:options.buildProductMap", + "browserstack.buildProductMap", + "projectName", // Added + "buildName", // Added + "sessionName", // Added + "bstack:options.projectName", // Added + "bstack:options.buildName", // Added + "bstack:options.sessionName", // Added + "browserstack.project", // Added + "browserstack.build", // Added + "browserstack.name", // Added + + // --- Features & Debugging --- + "bstack:options.accessibility", + "bstack:options.accessibilityOptions", + "bstack:options.debug", // Added + "bstack:options.networkLogs", // Added + "bstack:options.video", // Added + "bstack:options.consoleLogs", // Added + "bstack:options.seleniumVersion", // Added + + // --- Security / Credentials --- + "browserstack.user", // Added + "browserstack.key", // Added + "bstack:options.userName", // Added + "bstack:options.accessKey" // Added + ]; + for (const key of keysToRemove) { + // Handle dot notation like "bstack:options.testhubBuildUuid" + if (key.includes(".")) { + const parts = key.split("."); + const parentKey = parts[0]; + const childKey = parts[1]; + + if ( + caps[parentKey] && + typeof caps[parentKey] === "object" + ) { + delete caps[parentKey][childKey]; + } else { + delete caps[key] + } + } else { + // Remove top-level key + delete caps[key]; + } } - } else { - // Remove top-level key - delete caps[key]; + return caps; + } catch (e) { + // JSON parsing failed, this might be a Playwright log + // Return empty capabilities for Playwright logs + console.warn("Failed to parse capabilities from log line, treating as Playwright log:", line[1]); + return {}; } + } else { + // No second element, likely a Playwright log or malformed Selenium log + console.warn("No capabilities found in log line, treating as Playwright log:", line); + return {}; } - return caps; } catch { throw new Error("Failed to parse Capabilities: " + line[1]) } @@ -260,14 +274,32 @@ export const parseAutomateTextLogs = (lines: string[]): ParsedTextLogsResult => if ([1, 2, 3].includes(i)) return; if (i === 0) { - capabilities = buildCapabilities(line.split("/session")); + try { + capabilities = buildCapabilities(line.split("/session")); + } catch (error) { + console.warn("Failed to parse capabilities from first line, assuming Playwright session:", error); + capabilities = {}; + } return; } const parts = line.split(" "); + + // Check if we have enough parts for the expected format + if (parts.length < 3) { + // Likely a Playwright log or malformed line, skip it + return; + } + const requestType = parts[2]; if (requestType === "REQUEST") { + // Check if we have enough parts for REQUEST format + if (parts.length < 7) { + // Malformed REQUEST line, skip it + return; + } + if (timeLastResponse !== undefined) { const timeRequest = Date.parse(`${parts[0]} ${parts[1]}`); const sleepTime = Math.floor((timeRequest - timeLastResponse) / 1000); @@ -287,6 +319,12 @@ export const parseAutomateTextLogs = (lines: string[]): ParsedTextLogsResult => requests.push({ method, endpoint, data, commandName }); } else if (requestType === "RESPONSE") { + // Check if we have enough parts for RESPONSE format + if (parts.length < 4) { + // Malformed RESPONSE line, skip it + return; + } + try { const json = JSON.parse(parts.slice(3).join(" ")); responses.push(json.value);