diff --git a/.circleci/config.yml b/.circleci/config.yml index afe5c5576b..1502767549 100644 --- a/.circleci/config.yml +++ b/.circleci/config.yml @@ -105,6 +105,51 @@ jobs: paths: - "persist" + test-remixdesktop-linux: + machine: + image: ubuntu-2004:current + resource_class: + xlarge + working_directory: ~/remix-project + parallelism: 10 + steps: + - run: ldd --version + - checkout + - attach_workspace: + at: . + - run: unzip ./persist/desktopbuild.zip + - run: + command: | + nvm install 20.2 + nvm use 20.2 + node -v + npm install --global yarn node-gyp + python -m pip install --upgrade pip + pip install setuptools + mkdir apps/remixdesktop/build + cp -r dist/apps/remix-ide apps/remixdesktop/build + cd apps/remixdesktop/ + yarn add node-pty + yarn --ignore-optional + yarn add @remix-project/remix-ws-templates + ./rundist.bash + - run: + name: "Run tests" + command: | + nvm use 20.2 + cd apps/remixdesktop/ + ./run_ci_test.sh + - run: + name: "Run isogit tests" + command: | + nvm use 20.2 + cd apps/remixdesktop/ + ./run_git_ui_isogit_tests.sh + - store_test_results: + path: ./apps/remixdesktop/reports/tests + - store_artifacts: + path: ./apps/remixdesktop/reports/screenshots + build-remixdesktop-linux: machine: image: ubuntu-2004:current @@ -119,22 +164,37 @@ jobs: - run: unzip ./persist/desktopbuild.zip - run: command: | + nvm install 20.2 + nvm use 20.2 node -v + npm install --global yarn node-gyp + python -m pip install --upgrade pip + pip install setuptools mkdir apps/remixdesktop/build cp -r dist/apps/remix-ide apps/remixdesktop/build cd apps/remixdesktop/ yarn add node-pty yarn --ignore-optional yarn add @remix-project/remix-ws-templates - PUBLISH_FOR_PULL_REQUEST='true' yarn dist + ./rundist.bash rm -rf release/*-unpacked - save_cache: key: remixdesktop-linux-deps-{{ checksum "apps/remixdesktop/yarn.lock" }} paths: - apps/remixdesktop/node_modules + - run: + name: "remove unnecessary files" + command: | + rm -rf ~/remix-project/apps/remixdesktop/release/.icon* + rm -rf ~/remix-project/apps/remixdesktop/release/builder* - store_artifacts: path: apps/remixdesktop/release/ destination: remixdesktop-linux + - persist_to_workspace: + root: apps/remixdesktop + paths: + - "release" + build-remixdesktop-windows: executor: @@ -147,39 +207,107 @@ jobs: - attach_workspace: at: . - run: unzip ./persist/desktopbuild.zip - - restore_cache: - key: node-20-windows-v3 + - run: command: | - nvm install 20.0.0 - nvm use 20.0.0 + nvm install 20.2 + nvm use 20.2 node -v npx -v npm install --global yarn + npm install --global node-gyp yarn -v - - save_cache: - key: node-20-windows-v3 - paths: - - /ProgramData/nvm/v20.0.0 - - restore_cache: - keys: - - remixdesktop-windows-deps-{{ checksum "apps/remixdesktop/yarn.lock" }} + - run: command: | mkdir apps/remixdesktop/build cp -r dist/apps/remix-ide apps/remixdesktop/build cd apps/remixdesktop/ + python -m pip install --upgrade pip + pip install setuptools yarn - PUBLISH_FOR_PULL_REQUEST='true' yarn dist + ./rundist.bash rm -rf release/*-unpacked - - save_cache: - key: remixdesktop-windows-deps-{{ checksum "apps/remixdesktop/yarn.lock" }} - paths: - - apps/remixdesktop/node_modules + - persist_to_workspace: root: apps/remixdesktop paths: - "release" + + test-remixdesktop-windows: + executor: + name: win/default # executor type + size: xlarge # can be medium, large, xlarge, 2xlarge + shell: bash.exe + parallelism: 10 + working_directory: ~/remix-project + steps: + - run: + name: Restart local mstsc + command: psexec64.exe -accepteula -nobanner -i 0 mstsc /v:localhost /w:2560 /h:1140 + background: true + shell: powershell.exe + - run: + name: Naive impl to wait until the screen stretches + command: Start-Sleep 5 + shell: powershell.exe + - run: + name: Get screen info + command: | + Add-Type -AssemblyName System.Windows.Forms + [System.Windows.Forms.Screen]::AllScreens | fl * + shell: powershell.exe + - checkout + - attach_workspace: + at: . + - run: unzip ./persist/desktopbuild.zip + + - run: + command: | + nvm install 20.2 + nvm use 20.2 + node -v + npx -v + npm install --global yarn + npm install --global node-gyp + yarn -v + - run: + name: start selenium + command: | + cd "apps/remixdesktop/" + yarn -v + shell: powershell.exe + + - run: + command: | + mkdir apps/remixdesktop/build + cp -r dist/apps/remix-ide apps/remixdesktop/build + cd apps/remixdesktop/ + nvm use 20.2 + node -v + python -m pip install --upgrade pip + pip install setuptools + yarn + ./rundist.bash + - run: + name: run tests + command: | + cd "apps/remixdesktop/" + yarn -v + sleep 15 + ./run_ci_test.sh + - run: + name: "Run isogit tests" + command: | + cd apps/remixdesktop/ + yarn -v + sleep 15 + ./run_git_ui_isogit_tests.sh + - store_test_results: + path: ./apps/remixdesktop/reports/tests + - store_artifacts: + path: ./apps/remixdesktop/reports/screenshots + # see https://docs.digicert.com/en/software-trust-manager/ci-cd-integrations/script-integrations/github-integration-ksp.html sign-remixdesktop-windows: executor: win/default # executor type @@ -230,28 +358,66 @@ jobs: command: | Get-ChildItem -Path 'C:\Program Files (x86)\Windows Kits\10\App Certification Kit' -Filter signtool.exe -Recurse - run: - name: "Signtool-Signing" + name: read env shell: powershell.exe command: | - & $env:Signtool sign /sha1 $env:SM_CODE_SIGNING_CERT_SHA1_HASH /tr http://timestamp.digicert.com /td SHA256 /fd SHA256 $env:RemixSetupExe + # Specify the path to your package.json file + $packageJsonPath = "C:\Users\circleci\remix-project\apps\remixdesktop\package.json" + + # Check if the file exists + if (Test-Path $packageJsonPath) { + # Read the content of the package.json file + $packageJsonContent = Get-Content $packageJsonPath -Raw | ConvertFrom-Json + + # Check if the 'version' field exists in the package.json + if ($packageJsonContent.'version' -ne $null) { + # Store the version value in an environment variable + $version = $packageJsonContent.version + $file = "C:\Users\circleci\remix-project\release\Remix-Desktop-Setup-$($version).exe" + Write-Host "Version $(file) stored in PACKAGE_VERSION environment variable." + "Set-Variable -Name 'PACKAGE_VERSION' -Value '$file' -Scope Global" > SetEnvVars.ps1 + dir Env: + } else { + Write-Host "Error: 'version' field not found in package.json." + } + } else { + Write-Host "Error: package.json file not found at $packageJsonPath." + } + - run: + name: "Signtool-Signing" + shell: powershell.exe + command: | + . .\SetEnvVars.ps1 + dir Env: + & $env:Signtool sign /sha1 $env:SM_CODE_SIGNING_CERT_SHA1_HASH /tr http://timestamp.digicert.com /td SHA256 /fd SHA256 $PACKAGE_VERSION - run: name: "Signtool-Verification" shell: powershell.exe command: | - $verify_output = $(& $env:Signtool verify /v /pa $env:RemixSetupExe) + . .\SetEnvVars.ps1 + $verify_output = $(& $env:Signtool verify /v /pa $PACKAGE_VERSION) echo ${verify_output} if (!$verify_output.Contains("Number of files successfully Verified: 1")) { echo 'Verification failed' exit 1 } + - run: + name: "remove unnecessary files" + shell: bash.exe + command: | + rm -rf ~/remix-project/release/.icon* + rm -rf ~/remix-project/release/builder* - store_artifacts: path: ~/remix-project/release/ destination: remixdesktop-windows + - persist_to_workspace: + root: ~/remix-project/ + paths: + - "release" environment: SM_CLIENT_CERT_FILE: 'C:\Certificate_pkcs12.p12' Signtool: 'C:\Program Files (x86)\Windows Kits\10\App Certification Kit\signtool.exe' SSM: 'C:\Program Files\DigiCert\DigiCert One Signing Manager Tools' - RemixSetupExe: 'C:\Users\circleci\remix-project\release\Remix IDE.exe' build-remixdesktop-mac: macos: @@ -259,23 +425,41 @@ jobs: resource_class: macos.m1.large.gen1 working_directory: ~/remix-project + parameters: + arch: + type: string steps: - checkout - attach_workspace: at: . + - run: + name: Install Apple Certificate + command: | + echo $APPLE_CERTIFICATE_BASE64 | base64 --decode > /tmp/certificate.p12 + security create-keychain -p ci-password build.keychain + security default-keychain -s build.keychain + security unlock-keychain -p ci-password build.keychain + curl -o DeveloperIDG2CA.cer "https://www.apple.com/certificateauthority/DeveloperIDG2CA.cer" + sudo security import DeveloperIDG2CA.cer -k /Library/Keychains/System.keychain -T /usr/bin/codesign + sudo security add-trusted-cert -d -r trustRoot -k /Library/Keychains/System.keychain DeveloperIDG2CA.cer + security import /tmp/certificate.p12 -k build.keychain -P $APPLE_CERTIFICATE_PASSWORD -T /usr/bin/codesign + security set-key-partition-list -S apple-tool:,apple: -s -k ci-password build.keychain + security find-identity -v -p codesigning - run: unzip ./persist/desktopbuild.zip - run: command: | ls -la dist/apps/remix-ide - nvm install 20.0.0 - nvm use 20.0.0 + nvm install 20.2 + nvm use 20.2 - restore_cache: keys: - remixdesktop-deps-mac-{{ checksum "apps/remixdesktop/yarn.lock" }} - run: command: | - nvm use 20.0.0 - cd apps/remixdesktop && yarn + nvm use 20.2 + cd apps/remixdesktop + yarn || yarn + find ./node_modules yarn add @remix-project/remix-ws-templates - save_cache: key: remixdesktop-deps-mac-{{ checksum "apps/remixdesktop/yarn.lock" }} @@ -284,20 +468,120 @@ jobs: # use USE_HARD_LINK=false https://github.com/electron-userland/electron-builder/issues/3179 - run: command: | - nvm use 20.0.0 + nvm use 20.2 mkdir apps/remixdesktop/build cp -r dist/apps/remix-ide apps/remixdesktop/build cd apps/remixdesktop yarn - yarn installRipGrepMacOXarm64 - PUBLISH_FOR_PULL_REQUEST='true' USE_HARD_LINKS=false yarn dist --mac --arm64 - yarn installRipGrepMacOXx64 - PUBLISH_FOR_PULL_REQUEST='true' USE_HARD_LINKS=false yarn dist --mac --x64 - rm -rf release/mac* + - run: + command: | + nvm use 20.2 + cd apps/remixdesktop + yarn installRipGrepMacOX<< parameters.arch >> + PUBLISH_FOR_PULL_REQUEST='false' USE_HARD_LINKS=false ./rundist.bash --<< parameters.arch >> + if [ -f release/latest-mac.yml ]; then + cat release/latest-mac.yml + mv release/latest-mac.yml release/latest-mac-<< parameters.arch >>.yml + fi + find build + - run: + name: Notarize the app + command: | + brew install jq + cd apps/remixdesktop + zsh notarizedmg.sh + - run: + name: "remove unnecessary files" + command: | + rm -rf ~/remix-project/apps/remixdesktop/release/.icon* + rm -rf ~/remix-project/apps/remixdesktop/release/builder* + rm -rf ~/remix-project/apps/remixdesktop/release/*.blockmap + rm -rf ~/remix-project/apps/remixdesktop/release/_.* - store_artifacts: path: apps/remixdesktop/release/ destination: remixdesktop-mac - + - persist_to_workspace: + root: apps/remixdesktop + paths: + - "release" + test-remixdesktop-mac: + macos: + xcode: 14.2.0 + resource_class: + macos.m1.large.gen1 + working_directory: ~/remix-project + parallelism: 10 + steps: + - checkout + - attach_workspace: + at: . + - run: unzip ./persist/desktopbuild.zip + - run: + command: | + ls -la dist/apps/remix-ide + nvm install 20.2 + nvm use 20.2 + - restore_cache: + keys: + - remixdesktop-deps-mac-{{ checksum "apps/remixdesktop/yarn.lock" }} + - run: + command: | + nvm use 20.2 + cd apps/remixdesktop + yarn || yarn + yarn add @remix-project/remix-ws-templates + - save_cache: + key: remixdesktop-deps-mac-{{ checksum "apps/remixdesktop/yarn.lock" }} + paths: + - apps/remixdesktop/node_modules + - run: + command: | + nvm use 20.2 + mkdir apps/remixdesktop/build + cp -r dist/apps/remix-ide apps/remixdesktop/build + cd apps/remixdesktop + yarn + - run: + command: | + nvm use 20.2 + cd apps/remixdesktop + yarn installRipGrepMacOXarm64 + PUBLISH_FOR_PULL_REQUEST='false' DO_NOT_NOTARIZE='true' USE_HARD_LINKS=false ./rundist.bash --arm64 + find build + - run: + name: "Run tests" + command: | + nvm use 20.2 + cd apps/remixdesktop + ./run_ci_test.sh + - run: + name: "Run isogit tests" + command: | + nvm use 20.2 + cd apps/remixdesktop + ./run_git_ui_isogit_tests.sh + - store_test_results: + path: ./apps/remixdesktop/reports/tests + - store_artifacts: + path: ./apps/remixdesktop/reports/screenshots + + uploadartifacts: + docker: + - image: cimg/node:20.0.0-browsers + resource_class: + xlarge + working_directory: ~/remix-project + steps: + - checkout + - attach_workspace: + at: . + - restore_cache: + keys: + - v1-deps-{{ checksum "yarn.lock" }} + - run: yarn + - run: + name: "Upload Artifacts" + command: npx ts-node apps/remix-ide/ci/update_desktop_release_assets.ts lint: docker: - image: cimg/node:20.0.0-browsers @@ -508,6 +792,12 @@ workflows: - build-remixdesktop-mac: requires: - build-desktop + matrix: + parameters: + arch: ["arm64", "x64"] + - test-remixdesktop-mac: + requires: + - build-desktop - build-remixdesktop-windows: requires: - build-desktop @@ -517,6 +807,20 @@ workflows: - build-remixdesktop-linux: requires: - build-desktop + - test-remixdesktop-linux: + requires: + - build-desktop + - test-remixdesktop-windows: + requires: + - build-desktop + - uploadartifacts: + requires: + - build-remixdesktop-mac + - build-remixdesktop-linux + - sign-remixdesktop-windows + - test-remixdesktop-windows + - test-remixdesktop-linux + - test-remixdesktop-mac - build-plugin: matrix: parameters: diff --git a/.gitignore b/.gitignore index ef8b36916c..a7d7b01cf4 100644 --- a/.gitignore +++ b/.gitignore @@ -15,6 +15,7 @@ soljson.js *_group*.*.ts *_group*.ts stats.json +release # compiled output @@ -61,6 +62,7 @@ testem.log apps/remixdesktop/.webpack apps/remixdesktop/out apps/remixdesktop/release/ +apps/remixdesktop/build*/ apps/remix-ide/src/assets/list.json apps/remix-ide/src/assets/esbuild.wasm apps/remixdesktop/build* diff --git a/apps/remix-ide-e2e/src/commands/addLocalPlugin.ts b/apps/remix-ide-e2e/src/commands/addLocalPlugin.ts index 51358b730f..492a44dfee 100644 --- a/apps/remix-ide-e2e/src/commands/addLocalPlugin.ts +++ b/apps/remix-ide-e2e/src/commands/addLocalPlugin.ts @@ -24,7 +24,7 @@ function addLocalPlugin (browser: NightwatchBrowser, profile: Profile & Location browser.waitForElementVisible('*[data-id="pluginManagerComponentPluginManager"]') .execute(function () { - window.testmode = true + (window as any).testmode = true }) .click('*[data-id="pluginManagerComponentPluginSearchButton"]') .waitForElementVisible('*[data-id="pluginManagerLocalPluginModalDialogModalDialogContainer-react"]') diff --git a/apps/remix-ide-e2e/src/tests/dgit_github.test.ts b/apps/remix-ide-e2e/src/tests/dgit_github.test.ts index 22bece4727..1b361b3591 100644 --- a/apps/remix-ide-e2e/src/tests/dgit_github.test.ts +++ b/apps/remix-ide-e2e/src/tests/dgit_github.test.ts @@ -218,6 +218,7 @@ module.exports = { 'disconnect github #group1': function (browser: NightwatchBrowser) { browser .waitForElementVisible('*[data-id="github-panel"]') + .pause(1000) .click('*[data-id="github-panel"]') .waitForElementVisible('*[data-id="disconnect-github"]') .pause(1000) @@ -370,11 +371,17 @@ module.exports = { browser. clickLaunchIcon('dgit') .waitForElementVisible('*[data-id="github-panel"]') + .pause(1000) .click('*[data-id="github-panel"]') + .pause(1000) .setValue('*[data-id="githubToken"]', 'invalidtoken') + .pause(1000) .setValue('*[data-id="gitubUsername"]', 'git') + .pause(1000) .setValue('*[data-id="githubEmail"]', 'git@example.com') + .pause(1000) .click('*[data-id="saveGitHubCredentials"]') + .pause(1000) .modalFooterOKClick('github-credentials-error') }, 'check the commits panel for pagination #group3': function (browser: NightwatchBrowser) { diff --git a/apps/remix-ide-e2e/src/tests/dgit_local.test.ts b/apps/remix-ide-e2e/src/tests/dgit_local.test.ts index a298f15d96..a20624a37c 100644 --- a/apps/remix-ide-e2e/src/tests/dgit_local.test.ts +++ b/apps/remix-ide-e2e/src/tests/dgit_local.test.ts @@ -37,6 +37,7 @@ module.exports = { .waitForElementVisible('*[data-id="initgit-btn"]') .click('*[data-id="initgit-btn"]') .waitForElementVisible('*[data-id="github-panel"]') + .pause(1000) .click('*[data-id="github-panel"]') .waitForElementVisible('*[data-id="gitubUsername"]') .setValue('*[data-id="gitubUsername"]', 'git') diff --git a/apps/remix-ide-e2e/src/tests/workspace_git.test.ts b/apps/remix-ide-e2e/src/tests/workspace_git.test.ts index bf5da591e9..c495ce11b8 100644 --- a/apps/remix-ide-e2e/src/tests/workspace_git.test.ts +++ b/apps/remix-ide-e2e/src/tests/workspace_git.test.ts @@ -181,7 +181,7 @@ module.exports = { .waitForElementVisible('[data-id="workspaceGitPanel"]') .waitForElementVisible('[data-id="workspaceGitBranchesDropdown"]') .click('[data-id="workspaceGitBranchesDropdown"]') - .pause() + .pause(1000) .waitForElementVisible('[data-id="custom-dropdown-menu"]') .waitForElementContainsText('[data-id="custom-dropdown-items"]', 'origin/dev') .waitForElementContainsText('[data-id="custom-dropdown-items"]', 'origin/production') @@ -404,7 +404,7 @@ module.exports = { .getEditorValue((content) => { browser.assert.ok(content.indexOf(`contract Counter is BaseHook {`) !== -1, 'Incorrect content') - }).pause() + }) }, 'Should create Remix default workspace with files #group5': function (browser: NightwatchBrowser) { @@ -426,6 +426,7 @@ module.exports = { .waitForElementVisible('*[data-id="initgit-btn"]') .click('*[data-id="initgit-btn"]') .waitForElementVisible('*[data-id="github-panel"]') + .pause(1000) .click('*[data-id="github-panel"]') .waitForElementVisible('*[data-id="gitubUsername"]') .setValue('*[data-id="gitubUsername"]', 'git') diff --git a/apps/remix-ide/ci/update_desktop_release_assets.ts b/apps/remix-ide/ci/update_desktop_release_assets.ts new file mode 100644 index 0000000000..ad01506bd6 --- /dev/null +++ b/apps/remix-ide/ci/update_desktop_release_assets.ts @@ -0,0 +1,242 @@ +import { Octokit } from 'octokit' +import * as fs from 'fs' +import * as path from 'path' +import YAML from 'yaml' +import crypto from 'crypto' + +const owner = 'remix-project-org' +let repo = 'remix-desktop' +const headers = { + 'X-GitHub-Api-Version': '2022-11-28', +} + +const version = getVersionFromPackageJson() +let channel = 'latest' + +if (version.includes('beta')) { + channel = 'beta' +} +if (version.includes('alpha')) { + channel = 'alpha' +} +if (version.includes('insiders')) { + channel = 'insiders' +} + +if (channel !== 'latest') repo = `remix-desktop-${channel}` + +const octokit = new Octokit({ + auth: process.env.GH_TOKEN_DESKTOP_PUBLISH, +}) + +async function getAllReleases() { + const releases = await octokit.request('GET /repos/{owner}/{repo}/releases', { + owner: owner, + repo: repo, + headers: headers, + }) + return releases.data +} + +async function uploadReleaseAsset(release, name, file) { + const upload_url = release.upload_url + console.log(`Uploading ${name} to ${upload_url}`) + if (fs.existsSync(file)) { + octokit.request({ + method: "POST", + url: upload_url, + headers: { + "content-type": "text/plain", + }, + data: fs.readFileSync(file), + name, + label: name + }); + } else { + console.log(`File ${file} does not exist. Skipping...`) + } +} + +function getVersionFromPackageJson() { + // ignore ts error + // eslint-disable-next-line @typescript-eslint/no-var-requires + const packageJson = require(__dirname + '/../../../apps/remixdesktop/package.json') + return packageJson.version +} + +async function readReleaseFilesFromLocalDirectory() { + const directoryPath = path.join(__dirname, '../../../release') + const files = fs.readdirSync(directoryPath) + return files +} + +async function removeAsset(asset) { + await octokit.request('DELETE /repos/{owner}/{repo}/releases/assets/{asset_id}', { + owner: owner, + repo: repo, + asset_id: asset.id, + headers: headers, + }) +} + +async function hashFile(file): Promise { + return new Promise((resolve, reject) => { + const hash = crypto.createHash('sha512').setEncoding('base64'); + // hash.on('error', reject).setEncoding(encoding); + fs.createReadStream( + file, + Object.assign({}, {}, { + highWaterMark: 1024 * 1024, + /* better to use more memory but hash faster */ + }) + ) + .on('error', reject) + .on('end', () => { + hash.end(); + console.log('hash done'); + console.log(hash.read()); + resolve(hash.digest('base64')); + }) + .pipe( + hash, + { + end: false, + } + ); + }); +} + +async function main() { + + const allReleases = await getAllReleases() + + console.log(`preparing release version: ${version}`) + let release + allReleases.find((r) => { + if (r.tag_name === `v${version}`) { + release = r + } + }) + if (!release) { + console.log('No release found.') + // create release + console.log(`Creating release ${version}`) + const r = await octokit.request('POST /repos/{owner}/{repo}/releases', { + owner: owner, + repo: repo, + tag_name: `v${version}`, + name: `${version}`, + draft: true, + prerelease: true, + headers: headers, + }) + release = r.data + } + + let ymlFiles = await readReleaseFilesFromLocalDirectory() + ymlFiles = ymlFiles.filter((file) => file.endsWith('.yml') && file.startsWith('latest')) + + console.log(`Found ${ymlFiles.length} yml files to upload`) + + // read and parse yml latest files + // the yml files contain the sha512 hash and file size of the executable + // we need to recalculate the hash and file size of the executable + // and update the yml files + // this is because the executable is resigned after the yml files are created + for (const file of ymlFiles) { + const content = fs.readFileSync(path.join(__dirname, '../../../release', file), 'utf8') + const parsed = YAML.parse(content) + const hashes: { + url: string, + sha512: string, + size: number + }[] = [] + if (parsed.files) { + console.log(`Found`, parsed.files) + for (const f of parsed.files) { + const executable = f.url + const exists = fs.existsSync(path.join(__dirname, '../../../release', executable)) + if (!exists) { + console.log(`File ${executable} does not exist on local fs. Skipping...`) + continue + } else { + console.log(`File ${executable} exists on local fs. Recalculating hash...`) + // calculate sha512 hash of executable + const hash: string = await hashFile(path.join(__dirname, '../../../release', executable)) + console.log(hash) + // calculate file size of executable + const stats = fs.statSync(path.join(__dirname, '../../../release', executable)) + const fileSizeInBytes = stats.size + console.log(fileSizeInBytes) + hashes.push({ + url: executable, + sha512: hash, + size: fileSizeInBytes + }) + if (parsed.path === executable) { + parsed.sha512 = hash + parsed.size = fileSizeInBytes + } + } + } + } + console.log(hashes) + parsed.files = hashes + const newYml = YAML.stringify(parsed) + fs.writeFileSync(path.join(__dirname, '../../../release', file), newYml) + } + + let files = await readReleaseFilesFromLocalDirectory() + + try { + if (fs.existsSync(path.join(__dirname, '../../../release', `latest-mac-arm64.yml`)) && fs.existsSync(path.join(__dirname, '../../../release', `latest-mac-x64.yml`))) { + // combine the two files + const macArm64 = fs.readFileSync(path.join(__dirname, '../../../release', `latest-mac-arm64.yml`), 'utf8') + const mac = fs.readFileSync(path.join(__dirname, '../../../release', `latest-mac-x64.yml`), 'utf8') + const parsedMacArm64 = YAML.parse(macArm64) + const parsedMac = YAML.parse(mac) + console.log(parsedMacArm64) + console.log(parsedMac) + const combined = { + ...parsedMac, + files: [ + ...parsedMac.files, + ...parsedMacArm64.files + ] + } + console.log(combined) + const newYml = YAML.stringify(combined) + fs.writeFileSync(path.join(__dirname, '../../../release', `latest-mac.yml`), newYml) + // remove the arm64 file + fs.unlinkSync(path.join(__dirname, '../../../release', `latest-mac-arm64.yml`)) + fs.unlinkSync(path.join(__dirname, '../../../release', `latest-mac-x64.yml`)) + } + } catch (e) { + console.log(e) + } + + files = await readReleaseFilesFromLocalDirectory() + files = files. + filter((file) => file.endsWith('.zip') || file.endsWith('.dmg') || file.endsWith('.exe') || file.endsWith('.AppImage') || file.endsWith('.snap') || file.endsWith('.deb') || file.startsWith(`latest`)) + .filter((file) => !file.startsWith('._')) + console.log(`Found ${files.length} files to upload`) + console.log(files) + if (!release.draft) { + console.log(`Release ${version} is not a draft. Aborting...`) + return + } + // upload files + for (const file of files) { + // check if it is already uploaded + const asset = release.assets.find((a) => a.label === file) + if (asset) { + console.log(`Asset ${file} already uploaded... replacing it`) + // remove it first + await removeAsset(asset) + } + await uploadReleaseAsset(release, file, path.join(__dirname, '../../../release', file)) + } +} + +main() + diff --git a/apps/remix-ide/src/app.js b/apps/remix-ide/src/app.js index a3722c7572..4c490aaf34 100644 --- a/apps/remix-ide/src/app.js +++ b/apps/remix-ide/src/app.js @@ -1,29 +1,29 @@ 'use strict' -import {RunTab, makeUdapp} from './app/udapp' -import {RemixEngine} from './remixEngine' -import {RemixAppManager} from './remixAppManager' -import {ThemeModule} from './app/tabs/theme-module' -import {LocaleModule} from './app/tabs/locale-module' -import {NetworkModule} from './app/tabs/network-module' -import {Web3ProviderModule} from './app/tabs/web3-provider' -import {CompileAndRun} from './app/tabs/compile-and-run' -import {PluginStateLogger} from './app/tabs/state-logger' -import {SidePanel} from './app/components/side-panel' -import {StatusBar} from './app/components/status-bar' -import {HiddenPanel} from './app/components/hidden-panel' -import {PinnedPanel} from './app/components/pinned-panel' -import {VerticalIcons} from './app/components/vertical-icons' -import {LandingPage} from './app/ui/landing-page/landing-page' -import {MainPanel} from './app/components/main-panel' -import {PermissionHandlerPlugin} from './app/plugins/permission-handler-plugin' -import {AstWalker} from '@remix-project/remix-astwalker' -import {LinkLibraries, DeployLibraries, OpenZeppelinProxy} from '@remix-project/core-plugin' -import {CodeParser} from './app/plugins/parser/code-parser' -import {SolidityScript} from './app/plugins/solidity-script' - -import {WalkthroughService} from './walkthroughService' - -import {OffsetToLineColumnConverter, CompilerMetadata, CompilerArtefacts, FetchAndCompile, CompilerImports, GistHandler} from '@remix-project/core-plugin' +import { RunTab, makeUdapp } from './app/udapp' +import { RemixEngine } from './remixEngine' +import { RemixAppManager } from './remixAppManager' +import { ThemeModule } from './app/tabs/theme-module' +import { LocaleModule } from './app/tabs/locale-module' +import { NetworkModule } from './app/tabs/network-module' +import { Web3ProviderModule } from './app/tabs/web3-provider' +import { CompileAndRun } from './app/tabs/compile-and-run' +import { PluginStateLogger } from './app/tabs/state-logger' +import { SidePanel } from './app/components/side-panel' +import { StatusBar } from './app/components/status-bar' +import { HiddenPanel } from './app/components/hidden-panel' +import { PinnedPanel } from './app/components/pinned-panel' +import { VerticalIcons } from './app/components/vertical-icons' +import { LandingPage } from './app/ui/landing-page/landing-page' +import { MainPanel } from './app/components/main-panel' +import { PermissionHandlerPlugin } from './app/plugins/permission-handler-plugin' +import { AstWalker } from '@remix-project/remix-astwalker' +import { LinkLibraries, DeployLibraries, OpenZeppelinProxy } from '@remix-project/core-plugin' +import { CodeParser } from './app/plugins/parser/code-parser' +import { SolidityScript } from './app/plugins/solidity-script' + +import { WalkthroughService } from './walkthroughService' + +import { OffsetToLineColumnConverter, CompilerMetadata, CompilerArtefacts, FetchAndCompile, CompilerImports, GistHandler } from '@remix-project/core-plugin' import {Registry} from '@remix-project/remix-lib' import {ConfigPlugin} from './app/plugins/config' @@ -56,10 +56,19 @@ import { electronTemplates } from './app/plugins/electron/templatesPlugin' import { xtermPlugin } from './app/plugins/electron/xtermPlugin' import { ripgrepPlugin } from './app/plugins/electron/ripgrepPlugin' import { compilerLoaderPlugin, compilerLoaderPluginDesktop } from './app/plugins/electron/compilerLoaderPlugin' +import { appUpdaterPlugin } from './app/plugins/electron/appUpdaterPlugin' +import { SlitherHandleDesktop } from './app/plugins/electron/slitherPlugin' +import { SlitherHandle } from './app/files/slither-handle' +import { FoundryHandle } from './app/files/foundry-handle' +import { FoundryHandleDesktop } from './app/plugins/electron/foundryPlugin' +import { HardhatHandle } from './app/files/hardhat-handle' +import { HardhatHandleDesktop } from './app/plugins/electron/hardhatPlugin' + +import { SolCoder } from './app/plugins/solcoderAI' import { GitPlugin } from './app/plugins/git' import { Matomo } from './app/plugins/matomo' -import {SolCoder} from './app/plugins/solcoderAI' + import { TemplatesSelectionPlugin } from './app/plugins/templates-selection/templates-selection-plugin' @@ -78,6 +87,7 @@ const Config = require('./config') const FileManager = require('./app/files/fileManager') import FileProvider from "./app/files/fileProvider" import { appPlatformTypes } from '@remix-ui/app' + const DGitProvider = require('./app/files/dgitProvider') const WorkspaceFileProvider = require('./app/files/workspaceFileProvider') @@ -86,19 +96,19 @@ const PluginManagerComponent = require('./app/components/plugin-manager-componen const CompileTab = require('./app/tabs/compile-tab') const SettingsTab = require('./app/tabs/settings-tab') const AnalysisTab = require('./app/tabs/analysis-tab') -const {DebuggerTab} = require('./app/tabs/debugger-tab') +const { DebuggerTab } = require('./app/tabs/debugger-tab') const TestTab = require('./app/tabs/test-tab') const FilePanel = require('./app/panels/file-panel') const Editor = require('./app/editor/editor') const Terminal = require('./app/panels/terminal') -const {TabProxy} = require('./app/panels/tab-proxy.js') +const { TabProxy } = require('./app/panels/tab-proxy.js') export class platformApi { - get name () { + get name() { return isElectron() ? appPlatformTypes.desktop : appPlatformTypes.web } - isDesktop () { + isDesktop() { return isElectron() } } @@ -118,7 +128,7 @@ class AppComponent { // load app config const config = new Config(configStorage) - Registry.getInstance().put({api: config, name: 'config'}) + Registry.getInstance().put({ api: config, name: 'config' }) // load file system this._components.filesProviders = {} @@ -170,7 +180,14 @@ class AppComponent { this.matomoConfAlreadySet = Registry.getInstance().get('config').api.exists('settings/matomo-analytics') this.matomoCurrentSetting = Registry.getInstance().get('config').api.get('settings/matomo-analytics') - this.showMatamo = matomoDomains[window.location.hostname] && !this.matomoConfAlreadySet + + let electronTracking = false + + if (window.electronAPI) { + electronTracking = await window.electronAPI.canTrackMatomo() + } + + this.showMatamo = (matomoDomains[window.location.hostname] || electronTracking) && !this.matomoConfAlreadySet this.walkthroughService = new WalkthroughService(appManager) @@ -192,12 +209,12 @@ class AppComponent { this.themeModule = new ThemeModule() // ----------------- locale service --------------------------------- this.localeModule = new LocaleModule() - Registry.getInstance().put({api: this.themeModule, name: 'themeModule'}) - Registry.getInstance().put({api: this.localeModule, name: 'localeModule'}) + Registry.getInstance().put({ api: this.themeModule, name: 'themeModule' }) + Registry.getInstance().put({ api: this.localeModule, name: 'localeModule' }) // ----------------- editor service ---------------------------- const editor = new Editor() // wrapper around ace editor - Registry.getInstance().put({api: editor, name: 'editor'}) + Registry.getInstance().put({ api: editor, name: 'editor' }) editor.event.register('requiringToSaveCurrentfile', (currentFile) => { fileManager.saveCurrentFile() if (currentFile.endsWith('.circom')) this.appManager.activatePlugin(['circuit-compiler']) @@ -205,7 +222,7 @@ class AppComponent { // ----------------- fileManager service ---------------------------- const fileManager = new FileManager(editor, appManager) - Registry.getInstance().put({api: fileManager, name: 'filemanager'}) + Registry.getInstance().put({ api: fileManager, name: 'filemanager' }) // ----------------- dGit provider --------------------------------- const dGitProvider = new DGitProvider() @@ -292,7 +309,7 @@ class AppComponent { // -------------------Terminal---------------------------------------- makeUdapp(blockchain, compilersArtefacts, (domEl) => terminal.logHtml(domEl)) const terminal = new Terminal( - {appManager, blockchain}, + { appManager, blockchain }, { getPosition: (event) => { const limitUp = 36 @@ -388,14 +405,28 @@ class AppComponent { this.engine.register([xterm]) const ripgrep = new ripgrepPlugin() this.engine.register([ripgrep]) + const appUpdater = new appUpdaterPlugin() + this.engine.register([appUpdater]) } - const compilerloader = isElectron()? new compilerLoaderPluginDesktop(): new compilerLoaderPlugin() + const compilerloader = isElectron() ? new compilerLoaderPluginDesktop() : new compilerLoaderPlugin() this.engine.register([compilerloader]) + // slither analyzer plugin (remixd / desktop) + const slitherPlugin = isElectron() ? new SlitherHandleDesktop() : new SlitherHandle() + this.engine.register([slitherPlugin]) + + //foundry plugin + const foundryPlugin = isElectron() ? new FoundryHandleDesktop() : new FoundryHandle() + this.engine.register([foundryPlugin]) + + // hardhat plugin + const hardhatPlugin = isElectron() ? new HardhatHandleDesktop() : new HardhatHandle() + this.engine.register([hardhatPlugin]) + // LAYOUT & SYSTEM VIEWS const appPanel = new MainPanel() - Registry.getInstance().put({api: this.mainview, name: 'mainview'}) + Registry.getInstance().put({ api: this.mainview, name: 'mainview' }) const tabProxy = new TabProxy(fileManager, editor) this.engine.register([appPanel, tabProxy]) @@ -447,10 +478,7 @@ class AppComponent { analysis, test, filePanel.remixdHandle, - filePanel.hardhatHandle, - filePanel.foundryHandle, filePanel.truffleHandle, - filePanel.slitherHandle, linkLibraries, deployLibraries, openZeppelinProxy, @@ -458,10 +486,10 @@ class AppComponent { ]) this.layout.panels = { - tabs: {plugin: tabProxy, active: true}, - editor: {plugin: editor, active: true}, - main: {plugin: appPanel, active: false}, - terminal: {plugin: terminal, active: true, minimized: false} + tabs: { plugin: tabProxy, active: true }, + editor: { plugin: editor, active: true }, + main: { plugin: appPanel, active: false }, + terminal: { plugin: terminal, active: true, minimized: false } } } @@ -474,7 +502,7 @@ class AppComponent { } catch (e) { console.log("couldn't register iframe plugins", e.message) } - if (isElectron()){ + if (isElectron()) { await this.appManager.activatePlugin(['fs']) } await this.appManager.activatePlugin(['layout']) @@ -517,8 +545,8 @@ class AppComponent { await this.appManager.activatePlugin(['walkthrough', 'storage', 'search', 'compileAndRun', 'recorder', 'dgitApi', 'dgit']) await this.appManager.activatePlugin(['solidity-script', 'remix-templates']) - if (isElectron()){ - await this.appManager.activatePlugin(['isogit', 'electronconfig', 'electronTemplates', 'xterm', 'ripgrep']) + if (isElectron()) { + await this.appManager.activatePlugin(['isogit', 'electronconfig', 'electronTemplates', 'xterm', 'ripgrep', 'appUpdater', 'slither', 'foundry', 'hardhat']) } this.appManager.on( diff --git a/apps/remix-ide/src/app/files/dgitProvider.ts b/apps/remix-ide/src/app/files/dgitProvider.ts index 9d4b01091c..cdb863b4b7 100644 --- a/apps/remix-ide/src/app/files/dgitProvider.ts +++ b/apps/remix-ide/src/app/files/dgitProvider.ts @@ -4,26 +4,16 @@ import { Plugin } from '@remixproject/engine' import git, { ReadBlobResult, ReadCommitResult, StatusRow } from 'isomorphic-git' -import IpfsHttpClient from 'ipfs-http-client' -import { - saveAs -} from 'file-saver' -import http from 'isomorphic-git/http/web' - -import JSZip from 'jszip' import path from 'path' -import FormData from 'form-data' import axios from 'axios' import { Registry } from '@remix-project/remix-lib' -import { Octokit, App } from "octokit" -import { OctokitResponse } from '@octokit/types' -import { Endpoints } from "@octokit/types" +import { Octokit } from "octokit" import { IndexedDBStorage } from './filesystems/indexedDB' -import { GitHubUser, branch, commitChange, remote, pagedCommits, remoteCommitsInputType, cloneInputType, fetchInputType, pullInputType, pushInputType, currentBranchInput, branchInputType, addInput, rmInput, resolveRefInput, readBlobInput, repositoriesInput, commitInput, branchDifference, compareBranchesInput, initInput, userEmails, checkoutInput } from '@remix-ui/git' -import { LibraryProfile, StatusEvents } from '@remixproject/plugin-utils' -import { ITerminal } from '@remixproject/plugin-api/src/lib/terminal' -import { partial } from 'lodash' - +import { branch, commitChange, remote } from '@remix-ui/git' +import { checkoutInputType, statusInput, logInputType, author, pagedCommits, remoteCommitsInputType, cloneInputType, fetchInputType, pullInputType, pushInputType, currentBranchInput, branchInputType, addInputType, rmInputType, resolveRefInput, readBlobInput, repositoriesInput, commitInputType, branchDifference, compareBranchesInput, initInputType, isoGitFSConfig, GitHubUser, userEmails } from '@remix-api' +import { LibraryProfile } from '@remixproject/plugin-utils' +import { CustomRemixApi } from '@remix-api' +import { isoGit } from "@remix-git" declare global { interface Window { remixFileSystemCallback: IndexedDBStorage; remixFileSystem: any; } } @@ -34,49 +24,17 @@ const profile: LibraryProfile = { description: 'Decentralized git provider', icon: 'assets/img/fileManager.webp', version: '0.0.1', - methods: ['init', 'localStorageUsed', 'addremote', 'delremote', 'remotes', 'fetch', 'clone', 'export', 'import', 'status', 'log', 'commit', 'add', 'remove', 'reset', 'rm', 'lsfiles', 'readblob', 'resolveref', 'branches', 'branch', 'checkout', 'currentbranch', 'push', 'pull', 'setIpfsConfig', 'zip', 'setItem', 'getItem', 'version', 'updateSubmodules' + methods: ['init', 'addremote', 'delremote', 'remotes', 'fetch', 'clone', 'status', 'log', 'commit', 'add', 'remove', 'rm', 'readblob', 'resolveref', 'branches', 'branch', 'checkout', 'currentbranch', 'push', 'pull', 'version', 'updateSubmodules' , 'getGitHubUser', 'remotebranches', 'remotecommits', 'repositories', 'getCommitChanges', 'compareBranches'], kind: 'file-system' } -class DGitProvider extends Plugin { - ipfsconfig: { host: string; port: number; protocol: string; ipfsurl: string } - globalIPFSConfig: { host: string; port: number; protocol: string; ipfsurl: string } - remixIPFS: { host: string; port: number; protocol: string; ipfsurl: string } - ipfsSources: any[] - ipfs: any - filesToSend: any[] +class DGitProvider extends Plugin { constructor() { super(profile) - this.ipfsconfig = { - host: 'jqgt.remixproject.org', - port: 443, - protocol: 'https', - ipfsurl: 'https://jqgt.remixproject.org/ipfs/' - } - this.globalIPFSConfig = { - host: 'ipfs.io', - port: 443, - protocol: 'https', - ipfsurl: 'https://ipfs.io/ipfs/' - } - this.remixIPFS = { - host: 'jqgt.remixproject.org', - port: 443, - protocol: 'https', - ipfsurl: 'https://jqgt.remixproject.org/ipfs/' - } - this.ipfsSources = [this.remixIPFS, this.globalIPFSConfig, this.ipfsconfig] } async addIsomorphicGitConfigFS(dir = '') { - if ((Registry.getInstance().get('platform').api.isDesktop())) { - return { - fs: window.remixFileSystem, - dir: '/' - } - } - const workspace = await this.call('filePanel', 'getCurrentWorkspace') if (!workspace) return @@ -86,62 +44,12 @@ class DGitProvider extends Plugin { } } - async addIsomorphicGitConfig(input) { - - const token = await this.call('config' as any, 'getAppParameter', 'settings/gist-access-token') - - let config = { - corsProxy: 'https://corsproxy.remixproject.org/', - http, - onAuth: url => { - url - const auth = { - username: input.token || token, - password: '' - } - return auth - } - } - if (input.url) { - - const url = new URL(input.url) - if (url.hostname.includes('localhost')) { - config = { - ...config, - corsProxy: null - } - } - } - if ((input.remote && input.remote.url)) { - - const url = new URL(input.remote.url) - if (url.hostname.includes('localhost')) { - config = { - ...config, - corsProxy: null, - } - } - } - - if (input.provider && input.provider === 'github') { - config = { - ...config, - corsProxy: 'https://corsproxy.remixproject.org/', - } - } - - if (input.provider && input.provider === 'localhost') { - config = { - ...config, - corsProxy: null - } - } - - return config + async getToken() { + return await this.call('config' as any, 'getAppParameter', 'settings/gist-access-token') } - async getCommandUser(input) { - const author = { + async getAuthor(input) { + const author: author = { name: '', email: '' } @@ -167,7 +75,7 @@ class DGitProvider extends Plugin { return author } - async init(input?: initInput): Promise { + async init(input?: initInputType): Promise { if ((Registry.getInstance().get('platform').api.isDesktop())) { await this.call('isogit', 'init', { defaultBranch: (input && input.defaultBranch) || 'main' @@ -192,11 +100,10 @@ class DGitProvider extends Plugin { return version } - async status(cmd): Promise> { + async status(cmd: statusInput): Promise> { if ((Registry.getInstance().get('platform').api.isDesktop())) { const status = await this.call('isogit', 'status', cmd) - return status } @@ -208,7 +115,7 @@ class DGitProvider extends Plugin { return status } - async add(cmd: addInput): Promise { + async add(cmd: addInputType): Promise { if ((Registry.getInstance().get('platform').api.isDesktop())) { await this.call('isogit', 'add', cmd) @@ -222,7 +129,7 @@ class DGitProvider extends Plugin { this.emit('add') } - async rm(cmd: rmInput) { + async rm(cmd: rmInputType) { if ((Registry.getInstance().get('platform').api.isDesktop())) { await this.call('isogit', 'rm', cmd) @@ -231,26 +138,11 @@ class DGitProvider extends Plugin { ...await this.addIsomorphicGitConfigFS(), ...cmd }) - this.emit('rm') - - } - } - - async reset(cmd) { - - if ((Registry.getInstance().get('platform').api.isDesktop())) { - await this.call('isogit', 'reset', cmd) - } else { - await git.resetIndex({ - ...await this.addIsomorphicGitConfigFS(), - ...cmd - }) - this.emit('rm') - } + this.emit('rm') } - async checkout(cmd: checkoutInput): Promise { + async checkout(cmd: checkoutInputType): Promise { if ((Registry.getInstance().get('platform').api.isDesktop())) { await this.call('isogit', 'checkout', cmd) @@ -291,12 +183,11 @@ class DGitProvider extends Plugin { this.emit('checkout') } - async log(cmd: { ref: string }): Promise { + async log(cmd: logInputType): Promise { if ((Registry.getInstance().get('platform').api.isDesktop())) { const status = await this.call('isogit', 'log', { ...cmd, - depth: 10 }) return status @@ -306,101 +197,32 @@ class DGitProvider extends Plugin { ...await this.addIsomorphicGitConfigFS(), ...cmd, }) + return status } async compareBranches({ branch, remote }: compareBranchesInput): Promise { - // Get current branch commits - const headCommits = await git.log({ - ...await this.addIsomorphicGitConfigFS(), - ref: branch.name, - }); - - // Get remote branch commits - const remoteCommits = await git.log({ - ...await this.addIsomorphicGitConfigFS(), - ref: `${remote.name}/${branch.name}`, - }); - - // Convert arrays of commit objects to sets of commit SHAs - const headCommitSHAs = new Set(headCommits.map(commit => commit.oid)); - const remoteCommitSHAs = new Set(remoteCommits.map(commit => commit.oid)); - - // Filter out commits that are only in the remote branch - const uniqueRemoteCommits = remoteCommits.filter(commit => !headCommitSHAs.has(commit.oid)); - - // filter out commits that are only in the local branch - const uniqueHeadCommits = headCommits.filter(commit => !remoteCommitSHAs.has(commit.oid)); - - return { - uniqueHeadCommits, - uniqueRemoteCommits, - }; + if ((Registry.getInstance().get('platform').api.isDesktop())) { + return await this.call('isogit', 'compareBranches', { branch, remote }) + } + return await isoGit.compareBranches({ branch, remote }, await this.addIsomorphicGitConfigFS()) } async getCommitChanges(commitHash1: string, commitHash2: string): Promise { - const result: commitChange[] = await git.walk({ - ...await this.addIsomorphicGitConfigFS(), - trees: [git.TREE({ ref: commitHash1 }), git.TREE({ ref: commitHash2 })], - map: async function (filepath, [A, B]) { - - if (filepath === '.') { - return - } - try { - if ((A && await A.type()) === 'tree' || B && (await B.type()) === 'tree') { - return - } - } catch (e) { - // ignore - } - - // generate ids - const Aoid = A && await A.oid() || undefined - const Boid = B && await B.oid() || undefined - - const commitChange: Partial = { - hashModified: commitHash1, - hashOriginal: commitHash2, - path: filepath, - } - - // determine modification type - if (Aoid !== Boid) { - commitChange.type = "modified" - } - if (Aoid === undefined) { - commitChange.type = "deleted" - } - if (Boid === undefined || !commitHash2) { - commitChange.type = "added" - } - if (Aoid === undefined && Boid === undefined) { - commitChange.type = "unknown" - } - if (commitChange.type) - return commitChange - else - return undefined - }, - }) + if ((Registry.getInstance().get('platform').api.isDesktop())) { + const result = this.call('isogit', 'getCommitChanges', commitHash1, commitHash2) + return result + } - return result + return await isoGit.getCommitChanges(commitHash1, commitHash2, await this.addIsomorphicGitConfigFS()) } - async remotes(config): Promise { + async remotes(): Promise { if ((Registry.getInstance().get('platform').api.isDesktop())) { - return await this.call('isogit', 'remotes', config) + return await this.call('isogit', 'remotes') } - let remotes: remote[] = [] - try { - remotes = (await git.listRemotes({ ...config ? config : await this.addIsomorphicGitConfigFS() })).map((remote) => { return { name: remote.remote, url: remote.url } } - ) - } catch (e) { - // do nothing - } - return remotes + return await isoGit.remotes(await this.addIsomorphicGitConfigFS()) } async branch(cmd: branchInputType): Promise { @@ -423,68 +245,28 @@ class DGitProvider extends Plugin { return status } - async currentbranch(config: currentBranchInput): Promise { + async currentbranch(input: currentBranchInput): Promise { if ((Registry.getInstance().get('platform').api.isDesktop())) { - return await this.call('isogit', 'currentbranch') + return await this.call('isogit', 'currentbranch', input) } - try { - const defaultConfig = await this.addIsomorphicGitConfigFS() - const cmd = config ? defaultConfig ? { ...defaultConfig, ...config } : config : defaultConfig - const name = await git.currentBranch(cmd) - let remote: remote = undefined - try { - const remoteName = await git.getConfig({ - ...defaultConfig, - path: `branch.${name}.remote` - }) - if (remoteName) { - const remoteUrl = await git.getConfig({ - ...defaultConfig, - path: `remote.${remoteName}.url` - }) - remote = { name: remoteName, url: remoteUrl } - } - - } catch (e) { - // do nothing - } - - return { - remote: remote, - name: name || '' - } - } catch (e) { - return undefined - } + const defaultConfig = await this.addIsomorphicGitConfigFS() + return await isoGit.currentbranch(input, defaultConfig) } - async branches(config): Promise { + async branches(config: isoGitFSConfig): Promise { if ((Registry.getInstance().get('platform').api.isDesktop())) { - return await this.call('isogit', 'branches') - } - - try { - const defaultConfig = await this.addIsomorphicGitConfigFS() - const cmd = config ? defaultConfig ? { ...defaultConfig, ...config } : config : defaultConfig - const remotes = await this.remotes(config) - let branches: branch[] = [] - branches = (await git.listBranches(cmd)).map((branch) => { return { remote: undefined, name: branch } }) - for (const remote of remotes) { - cmd.remote = remote.name - const remotebranches = (await git.listBranches(cmd)).map((branch) => { return { remote: remote, name: branch } }) - branches = [...branches, ...remotebranches] - } + const branches = await this.call('isogit', 'branches') return branches - } catch (e) { - console.log(e) - return [] } + const defaultConfig = await this.addIsomorphicGitConfigFS() + const cmd = config ? defaultConfig ? { ...defaultConfig, ...config } : config : defaultConfig + return await isoGit.branches(cmd) } - async commit(cmd: commitInput): Promise { + async commit(cmd: commitInputType): Promise { if ((Registry.getInstance().get('platform').api.isDesktop())) { try { @@ -511,19 +293,6 @@ class DGitProvider extends Plugin { } } - async lsfiles(cmd) { - - if ((Registry.getInstance().get('platform').api.isDesktop())) { - return await this.call('isogit', 'lsfiles', cmd) - } - - const filesInStaging = await git.listFiles({ - ...await this.addIsomorphicGitConfigFS(), - ...cmd - }) - return filesInStaging - } - async resolveref(cmd: resolveRefInput): Promise { if ((Registry.getInstance().get('platform').api.isDesktop())) { @@ -550,26 +319,9 @@ class DGitProvider extends Plugin { return readBlobResult } - async setIpfsConfig(config) { - this.ipfsconfig = config - return new Promise((resolve) => { - resolve(this.checkIpfsConfig()) - }) - } - - async checkIpfsConfig(config?) { - this.ipfs = IpfsHttpClient(config || this.ipfsconfig) - try { - await this.ipfs.config.getAll() - return true - } catch (e) { - return false - } - } - async addremote(input: remote): Promise { if ((Registry.getInstance().get('platform').api.isDesktop())) { - await this.call('isogit', 'addremote', { url: input.url, remote: input.name }) + await this.call('isogit', 'addremote', input) return } await git.addRemote({ ...await this.addIsomorphicGitConfigFS(), url: input.url, remote: input.name }) @@ -577,51 +329,39 @@ class DGitProvider extends Plugin { async delremote(input: remote) { if ((Registry.getInstance().get('platform').api.isDesktop())) { - await this.call('isogit', 'delremote', { remote: input.name }) + await this.call('isogit', 'delremote', input) return } await git.deleteRemote({ ...await this.addIsomorphicGitConfigFS(), remote: input.name }) } - async localStorageUsed() { - return this.calculateLocalStorage() - } - async clone(input: cloneInputType) { if ((Registry.getInstance().get('platform').api.isDesktop())) { - const folder = await this.call('fs', 'selectFolder', null, 'Select or create a folder to clone the repository in', 'Select as Repository Destination') - if (!folder) return false - const cmd = { - url: input.url, - singleBranch: input.singleBranch, - ref: input.branch, - depth: input.depth || 10, - dir: folder, - input - } - this.call('terminal', 'logHtml', `Cloning ${input.url}... please wait...`) try { - const result = await this.call('isogit', 'clone', cmd) - this.call('fs', 'openWindow', folder) - return result + const folder = await this.call('fs', 'selectFolder', null, 'Select or create a folder to clone the repository in', 'Select as Repository Destination') + if (!folder) return false + input.dir = folder + input.depth = input.depth || 10 + const result = await this.call('isogit', 'clone', input) + this.call('fs' as any, 'openWindow', folder) } catch (e) { this.call('notification', 'alert', { id: 'dgitAlert', + title: 'Error Cloning', message: 'Unexpected error while cloning the repository: \n' + e.toString(), }) } } else { const permission = await this.askUserPermission('clone', 'Import multiple files into your workspaces.') if (!permission) return false - if (parseFloat(this.calculateLocalStorage()) > 10000) throw new Error('The local storage of the browser is full.') if (!input.workspaceExists) await this.call('filePanel', 'createWorkspace', input.workspaceName || `workspace_${Date.now()}`, true) const cmd = { url: input.url, singleBranch: input.singleBranch, ref: input.branch, depth: input.depth || 10, - ...await this.addIsomorphicGitConfig(input), + ...await isoGit.addIsomorphicGitProxyConfig(input, this), ...await this.addIsomorphicGitConfigFS() } this.call('terminal', 'logHtml', `Cloning ${input.url}... please wait...`) @@ -674,6 +414,9 @@ class DGitProvider extends Plugin { } async updateSubmodules(input) { + if ((Registry.getInstance().get('platform').api.isDesktop())) { + return await this.call('isogit', 'updateSubmodules', null) + } try { const currentDir = (input && input.dir) || '' const gitmodules = await this.parseGitmodules(currentDir) @@ -705,10 +448,10 @@ class DGitProvider extends Plugin { url: module.url, singleBranch: true, depth: 1, - ...await this.addIsomorphicGitConfig({ + ...await isoGit.addIsomorphicGitProxyConfig({ ...input, - provider: 'github' - }), + provider: 'github', + }, this), ...await this.addIsomorphicGitConfigFS(dir) } this.call('terminal', 'logHtml', `Cloning submodule ${dir}...`) @@ -732,10 +475,10 @@ class DGitProvider extends Plugin { if (result && result.length) { this.call('terminal', 'logHtml', `Checking out submodule ${dir} to ${result[0]} in directory ${dir}`) await git.fetch({ - ...await this.addIsomorphicGitConfig({ + ...await isoGit.addIsomorphicGitProxyConfig({ ...input, - provider: 'github' - }), + provider: 'github', + }, this), ...await this.addIsomorphicGitConfigFS(dir), singleBranch: true, ref: result[0] @@ -782,55 +525,22 @@ class DGitProvider extends Plugin { async push(input: pushInputType) { - const cmd = { - force: input.force, - ref: input.ref.name, - remoteRef: input.remoteRef && input.remoteRef.name, - remote: input.remote.name, - author: await this.getCommandUser(input), - input, - } if ((Registry.getInstance().get('platform').api.isDesktop())) { - return await this.call('isogit', 'push', cmd) + return await this.call('isogit', 'push', input) } else { - - const cmd2 = { - ...cmd, - ...await this.addIsomorphicGitConfig(input), - } - - const result = await git.push({ - ...await this.addIsomorphicGitConfigFS(), - ...cmd2 - }) - + const result = await isoGit.push(input, await this.addIsomorphicGitConfigFS(), this) return result - } } async pull(input: pullInputType) { - const cmd = { - ref: input.ref.name, - remoteRef: input.remoteRef && input.remoteRef.name, - author: await this.getCommandUser(input), - remote: input.remote.name, - input, - } let result if ((Registry.getInstance().get('platform').api.isDesktop())) { - result = await this.call('isogit', 'pull', cmd) + result = await this.call('isogit', 'pull', input) } else { - const cmd2 = { - ...cmd, - ...await this.addIsomorphicGitConfig(input), - } - result = await git.pull({ - ...await this.addIsomorphicGitConfigFS(), - ...cmd2 - }) + result = await isoGit.pull(input, await this.addIsomorphicGitConfigFS(), this) } setTimeout(async () => { await this.call('fileManager', 'refresh') @@ -839,192 +549,19 @@ class DGitProvider extends Plugin { } async fetch(input: fetchInputType) { - const cmd = { - ref: input.ref && input.ref.name, - remoteRef: input.remoteRef && input.remoteRef.name, - author: await this.getCommandUser(input), - remote: input.remote && input.remote.name, - depth: input.depth || 5, - singleBranch: input.singleBranch, - relative: input.relative, - input - } let result if ((Registry.getInstance().get('platform').api.isDesktop())) { - result = await this.call('isogit', 'fetch', cmd) - } else { - const cmd2 = { - ...cmd, - ...await this.addIsomorphicGitConfig(input), - } - result = await git.fetch({ - ...await this.addIsomorphicGitConfigFS(), - ...cmd2 + result = await this.call('isogit', 'fetch', { + ...input, }) - - } - - setTimeout(async () => { - await this.call('fileManager', 'refresh') - }, 1000) - return result - } - - async export(config) { - if (!this.checkIpfsConfig(config)) return false - const workspace = await this.call('filePanel', 'getCurrentWorkspace') - const files = await this.getDirectory('/') - this.filesToSend = [] - for (const file of files) { - const c = await window.remixFileSystem.readFile(`${workspace.absolutePath}/${file}`, null) - const ob = { - path: file, - content: c - } - this.filesToSend.push(ob) - } - const addOptions = { - wrapWithDirectory: true - } - const r = await this.ipfs.add(this.filesToSend, addOptions) - return r.cid.string - } - - async importIPFSFiles(config, cid, workspace) { - const ipfs = IpfsHttpClient(config) - let result = false - try { - const data = ipfs.get(cid, { timeout: 60000 }) - for await (const file of data) { - if (file.path) result = true - file.path = file.path.replace(cid, '') - if (!file.content) { - continue - } - const content = [] - for await (const chunk of file.content) { - content.push(chunk) - } - const dir = path.dirname(file.path) - try { - await this.createDirectories(`${workspace.absolutePath}/${dir}`) - } catch (e) { throw new Error(e) } - try { - await window.remixFileSystem.writeFile(`${workspace.absolutePath}/${file.path}`, Buffer.concat(content) || new Uint8Array(), null) - } catch (e) { throw new Error(e) } - } - } catch (e) { - throw new Error(e) - } - return result - } - - calculateLocalStorage() { - let _lsTotal = 0 - let _xLen; let _x - for (_x in localStorage) { - // eslint-disable-next-line no-prototype-builtins - if (!localStorage.hasOwnProperty(_x)) { - continue - } - _xLen = ((localStorage[_x].length + _x.length) * 2) - _lsTotal += _xLen - } - return (_lsTotal / 1024).toFixed(2) - } - - async import(cmd) { - const permission = await this.askUserPermission('import', 'Import multiple files into your workspaces.') - if (!permission) return false - if (parseFloat(this.calculateLocalStorage()) > 10000) throw new Error('The local storage of the browser is full.') - const cid = cmd.cid - await this.call('filePanel', 'createWorkspace', `workspace_${Date.now()}`, true) - const workspace = await this.call('filePanel', 'getCurrentWorkspace') - let result - if (cmd.local) { - result = await this.importIPFSFiles(this.ipfsconfig, cid, workspace) } else { - result = await this.importIPFSFiles(this.remixIPFS, cid, workspace) || await this.importIPFSFiles(this.ipfsconfig, cid, workspace) || await this.importIPFSFiles(this.globalIPFSConfig, cid, workspace) + result = await isoGit.fetch(input, await this.addIsomorphicGitConfigFS(), this) } + setTimeout(async () => { await this.call('fileManager', 'refresh') }, 1000) - if (!result) throw new Error(`Cannot pull files from IPFS at ${cid}`) - } - - async getItem(name) { - if (typeof window !== 'undefined') { - return window.localStorage.getItem(name) - } - } - - async setItem(name, content) { - try { - if (typeof window !== 'undefined') { - window.localStorage.setItem(name, content) - } - } catch (e) { - console.log(e) - return false - } - return true - } - - async zip() { - const zip = new JSZip() - const workspace = await this.call('filePanel', 'getCurrentWorkspace') - const files = await this.getDirectory('/') - this.filesToSend = [] - for (const file of files) { - const c = await window.remixFileSystem.readFile(`${workspace.absolutePath}/${file}`, null) - zip.file(file, c) - } - await zip.generateAsync({ - type: 'blob' - }) - .then(function (content) { - saveAs(content, `${workspace.name}.zip`) - }) - } - - async createDirectories(strdirectories) { - const ignore = ['.', '/.', ''] - if (ignore.indexOf(strdirectories) > -1) return false - const directories = strdirectories.split('/') - for (let i = 0; i < directories.length; i++) { - let previouspath = '' - if (i > 0) previouspath = '/' + directories.slice(0, i).join('/') - const finalPath = previouspath + '/' + directories[i] - try { - if (!await window.remixFileSystem.exists(finalPath)) { - await window.remixFileSystem.mkdir(finalPath) - } - } catch (e) { - console.log(e) - } - } - } - - async getDirectory(dir) { - let result = [] - const files = await this.call('fileManager', 'readdir', dir) - const fileArray = normalize(files) - for (const fi of fileArray) { - if (fi) { - const type = fi.data.isDirectory - if (type === true) { - result = [ - ...result, - ...(await this.getDirectory( - `${fi.filename}` - )) - ] - } else { - result = [...result, fi.filename] - } - } - } return result } @@ -1079,6 +616,7 @@ class DGitProvider extends Plugin { } async remotecommits(input: remoteCommitsInputType): Promise { + const octokit = new Octokit({ auth: input.token }) @@ -1169,23 +707,4 @@ const addSlash = (file) => { return file } -const normalize = (filesList) => { - const folders = [] - const files = [] - Object.keys(filesList || {}).forEach(key => { - if (filesList[key].isDirectory) { - folders.push({ - filename: key, - data: filesList[key] - }) - } else { - files.push({ - filename: key, - data: filesList[key] - }) - } - }) - return [...folders, ...files] -} - module.exports = DGitProvider diff --git a/apps/remix-ide/src/app/panels/file-panel.js b/apps/remix-ide/src/app/panels/file-panel.js index b6ff040513..2b3946bca1 100644 --- a/apps/remix-ide/src/app/panels/file-panel.js +++ b/apps/remix-ide/src/app/panels/file-panel.js @@ -6,10 +6,7 @@ import { FileSystemProvider } from '@remix-ui/workspace' // eslint-disable-line import {Registry} from '@remix-project/remix-lib' import { RemixdHandle } from '../plugins/remixd-handle' import {PluginViewWrapper} from '@remix-ui/helper' -const { HardhatHandle } = require('../files/hardhat-handle.js') -const { FoundryHandle } = require('../files/foundry-handle.js') const { TruffleHandle } = require('../files/truffle-handle.js') -const { SlitherHandle } = require('../files/slither-handle.js') /* Overview of APIs: @@ -69,10 +66,7 @@ module.exports = class Filepanel extends ViewPlugin { this.el.setAttribute('id', 'fileExplorerView') this.remixdHandle = new RemixdHandle(this.fileProviders.localhost, appManager) - this.hardhatHandle = new HardhatHandle() - this.foundryHandle = new FoundryHandle() this.truffleHandle = new TruffleHandle() - this.slitherHandle = new SlitherHandle() this.contentImport = contentImport this.workspaces = [] this.appManager = appManager diff --git a/apps/remix-ide/src/app/plugins/electron/appUpdaterPlugin.ts b/apps/remix-ide/src/app/plugins/electron/appUpdaterPlugin.ts new file mode 100644 index 0000000000..e2a0c38cfc --- /dev/null +++ b/apps/remix-ide/src/app/plugins/electron/appUpdaterPlugin.ts @@ -0,0 +1,54 @@ +import { ElectronPlugin } from '@remixproject/engine-electron' + +const profile = { + displayName: 'appUpdater', + name: 'appUpdater', + description: 'appUpdater', +} + +export class appUpdaterPlugin extends ElectronPlugin { + constructor() { + super(profile) + } + + onActivation(): void { + this.on('appUpdater', 'askForUpdate', () => { + console.log('askForUpdate') + const upgradeModal = { + id: 'confirmUpdate', + title: 'An update is available', + message: `A new version of Remix Desktop is available. Do you want to update?`, + modalType: 'modal', + okLabel: 'Yes', + cancelLabel: 'No', + okFn: () => { + this.call('appUpdater', 'download') + }, + cancelFn: () => { + + }, + hideFn: () => null + } + this.call('notification', 'modal', upgradeModal) + }) + this.on('appUpdater', 'downloadReady', () => { + console.log('downloadReady') + const upgradeModal = { + id: 'confirmInstall', + title: 'An update is ready to install', + message: `A new version of Remix Desktop is ready to install. Do you want to install it now? This will close Remix Desktop.`, + modalType: 'modal', + okLabel: 'Yes', + cancelLabel: 'No', + okFn: () => { + this.call('appUpdater', 'install') + }, + cancelFn: () => { + + }, + hideFn: () => null + } + this.call('notification', 'modal', upgradeModal) + }) + } +} \ No newline at end of file diff --git a/apps/remix-ide/src/app/plugins/electron/foundryPlugin.ts b/apps/remix-ide/src/app/plugins/electron/foundryPlugin.ts new file mode 100644 index 0000000000..1655681697 --- /dev/null +++ b/apps/remix-ide/src/app/plugins/electron/foundryPlugin.ts @@ -0,0 +1,13 @@ +import { ElectronPlugin } from '@remixproject/engine-electron'; + +export class FoundryHandleDesktop extends ElectronPlugin { + constructor() { + super({ + displayName: 'foundry', + name: 'foundry', + description: 'electron foundry', + methods: ['sync', 'compile'] + }) + this.methods = ['sync', 'compile'] + } +} diff --git a/apps/remix-ide/src/app/plugins/electron/hardhatPlugin.ts b/apps/remix-ide/src/app/plugins/electron/hardhatPlugin.ts new file mode 100644 index 0000000000..fad7190df4 --- /dev/null +++ b/apps/remix-ide/src/app/plugins/electron/hardhatPlugin.ts @@ -0,0 +1,13 @@ +import { ElectronPlugin } from '@remixproject/engine-electron'; + +export class HardhatHandleDesktop extends ElectronPlugin { + constructor() { + super({ + displayName: 'hardhat', + name: 'hardhat', + description: 'electron hardhat', + methods: ['sync', 'compile'] + }) + this.methods = ['sync', 'compile'] + } +} diff --git a/apps/remix-ide/src/app/plugins/electron/slitherPlugin.ts b/apps/remix-ide/src/app/plugins/electron/slitherPlugin.ts new file mode 100644 index 0000000000..b08cca82c2 --- /dev/null +++ b/apps/remix-ide/src/app/plugins/electron/slitherPlugin.ts @@ -0,0 +1,13 @@ +import { ElectronPlugin } from '@remixproject/engine-electron'; + +export class SlitherHandleDesktop extends ElectronPlugin { + constructor() { + super({ + displayName: 'slither', + name: 'slither', + description: 'electron slither', + methods: ['analyse'] + }) + this.methods = ['analyse'] + } +} diff --git a/apps/remix-ide/src/app/plugins/permission-handler-plugin.tsx b/apps/remix-ide/src/app/plugins/permission-handler-plugin.tsx index a01425088a..6f242c1c9d 100644 --- a/apps/remix-ide/src/app/plugins/permission-handler-plugin.tsx +++ b/apps/remix-ide/src/app/plugins/permission-handler-plugin.tsx @@ -98,7 +98,7 @@ export class PermissionHandlerPlugin extends Plugin {
{}}>To change the permission go to Plugin Manager - + / Permissions
diff --git a/apps/remix-ide/src/app/plugins/remix-templates.ts b/apps/remix-ide/src/app/plugins/remix-templates.ts index e7846fbf47..8604ddb460 100644 --- a/apps/remix-ide/src/app/plugins/remix-templates.ts +++ b/apps/remix-ide/src/app/plugins/remix-templates.ts @@ -1,11 +1,12 @@ import { Plugin } from '@remixproject/engine' import * as templateWithContent from '@remix-project/remix-ws-templates' +import { TEMPLATE_METADATA } from '@remix-ui/workspace' const profile = { name: 'remix-templates', displayName: 'remix-templates', description: 'Remix Templates plugin', - methods: ['getTemplate', 'loadTemplateInNewWindow'], + methods: ['getTemplate', 'loadTemplateInNewWindow', 'loadFilesInNewWindow'], } export class TemplatesPlugin extends Plugin { @@ -23,8 +24,28 @@ export class TemplatesPlugin extends Plugin { } // electron only method async loadTemplateInNewWindow (template: string, opts?: any) { + const metadata = TEMPLATE_METADATA[template] + if (metadata) { + if (metadata.type === 'git') { + this.call('notification', 'alert', { + id: 'dgitAlert', + message: 'This template is not available in the desktop version', + }) + return + } else if (metadata.type === 'plugin'){ + this.call('notification', 'alert', { + id: 'dgitAlert', + message: 'This template is not available in the desktop version', + }) + return + } + } const files = await this.getTemplate(template, opts) this.call('electronTemplates', 'loadTemplateInNewWindow', files) } + + async loadFilesInNewWindow (files: any) { + this.call('electronTemplates', 'loadTemplateInNewWindow', files) + } } diff --git a/apps/remix-ide/src/app/plugins/remixGuide.tsx b/apps/remix-ide/src/app/plugins/remixGuide.tsx index 96d6adcf2f..2a4a79cdc2 100644 --- a/apps/remix-ide/src/app/plugins/remixGuide.tsx +++ b/apps/remix-ide/src/app/plugins/remixGuide.tsx @@ -93,7 +93,7 @@ export class RemixGuidePlugin extends ViewPlugin { { + if (!canTrack) { + console.log('Matomo tracking is disabled on Dev mode') + return + } + window._paq = { + push: function (...data) { + if (!window.localStorage.getItem('config-v0.8:.remix.config') || + (window.localStorage.getItem('config-v0.8:.remix.config') && !window.localStorage.getItem('config-v0.8:.remix.config').includes('settings/matomo-analytics'))) { + // require user tracking consent before processing data + } else { + if (JSON.parse(window.localStorage.getItem('config-v0.8:.remix.config'))['settings/matomo-analytics']) { + window.electronAPI.trackEvent(...data) + } + } + } + } + }) +} else { + if (domainToTrack) { + trackDomain(domainToTrack) + } +} function isElectron() { // Renderer process if (typeof window !== 'undefined' && typeof window.process === 'object' && window.process.type === 'renderer') { diff --git a/apps/remix-ide/src/remixAppManager.js b/apps/remix-ide/src/remixAppManager.js index dc370bd5d5..8f6ca32cc1 100644 --- a/apps/remix-ide/src/remixAppManager.js +++ b/apps/remix-ide/src/remixAppManager.js @@ -165,7 +165,7 @@ export class RemixAppManager extends PluginManager { this.pluginsDirectory = 'https://raw.githubusercontent.com/ethereum/remix-plugins-directory/master/build/metadata.json' this.pluginLoader = new PluginLoader() if (Registry.getInstance().get('platform').api.isDesktop()) { - requiredModules = [...requiredModules, 'fs', 'electronTemplates', 'isogit', 'remix-templates', 'electronconfig', 'xterm', 'compilerloader', 'ripgrep'] + requiredModules = [...requiredModules, 'fs', 'electronTemplates', 'isogit', 'remix-templates', 'electronconfig', 'xterm', 'compilerloader', 'ripgrep', 'slither'] } } @@ -299,7 +299,7 @@ export class RemixAppManager extends PluginManager { } return plugins.map(plugin => { - if (plugin.name === 'dgit' && Registry.getInstance().get('platform').api.isDesktop()) { plugin.url = 'https://dgit4-76cc9.web.app/' } // temporary fix + if (plugin.name === 'dgit' && Registry.getInstance().get('platform').api.isDesktop()) { plugin.url = 'https://dgit4-76cc9.web.app/' } if (plugin.name === testPluginName) plugin.url = testPluginUrl return new IframePlugin(plugin) }) diff --git a/apps/remixdesktop/README.md b/apps/remixdesktop/README.md index 692b5b3c4d..bd1efb612c 100644 --- a/apps/remixdesktop/README.md +++ b/apps/remixdesktop/README.md @@ -2,21 +2,159 @@ ## Development +### Running the app locally + In the main repo yarn, then run yarn serve In this directory apps/remixdesktop, yarn, then run: yarn start:dev to boot the electron app -In chrome chrome://inspect/#devices you can add localhost:5858 to the network targets and then you will see an inspect button electron/js2c/browser_init -file:/// -You can use that to inspect the output of the electron app + +Then app will be started in live reload mode, anything you do in Remix IDE will be reloaded. +It will not however reload electron code. You need to rerun yarn start:dev every time. If you run into issues with yarn when native node modules are being rebuilt you need - Windows: install Visual Studio Tools with Desktop Development C++ enabled in the Workloads -- MacOS: install Xcode or Xcode Command Line Tools +- MacOS: install Xcode or Xcode Command Line Tools. Also make sure the compilers (clang++ | g++) target the right sdk includes, ```export SDKROOT="xcrun --show-sdk-path"``` - Linux: unknown, probably a C++ compiler -## Builds -Builds can be found in the artefacts of CI. +### Electron Plugin + +Electron has its own Plugin Engine, which holds plugins, these plugins have plugin clients attached to them. Each of those clients is created when an instance of Remix Desktop connects +and activates a plugin. Follow all these steps to make that work. + +1. create a plugin file in apps/remixdesktop/src/plugins +2. add imports: +``` +import { Profile } from '@remixproject/plugin-utils' +import { ElectronBasePlugin, ElectronBasePluginClient } from '@remixproject/plugin-electron' +``` +3. add a base profile and a client profile: +``` +const profile: Profile = { + displayName: 'compilerLoader', + name: 'compilerloader', + description: 'Compiler Loader', +} +const clientProfile: Profile = { + name: 'compilerloader', + displayName: 'compilerloader', + description: 'Compiler Loader', + methods: ['downloadCompiler', 'listCompilers', 'getBaseUrls', 'getJsonBinData'], +} +``` + +As you can see in the clientProfile you define the methods which are exposed to the Remix plugin system. + +5. add a base plugin and a plugin client +``` +export class CompilerLoaderPlugin extends ElectronBasePlugin { + clients: CompilerLoaderPluginClient[] = [] + constructor() { + super(profile, clientProfile, CompilerLoaderPluginClient) + this.methods = [...super.methods] + } +} + +class CompilerLoaderPluginClient extends ElectronBasePluginClient { + solJsonBinData: iSolJsonBinData + constructor(webContentsId: number, profile: Profile) { + super(webContentsId, profile) + } + + async onActivation(): Promise { + this.onload(() => { + this.emit('loaded') + }) + } +} +``` +The ElectronBasePluginClient is the specific instance which will be connected to the IDE. The BasePlugin is just holding all the clients for all the instances. + +Any instance specific code is set as functions on the ElectronBasePluginClient class. + +6. If you need fs access you need to track the workingdir like we do here: +This ensures you know where the user is working + +``` + +class IsoGitPluginClient extends ElectronBasePluginClient { + workingDir: string = '' + + constructor(webContentsId: number, profile: Profile) { + super(webContentsId, profile) + this.onload(async () => { + this.on('fs' as any, 'workingDirChanged', async (path: string) => { + this.workingDir = path + }) + this.workingDir = await this.call('fs' as any, 'getWorkingDir') + + }) + } + + ``` + +7. If you need to call methods on the BASE which holds all the clients you can add methods there, for example this iterates over clients +and finds the one with the webContentsId. This ID passed on ie by menu items. Look at menu.ts to see how that works. + +``` + openTemplate(webContentsId: any): void { + const client = this.clients.find(c => c.webContentsId === webContentsId) + if (client) { + client.openTemplate() + } + } +``` + +8. Add your plugin to engine.ts + +``` +const compilerLoaderPlugin = new CompilerLoaderPlugin() +``` + +9. Register the plugin in engine.ts + +``` +engine.register(compilerLoaderPlugin) +``` + +10. activation of plugins is done when the clients connect to the engine. No need to activate it. + +11. Add the plugin to the preload.ts. Add it to this list: + +``` +const exposedPLugins = ['fs', 'git', 'xterm', 'isogit', 'electronconfig', 'electronTemplates', 'ripgrep', 'compilerloader', 'appUpdater'] +``` + +If you don't this, it won't work. + +12. In Remix IDE create a plugin in src/app/plugins/electron. If everything works correctly the methods will be loaded from the electron side, no need to specify them here. +This plugin is only a passthrough. + +``` +const profile = { + displayName: 'compilerLoader', + name: 'compilerloader', + description: 'Loads the compiler for offline use', +} + +export class compilerLoaderPluginDesktop extends ElectronPlugin { + constructor() { + super(profile) + this.methods = [] + } + + async onActivation(): Promise { + + // something to do + + } +} +``` + +13. if you need to activate that on load you need to add it to the app.js where other plugins are activated. + + ## CI -CI will only run the builds is the branch is master or contains the word: desktop \ No newline at end of file +CI will only run the builds is the branch is master or contains the word: desktop + diff --git a/apps/remixdesktop/after-pack.js b/apps/remixdesktop/after-pack.js new file mode 100644 index 0000000000..692890f813 --- /dev/null +++ b/apps/remixdesktop/after-pack.js @@ -0,0 +1,14 @@ +const fs = require('fs-extra'); +const path = require('path'); + +exports.default = async function (context) { + console.log('Running after-pack hook', context); + const resourcesPath = context.appOutDir; + console.log('resourcesPath', resourcesPath); + console.log('context outdir', context.appOutDir); + // Copy the node-pty module to the app folder + await fs.copy( + path.join('./node_modules', 'node-pty'), + path.join(resourcesPath, 'node_modules', 'node-pty') + ); +}; diff --git a/apps/remixdesktop/afterbuild.js b/apps/remixdesktop/afterbuild.js new file mode 100644 index 0000000000..bc2b1ff49d --- /dev/null +++ b/apps/remixdesktop/afterbuild.js @@ -0,0 +1,30 @@ +const fs = require('fs'); + +exports.default = async function afterbuild(context) { + // do not run when not on macOS or when not on CIRCLECI + if (process.platform !== 'darwin' || !process.env.CIRCLE_BRANCH) { + return; + } + + console.log('AFTER BUILD', context); + + const artifactPaths = context.artifactPaths; + const newDmgs = artifactPaths.filter((dmg) => dmg.endsWith('.dmg')).map((dmg) => dmg); // Removed unnecessary quotes for consistency + + let existingDmgs = []; + try { + // Attempt to read the existing dmgs.json file + const data = fs.readFileSync('dmgs.json', 'utf8'); + const parsedData = JSON.parse(data); + existingDmgs = parsedData.dmgs || []; // Ensure existingDmgs is an array + } catch (error) { + // If there's an error reading the file (e.g., file does not exist), proceed with an empty array + console.log('No existing dmgs.json or error reading file, creating new one.'); + } + + // Combine existing and new dmgs, avoiding duplicates + const combinedDmgs = [...new Set([...existingDmgs, ...newDmgs])]; + + // Write/overwrite the dmgs.json with the combined list of dmgs + fs.writeFileSync('dmgs.json', JSON.stringify({ dmgs: combinedDmgs }, null, 2)); +}; diff --git a/apps/remixdesktop/aftersign.js b/apps/remixdesktop/aftersign.js new file mode 100644 index 0000000000..bb1e2102c9 --- /dev/null +++ b/apps/remixdesktop/aftersign.js @@ -0,0 +1,104 @@ +const { notarize } = require('@electron/notarize') +const fs = require('fs') +const { exec } = require('child_process') // Import the exec function + +// read the environment variables from process + +console.log(process.env.DO_NOT_NOTARIZE) + +if (process.env.DO_NOT_NOTARIZE) { + console.log('NOTARIZING DISABLED') + exports.default = async function notarizing(context) { + return [] + } +} else { + + exports.default = async function notarizing(context) { + const { electronPlatformName, appOutDir } = context // Provided by electron-builder + + console.log('NOTARIZING') + + if (electronPlatformName !== 'darwin' || !process.env.CIRCLE_BRANCH) { + return + } + + const appName = context.packager.appInfo.productFilename + const appPath = `${appOutDir}/${appName}.app` + + // Function to promisify the exec command + function execShellCommand(cmd) { + return new Promise((resolve, reject) => { + exec(cmd, (error, stdout, stderr) => { + if (error) { + reject(new Error(`Error: ${error.message}`)); + return; + } + if (stderr) { + reject(new Error(`Stderr: ${stderr}`)); + return; + } + console.log(`stdout: ${stdout}`); + resolve(stdout); + }); + }); + } + + // Function to check if the app is stapled + // Async function to check the stapling status + async function checkStapleStatus() { + try { + console.log(`xcrun stapler validate "${appPath}"`) + await execShellCommand(`xcrun stapler validate "${appPath}"`); + console.log('App is already stapled. No action needed.'); + return true + } catch (error) { + console.log(`App is not stapled: ${error.message}`); + return false + } + } + + + + + async function runNotarize() { + + console.log('NOTARIZING + ', `xcrun stapler staple "${appPath}"`) + console.log({ + appBundleId: 'org.ethereum.remix-ide', // Your app's bundle ID + appPath: `${appOutDir}/${appName}.app`, // Path to your .app + appleId: process.env.APPLE_ID, // Your Apple ID + appleIdPassword: process.env.APPLE_ID_PASSWORD, // App-specific password + teamId: process.env.APPLE_TEAM_ID, // Your Apple Developer team ID (optional) + }) + + try { + const r = await notarize({ + appBundleId: 'org.ethereum.remix-ide', // Your app's bundle ID + appPath: `${appOutDir}/${appName}.app`, // Path to your .app + appleId: process.env.APPLE_ID, // Your Apple ID + appleIdPassword: process.env.APPLE_ID_PASSWORD, // App-specific password + teamId: process.env.APPLE_TEAM_ID, // Your Apple Developer team ID (optional) + }) + + console.log(r) + + // Stapling the app + console.log('STAPLING', `xcrun stapler staple "${appPath}"`) + + await execShellCommand(`xcrun stapler staple "${appPath}"`) + + } catch (error) { + console.error('Error during notarization:', error) + throw new Error('Error during notarization', error) + } + + } + + if (!await checkStapleStatus()) { + await runNotarize() + await checkStapleStatus() + } else { + return [] + } + } +} \ No newline at end of file diff --git a/apps/remixdesktop/alpha.json b/apps/remixdesktop/alpha.json new file mode 100644 index 0000000000..c1fc03dd53 --- /dev/null +++ b/apps/remixdesktop/alpha.json @@ -0,0 +1,61 @@ +{ + "productName": "Remix-Desktop-alpha", + "appId": "org.ethereum.remix-ide", + "asar": true, + "generateUpdatesFilesForAllChannels": false, + "icon": "assets", + "files": [ + "build/**/*" + ], + "afterSign": "aftersign.js", + "afterAllArtifactBuild": "afterbuild.js", + "publish": [ + { + "provider": "github", + "owner": "remix-project-org", + "repo": "remix-desktop-alpha", + "releaseType": "draft", + "publishAutoUpdate": true + } + ], + "mac": { + "category": "public.app-category.productivity", + "icon": "assets/icon.png", + "darkModeSupport": true, + "hardenedRuntime": true, + "gatekeeperAssess": false, + "entitlements": "entitlements.mac.plist", + "entitlementsInherit": "entitlements.mac.plist" + }, + "dmg": { + "writeUpdateInfo": true, + "sign": true + }, + "nsis": { + "createDesktopShortcut": "always", + "allowToChangeInstallationDirectory": true, + "oneClick": false, + "shortcutName": "Remix Desktop alpha", + "differentialPackage": false + }, + "win": { + "target": [ + "nsis" + ], + "artifactName": "${productName}-Setup-${version}.${ext}", + "icon": "assets/icon.png" + }, + "deb": {}, + "linux": { + "target": [ + "deb", + "snap", + "AppImage" + ], + "category": "WebBrowser", + "icon": "assets" + }, + "directories": { + "output": "release" + } +} \ No newline at end of file diff --git a/apps/remixdesktop/beta.json b/apps/remixdesktop/beta.json new file mode 100644 index 0000000000..7087d9147b --- /dev/null +++ b/apps/remixdesktop/beta.json @@ -0,0 +1,61 @@ +{ + "productName": "Remix-Desktop-Beta", + "appId": "org.ethereum.remix-ide", + "asar": true, + "generateUpdatesFilesForAllChannels": false, + "icon": "assets", + "files": [ + "build/**/*" + ], + "afterSign": "aftersign.js", + "afterAllArtifactBuild": "afterbuild.js", + "publish": [ + { + "provider": "github", + "owner": "remix-project-org", + "repo": "remix-desktop-beta", + "releaseType": "draft", + "publishAutoUpdate": true + } + ], + "mac": { + "category": "public.app-category.productivity", + "icon": "assets/icon.png", + "darkModeSupport": true, + "hardenedRuntime": true, + "gatekeeperAssess": false, + "entitlements": "entitlements.mac.plist", + "entitlementsInherit": "entitlements.mac.plist" + }, + "dmg": { + "writeUpdateInfo": true, + "sign": true + }, + "nsis": { + "createDesktopShortcut": "always", + "allowToChangeInstallationDirectory": true, + "oneClick": false, + "shortcutName": "Remix Desktop Beta", + "differentialPackage": false + }, + "win": { + "target": [ + "nsis" + ], + "artifactName": "Remix-Desktop-Setup-${version}.${ext}", + "icon": "assets/icon.png" + }, + "deb": {}, + "linux": { + "target": [ + "deb", + "snap", + "AppImage" + ], + "category": "WebBrowser", + "icon": "assets" + }, + "directories": { + "output": "release" + } +} \ No newline at end of file diff --git a/apps/remixdesktop/entitlements.mac.plist b/apps/remixdesktop/entitlements.mac.plist new file mode 100644 index 0000000000..0be645bdc8 --- /dev/null +++ b/apps/remixdesktop/entitlements.mac.plist @@ -0,0 +1,13 @@ + + + + + + com.apple.security.cs.allow-jit + + com.apple.security.cs.allow-unsigned-executable-memory + + com.apple.security.cs.allow-dyld-environment-variables + + + \ No newline at end of file diff --git a/apps/remixdesktop/esbuild.js b/apps/remixdesktop/esbuild.js new file mode 100644 index 0000000000..88ce4045eb --- /dev/null +++ b/apps/remixdesktop/esbuild.js @@ -0,0 +1,12 @@ +const esbuild = require('esbuild'); + +esbuild.build({ + entryPoints: ['src/main.ts', 'src/preload.ts'], // Your TypeScript entry point + outdir: 'build', // Output bundled file + bundle: true, // Bundle all dependencies + platform: 'node', // Target Node.js platform + external: ['electron', 'fsevents', 'node-pty'], // Exclude native modules + target: ['node20'], // Match the Node.js version for Electron + tsconfig: 'tsconfig.json', // Your TypeScript config + minify: false, // Optional: Minify for production +}).catch(() => process.exit(1)); diff --git a/apps/remixdesktop/insiders.json b/apps/remixdesktop/insiders.json new file mode 100644 index 0000000000..4b5bd39c00 --- /dev/null +++ b/apps/remixdesktop/insiders.json @@ -0,0 +1,62 @@ +{ + "productName": "Remix-Desktop-Insiders", + "appId": "org.ethereum.remix-ide", + "asar": true, + "generateUpdatesFilesForAllChannels": false, + "icon": "assets", + "files": [ + "build/**/*", + "node_modules/node-pty/**/*" + ], + "afterSign": "aftersign.js", + "afterAllArtifactBuild": "afterbuild.js", + "publish": [ + { + "provider": "github", + "owner": "remix-project-org", + "repo": "remix-desktop-insiders", + "releaseType": "draft", + "publishAutoUpdate": true + } + ], + "mac": { + "category": "public.app-category.productivity", + "icon": "assets/icon.png", + "darkModeSupport": true, + "hardenedRuntime": true, + "gatekeeperAssess": false, + "entitlements": "entitlements.mac.plist", + "entitlementsInherit": "entitlements.mac.plist" + }, + "dmg": { + "writeUpdateInfo": true, + "sign": true + }, + "nsis": { + "createDesktopShortcut": "always", + "allowToChangeInstallationDirectory": true, + "oneClick": false, + "shortcutName": "Remix Desktop Insiders", + "differentialPackage": false + }, + "win": { + "target": [ + "nsis" + ], + "artifactName": "Remix-Desktop-Setup-${version}.${ext}", + "icon": "assets/icon.png" + }, + "deb": {}, + "linux": { + "target": [ + "deb", + "snap", + "AppImage" + ], + "category": "WebBrowser", + "icon": "assets" + }, + "directories": { + "output": "release" + } +} \ No newline at end of file diff --git a/apps/remixdesktop/latest.json b/apps/remixdesktop/latest.json new file mode 100644 index 0000000000..dd2f962c8c --- /dev/null +++ b/apps/remixdesktop/latest.json @@ -0,0 +1,61 @@ +{ + "productName": "Remix-Desktop", + "appId": "org.ethereum.remix-ide", + "asar": true, + "generateUpdatesFilesForAllChannels": false, + "icon": "assets", + "files": [ + "build/**/*" + ], + "afterSign": "aftersign.js", + "afterAllArtifactBuild": "afterbuild.js", + "publish": [ + { + "provider": "github", + "owner": "remix-project-org", + "repo": "remix-desktop", + "releaseType": "draft", + "publishAutoUpdate": true + } + ], + "mac": { + "category": "public.app-category.productivity", + "icon": "assets/icon.png", + "darkModeSupport": true, + "hardenedRuntime": true, + "gatekeeperAssess": false, + "entitlements": "entitlements.mac.plist", + "entitlementsInherit": "entitlements.mac.plist" + }, + "dmg": { + "writeUpdateInfo": true, + "sign": true + }, + "nsis": { + "createDesktopShortcut": "always", + "allowToChangeInstallationDirectory": true, + "oneClick": false, + "shortcutName": "Remix Desktop", + "differentialPackage": false + }, + "win": { + "target": [ + "nsis" + ], + "artifactName": "${productName}-Setup-${version}.${ext}", + "icon": "assets/icon.png" + }, + "deb": {}, + "linux": { + "target": [ + "deb", + "snap", + "AppImage" + ], + "category": "WebBrowser", + "icon": "assets" + }, + "directories": { + "output": "release" + } +} \ No newline at end of file diff --git a/apps/remixdesktop/nightwatch.conf.js b/apps/remixdesktop/nightwatch.conf.js new file mode 100644 index 0000000000..03f35c4350 --- /dev/null +++ b/apps/remixdesktop/nightwatch.conf.js @@ -0,0 +1,344 @@ +// +// Refer to the online docs for more details: +// https://nightwatchjs.org/guide/configuration/nightwatch-configuration-file.html +// +// _ _ _ _ _ _ _ +// | \ | |(_) | | | | | | | | +// | \| | _ __ _ | |__ | |_ __ __ __ _ | |_ ___ | |__ +// | . ` || | / _` || '_ \ | __|\ \ /\ / / / _` || __| / __|| '_ \ +// | |\ || || (_| || | | || |_ \ V V / | (_| || |_ | (__ | | | | +// \_| \_/|_| \__, ||_| |_| \__| \_/\_/ \__,_| \__| \___||_| |_| +// __/ | +// |___/ +// + +module.exports = { + // An array of folders (excluding subfolders) where your tests are located; + // if this is not specified, the test source must be passed as the second argument to the test runner. + src_folders: [], + + // See https://nightwatchjs.org/guide/concepts/page-object-model.html + page_objects_path: ['node_modules/nightwatch/examples/pages/'], + + // See https://nightwatchjs.org/guide/extending-nightwatch/adding-custom-commands.html + custom_commands_path: ['node_modules/nightwatch/examples/custom-commands/'], + + // See https://nightwatchjs.org/guide/extending-nightwatch/adding-custom-assertions.html + custom_assertions_path: '', + + // See https://nightwatchjs.org/guide/extending-nightwatch/adding-plugins.html + plugins: [], + + // See https://nightwatchjs.org/guide/concepts/test-globals.html#external-test-globals + globals_path : '', + + webdriver: {}, + + test_settings: { + default: { + disable_error_log: false, + launch_url: 'https://nightwatchjs.org', + + screenshots: { + enabled: false, + path: 'screens', + on_failure: true + }, + + desiredCapabilities: { + browserName : 'firefox' + }, + + webdriver: { + start_process: true, + server_path: '' + } + }, + + + + firefox: { + desiredCapabilities : { + browserName : 'firefox', + alwaysMatch: { + acceptInsecureCerts: true, + 'moz:firefoxOptions': { + args: [ + // '-headless', + // '-verbose' + ] + } + } + }, + webdriver: { + start_process: true, + server_path: '', + cli_args: [ + // very verbose geckodriver logs + // '-vv' + ] + } + }, + + chrome: { + desiredCapabilities : { + browserName : 'chrome', + 'goog:chromeOptions' : { + // More info on Chromedriver: https://sites.google.com/a/chromium.org/chromedriver/ + // + // w3c:false tells Chromedriver to run using the legacy JSONWire protocol (not required in Chrome 78) + w3c: true, + args: [ + //'--no-sandbox', + //'--ignore-certificate-errors', + //'--allow-insecure-localhost', + //'--headless' + ] + } + }, + + webdriver: { + start_process: true, + server_path: '', + cli_args: [ + // --verbose + ] + } + }, + + edge: { + desiredCapabilities : { + browserName : 'MicrosoftEdge', + 'ms:edgeOptions' : { + w3c: true, + // More info on EdgeDriver: https://docs.microsoft.com/en-us/microsoft-edge/webdriver-chromium/capabilities-edge-options + args: [ + //'--headless' + ] + } + }, + + webdriver: { + start_process: true, + // Download msedgedriver from https://docs.microsoft.com/en-us/microsoft-edge/webdriver-chromium/ + // and set the location below: + server_path: '', + cli_args: [ + // --verbose + ] + } + }, + + ////////////////////////////////////////////////////////////////////////////////// + // Configuration for when using cucumber-js (https://cucumber.io) | + // | + // It uses the bundled examples inside the nightwatch examples folder; feel free | + // to adapt this to your own project needs | + ////////////////////////////////////////////////////////////////////////////////// + 'cucumber-js': { + src_folders: ['examples/cucumber-js/features/step_definitions'], + + test_runner: { + // set cucumber as the runner + type: 'cucumber', + + // define cucumber specific options + options: { + //set the feature path + feature_path: 'node_modules/nightwatch/examples/cucumber-js/*/*.feature', + + // start the webdriver session automatically (enabled by default) + // auto_start_session: true + + // use parallel execution in Cucumber + // parallel: 2 // set number of workers to use (can also be defined in the cli as --parallel 2 + } + } + }, + + ////////////////////////////////////////////////////////////////////////////////// + // Configuration for when using the browserstack.com cloud service | + // | + // Please set the username and access key by setting the environment variables: | + // - BROWSERSTACK_USERNAME | + // - BROWSERSTACK_ACCESS_KEY | + // .env files are supported | + ////////////////////////////////////////////////////////////////////////////////// + browserstack: { + selenium: { + host: 'hub.browserstack.com', + port: 443 + }, + // More info on configuring capabilities can be found on: + // https://www.browserstack.com/automate/capabilities?tag=selenium-4 + desiredCapabilities: { + 'bstack:options' : { + userName: '${BROWSERSTACK_USERNAME}', + accessKey: '${BROWSERSTACK_ACCESS_KEY}', + } + }, + + disable_error_log: true, + webdriver: { + timeout_options: { + timeout: 15000, + retry_attempts: 3 + }, + keep_alive: true, + start_process: false + } + }, + + 'browserstack.local': { + extends: 'browserstack', + desiredCapabilities: { + 'browserstack.local': true + } + }, + + 'browserstack.chrome': { + extends: 'browserstack', + desiredCapabilities: { + browserName: 'chrome', + chromeOptions : { + w3c: true + } + } + }, + + 'browserstack.firefox': { + extends: 'browserstack', + desiredCapabilities: { + browserName: 'firefox' + } + }, + + 'browserstack.ie': { + extends: 'browserstack', + desiredCapabilities: { + browserName: 'internet explorer', + browserVersion: '11.0' + } + }, + + 'browserstack.safari': { + extends: 'browserstack', + desiredCapabilities: { + browserName: 'safari' + } + }, + + 'browserstack.local_chrome': { + extends: 'browserstack.local', + desiredCapabilities: { + browserName: 'chrome' + } + }, + + 'browserstack.local_firefox': { + extends: 'browserstack.local', + desiredCapabilities: { + browserName: 'firefox' + } + }, + ////////////////////////////////////////////////////////////////////////////////// + // Configuration for when using the SauceLabs cloud service | + // | + // Please set the username and access key by setting the environment variables: | + // - SAUCE_USERNAME | + // - SAUCE_ACCESS_KEY | + ////////////////////////////////////////////////////////////////////////////////// + saucelabs: { + selenium: { + host: 'ondemand.saucelabs.com', + port: 443 + }, + // More info on configuring capabilities can be found on: + // https://docs.saucelabs.com/dev/test-configuration-options/ + desiredCapabilities: { + 'sauce:options' : { + username: '${SAUCE_USERNAME}', + accessKey: '${SAUCE_ACCESS_KEY}', + screenResolution: '1280x1024' + // https://docs.saucelabs.com/dev/cli/sauce-connect-proxy/#--region + // region: 'us-west-1' + // https://docs.saucelabs.com/dev/test-configuration-options/#tunnelidentifier + // parentTunnel: '', + // tunnelIdentifier: '', + } + }, + disable_error_log: false, + webdriver: { + start_process: false + } + }, + 'saucelabs.chrome': { + extends: 'saucelabs', + desiredCapabilities: { + browserName: 'chrome', + browserVersion: 'latest', + javascriptEnabled: true, + acceptSslCerts: true, + timeZone: 'London', + chromeOptions : { + w3c: true + } + } + }, + 'saucelabs.firefox': { + extends: 'saucelabs', + desiredCapabilities: { + browserName: 'firefox', + browserVersion: 'latest', + javascriptEnabled: true, + acceptSslCerts: true, + timeZone: 'London' + } + }, + ////////////////////////////////////////////////////////////////////////////////// + // Configuration for when using the Selenium service, either locally or remote, | + // like Selenium Grid | + ////////////////////////////////////////////////////////////////////////////////// + selenium_server: { + // Selenium Server is running locally and is managed by Nightwatch + // Install the NPM package @nightwatch/selenium-server or download the selenium server jar file from https://github.com/SeleniumHQ/selenium/releases/, e.g.: selenium-server-4.1.1.jar + selenium: { + start_process: true, + port: 4444, + server_path: '', // Leave empty if @nightwatch/selenium-server is installed + command: 'standalone', // Selenium 4 only + cli_args: { + //'webdriver.gecko.driver': '', + //'webdriver.chrome.driver': '' + } + }, + webdriver: { + start_process: false, + default_path_prefix: '/wd/hub' + } + }, + + 'selenium.chrome': { + extends: 'selenium_server', + desiredCapabilities: { + browserName: 'chrome', + chromeOptions : { + w3c: true + } + } + }, + + 'selenium.firefox': { + extends: 'selenium_server', + desiredCapabilities: { + browserName: 'firefox', + 'moz:firefoxOptions': { + args: [ + // '-headless', + // '-verbose' + ] + } + } + } + } +}; diff --git a/apps/remixdesktop/notarizedmg.sh b/apps/remixdesktop/notarizedmg.sh new file mode 100644 index 0000000000..3522476f08 --- /dev/null +++ b/apps/remixdesktop/notarizedmg.sh @@ -0,0 +1,39 @@ +#!/bin/bash + +# Path to the JSON file containing the DMG paths +JSON_FILE="dmgs.json" + +# Read the DMGs array from the JSON file +DMG_PATHS=$(jq -r '.dmgs[]' "$JSON_FILE") + +echo $DMG_PATHS + +xcrun notarytool store-credentials "notarytool-password" \ + --apple-id ${APPLE_ID} \ + --team-id ${APPLE_TEAM_ID} \ + --password ${APPLE_ID_PASSWORD} || exit 1 + +# Use jq to parse the DMGs array and read each line +while IFS= read -r DMG_PATH; do + # Remove single quotes from the path if present + DMG_PATH_CLEANED=$(echo $DMG_PATH | tr -d "'") + + echo "Submitting $DMG_PATH_CLEANED for notarization..." + + # Replace `your-app-specific-args` with the actual arguments for your app + # Ensure your notarytool command and arguments are correct for your application + xcrun notarytool submit "$DMG_PATH_CLEANED" --keychain-profile "notarytool-password" --wait + + # Check the command's success + if [ $? -eq 0 ]; then + echo "Successfully submitted $DMG_PATH_CLEANED for notarization." + xcrun stapler staple "$DMG_PATH_CLEANED" + echo "Successfully stapled $DMG_PATH_CLEANED." + spctl -a -t open -vvv --context context:primary-signature "$DMG_PATH_CLEANED" + echo "Successfully checked $DMG_PATH_CLEANED." + else + echo "Failed to submit $DMG_PATH_CLEANED for notarization." + fi +done < <(jq -r '.dmgs[]' "$JSON_FILE") + +echo "All DMG submissions completed." diff --git a/apps/remixdesktop/package.json b/apps/remixdesktop/package.json index 0651bff88b..edbeb7e263 100644 --- a/apps/remixdesktop/package.json +++ b/apps/remixdesktop/package.json @@ -1,18 +1,21 @@ { "name": "remixdesktop", - "version": "0.0.11-Alpha", + "version": "1.0.8-insiders", "main": "build/main.js", "license": "MIT", "type": "commonjs", "description": "Remix IDE Desktop", "repository": { "type": "git", - "url": "git+https://github.com/bunsenstraat/remix-desktop.git" + "url": "git+https://github.com/remix-project-org/remix-desktop.git" }, "author": { "name": "Remix Team", "email": "remix@ethereum.org" }, + "engines": { + "node": "20.2.0" + }, "bugs": { "url": "https://github.com/ethereum/remix-project/issues" }, @@ -22,100 +25,65 @@ "category": "public.app-category.productivity" }, "scripts": { - "start:dev": "tsc && cp -R node_modules/yarn build/tools/ && cross-env NODE_ENV=development electron --inspect=5858 .", - "start:production": "tsc && && cp -R node_modules/yarn build/tools/ && cross-env NODE_ENV=production electron .", - "dist": "tsc && cp -R node_modules/yarn build/tools/ && electron-builder", + "start:dev": "yarn webpack --config webpack.config.js && electron --inspect=5858 .", + "start:production": "cross-env NODE_ENV=production yarn webpack --config webpack.config.js && electron .", + "dist": "cross-env NODE_ENV=production yarn webpack --config webpack.config.js && electron-builder -p never", + "tscbuild": "tsc && cp -R node_modules/yarn build/tools/ && electron-builder -p never", + "esbuild": "cross-env NODE_ENV=production node esbuild.js && electron-builder -p never", "installRipGrepMacOXx64": "rm -rf node_modules/@vscode/ripgrep/bin && npm_config_arch=x64 node node_modules/@vscode/ripgrep/lib/postinstall.js", "installRipGrepMacOXarm64": "rm -rf node_modules/@vscode/ripgrep/bin && npm_config_arch=arm64 node node_modules/@vscode/ripgrep/lib/postinstall.js", - "postinstall": "electron-builder install-app-deps" + "postinstall": "electron-builder install-app-deps", + "test": "yarn run build:e2e && nightwatch --config build-e2e/remixdesktop/test/nighwatch.app.js", + "test:isogit": "yarn run test --use-isogit", + "test:offline": "yarn run test --use-offline --test build-e2e/remixdesktop/test/tests/app/offline.test.js", + "build:e2e": "tsc -p tsconfig.e2e.json" }, "devDependencies": { - "@electron/rebuild": "^3.2.13", + "@electron/notarize": "^2.3.0", "@types/byline": "^4.2.35", "@types/express": "^4.17.21", + "@types/nightwatch": "^2.3.23", + "chromedriver": "116", "cross-env": "^7.0.3", - "electron": "^25.0.1", - "electron-builder": "^23.6.0", + "deep-equal": "^2.2.3", + "electron": "^26.0.0", + "electron-builder": "24.9.1", "electron-devtools-installer": "^3.2.0", + "esbuild": "^0.23.1", + "nightwatch": "2.3", + "node-loader": "^2.0.0", + "selenium-standalone": "^9.3.1", + "tree-kill": "^1.2.2", + "ts-loader": "^9.5.1", + "tsconfig-paths-webpack-plugin": "^4.1.0", "typescript": "^5.1.3", + "webpack": "^5.92.1", + "webpack-cli": "^5.1.4", + "webpack-merge": "^6.0.1", + "webpack-node-externals": "^3.0.0", "yarn": "^1.22.21" }, "dependencies": { "@remix-project/remix-url-resolver": "^0.0.65", - "@remixproject/engine": "0.3.41", - "@remixproject/engine-electron": "0.3.41", - "@remixproject/plugin": "0.3.41", - "@remixproject/plugin-api": "^0.3.38", - "@remixproject/plugin-electron": "0.3.41", + "@remixproject/engine": "0.3.43", + "@remixproject/engine-electron": "0.3.43", + "@remixproject/plugin": "0.3.43", + "@remixproject/plugin-api": "^0.3.43", + "@remixproject/plugin-electron": "0.3.43", "@vscode/ripgrep": "^1.15.6", "add": "^2.0.6", "axios": "^1.7.4", "byline": "^5.0.0", "chokidar": "^3.5.3", + "electron-updater": "^6.1.8", "express": "^4.20.0", "isomorphic-git": "^1.24.2", - "node-pty": "^0.10.1", + "matomo-tracker": "^2.2.4", + "node-pty": "^1.0.0", + "octokit": "^3.1.2", "semver": "^7.5.4" }, "optionalDependencies": { "@remix-project/remix-ws-templates": "^1.0.27" - }, - "build": { - "productName": "Remix IDE", - "appId": "org.ethereum.remix-ide", - "asar": true, - "generateUpdatesFilesForAllChannels": true, - "icon": "assets", - "files": [ - "build/**/*" - ], - "publish": [{ - "provider": "github", - "owner": "bunsenstraat", - "repo": "remix-desktop", - "releaseType": "draft", - "publishAutoUpdate": true - }], - "mac": { - "category": "public.app-category.productivity", - "target": [ - { - "target": "dmg", - "arch": [ - "x64", - "arm64" - ] - } - ], - "icon": "assets/icon.png", - "darkModeSupport": true - }, - "dmg": { - "writeUpdateInfo": false - }, - "nsis": { - "createDesktopShortcut": "always", - "allowToChangeInstallationDirectory": true, - "oneClick": false, - "shortcutName": "Remix IDE", - "differentialPackage": false - }, - "win": { - "target": [ - "nsis" - ], - "icon": "assets/icon.png", - "artifactName": "${productName}.${ext}" - }, - "linux": { - "target": [ - "deb" - ], - "category": "WebBrowser", - "icon": "assets" - }, - "directories": { - "output": "release" - } } } diff --git a/apps/remixdesktop/run_ci_test.sh b/apps/remixdesktop/run_ci_test.sh new file mode 100755 index 0000000000..9b3ebfcdd1 --- /dev/null +++ b/apps/remixdesktop/run_ci_test.sh @@ -0,0 +1,19 @@ +#!/usr/bin/env bash +set -e +TEST_EXITCODE=0 +yarn run build:e2e && node ./splice_tests.js +TESTFILES=$(node ./splice_tests.js | circleci tests split --split-by=timings) +for TESTFILE in $TESTFILES; do + yarn run test --test ./build-e2e/remixdesktop/test/tests/app/${TESTFILE} || yarn run test --test ./build-e2e/remixdesktop/test/tests/app/${TESTFILE} || TEST_EXITCODE=1 +done + + +if [ "$CIRCLE_NODE_INDEX" -eq 1 ]; then + yarn test:offline || TEST_EXITCODE=1 +fi + +echo "$TEST_EXITCODE" +if [ "$TEST_EXITCODE" -eq 1 ] +then + exit 1 +fi diff --git a/apps/remixdesktop/run_git_ui_isogit_tests.sh b/apps/remixdesktop/run_git_ui_isogit_tests.sh new file mode 100755 index 0000000000..2b88b26e24 --- /dev/null +++ b/apps/remixdesktop/run_git_ui_isogit_tests.sh @@ -0,0 +1,14 @@ +#!/usr/bin/env bash +set -e +TEST_EXITCODE=0 +yarn run build:e2e && node ./splice_tests.js +TESTFILES=$(node ./splice_tests.js | grep -i 'git' | circleci tests split --split-by=timings) +for TESTFILE in $TESTFILES; do + yarn run test --use-isogit --test ./build-e2e/remixdesktop/test/tests/app/${TESTFILE} || yarn run test --use-isogit --test ./build-e2e/remixdesktop/test/tests/app/${TESTFILE} || TEST_EXITCODE=1 +done + +echo "$TEST_EXITCODE" +if [ "$TEST_EXITCODE" -eq 1 ] +then + exit 1 +fi diff --git a/apps/remixdesktop/rundist.bash b/apps/remixdesktop/rundist.bash new file mode 100755 index 0000000000..66a3a9a0dc --- /dev/null +++ b/apps/remixdesktop/rundist.bash @@ -0,0 +1,24 @@ +#!/bin/bash + +# Read the version from package.json +version=$(awk -F'"' '/"version":/ {print $4}' package.json) + +# Determine the command to run based on the version +if [[ $version == *"beta"* ]]; then + command="yarn dist -c beta.json" +elif [[ $version == *"alpha"* ]]; then + command="yarn dist -c alpha.json" +elif [[ $version == *"insiders"* ]]; then + command="yarn dist -c insiders.json" +else + command="yarn dist -c latest.json" +fi + +# Append any arguments passed in CLI +for arg in "$@"; do + command+=" $arg" +done + +# Print and run the command +echo "Running command: $command" +$command diff --git a/apps/remixdesktop/rundist_esbuild.bash b/apps/remixdesktop/rundist_esbuild.bash new file mode 100755 index 0000000000..dfda14a074 --- /dev/null +++ b/apps/remixdesktop/rundist_esbuild.bash @@ -0,0 +1,24 @@ +#!/bin/bash + +# Read the version from package.json +version=$(awk -F'"' '/"version":/ {print $4}' package.json) + +# Determine the command to run based on the version +if [[ $version == *"beta"* ]]; then + command="yarn esbuild -c beta.json" +elif [[ $version == *"alpha"* ]]; then + command="yarn esbuild -c alpha.json" +elif [[ $version == *"insiders"* ]]; then + command="yarn esbuild -c insiders.json" +else + command="yarn esbuild -c latest.json" +fi + +# Append any arguments passed in CLI +for arg in "$@"; do + command+=" $arg" +done + +# Print and run the command +echo "Running command: $command" +$command diff --git a/apps/remixdesktop/rundist_tsc.bash b/apps/remixdesktop/rundist_tsc.bash new file mode 100755 index 0000000000..886032ec62 --- /dev/null +++ b/apps/remixdesktop/rundist_tsc.bash @@ -0,0 +1,24 @@ +#!/bin/bash + +# Read the version from package.json +version=$(awk -F'"' '/"version":/ {print $4}' package.json) + +# Determine the command to run based on the version +if [[ $version == *"beta"* ]]; then + command="yarn tscbuild -c beta.json" +elif [[ $version == *"alpha"* ]]; then + command="yarn tscbuild -c alpha.json" +elif [[ $version == *"insiders"* ]]; then + command="yarn tscbuild -c insiders.json" +else + command="yarn tscbuild -c latest.json" +fi + +# Append any arguments passed in CLI +for arg in "$@"; do + command+=" $arg" +done + +# Print and run the command +echo "Running command: $command" +$command diff --git a/apps/remixdesktop/rundist_webpack.bash b/apps/remixdesktop/rundist_webpack.bash new file mode 100755 index 0000000000..66a3a9a0dc --- /dev/null +++ b/apps/remixdesktop/rundist_webpack.bash @@ -0,0 +1,24 @@ +#!/bin/bash + +# Read the version from package.json +version=$(awk -F'"' '/"version":/ {print $4}' package.json) + +# Determine the command to run based on the version +if [[ $version == *"beta"* ]]; then + command="yarn dist -c beta.json" +elif [[ $version == *"alpha"* ]]; then + command="yarn dist -c alpha.json" +elif [[ $version == *"insiders"* ]]; then + command="yarn dist -c insiders.json" +else + command="yarn dist -c latest.json" +fi + +# Append any arguments passed in CLI +for arg in "$@"; do + command+=" $arg" +done + +# Print and run the command +echo "Running command: $command" +$command diff --git a/apps/remixdesktop/splice_tests.js b/apps/remixdesktop/splice_tests.js new file mode 100755 index 0000000000..2ee58d0c02 --- /dev/null +++ b/apps/remixdesktop/splice_tests.js @@ -0,0 +1,35 @@ +const fs = require('fs'); +const path = require('path'); + +// Directory to read files from +const testDirectory = './build-e2e/remixdesktop/test/tests/app/'; + +// Function to read files in a directory and return their paths +function getTestFiles(directory) { + return fs.readdirSync(directory) + .filter(file => file.endsWith('.test.js')) // Get only .test.js files + .map(file => path.join(directory, file)); // Return full path of each file +} + +// Function to check if a file contains a specific word +function fileContainsWord(filePath, word) { + const content = fs.readFileSync(filePath, 'utf-8'); // Read file content + return content.includes(word); // Check if word is in content +} + +// Function to filter out files that do not contain the specified word +function filterFilesByWord(files, word) { + return files.filter(file => fileContainsWord(file, word)); // Return files that do not contain the word +} + +// Get all test files in the specified directory +const testFiles = getTestFiles(testDirectory); + +// Filter out files that do not contain "@offline" +const filteredFiles = filterFilesByWord(testFiles, ''); + +// Output the list of filtered files +//console.log('Files without "@offline":', filteredFiles); +for (let i = 0; i < filteredFiles.length; i++) { + console.log(path.basename(filteredFiles[i])); +} diff --git a/apps/remixdesktop/src/engine.ts b/apps/remixdesktop/src/engine.ts index 004f2d13e1..534cdf850c 100644 --- a/apps/remixdesktop/src/engine.ts +++ b/apps/remixdesktop/src/engine.ts @@ -9,6 +9,11 @@ import { ConfigPlugin } from './plugins/configPlugin'; import { TemplatesPlugin } from './plugins/templates'; import { RipgrepPlugin } from './plugins/ripgrepPlugin'; import { CompilerLoaderPlugin } from './plugins/compilerLoader'; +import { SlitherPlugin } from './plugins/slitherPlugin'; +import { AppUpdaterPlugin } from './plugins/appUpdater'; +import { FoundryPlugin } from './plugins/foundryPlugin'; +import { HardhatPlugin } from './plugins/hardhatPlugin'; +import { isE2E } from './main'; const engine = new Engine() const appManager = new PluginManager() @@ -19,6 +24,10 @@ const configPlugin = new ConfigPlugin() const templatesPlugin = new TemplatesPlugin() const ripgrepPlugin = new RipgrepPlugin() const compilerLoaderPlugin = new CompilerLoaderPlugin() +const slitherPlugin = new SlitherPlugin() +const appUpdaterPlugin = new AppUpdaterPlugin() +const foundryPlugin = new FoundryPlugin() +const hardhatPlugin = new HardhatPlugin() engine.register(appManager) engine.register(fsPlugin) @@ -28,6 +37,10 @@ engine.register(configPlugin) engine.register(templatesPlugin) engine.register(ripgrepPlugin) engine.register(compilerLoaderPlugin) +engine.register(slitherPlugin) +engine.register(foundryPlugin) +engine.register(appUpdaterPlugin) +engine.register(hardhatPlugin) appManager.activatePlugin('electronconfig') appManager.activatePlugin('fs') @@ -40,6 +53,18 @@ ipcMain.on('fs:openFolder', async (event, path?) => { fsPlugin.openFolder(event, path) }) +ipcMain.handle('fs:openFolder', async (event, webContentsId, path?) => { + if(!isE2E) return + console.log('openFolder', webContentsId, path) + fsPlugin.openFolder(webContentsId, path) +}) + +ipcMain.handle('fs:openFolderInSameWindow', async (event, webContentsId, path?) => { + if(!isE2E) return + console.log('openFolderInSameWindow', webContentsId, path) + fsPlugin.openFolderInSameWindow(webContentsId, path) +}) + ipcMain.on('terminal:new', async (event) => { xtermPlugin.new(event) @@ -53,12 +78,6 @@ ipcMain.on('git:startclone', async (event) => { isoGitPlugin.startClone(event) }) -ipcMain.on('terminal:new', async (event) => { - console.log('new terminal') - xtermPlugin.new(event) -}) - - ipcMain.handle('getWebContentsID', (event, message) => { return event.sender.id }) diff --git a/apps/remixdesktop/src/lib/remixd.ts b/apps/remixdesktop/src/lib/remixd.ts new file mode 100644 index 0000000000..ea3c2afd2b --- /dev/null +++ b/apps/remixdesktop/src/lib/remixd.ts @@ -0,0 +1,37 @@ +import { ElectronBasePluginClient } from "@remixproject/plugin-electron"; +import { Profile } from "@remixproject/plugin-utils"; + +export class ElectronBasePluginRemixdClient extends ElectronBasePluginClient { + log: (...message: any) => void + error: (...message: any) => void + + currentSharedFolder: string = '' + constructor(webContentsId: number, profile: Profile) { + super(webContentsId, profile); + this.log = (...message: any) => { + for(const m of message) { + this.call('terminal', 'log', { + type: 'log', + value: m + }) + } + } + this.error = (...message: any) => { + for(const m of message) { + this.call('terminal', 'log', { + type: 'error', + value: m + }) + } + } + + + this.onload(async () => { + this.on('fs' as any, 'workingDirChanged', async (path: string) => { + console.log('workingDirChanged base remixd', path) + this.currentSharedFolder = path + }) + this.currentSharedFolder = await this.call('fs' as any, 'getWorkingDir') + }) + } + } \ No newline at end of file diff --git a/apps/remixdesktop/src/lib/utils.ts b/apps/remixdesktop/src/lib/utils.ts new file mode 100644 index 0000000000..1520915d8b --- /dev/null +++ b/apps/remixdesktop/src/lib/utils.ts @@ -0,0 +1,24 @@ +import * as pathModule from 'path' +/** + * returns the absolute path of the given @arg path + * + * @param {String} path - relative path (Unix style which is the one used by Remix IDE) + * @param {String} sharedFolder - absolute shared path. platform dependent representation. + * @return {String} platform dependent absolute path (/home/user1/.../... for unix, c:\user\...\... for windows) + */ +function absolutePath (path: string, sharedFolder:string): string { + path = normalizePath(path) + path = pathModule.resolve(sharedFolder, path) + return path +} +function normalizePath (path) { + if (path === '/') path = './' + if (process.platform === 'win32') { + return path.replace(/\//g, '\\') + } + return path +} + +export { absolutePath, normalizePath } + + diff --git a/apps/remixdesktop/src/main.ts b/apps/remixdesktop/src/main.ts index 1b75ec0216..863cdf6512 100644 --- a/apps/remixdesktop/src/main.ts +++ b/apps/remixdesktop/src/main.ts @@ -1,10 +1,24 @@ -import { app, BrowserWindow, dialog, Menu, MenuItem, shell, utilityProcess } from 'electron'; +import { app, BrowserWindow, dialog, Menu, MenuItem, shell, utilityProcess, screen, ipcMain } from 'electron'; import path from 'path'; export let isPackaged = false; export const version = app.getVersion(); +const args = process.argv.slice(1) +console.log("args", args) +export const isE2ELocal = args.find(arg => arg.startsWith('--e2e-local')) +export const isE2E = args.find(arg => arg.startsWith('--e2e')) + +if (isE2ELocal) { + console.log('e2e mode') +} +const cache_dir_arg = args.find(arg => arg.startsWith('--cache_dir=')) +export let cache_dir = '' +if (cache_dir_arg) { + cache_dir = cache_dir_arg.split('=')[1] +} + if ( process.mainModule && process.mainModule.filename.indexOf('app.asar') !== -1 @@ -17,14 +31,17 @@ if ( // get system home dir const homeDir = app.getPath('userData') + const windowSet = new Set([]); export const createWindow = async (dir?: string): Promise => { // Create the browser window. const mainWindow = new BrowserWindow({ - height: 800, - width: 1024, + width: (isE2E ? 2560 : screen.getPrimaryDisplay().size.width * 0.8), + height: (isE2E ? 1140 : screen.getPrimaryDisplay().size.height * 0.8), + frame: true, webPreferences: { preload: path.join(__dirname, 'preload.js') + }, }); mainWindow.webContents.setWindowOpenHandler((details) => { @@ -35,10 +52,10 @@ export const createWindow = async (dir?: string): Promise => { const params = dir ? `?opendir=${encodeURIComponent(dir)}` : ''; // and load the index.html of the app. mainWindow.loadURL( - process.env.NODE_ENV === 'production' || isPackaged ? `file://${__dirname}/remix-ide/index.html` + params : + (process.env.NODE_ENV === 'production' || isPackaged) && !isE2ELocal ? `file://${__dirname}/remix-ide/index.html` + params : 'http://localhost:8080' + params) - mainWindow.maximize(); + trackEvent('Instance', 'create_window', '', 1); if (dir) { mainWindow.setTitle(dir) @@ -49,6 +66,9 @@ export const createWindow = async (dir?: string): Promise => { windowSet.delete(mainWindow) }) + if (isE2E) + mainWindow.maximize() + windowSet.add(mainWindow) //mainWindow.webContents.openDevTools(); }; @@ -57,6 +77,8 @@ export const createWindow = async (dir?: string): Promise => { // initialization and is ready to create browser windows. // Some APIs can only be used after this event occurs. app.on('ready', async () => { + trackEvent('App', 'Launch', app.getVersion(), 1, 1); + trackEvent('App', 'OS', process.platform, 1); require('./engine') }); @@ -102,6 +124,8 @@ import ViewMenu from './menus/view'; import TerminalMenu from './menus/terminal'; import HelpMenu from './menus/help'; import { execCommand } from './menus/commands'; +import main from './menus/main'; +import { trackEvent } from './utils/matamo'; const commandKeys: Record = { @@ -110,16 +134,39 @@ const commandKeys: Record = { }; const menu = [...(process.platform === 'darwin' ? [darwinMenu(commandKeys, execCommand, showAbout)] : []), - FileMenu(commandKeys, execCommand), - GitMenu(commandKeys, execCommand), - EditMenu(commandKeys, execCommand), - ViewMenu(commandKeys, execCommand), - TerminalMenu(commandKeys, execCommand), - WindowMenu(commandKeys, execCommand, []), - HelpMenu(commandKeys, execCommand), +FileMenu(commandKeys, execCommand), +GitMenu(commandKeys, execCommand), +EditMenu(commandKeys, execCommand), +ViewMenu(commandKeys, execCommand), +TerminalMenu(commandKeys, execCommand), +WindowMenu(commandKeys, execCommand, []), +HelpMenu(commandKeys, execCommand), ] +if (!isE2E || isE2ELocal) + Menu.setApplicationMenu(Menu.buildFromTemplate(menu)) + +ipcMain.handle('logger', async (...args) => { + console.log('log:', ...args) +}) + +ipcMain.handle('config:isPackaged', async () => { + return isPackaged +}) -Menu.setApplicationMenu(Menu.buildFromTemplate(menu)) +ipcMain.handle('config:isE2E', async () => { + return isE2E +}) + +ipcMain.handle('config:canTrackMatomo', async (event, name: string) => { + console.log('config:canTrackMatomo', ((process.env.NODE_ENV === 'production' || isPackaged) && !isE2E)) + return ((process.env.NODE_ENV === 'production' || isPackaged) && !isE2E) +}) + +ipcMain.handle('matomo:trackEvent', async (event, data) => { + if (data && data[0] && data[0] === 'trackEvent') { + trackEvent(data[1], data[2], data[3], data[4]) + } +}) diff --git a/apps/remixdesktop/src/menus/file.ts b/apps/remixdesktop/src/menus/file.ts index 3693da348f..7b48bd94f6 100644 --- a/apps/remixdesktop/src/menus/file.ts +++ b/apps/remixdesktop/src/menus/file.ts @@ -1,22 +1,4 @@ import { BrowserWindow, MenuItemConstructorOptions, app, ipcMain } from 'electron'; -import fs from 'fs' -import os from 'os' -import path from 'path' -import { cacheDir } from '../utils/config'; - -let recentFolders: string[] = [] - -if (fs.existsSync(cacheDir + '/remixdesktop.json')) { - try { - // read the cache file - const cache = fs.readFileSync(cacheDir + '/remixdesktop.json') - const data = JSON.parse(cache.toString()) - recentFolders = data && data.recentFolders || [] - console.log('recentFolders', recentFolders) - } catch (e) { - - } -} export default ( commandKeys: Record, @@ -47,19 +29,6 @@ export default ( execCommand('template:open', focusedWindow); } }, - { - role: 'recentDocuments', - submenu: recentFolders.map((folder) => { - return { - label: folder, - click(item, focusedWindow) { - if(focusedWindow) { - ipcMain.emit('fs:openFolder', focusedWindow.webContents.id, folder); - } - } - } - }) - }, { role: 'close', accelerator: commandKeys['window:close'] diff --git a/apps/remixdesktop/src/plugins/appUpdater.ts b/apps/remixdesktop/src/plugins/appUpdater.ts new file mode 100644 index 0000000000..78abaa3721 --- /dev/null +++ b/apps/remixdesktop/src/plugins/appUpdater.ts @@ -0,0 +1,122 @@ +import { ElectronBasePlugin, ElectronBasePluginClient } from "@remixproject/plugin-electron" +import { Profile } from "@remixproject/plugin-utils" +import { autoUpdater } from "electron-updater" +import { app } from 'electron'; +import { isE2E } from "../main"; +import { trackEvent } from "../utils/matamo"; + +const profile = { + displayName: 'appUpdater', + name: 'appUpdater', + description: 'appUpdater', +} + +export class AppUpdaterPlugin extends ElectronBasePlugin { + clients: AppUpdaterPluginClient[] = [] + constructor() { + super(profile, clientProfile, AppUpdaterPluginClient) + this.methods = [...super.methods] + + autoUpdater.autoDownload = false + autoUpdater.disableDifferentialDownload = true + + autoUpdater.on('checking-for-update', () => { + console.log('Checking for update...'); + this.sendToLog('Checking for update...') + }) + autoUpdater.on('update-available', (info: any) => { + console.log('Update available.', info); + this.sendToLog('Update available.') + for (const client of this.clients) { + client.askForUpdate() + } + }) + autoUpdater.on('update-not-available', () => { + console.log('Update not available.'); + this.sendToLog('App is already up to date.') + + }) + autoUpdater.on('error', (err) => { + console.log('Error in auto-updater. ' + err); + this.sendToLog('Cannot find updates...') + }) + autoUpdater.on('download-progress', (progressObj) => { + let log_message = "Download speed: " + progressObj.bytesPerSecond; + log_message = log_message + ' - Downloaded ' + progressObj.percent + '%'; + log_message = log_message + ' (' + progressObj.transferred + "/" + progressObj.total + ')'; + console.log(log_message); + this.sendToLog(log_message) + }) + autoUpdater.on('update-downloaded', (info) => { + console.log('Update downloaded'); + this.sendToLog('Update downloaded') + this.sendToLog('processing download... please wait...') + for(const client of this.clients) { + client.downloadReady() + } + }) + } + + async sendToLog(message: string): Promise { + for (const client of this.clients) { + client.call('terminal', 'log', { + type: 'log', + value: message, + }) + } + } + +} + +const clientProfile: Profile = { + name: 'appUpdater', + displayName: 'appUpdater', + description: 'appUpdater', + methods: ['checkForUpdates', 'download', 'install'], +} + +class AppUpdaterPluginClient extends ElectronBasePluginClient { + constructor(webContentsId: number, profile: Profile) { + super(webContentsId, profile) + } + + async onActivation(): Promise { + this.onload(async () => { + this.emit('loaded') + if(isE2E) return + await this.checkForUpdates() + }) + } + + async askForUpdate(): Promise { + this.emit('askForUpdate') + } + + async downloadReady(): Promise { + // we do a wait here to make sure that the download is done, it's a bug in electron-updater + setTimeout(() => { + this.emit('downloadReady') + } + , 10000) + } + + async download(): Promise { + autoUpdater.downloadUpdate() + } + + async install(): Promise { + autoUpdater.quitAndInstall() + } + + async checkForUpdates(): Promise { + console.log('checkForUpdates') + this.call('terminal', 'log', { + type: 'log', + value: 'Remix Desktop version: ' + autoUpdater.currentVersion, + }) + trackEvent('App', 'CheckForUpdate', 'Remix Desktop version: ' + autoUpdater.currentVersion, 1); + + autoUpdater.checkForUpdates() + } +} + diff --git a/apps/remixdesktop/src/plugins/compilerLoader.ts b/apps/remixdesktop/src/plugins/compilerLoader.ts index e44653135c..9a74931543 100644 --- a/apps/remixdesktop/src/plugins/compilerLoader.ts +++ b/apps/remixdesktop/src/plugins/compilerLoader.ts @@ -1,16 +1,19 @@ -import {Profile} from '@remixproject/plugin-utils' -import {ElectronBasePlugin, ElectronBasePluginClient} from '@remixproject/plugin-electron' +import { Profile } from '@remixproject/plugin-utils' +import { ElectronBasePlugin, ElectronBasePluginClient } from '@remixproject/plugin-electron' import fs from 'fs/promises' import axios from 'axios' import express from 'express' -import {cacheDir} from '../utils/config' +import { cacheDir } from '../utils/config' export const baseURLBin = 'https://binaries.soliditylang.org/bin' export const baseURLWasm = 'https://binaries.soliditylang.org/wasm' const appExpress = express() +// used in e2e tests +const useOffline = process.argv.includes('--use-offline'); + console.log('cacheDir', cacheDir) appExpress.use(express.static(cacheDir)) const server = appExpress.listen(0, () => { @@ -28,9 +31,9 @@ export class CompilerLoaderPlugin extends ElectronBasePlugin { constructor() { super(profile, clientProfile, CompilerLoaderPluginClient) this.methods = [...super.methods] - ;(async () => { - await getLists() - })() + ; (async () => { + await getLists() + })() } @@ -66,16 +69,14 @@ class CompilerLoaderPluginClient extends ElectronBasePluginClient { } async onActivation(): Promise { - console.log('onActivation', 'CompilerLoaderPluginClient') this.onload(() => { - console.log('onload', 'CompilerLoaderPluginClient') this.emit('loaded') }) } async downloadCompiler(url: string): Promise { console.log('downloadCompiler', url) - if(url.includes('localhost')) return + if (url.includes('localhost')) return const plugin = this try { const fileName = url.split('/').pop() @@ -129,7 +130,7 @@ class CompilerLoaderPluginClient extends ElectronBasePluginClient { async getJsonBinData() { const lists = await this.getLists() - + this.solJsonBinData = { baseURLWasm: 'http://localhost:' + (server.address() as any).port + '/compilers', baseURLBin: 'http://localhost:' + (server.address() as any).port + '/compilers', @@ -139,11 +140,11 @@ class CompilerLoaderPluginClient extends ElectronBasePluginClient { const localCompilers = await this.listCompilers() this.solJsonBinData.wasmList && (this.solJsonBinData.wasmList = this.solJsonBinData.wasmList.map((item) => { - localCompilers.includes(item.path) ? (item.wasmURL = 'http://localhost:' + (server.address() as any).port + '/compilers/') && (item.isDownloaded=true) : (item.wasmURL = baseURLWasm) && (item.isDownloaded = false) + localCompilers.includes(item.path) ? (item.wasmURL = 'http://localhost:' + (server.address() as any).port + '/compilers/') && (item.isDownloaded = true) : (item.wasmURL = baseURLWasm) && (item.isDownloaded = false) return item })) this.solJsonBinData.binList && (this.solJsonBinData.binList = this.solJsonBinData.binList.map((item) => { - localCompilers.includes(item.path) ? (item.binURL = 'http://localhost:' + (server.address() as any).port + '/compilers/') && (item.isDownloaded=true) : (item.binURL = baseURLBin) && (item.isDownloaded = false) + localCompilers.includes(item.path) ? (item.binURL = 'http://localhost:' + (server.address() as any).port + '/compilers/') && (item.isDownloaded = true) : (item.binURL = baseURLBin) && (item.isDownloaded = false) return item })) this.emit('jsonBinDataLoaded', this.solJsonBinData) @@ -158,17 +159,19 @@ const getLists = async () => { let binData let wasmData - try { - const binRes = await axios.get(baseURLBin + '/list.json') - await fs.writeFile(cacheDir + '/binlist.json', JSON.stringify(binRes.data, null, 2)) - binData = binRes.data - } catch (e) {} - - try { - const wasmRes = await axios.get(baseURLWasm + '/list.json') - await fs.writeFile(cacheDir + '/wasmlist.json', JSON.stringify(wasmRes.data, null, 2)) - wasmData = wasmRes.data - } catch (e) {} + if (!useOffline) { + try { + const binRes = await axios.get(baseURLBin + '/list.json') + await fs.writeFile(cacheDir + '/binlist.json', JSON.stringify(binRes.data, null, 2)) + binData = binRes.data + } catch (e) { } + + try { + const wasmRes = await axios.get(baseURLWasm + '/list.json') + await fs.writeFile(cacheDir + '/wasmlist.json', JSON.stringify(wasmRes.data, null, 2)) + wasmData = wasmRes.data + } catch (e) { } + } if (!wasmData) { try { diff --git a/apps/remixdesktop/src/plugins/foundryPlugin.ts b/apps/remixdesktop/src/plugins/foundryPlugin.ts new file mode 100644 index 0000000000..71a24c58b8 --- /dev/null +++ b/apps/remixdesktop/src/plugins/foundryPlugin.ts @@ -0,0 +1,248 @@ +import { Profile } from "@remixproject/plugin-utils"; +import { ElectronBasePlugin, ElectronBasePluginClient } from "@remixproject/plugin-electron" +import chokidar from 'chokidar' +import { ElectronBasePluginRemixdClient } from "../lib/remixd" +import fs from 'fs' +import * as utils from '../lib/utils' + +import { basename, join } from "path"; +import { spawn } from "child_process"; +const profile: Profile = { + name: 'foundry', + displayName: 'electron foundry', + description: 'electron foundry', +} + +export class FoundryPlugin extends ElectronBasePlugin { + clients: any[] + constructor() { + super(profile, clientProfile, FoundryPluginClient) + this.methods = [...super.methods] + } +} + +const clientProfile: Profile = { + name: 'foundry', + displayName: 'electron foundry', + description: 'electron foundry', + methods: ['sync', 'compile'] +} + + +class FoundryPluginClient extends ElectronBasePluginRemixdClient { + + watcher: chokidar.FSWatcher + warnlog: boolean + buildPath: string + cachePath: string + logTimeout: NodeJS.Timeout + processingTimeout: NodeJS.Timeout + + async onActivation(): Promise { + console.log('Foundry plugin activated') + this.call('terminal', 'log', { type: 'log', value: 'Foundry plugin activated' }) + this.on('fs' as any, 'workingDirChanged', async (path: string) => { + console.log('workingDirChanged foundry', path) + this.currentSharedFolder = path + this.startListening() + }) + this.currentSharedFolder = await this.call('fs' as any, 'getWorkingDir') + if(this.currentSharedFolder) this.startListening() + } + + startListening() { + this.buildPath = utils.absolutePath('out', this.currentSharedFolder) + this.cachePath = utils.absolutePath('cache', this.currentSharedFolder) + console.log('Foundry plugin checking for', this.buildPath, this.cachePath) + if (fs.existsSync(this.buildPath) && fs.existsSync(this.cachePath)) { + this.listenOnFoundryCompilation() + } else { + this.listenOnFoundryFolder() + } + } + + listenOnFoundryFolder() { + console.log('Foundry out folder doesn\'t exist... waiting for the compilation.') + try { + if (this.watcher) this.watcher.close() + this.watcher = chokidar.watch(this.currentSharedFolder, { depth: 1, ignorePermissionErrors: true, ignoreInitial: true }) + // watch for new folders + this.watcher.on('addDir', (path: string) => { + console.log('add dir foundry', path) + if (fs.existsSync(this.buildPath) && fs.existsSync(this.cachePath)) { + this.listenOnFoundryCompilation() + } + }) + } catch (e) { + console.log(e) + } + } + + compile() { + return new Promise((resolve, reject) => { + const cmd = `forge build` + const options = { cwd: this.currentSharedFolder, shell: true } + const child = spawn(cmd, options) + let result = '' + let error = '' + child.stdout.on('data', (data) => { + const msg = `[Foundry Compilation]: ${data.toString()}` + console.log('\x1b[32m%s\x1b[0m', msg) + result += msg + '\n' + }) + child.stderr.on('data', (err) => { + error += `[Foundry Compilation]: ${err.toString()} \n` + }) + child.on('close', () => { + if (error && result) resolve(error + result) + else if (error) reject(error) + else resolve(result) + }) + }) + } + + checkPath() { + if (!fs.existsSync(this.buildPath) || !fs.existsSync(this.cachePath)) { + this.listenOnFoundryFolder() + return false + } + if (!fs.existsSync(join(this.cachePath, 'solidity-files-cache.json'))) return false + return true + } + + private async processArtifact() { + if (!this.checkPath()) return + const folderFiles = await fs.promises.readdir(this.buildPath) // "out" folder + try { + const cache = JSON.parse(await fs.promises.readFile(join(this.cachePath, 'solidity-files-cache.json'), { encoding: 'utf-8' })) + // name of folders are file names + for (const file of folderFiles) { + const path = join(this.buildPath, file) // out/Counter.sol/ + const compilationResult = { + input: {}, + output: { + contracts: {}, + sources: {} + }, + inputSources: { sources: {}, target: '' }, + solcVersion: null, + compilationTarget: null + } + compilationResult.inputSources.target = file + await this.readContract(path, compilationResult, cache) + this.emit('compilationFinished', compilationResult.compilationTarget, { sources: compilationResult.input }, 'soljson', compilationResult.output, compilationResult.solcVersion) + } + + clearTimeout(this.logTimeout) + this.logTimeout = setTimeout(() => { + // @ts-ignore + this.call('terminal', 'log', { type: 'log', value: `receiving compilation result from Foundry. Select a file to populate the contract interaction interface.` }) + console.log('Syncing compilation result from Foundry') + }, 1000) + + } catch (e) { + console.log(e) + } + } + + async triggerProcessArtifact() { + // prevent multiple calls + clearTimeout(this.processingTimeout) + this.processingTimeout = setTimeout(async () => await this.processArtifact(), 1000) + } + + listenOnFoundryCompilation() { + try { + console.log('Foundry out folder exists... processing the artifact.') + if (this.watcher) this.watcher.close() + this.watcher = chokidar.watch(this.cachePath, { depth: 0, ignorePermissionErrors: true, ignoreInitial: true }) + this.watcher.on('change', async () => await this.triggerProcessArtifact()) + this.watcher.on('add', async () => await this.triggerProcessArtifact()) + this.watcher.on('unlink', async () => await this.triggerProcessArtifact()) + // process the artifact on activation + this.triggerProcessArtifact() + } catch (e) { + console.log(e) + } + } + + async readContract(contractFolder, compilationResultPart, cache) { + const files = await fs.promises.readdir(contractFolder) + for (const file of files) { + const path = join(contractFolder, file) + const content = await fs.promises.readFile(path, { encoding: 'utf-8' }) + compilationResultPart.inputSources.sources[file] = { content } + await this.feedContractArtifactFile(file, content, compilationResultPart, cache) + } + } + + async feedContractArtifactFile(path, content, compilationResultPart, cache) { + const contentJSON = JSON.parse(content) + const contractName = basename(path).replace('.json', '') + + let sourcePath = '' + if (contentJSON?.metadata?.settings?.compilationTarget) { + for (const key in contentJSON.metadata.settings.compilationTarget) { + if (contentJSON.metadata.settings.compilationTarget[key] === contractName) { + sourcePath = key + break + } + } + } + + if (!sourcePath) return + + const currentCache = cache.files[sourcePath] + if (!currentCache.artifacts[contractName]) return + + // extract source and version + const metadata = contentJSON.metadata + if (metadata.compiler && metadata.compiler.version) { + compilationResultPart.solcVersion = metadata.compiler.version + } else { + compilationResultPart.solcVersion = '' + console.log('\x1b[32m%s\x1b[0m', 'compiler version not found, please update Foundry to the latest version.') + } + + if (metadata.sources) { + for (const path in metadata.sources) { + const absPath = utils.absolutePath(path, this.currentSharedFolder) + try { + const content = await fs.promises.readFile(absPath, { encoding: 'utf-8' }) + compilationResultPart.input[path] = { content } + } catch (e) { + compilationResultPart.input[path] = { content: '' } + } + } + } else { + console.log('\x1b[32m%s\x1b[0m', 'sources input not found, please update Foundry to the latest version.') + } + + compilationResultPart.compilationTarget = sourcePath + // extract data + if (!compilationResultPart.output['sources'][sourcePath]) compilationResultPart.output['sources'][sourcePath] = {} + compilationResultPart.output['sources'][sourcePath] = { + ast: contentJSON['ast'], + id: contentJSON['id'] + } + if (!compilationResultPart.output['contracts'][sourcePath]) compilationResultPart.output['contracts'][sourcePath] = {} + + contentJSON.bytecode.object = contentJSON.bytecode.object.replace('0x', '') + contentJSON.deployedBytecode.object = contentJSON.deployedBytecode.object.replace('0x', '') + compilationResultPart.output['contracts'][sourcePath][contractName] = { + abi: contentJSON.abi, + evm: { + bytecode: contentJSON.bytecode, + deployedBytecode: contentJSON.deployedBytecode, + methodIdentifiers: contentJSON.methodIdentifiers + } + } + } + + async sync() { + console.log('syncing Foundry with Remix...') + this.processArtifact() + } +} + + diff --git a/apps/remixdesktop/src/plugins/fsPlugin.ts b/apps/remixdesktop/src/plugins/fsPlugin.ts index 0a416b52a1..bbf96e0856 100644 --- a/apps/remixdesktop/src/plugins/fsPlugin.ts +++ b/apps/remixdesktop/src/plugins/fsPlugin.ts @@ -3,13 +3,16 @@ import fs from 'fs/promises' import {Profile} from '@remixproject/plugin-utils' import chokidar from 'chokidar' import {dialog, shell} from 'electron' -import {createWindow, isPackaged} from '../main' +import {createWindow, isE2E, isPackaged} from '../main' import {writeConfig} from '../utils/config' import path from 'path' import {customAction} from '@remixproject/plugin-api' import { PluginEventDataBatcher } from '../utils/pluginEventDataBatcher' - +type recentFolder = { + timestamp: number, + path: string +} const profile: Profile = { displayName: 'fs', @@ -29,36 +32,44 @@ const getBaseName = (pathName: string): string => { return path.basename(pathName) } +function onlyUnique(value: recentFolder, index: number, self: recentFolder[]) { + return self.findIndex((rc, index) => rc.path === value.path) === index +} + +const deplucateFolderList = (list: recentFolder[]): recentFolder[] => { + return list.filter(onlyUnique) +} + export class FSPlugin extends ElectronBasePlugin { clients: FSPluginClient[] = [] constructor() { - super(profile, clientProfile, FSPluginClient) + super(profile, clientProfile, isE2E? FSPluginClientE2E: FSPluginClient) this.methods = [...super.methods, 'closeWatch', 'removeCloseListener'] } async onActivation(): Promise { - const config = await this.call('electronconfig' as any, 'readConfig') + const config = await this.call('electronconfig', 'readConfig') const openedFolders = (config && config.openedFolders) || [] - const recentFolders = (config && config.recentFolders) || [] + const recentFolders: recentFolder[] = (config && config.recentFolders) || [] this.call('electronconfig', 'writeConfig', {...config, - recentFolders: recentFolders, + recentFolders: deplucateFolderList(recentFolders), openedFolders: openedFolders}) const foldersToDelete: string[] = [] - if (openedFolders && openedFolders.length) { - for (const folder of openedFolders) { + if (recentFolders && recentFolders.length) { + for (const folder of recentFolders) { try { - const stat = await fs.stat(folder) + const stat = await fs.stat(folder.path); if (stat.isDirectory()) { // do nothing } } catch (e) { console.log('error opening folder', folder, e) - foldersToDelete.push(folder) + foldersToDelete.push(folder.path) } } if (foldersToDelete.length) { - const newFolders = openedFolders.filter((f: string) => !foldersToDelete.includes(f)) - this.call('electronconfig', 'writeConfig', {recentFolders: newFolders}) + const newFolders = recentFolders.filter((f: recentFolder) => !foldersToDelete.includes(f.path)) + this.call('electronconfig', 'writeConfig', {recentFolders: deplucateFolderList(newFolders)}) } } createWindow() @@ -82,6 +93,13 @@ export class FSPlugin extends ElectronBasePlugin { client.openFolder(path) } } + + openFolderInSameWindow(webContentsId: any, path?: string): void { + const client = this.clients.find((c) => c.webContentsId === webContentsId) + if (client) { + client.openFolderInSameWindow(path) + } + } } const clientProfile: Profile = { @@ -200,6 +218,7 @@ class FSPluginClient extends ElectronBasePluginClient { } async exists(path: string): Promise { + if (this.workingDir === '') return false return fs .access(this.fixPath(path)) .then(() => true) @@ -257,7 +276,7 @@ class FSPluginClient extends ElectronBasePluginClient { depth: 0, }) .on('all', async (eventName, path, stats) => { - this.watcherExec(eventName, path) + this.watcherExec(eventName, convertPathToPosix(path)) }) .on('error', (error) => { watcher.close() @@ -294,7 +313,6 @@ class FSPluginClient extends ElectronBasePluginClient { } else { try { const dirname = path.dirname(pathWithoutPrefix) - //console.log('check emitting', eventName, pathWithoutPrefix, this.expandedPaths, dirname) if (this.expandedPaths.includes(dirname) || this.expandedPaths.includes(pathWithoutPrefix)) { //console.log('emitting', eventName, pathWithoutPrefix, this.expandedPaths) //this.emit('change', eventName, pathWithoutPrefix) @@ -312,11 +330,38 @@ class FSPluginClient extends ElectronBasePluginClient { } } + async convertRecentFolders(): Promise { + const config = await this.call('electronconfig' as any, 'readConfig') + if(config.recentFolders) { + + const remaps = config.recentFolders.map((f: any) => { + // if type is string + if(typeof f ==='string') { + return { + path: f, + timestamp: new Date().getTime(), + } + }else{ + return f + } + }) + + config.recentFolders = remaps + await writeConfig(config) + } + } + async updateRecentFolders(path: string): Promise { + await this.convertRecentFolders() const config = await this.call('electronconfig' as any, 'readConfig') config.recentFolders = config.recentFolders || [] config.recentFolders = config.recentFolders.filter((p: string) => p !== path) - config.recentFolders.push(path) + const timestamp = new Date().getTime() + config.recentFolders.push({ + path, + timestamp, + }) + config.recentFolders = deplucateFolderList(config.recentFolders) writeConfig(config) } @@ -336,16 +381,18 @@ class FSPluginClient extends ElectronBasePluginClient { } async getRecentFolders(): Promise { + await this.convertRecentFolders() const config = await this.call('electronconfig' as any, 'readConfig') - let folders: string[] = config.recentFolders || [] - folders = folders.map((f: string) => convertPathToPosix(f)) + let folders: string[] = [] + folders = (config.recentFolders || []).map((f: recentFolder) => convertPathToPosix(f.path)).sort((a: recentFolder, b: recentFolder) => a.timestamp - b.timestamp).slice(-15).reverse() return folders } async removeRecentFolder(path: string): Promise { + await this.convertRecentFolders() const config = await this.call('electronconfig' as any, 'readConfig') config.recentFolders = config.recentFolders || [] - config.recentFolders = config.recentFolders.filter((p: string) => p !== path) + config.recentFolders = config.recentFolders.filter((p: recentFolder) => p.path !== path) writeConfig(config) } @@ -389,7 +436,7 @@ class FSPluginClient extends ElectronBasePluginClient { } path = dirs && dirs.length && dirs[0] ? dirs[0] : path if (!path) return - this.workingDir = path + this.workingDir = convertPathToPosix(path) await this.updateRecentFolders(path) await this.updateOpenedFolders(path) this.window.setTitle(this.workingDir) @@ -398,13 +445,14 @@ class FSPluginClient extends ElectronBasePluginClient { } async setWorkingDir(path: string): Promise { - this.workingDir = path + console.log('setWorkingDir', path) + this.workingDir = convertPathToPosix(path) await this.updateRecentFolders(path) await this.updateOpenedFolders(path) this.window.setTitle(getBaseName(this.workingDir)) this.watch() this.emit('workingDirChanged', path) - await this.call('fileManager', 'closeAllFiles') + return } async revealInExplorer(action: customAction, isAbsolutePath: boolean = false): Promise { @@ -433,3 +481,43 @@ class FSPluginClient extends ElectronBasePluginClient { createWindow(path) } } + +import os from 'os' +export class FSPluginClientE2E extends FSPluginClient { + constructor(webContentsId: number, profile: Profile) { + super(webContentsId, profile) + } + + async selectFolder(dir?: string, title?: string, button?: string): Promise { + if (!dir) { + // create random directory on os homedir + const randomdir = path.join(os.homedir(), 'remix-tests' + Date.now().toString()) + await fs.mkdir(randomdir) + return randomdir + } + if (!dir) return '' + return dir + } + + async openFolder(dir?: string): Promise { + dir = await this.selectFolder(dir) + + await this.updateRecentFolders(dir) + await this.updateOpenedFolders(dir) + if (!dir) return + + this.openWindow(dir) + } + + async openFolderInSameWindow(dir?: string): Promise { + dir = await this.selectFolder(dir) + if (!dir) return + this.workingDir = convertPathToPosix(dir) + await this.updateRecentFolders(dir) + await this.updateOpenedFolders(dir) + this.window.setTitle(this.workingDir) + this.watch() + this.emit('workingDirChanged', dir) + } + +} diff --git a/apps/remixdesktop/src/plugins/hardhatPlugin.ts b/apps/remixdesktop/src/plugins/hardhatPlugin.ts new file mode 100644 index 0000000000..ffef08e1c7 --- /dev/null +++ b/apps/remixdesktop/src/plugins/hardhatPlugin.ts @@ -0,0 +1,220 @@ +import { Profile } from "@remixproject/plugin-utils"; +import { ElectronBasePlugin, ElectronBasePluginClient } from "@remixproject/plugin-electron" +import chokidar from 'chokidar' +import { ElectronBasePluginRemixdClient } from "../lib/remixd" +import fs from 'fs' +import * as utils from '../lib/utils' + +import { basename, join } from "path"; +import { spawn } from "child_process"; +const profile: Profile = { + name: 'hardhat', + displayName: 'electron slither', + description: 'electron slither', +} + +export class HardhatPlugin extends ElectronBasePlugin { + clients: any[] + constructor() { + super(profile, clientProfile, HardhatPluginClient) + this.methods = [...super.methods] + } +} + +const clientProfile: Profile = { + name: 'hardhat', + displayName: 'electron hardhat', + description: 'electron hardhat', + methods: ['sync', 'compile'] +} + + +class HardhatPluginClient extends ElectronBasePluginRemixdClient { + watcher: chokidar.FSWatcher + warnlog: boolean + buildPath: string + cachePath: string + logTimeout: NodeJS.Timeout + processingTimeout: NodeJS.Timeout + + async onActivation(): Promise { + console.log('Hardhat plugin activated') + this.call('terminal', 'log', { type: 'log', value: 'Hardhat plugin activated' }) + + this.on('fs' as any, 'workingDirChanged', async (path: string) => { + console.log('workingDirChanged hardhat', path) + this.currentSharedFolder = path + this.startListening() + }) + this.currentSharedFolder = await this.call('fs' as any, 'getWorkingDir') + if(this.currentSharedFolder) this.startListening() + } + + startListening() { + this.buildPath = utils.absolutePath('artifacts/contracts', this.currentSharedFolder) + if (fs.existsSync(this.buildPath)) { + this.listenOnHardhatCompilation() + } else { + console.log('If you are using Hardhat, run `npx hardhat compile` or run the compilation with `Enable Hardhat Compilation` checked from the Remix IDE.') + this.listenOnHardHatFolder() + } + } + + compile(configPath: string) { + return new Promise((resolve, reject) => { + const cmd = `npx hardhat compile --config ${utils.normalizePath(configPath)}` + const options = { cwd: this.currentSharedFolder, shell: true } + const child = spawn(cmd, options) + let result = '' + let error = '' + child.stdout.on('data', (data) => { + const msg = `[Hardhat Compilation]: ${data.toString()}` + console.log('\x1b[32m%s\x1b[0m', msg) + result += msg + '\n' + }) + child.stderr.on('data', (err) => { + error += `[Hardhat Compilation]: ${err.toString()} \n` + }) + child.on('close', () => { + if (error && result) resolve(error + result) + else if (error) reject(error) + else resolve(result) + }) + }) + } + + checkPath() { + if (!fs.existsSync(this.buildPath)) { + this.listenOnHardHatFolder() + return false + } + return true + } + + private async processArtifact() { + console.log('processing artifact') + if (!this.checkPath()) return + // resolving the files + const folderFiles = await fs.promises.readdir(this.buildPath) + const targetsSynced = [] + // name of folders are file names + for (const file of folderFiles) { // ["artifacts/contracts/Greeter.sol/"] + const contractFilePath = join(this.buildPath, file) + const stat = await fs.promises.stat(contractFilePath) + if (!stat.isDirectory()) continue + const files = await fs.promises.readdir(contractFilePath) + const compilationResult = { + input: {}, + output: { + contracts: {}, + sources: {} + }, + solcVersion: null, + target: null + } + for (const file of files) { + if (file.endsWith('.dbg.json')) { // "artifacts/contracts/Greeter.sol/Greeter.dbg.json" + const stdFile = file.replace('.dbg.json', '.json') + const contentStd = await fs.promises.readFile(join(contractFilePath, stdFile), { encoding: 'utf-8' }) + const contentDbg = await fs.promises.readFile(join(contractFilePath, file), { encoding: 'utf-8' }) + const jsonDbg = JSON.parse(contentDbg) + const jsonStd = JSON.parse(contentStd) + compilationResult.target = jsonStd.sourceName + + targetsSynced.push(compilationResult.target) + const path = join(contractFilePath, jsonDbg.buildInfo) + const content = await fs.promises.readFile(path, { encoding: 'utf-8' }) + + await this.feedContractArtifactFile(content, compilationResult) + } + if (compilationResult.target) { + // we are only interested in the contracts that are in the target of the compilation + compilationResult.output = { + ...compilationResult.output, + contracts: { [compilationResult.target]: compilationResult.output.contracts[compilationResult.target] } + } + this.emit('compilationFinished', compilationResult.target, { sources: compilationResult.input }, 'soljson', compilationResult.output, compilationResult.solcVersion) + } + } + } + + clearTimeout(this.logTimeout) + this.logTimeout = setTimeout(() => { + this.call('terminal', 'log', { value: 'receiving compilation result from Hardhat. Select a file to populate the contract interaction interface.', type: 'log' }) + if (targetsSynced.length) { + console.log(`Processing artifacts for files: ${[...new Set(targetsSynced)].join(', ')}`) + // @ts-ignore + this.call('terminal', 'log', { type: 'log', value: `synced with Hardhat: ${[...new Set(targetsSynced)].join(', ')}` }) + } else { + console.log('No artifacts to process') + // @ts-ignore + this.call('terminal', 'log', { type: 'log', value: 'No artifacts from Hardhat to process' }) + } + }, 1000) + + } + + listenOnHardHatFolder() { + console.log('Hardhat artifacts folder doesn\'t exist... waiting for the compilation.') + try { + if (this.watcher) this.watcher.close() + this.watcher = chokidar.watch(this.currentSharedFolder, { depth: 2, ignorePermissionErrors: true, ignoreInitial: true }) + // watch for new folders + this.watcher.on('addDir', (path: string) => { + console.log('add dir hardhat', path) + if (fs.existsSync(this.buildPath)) { + this.listenOnHardhatCompilation() + } + }) + } catch (e) { + console.log('listenOnHardHatFolder', e) + } + } + + async triggerProcessArtifact() { + console.log('triggerProcessArtifact') + // prevent multiple calls + clearTimeout(this.processingTimeout) + this.processingTimeout = setTimeout(async () => await this.processArtifact(), 1000) + } + + listenOnHardhatCompilation() { + try { + console.log('listening on Hardhat compilation...', this.buildPath) + if (this.watcher) this.watcher.close() + this.watcher = chokidar.watch(this.buildPath, { depth: 1, ignorePermissionErrors: true, ignoreInitial: true }) + this.watcher.on('change', async () => await this.triggerProcessArtifact()) + this.watcher.on('add', async () => await this.triggerProcessArtifact()) + this.watcher.on('unlink', async () => await this.triggerProcessArtifact()) + // process the artifact on activation + this.processArtifact() + } catch (e) { + console.log('listenOnHardhatCompilation', e) + } + } + + async sync() { + console.log('syncing from Hardhat') + this.processArtifact() + } + + async feedContractArtifactFile(artifactContent, compilationResultPart) { + const contentJSON = JSON.parse(artifactContent) + compilationResultPart.solcVersion = contentJSON.solcVersion + for (const file in contentJSON.input.sources) { + const source = contentJSON.input.sources[file] + const absPath = join(this.currentSharedFolder, file) + if (fs.existsSync(absPath)) { // if not that is a lib + const contentOnDisk = await fs.promises.readFile(absPath, { encoding: 'utf-8' }) + if (contentOnDisk === source.content) { + compilationResultPart.input[file] = source + compilationResultPart.output['sources'][file] = contentJSON.output.sources[file] + compilationResultPart.output['contracts'][file] = contentJSON.output.contracts[file] + if (contentJSON.output.errors && contentJSON.output.errors.length) { + compilationResultPart.output['errors'] = contentJSON.output.errors.filter(error => error.sourceLocation.file === file) + } + } + } + } + } +} \ No newline at end of file diff --git a/apps/remixdesktop/src/plugins/isoGitPlugin.ts b/apps/remixdesktop/src/plugins/isoGitPlugin.ts index fad68d02da..201d19b6d4 100644 --- a/apps/remixdesktop/src/plugins/isoGitPlugin.ts +++ b/apps/remixdesktop/src/plugins/isoGitPlugin.ts @@ -1,19 +1,19 @@ -import { PluginClient } from "@remixproject/plugin"; -import { Profile } from "@remixproject/plugin-utils"; -import { ElectronBasePlugin, ElectronBasePluginClient } from "@remixproject/plugin-electron" +import {Profile} from '@remixproject/plugin-utils' +import {ElectronBasePlugin, ElectronBasePluginClient} from '@remixproject/plugin-electron' import fs from 'fs/promises' import git from 'isomorphic-git' -import { dialog } from "electron"; import http from 'isomorphic-git/http/web' -import { gitProxy } from "../tools/git"; -import { remote } from "../types"; +import {gitProxy} from '../tools/git' +import {isoGit} from '@remix-git' +import {branchDifference, branchInputType, checkoutInputType, cloneInputType, commitChange, commitInputType, compareBranchesInput, currentBranchInput, fetchInputType, initInputType, logInputType, pullInputType, pushInputType, remote, resolveRefInput, statusInput} from '@remix-api' const profile: Profile = { name: 'isogit', displayName: 'isogit', description: 'isogit plugin', } - +// used in e2e tests +const useIsoGit = process.argv.includes('--use-isogit') export class IsoGitPlugin extends ElectronBasePlugin { clients: IsoGitPluginClient[] = [] constructor() { @@ -21,33 +21,18 @@ export class IsoGitPlugin extends ElectronBasePlugin { } startClone(webContentsId: any): void { - const client = this.clients.find(c => c.webContentsId === webContentsId) + const client = this.clients.find((c) => c.webContentsId === webContentsId) if (client) { client.startClone() } } } -const parseInput = (input: any) => { - return { - corsProxy: 'https://corsproxy.remixproject.org/', - http, - onAuth: (url: any) => { - url - const auth = { - username: input.token, - password: '' - } - return auth - } - } -} - const clientProfile: Profile = { name: 'isogit', displayName: 'isogit', description: 'isogit plugin', - methods: ['init', 'localStorageUsed', 'version', 'addremote', 'delremote', 'remotes', 'fetch', 'clone', 'export', 'import', 'status', 'log', 'commit', 'add', 'remove', 'reset', 'rm', 'lsfiles', 'readblob', 'resolveref', 'branches', 'branch', 'checkout', 'currentbranch', 'push', 'pin', 'pull', 'pinList', 'unPin', 'setIpfsConfig', 'zip', 'setItem', 'getItem', 'openFolder'] + methods: ['init', 'localStorageUsed', 'version', 'addremote', 'delremote', 'remotes', 'fetch', 'clone', 'export', 'import', 'status', 'log', 'commit', 'add', 'remove', 'rm', 'readblob', 'resolveref', 'branches', 'branch', 'checkout', 'currentbranch', 'push', 'pin', 'pull', 'pinList', 'unPin', 'setIpfsConfig', 'zip', 'setItem', 'getItem', 'openFolder', 'getCommitChanges', 'compareBranches', 'startClone', 'updateSubmodules'], } class IsoGitPluginClient extends ElectronBasePluginClient { @@ -58,15 +43,15 @@ class IsoGitPluginClient extends ElectronBasePluginClient { this.onload(async () => { this.on('fs' as any, 'workingDirChanged', async (path: string) => { this.workingDir = path - this.gitIsInstalled = await gitProxy.version() ? true : false + this.gitIsInstalled = (await gitProxy.version()) && !useIsoGit ? true : false }) this.workingDir = await this.call('fs' as any, 'getWorkingDir') - this.gitIsInstalled = await gitProxy.version() ? true : false + this.gitIsInstalled = (await gitProxy.version()) && !useIsoGit ? true : false }) } async version() { - return gitProxy.version() + return this.gitIsInstalled ? gitProxy.version() : 'built-in' } async getGitConfig() { @@ -76,13 +61,12 @@ class IsoGitPluginClient extends ElectronBasePluginClient { } } - async status(cmd: any) { + async status(cmd: statusInput) { if (!this.workingDir || this.workingDir === '') { throw new Error('No working directory') } - if (this.workingDir === '') { return [] } @@ -93,30 +77,25 @@ class IsoGitPluginClient extends ElectronBasePluginClient { } const status = await git.statusMatrix({ - ...await this.getGitConfig(), - ...cmd + ...(await this.getGitConfig()), + ...cmd, }) - //console.log('STATUS', status, await this.getGitConfig()) + return status } - async log(cmd: any) { + async log(cmd: logInputType) { - /* we will use isomorphic git for now - if(this.gitIsInstalled){ - const log = await gitProxy.log(this.workingDir, cmd.ref) - console.log('LOG', log) - return log - } - */ + const token = await this.call('config' as any, 'getAppParameter', 'settings/gist-access-token') if (this.workingDir === '') { return [] } const log = await git.log({ - ...await this.getGitConfig(), - ...cmd + ...(await this.getGitConfig()), + ...cmd, + depth: cmd.depth || 10, }) return log @@ -128,62 +107,45 @@ class IsoGitPluginClient extends ElectronBasePluginClient { } const add = await git.add({ - ...await this.getGitConfig(), - ...cmd + ...(await this.getGitConfig()), + ...cmd, }) return add } async rm(cmd: any) { - if (!this.workingDir || this.workingDir === '') { throw new Error('No working directory') } const rm = await git.remove({ - ...await this.getGitConfig(), - ...cmd + ...(await this.getGitConfig()), + ...cmd, }) return rm } - async reset(cmd: any) { - - if (!this.workingDir || this.workingDir === '') { - throw new Error('No working directory') - } - - const reset = await git.resetIndex({ - ...await this.getGitConfig(), - ...cmd - }) - - return reset - } - - - async commit(cmd: any) { + async commit(cmd: commitInputType) { if (!this.workingDir || this.workingDir === '') { throw new Error('No working directory') } if (this.gitIsInstalled) { - const status = await gitProxy.commit(this.workingDir, cmd.message) + const status = await gitProxy.commit(this.workingDir, cmd) return status } const commit = await git.commit({ - ...await this.getGitConfig(), - ...cmd + ...(await this.getGitConfig()), + ...cmd, }) return commit } - async init(input: any) { - + async init(input: initInputType) { if (!this.workingDir || this.workingDir === '') { throw new Error('No working directory') } @@ -192,157 +154,119 @@ class IsoGitPluginClient extends ElectronBasePluginClient { return status } await git.init({ - ...await this.getGitConfig(), - defaultBranch: (input && input.branch) || 'main' + ...(await this.getGitConfig()), + defaultBranch: (input && input.defaultBranch) || 'main', }) } - async branch(cmd: any) { + async branch(cmd: branchInputType) { if (!this.workingDir || this.workingDir === '') { return null } const branch = await git.branch({ - ...await this.getGitConfig(), - ...cmd + ...(await this.getGitConfig()), + ...cmd, }) return branch } - async lsfiles(cmd: any) { - if (!this.workingDir || this.workingDir === '') { - return [] - } - const lsfiles = await git.listFiles({ - ...await this.getGitConfig(), - ...cmd - }) - return lsfiles - } + async resolveref(cmd: resolveRefInput) { - async resolveref(cmd: any) { if (!this.workingDir || this.workingDir === '') { return null } const resolveref = await git.resolveRef({ - ...await this.getGitConfig(), - ...cmd + ...(await this.getGitConfig()), + ...cmd, }) return resolveref } - async readblob(cmd: any) { - if (!this.workingDir || this.workingDir === '') { throw new Error('No working directory') } const readblob = await git.readBlob({ - ...await this.getGitConfig(), - ...cmd + ...(await this.getGitConfig()), + ...cmd, }) return readblob } - async checkout(cmd: any) { + async checkout(cmd: checkoutInputType) { if (!this.workingDir || this.workingDir === '') { throw new Error('No working directory') } - - const checkout = await git.checkout({ - ...await this.getGitConfig(), - ...cmd - }) - - return checkout + if (this.gitIsInstalled) { + return await gitProxy.checkout(this.workingDir, cmd) + } else { + const checkout = await git.checkout({ + ...(await this.getGitConfig()), + ...cmd, + }) + return checkout + } } - async push(cmd: any) { - + async push(input: pushInputType) { if (!this.workingDir || this.workingDir === '') { throw new Error('No working directory') } if (this.gitIsInstalled) { - await gitProxy.push(this.workingDir, cmd.remote, cmd.ref, cmd.remoteRef, cmd.force) - + return await gitProxy.push(this.workingDir, input) } else { - - const push = await git.push({ - ...await this.getGitConfig(), - ...cmd, - ...parseInput(cmd.input) - }) + const push = await isoGit.push(input, await this.getGitConfig(), this) return push } - } - async pull(cmd: any) { + async pull(input: pullInputType) { if (!this.workingDir || this.workingDir === '') { throw new Error('No working directory') } if (this.gitIsInstalled) { - await gitProxy.pull(this.workingDir, cmd.remote, cmd.ref, cmd.remoteRef) - + return await gitProxy.pull(this.workingDir, input) } else { - - const pull = await git.pull({ - ...await this.getGitConfig(), - ...cmd, - ...parseInput(cmd.input) - }) - + const pull = await isoGit.pull(input, await this.getGitConfig(), this) return pull - } } - async fetch(cmd: any) { + async fetch(input: fetchInputType) { if (!this.workingDir || this.workingDir === '') { throw new Error('No working directory') } if (this.gitIsInstalled) { - await gitProxy.fetch(this.workingDir, cmd.remote, cmd.remoteRef) - + await gitProxy.fetch(this.workingDir, input) } else { - - const fetch = await git.fetch({ - ...await this.getGitConfig(), - ...cmd, - ...parseInput(cmd.input) - }) - + const fetch = await isoGit.fetch(input, await this.getGitConfig(), this) return fetch } } - async clone(cmd: any) { - + async clone(cmd: cloneInputType) { if (this.gitIsInstalled) { try { - await gitProxy.clone(cmd.url, cmd.dir) + this.call('terminal' as any, 'log', 'Cloning using git... please wait.') + await gitProxy.clone(cmd) } catch (e) { throw e } } else { try { - const clone = await git.clone({ - ...await this.getGitConfig(), - ...cmd, - ...parseInput(cmd.input), - dir: cmd.dir || this.workingDir - }) - + this.call('terminal' as any, 'log', 'Cloning using builtin git... please wait.') + const clone = await isoGit.clone(cmd, await this.getGitConfig(), this) return clone } catch (e) { console.log('CLONE ERROR', e) @@ -351,85 +275,74 @@ class IsoGitPluginClient extends ElectronBasePluginClient { } } - async addremote(cmd: any) { - + async addremote(input: remote) { const addremote = await git.addRemote({ - ...await this.getGitConfig(), - ...cmd + ...(await this.getGitConfig()), + url: input.url, + remote: input.name, }) return addremote } - async delremote(cmd: any) { - + async delremote(input: remote) { const delremote = await git.deleteRemote({ - ...await this.getGitConfig(), - ...cmd + ...(await this.getGitConfig()), + remote: input.name, }) return delremote } + async remotes() { - - remotes = async () => { if (!this.workingDir || this.workingDir === '') { return [] } - let remotes: remote[] = [] - remotes = (await git.listRemotes({ ...await this.getGitConfig() })).map((remote) => { return { name: remote.remote, url: remote.url } } - ) - return remotes + const defaultConfig = await this.getGitConfig() + return await isoGit.remotes(defaultConfig) } - async currentbranch() { - if (!this.workingDir || this.workingDir === '') { - return '' - } - try { - const defaultConfig = await this.getGitConfig() - const name = await git.currentBranch(defaultConfig) + async currentbranch(input: currentBranchInput) { - return name - } catch (e) { + if (!this.workingDir || this.workingDir === '') { return '' } + const defaultConfig = await this.getGitConfig() + return await isoGit.currentbranch(input, defaultConfig) } + async branches(config: any) { - async branches() { if (!this.workingDir || this.workingDir === '') { return [] } - try { - let cmd: any = { ...await this.getGitConfig() } - const remotes = await this.remotes() - let branches = [] - branches = (await git.listBranches(cmd)).map((branch) => { return { remote: undefined, name: branch } }) - for (const remote of remotes) { - cmd = { - ...cmd, - remote: remote.name - } - - const remotebranches = (await git.listBranches(cmd)).map((branch) => { return { remote: remote.name, name: branch } }) - branches = [...branches, ...remotebranches] - } - - return branches - } catch (e) { - return [] - } + const defaultConfig = await this.getGitConfig() + return await isoGit.branches(defaultConfig) } - async startClone() { this.call('filePanel' as any, 'clone') } -} - + async getCommitChanges(commitHash1: string, commitHash2: string): Promise { + return await isoGit.getCommitChanges(commitHash1, commitHash2, await this.getGitConfig()) + } + async compareBranches({branch, remote}: compareBranchesInput): Promise { + return await isoGit.compareBranches({branch, remote}, await this.getGitConfig()) + } + async updateSubmodules(input) { + if (this.gitIsInstalled) { + try { + return await gitProxy.updateSubmodules(this.workingDir) + } catch (e) { + throw e + } + } else { + this.call('terminal', 'log', {type: 'error', value: 'Please install git into your OS to use this functionality...'}) + } + } +} diff --git a/apps/remixdesktop/src/plugins/ripgrepPlugin.ts b/apps/remixdesktop/src/plugins/ripgrepPlugin.ts index 4b620bb596..f0d3d82285 100644 --- a/apps/remixdesktop/src/plugins/ripgrepPlugin.ts +++ b/apps/remixdesktop/src/plugins/ripgrepPlugin.ts @@ -1,10 +1,9 @@ -import {PluginClient} from '@remixproject/plugin' -import {Profile} from '@remixproject/plugin-utils' -import {ElectronBasePlugin, ElectronBasePluginClient} from '@remixproject/plugin-electron' +import { Profile } from '@remixproject/plugin-utils' +import { ElectronBasePlugin, ElectronBasePluginClient } from '@remixproject/plugin-electron' import path from 'path' -import {rgPath} from '@vscode/ripgrep' +import { rgPath } from '@vscode/ripgrep' import byline from 'byline' -import {spawn} from 'child_process' +import { spawn } from 'child_process' import { SearchInWorkspaceOptions } from '../lib' const profile: Profile = { @@ -69,14 +68,14 @@ export class RipgrepPluginClient extends ElectronBasePluginClient { if (opts && opts.include) { for (const include of opts.include) { if (include !== '') { - globs.push('--glob=' + include) + globs.push('--glob=' + include + '') } } } if (opts && opts.exclude) { for (const exclude of opts.exclude) { if (exclude !== '') { - globs.push('--glob=!=' + exclude) + globs.push('--glob=!' + exclude + '') } } } @@ -85,29 +84,37 @@ export class RipgrepPluginClient extends ElectronBasePluginClient { // replace packed app path with unpacked app path for release on windows const customRgPath = rgPath.includes('app.asar.unpacked') ? rgPath : rgPath.replace('app.asar', 'app.asar.unpacked') + console.log('customRgPath', [...globs, ...args, opts.pattern, '.'], path) + const rg = spawn(customRgPath, [...globs, ...args, opts.pattern, '.'], { + cwd: path + }); - const rg = spawn(customRgPath, [...globs, ...args, opts.pattern, path]) const resultrg: any[] = [] const stream = byline(rg.stdout.setEncoding('utf8')) stream.on('data', (rgresult: string) => { - let pathWithoutWorkingDir = rgresult.replace(convertPathToPosix(this.workingDir), '') + console.log('rgresult', rgresult, convertPathToPosix(this.workingDir), convertPathToPosix(rgresult)) + let pathWithoutWorkingDir = convertPathToPosix(rgresult).replace(convertPathToPosix(this.workingDir), '') + console.log(pathWithoutWorkingDir) if (pathWithoutWorkingDir.endsWith('/')) { pathWithoutWorkingDir = pathWithoutWorkingDir.slice(0, -1) } if (pathWithoutWorkingDir.startsWith('/')) { pathWithoutWorkingDir = pathWithoutWorkingDir.slice(1) } + if (pathWithoutWorkingDir.startsWith('./')) { + pathWithoutWorkingDir = pathWithoutWorkingDir.slice(2) + } if (pathWithoutWorkingDir.startsWith('\\')) { pathWithoutWorkingDir = pathWithoutWorkingDir.slice(1) } resultrg.push({ - path: convertPathToPosix(pathWithoutWorkingDir), + path: pathWithoutWorkingDir, isDirectory: false, }) }) - stream.on('end', () => { + stream.on('end', () => { c(resultrg) }) }) diff --git a/apps/remixdesktop/src/plugins/slitherPlugin.ts b/apps/remixdesktop/src/plugins/slitherPlugin.ts new file mode 100644 index 0000000000..abf7971e30 --- /dev/null +++ b/apps/remixdesktop/src/plugins/slitherPlugin.ts @@ -0,0 +1,197 @@ +import { Profile } from "@remixproject/plugin-utils"; +import { ElectronBasePlugin, ElectronBasePluginClient } from "@remixproject/plugin-electron" + +import { ElectronBasePluginRemixdClient } from "../lib/remixd" +import * as utils from '../lib/utils' +import { existsSync, readdirSync, readFileSync, unlinkSync } from "fs-extra"; + +export interface OutputStandard { + description: string + title: string + confidence: string + severity: string + sourceMap: any + category?: string + reference?: string + example?: any + [key: string]: any +} + +const { spawn, execSync } = require('child_process') // eslint-disable-line +const profile: Profile = { + name: 'slither', + displayName: 'electron slither', + description: 'electron slither', +} + +export class SlitherPlugin extends ElectronBasePlugin { + clients: any[] + constructor() { + super(profile, clientProfile, SlitherPluginClient) + this.methods = [...super.methods] + } +} + +const clientProfile: Profile = { + name: 'slither', + displayName: 'electron slither', + description: 'electron slither', + methods: ['analyse'] +} + +class SlitherPluginClient extends ElectronBasePluginRemixdClient { + + mapNpmDepsDir(list) { + const remixNpmDepsPath = utils.absolutePath('.deps/npm', this.currentSharedFolder) + const localNpmDepsPath = utils.absolutePath('node_modules', this.currentSharedFolder) + const npmDepsExists = existsSync(remixNpmDepsPath) + const nodeModulesExists = existsSync(localNpmDepsPath) + let isLocalDep = false + let isRemixDep = false + let allowPathString = '' + let remapString = '' + + for (const e of list) { + const importPath = e.replace(/import ['"]/g, '').trim() + const packageName = importPath.split('/')[0] + if (nodeModulesExists && readdirSync(localNpmDepsPath).includes(packageName)) { + isLocalDep = true + remapString += `${packageName}=./node_modules/${packageName} ` + } else if (npmDepsExists && readdirSync(remixNpmDepsPath).includes(packageName)) { + isRemixDep = true + remapString += `${packageName}=./.deps/npm/${packageName} ` + } + } + if (isLocalDep) allowPathString += './node_modules,' + if (isRemixDep) allowPathString += './.deps/npm,' + + return { remapString, allowPathString } + } + + transform(detectors: Record[]): OutputStandard[] { + const standardReport: OutputStandard[] = [] + for (const e of detectors) { + const obj = {} as OutputStandard + obj.description = e.description + obj.title = e.check + obj.confidence = e.confidence + obj.severity = e.impact + obj.sourceMap = e.elements.map((element) => { + delete element.source_mapping.filename_used + delete element.source_mapping.filename_absolute + return element + }) + standardReport.push(obj) + } + return standardReport + } + + analyse(filePath: string, compilerConfig: Record) { + return new Promise((resolve, reject) => { + const options = { cwd: this.currentSharedFolder, shell: true } + + const { currentVersion, optimize, evmVersion } = compilerConfig + if (currentVersion && currentVersion.includes('+commit')) { + // Get compiler version with commit id e.g: 0.8.2+commit.661d110 + const versionString: string = currentVersion.substring(0, currentVersion.indexOf('+commit') + 16) + this.log(`[Slither Analysis]: Compiler version is ${versionString}`) + let solcOutput: Buffer + // Check solc current installed version + try { + solcOutput = execSync('solc --version', options) + } catch (err) { + this.error(err) + reject(new Error('Error in running solc command')) + } + if (!solcOutput.toString().includes(versionString)) { + this.log('[Slither Analysis]: Compiler version is different from installed solc version') + // Get compiler version without commit id e.g: 0.8.2 + const version: string = versionString.substring(0, versionString.indexOf('+commit')) + // List solc versions installed using solc-select + try { + const solcSelectInstalledVersions: Buffer = execSync('solc-select versions', options) + // Check if required version is already installed + if (!solcSelectInstalledVersions.toString().includes(version)) { + this.log(`[Slither Analysis]: Installing ${version} using solc-select`) + // Install required version + execSync(`solc-select install ${version}`, options) + } + this.log(`[Slither Analysis]: Setting ${version} as current solc version using solc-select`) + // Set solc current version as required version + execSync(`solc-select use ${version}`, options) + } catch (err) { + this.error(err) + reject(new Error('Error in running solc-select command')) + } + } else this.log('[Slither Analysis]: Compiler version is same as installed solc version') + } + // Allow paths and set solc remapping for import URLs + const fileContent = readFileSync(utils.absolutePath(filePath, this.currentSharedFolder), 'utf8') + const importsArr = fileContent.match(/import ['"][^.|..](.+?)['"];/g) + let remaps = '' + if (importsArr?.length) { + const { remapString } = this.mapNpmDepsDir(importsArr) + remaps = remapString.trim() + } + const optimizeOption: string = optimize ? '--optimize' : '' + const evmOption: string = evmVersion ? `--evm-version ${evmVersion}` : '' + let solcArgs = '' + if (optimizeOption) { + solcArgs += optimizeOption + ' ' + } + if (evmOption) { + if (!solcArgs.endsWith(' ')) solcArgs += ' ' + solcArgs += evmOption + } + if (solcArgs) { + solcArgs = `--solc-args "${solcArgs.trimStart()}"` + } + const solcRemaps = remaps ? `--solc-remaps "${remaps}"` : '' + + const outputFile = 'remix-slither-report.json' + try { + // We don't keep the previous analysis + const outputFilePath = utils.absolutePath(outputFile, this.currentSharedFolder) + if (existsSync(outputFilePath)) unlinkSync(outputFilePath) + } catch (e) { + this.error('unable to remove the output file') + this.error(e.message) + } + const cmd = `slither ${filePath} ${solcArgs} ${solcRemaps} --json ${outputFile}` + this.log('[Slither Analysis]: Running Slither...') + // Added `stdio: 'ignore'` as for contract with NPM imports analysis which is exported in 'stderr' + // get too big and hangs the process. We process analysis from the report file only + const child = spawn(cmd, { cwd: this.currentSharedFolder, shell: true, stdio: 'ignore' }) + + const response = {} + child.on('close', () => { + const outputFileAbsPath: string = utils.absolutePath(outputFile, this.currentSharedFolder) + // Check if slither report file exists + if (existsSync(outputFileAbsPath)) { + let report = readFileSync(outputFileAbsPath, 'utf8') + report = JSON.parse(report) + if (report['success']) { + response['status'] = true + if (!report['results'] || !report['results'].detectors || !report['results'].detectors.length) { + response['count'] = 0 + } else { + const { detectors } = report['results'] + response['count'] = detectors.length + response['data'] = this.transform(detectors) + } + + resolve(response) + } else { + this.log(report['error']) + reject(new Error('Error in running Slither Analysis.')) + } + } else { + this.error('Error in generating Slither Analysis Report. Make sure Slither is properly installed.') + reject(new Error('Error in generating Slither Analysis Report. Make sure Slither is properly installed.')) + } + }) + }) + } +} + + diff --git a/apps/remixdesktop/src/plugins/templates.ts b/apps/remixdesktop/src/plugins/templates.ts index aefadcae1b..62cce1caf2 100644 --- a/apps/remixdesktop/src/plugins/templates.ts +++ b/apps/remixdesktop/src/plugins/templates.ts @@ -42,20 +42,26 @@ class TemplatesPluginClient extends ElectronBasePluginClient { super(webContentsId, profile) } - async loadTemplateInNewWindow (files: any) { + async loadTemplateInNewWindow(files: any) { - let folder = await this.call('fs' as any, 'selectFolder', null ,'Select or create a folder to load the template in', 'Set as destination folder for the template') + let folder = await this.call('fs' as any, 'selectFolder', null, 'Select or create a folder to load the files in', 'Set as destination folder for the files') if (!folder || folder === '') return // @ts-ignore for (const file in files) { try { - if(!folder.endsWith('/')) folder += '/' - - await fs.mkdir(path.dirname(folder + file), { recursive: true}) - await fs.writeFile(folder + file, files[file], { - encoding: 'utf8' - }) + if (!folder.endsWith('/')) folder += '/' + + await fs.mkdir(path.dirname(folder + file), { recursive: true }) + if (typeof files[file] !== 'string' && files[file].content) { + await fs.writeFile(folder + file, files[file].content, { + encoding: 'utf8', + }) + } else { + await fs.writeFile(folder + file, files[file], { + encoding: 'utf8' + }) + } } catch (error) { console.error(error) } @@ -63,7 +69,7 @@ class TemplatesPluginClient extends ElectronBasePluginClient { createWindow(folder) } - async openTemplate(){ + async openTemplate() { this.call('filePanel' as any, 'loadTemplate') } diff --git a/apps/remixdesktop/src/plugins/xtermPlugin.ts b/apps/remixdesktop/src/plugins/xtermPlugin.ts index 4b5b6c6e16..6c8f16ca28 100644 --- a/apps/remixdesktop/src/plugins/xtermPlugin.ts +++ b/apps/remixdesktop/src/plugins/xtermPlugin.ts @@ -1,18 +1,15 @@ import {PluginClient} from '@remixproject/plugin' import {Profile} from '@remixproject/plugin-utils' -import { - ElectronBasePlugin, - ElectronBasePluginClient, -} from '@remixproject/plugin-electron' +import {ElectronBasePlugin, ElectronBasePluginClient} from '@remixproject/plugin-electron' import os from 'os' import * as pty from 'node-pty' import process from 'node:process' import {userInfo} from 'node:os' import {findExecutable} from '../utils/findExecutable' -import {spawnSync} from 'child_process' -import { stripAnsi } from '../lib' -import { DataBatcher } from '../lib/databatcher' +import {exec, spawnSync} from 'child_process' +import {stripAnsi} from '../lib' +import {DataBatcher} from '../lib/databatcher' export const detectDefaultShell = () => { const {env} = process @@ -38,10 +35,7 @@ export const detectDefaultShell = () => { // Stores default shell when imported. const defaultShell = detectDefaultShell() -const getShellEnvArgs = [ - '-ilc', - 'echo -n "_SHELL_ENV_DELIMITER_"; env; echo -n "_SHELL_ENV_DELIMITER_"; exit', -] +const getShellEnvArgs = ['-ilc', 'echo -n "_SHELL_ENV_DELIMITER_"; env; echo -n "_SHELL_ENV_DELIMITER_"; exit'] const getShellEnvEnv = { // Disables Oh My Zsh auto-update thing that can block the process. @@ -81,7 +75,9 @@ export class XtermPlugin extends ElectronBasePlugin { new(webContentsId: any): void { const client = this.clients.find((c) => c.webContentsId === webContentsId) + console.log('new terminal', webContentsId) if (client) { + console.log('client exists') client.new() } } @@ -104,6 +100,7 @@ class XtermPluginClient extends ElectronBasePluginClient { terminals: pty.IPty[] = [] dataBatchers: DataBatcher[] = [] workingDir: string = '' + parsedEnv: any = null constructor(webContentsId: number, profile: Profile) { super(webContentsId, profile) this.onload(async () => { @@ -114,6 +111,13 @@ class XtermPluginClient extends ElectronBasePluginClient { this.workingDir = await this.call('fs' as any, 'getWorkingDir') console.log('workingDir', this.workingDir) }) + + if (!(process.platform === 'win32')) { + const {stdout} = spawnSync(defaultShell, getShellEnvArgs, { + encoding: 'utf8', + }) + this.parsedEnv = parseEnv(stdout) + } } async keystroke(key: string, pid: number): Promise { @@ -123,7 +127,7 @@ class XtermPluginClient extends ElectronBasePluginClient { async getShells(): Promise { if (os.platform() === 'win32') { let bash = await findExecutable('bash.exe') - if(bash.length === 0) { + if (bash.length === 0) { bash = await findExecutable('bash.exe', undefined, [process.env['ProgramFiles'] + '\\Git\\bin']) } if (bash) { @@ -137,40 +141,72 @@ class XtermPluginClient extends ElectronBasePluginClient { } async createTerminal(path?: string, shell?: string): Promise { - let parsedEnv: any = null - if (!(process.platform === 'win32')) { - const {stdout} = spawnSync(defaultShell, getShellEnvArgs, { - encoding: 'utf8', - }) - parsedEnv = parseEnv(stdout) - } + const start_time = Date.now() + console.log('createTerminal', path, shell || defaultShell) - const env = parsedEnv || process.env + const env = this.parsedEnv || process.env const ptyProcess = pty.spawn(shell || defaultShell, [], { name: 'xterm-color', cols: 80, rows: 20, - cwd: path || process.cwd(), + cwd: path || this.workingDir || process.cwd(), env: env, + encoding: 'utf8', }) const dataBatcher = new DataBatcher(ptyProcess.pid) + this.dataBatchers[ptyProcess.pid] = dataBatcher ptyProcess.onData((data: string) => { dataBatcher.write(Buffer.from(data)) - //this.sendData(data, ptyProcess.pid) + }) + ptyProcess.onExit(() => { + const pid = ptyProcess.pid + this.closeTerminal(pid) }) dataBatcher.on('flush', (data: string, uid: number) => { this.sendData(data, uid) }) this.terminals[ptyProcess.pid] = ptyProcess - + const end_time = Date.now() + console.log('createTerminal', end_time - start_time) return ptyProcess.pid } async closeTerminal(pid: number): Promise { - this.terminals[pid].kill() - delete this.terminals[pid] - this.emit('close', pid) + console.log('closeTerminal', pid) + + try { + if (this.terminals) { + + if (this.dataBatchers[pid]) delete this.dataBatchers[pid] + + if (this.terminals[pid]) { + try { + if (os.platform() === 'win32') { + // For Windows, use taskkill to terminate the process + exec(`taskkill /PID ${pid} /T /F`, (error, stdout, stderr) => { + if (error) { + console.error(`Error killing process: ${error}`); + }else{ + console.log(`stdout: ${stdout}`); + console.error(`stderr: ${stderr}`); + } + }); + } else { + this.terminals[pid].kill(); + } + } catch (err) { + console.error(err) + // ignore + } + delete this.terminals[pid] + } + } + this.emit('close', pid) + } catch (err) { + console.error(err) + } + } async resize({cols, rows}: {cols: number; rows: number}, pid: number) { @@ -199,8 +235,6 @@ class XtermPluginClient extends ElectronBasePluginClient { } async new(): Promise { - console.log('new terminal') - const pid = await this.createTerminal(this.workingDir) - this.emit('new', pid) + this.emit('new') } } diff --git a/apps/remixdesktop/src/preload.ts b/apps/remixdesktop/src/preload.ts index 007fe098e9..984dc41e2d 100644 --- a/apps/remixdesktop/src/preload.ts +++ b/apps/remixdesktop/src/preload.ts @@ -6,7 +6,7 @@ console.log('preload.ts', new Date().toLocaleTimeString()) /* preload script needs statically defined API for each plugin */ -const exposedPLugins = ['fs', 'git', 'xterm', 'isogit', 'electronconfig', 'electronTemplates', 'ripgrep', 'compilerloader'] +const exposedPLugins = ['fs', 'git', 'xterm', 'isogit', 'electronconfig', 'electronTemplates', 'ripgrep', 'compilerloader', 'appUpdater', 'slither', 'foundry', 'hardhat'] let webContentsId: number | undefined @@ -15,19 +15,29 @@ ipcRenderer.invoke('getWebContentsID').then((id: number) => { }) contextBridge.exposeInMainWorld('electronAPI', { + isPackaged: () => ipcRenderer.invoke('config:isPackaged'), + isE2E: () => ipcRenderer.invoke('config:isE2E'), + canTrackMatomo: () => ipcRenderer.invoke('config:canTrackMatomo'), + trackEvent: (args: any[]) => ipcRenderer.invoke('matomo:trackEvent', args), + openFolder: (path: string) => ipcRenderer.invoke('fs:openFolder', webContentsId, path), + openFolderInSameWindow: (path: string) => ipcRenderer.invoke('fs:openFolderInSameWindow', webContentsId, path), activatePlugin: (name: string) => { return ipcRenderer.invoke('manager:activatePlugin', name) }, - getWindowId: () => ipcRenderer.invoke('getWindowID'), - plugins: exposedPLugins.map(name => { return { name, - on: (cb:any) => ipcRenderer.on(`${name}:send`, cb), + on: (cb:any) => { + ipcRenderer.on(`${name}:send`, cb) + }, send: (message: Partial) => { + //if(name === 'isogit') console.log(name, message) + //if(name === 'isogit') ipcRenderer.invoke(`logger`, name, message) ipcRenderer.send(`${name}:on:${webContentsId}`, message) } } }) + + }) \ No newline at end of file diff --git a/apps/remixdesktop/src/tools/git.ts b/apps/remixdesktop/src/tools/git.ts index a85d036997..ed28a70b82 100644 --- a/apps/remixdesktop/src/tools/git.ts +++ b/apps/remixdesktop/src/tools/git.ts @@ -1,6 +1,7 @@ import { exec } from 'child_process'; import { CommitObject, ReadCommitResult } from 'isomorphic-git'; import { promisify } from 'util'; +import { cloneInputType, commitInputType, fetchInputType, pullInputType, pushInputType, checkoutInputType } from "@remix-api"; const execAsync = promisify(exec); const statusTransFormMatrix = (status: string) => { @@ -9,12 +10,16 @@ const statusTransFormMatrix = (status: string) => { return [0, 2, 0] case 'A ': return [0, 2, 2] + case 'R ': + return [0, 2, 2] case 'M ': return [1, 2, 2] case 'MM': return [1, 2, 3] case ' M': - return [1, 2, 0] + return [1, 2, 1] + case 'AD': + return [0, 0, 3] case ' D': return [1, 0, 1] case 'D ': @@ -37,34 +42,87 @@ export const gitProxy = { } }, + async defaultRemoteName(path: string) { + try { + const { stdout } = await execAsync('git remote', { cwd: path }); + const remotes = stdout.trim().split('\n'); + return remotes[0]; + } catch (error) { + throw new Error(`Failed to get the default remote name: ${error.message}`); + } + }, - clone: async (url: string, path: string) => { - const { stdout, stderr } = await execAsync(`git clone ${url} ${path}`); + clone: async (input: cloneInputType) => { + const { stdout, stderr } = await execAsync(`git clone ${input.url} "${input.dir}"`); }, - async push(path: string, remote: string, src: string, branch: string, force: boolean = false) { - const { stdout, stderr } = await execAsync(`git push ${force ? ' -f' : ''} ${remote} ${src}:${branch}`, { cwd: path }); + async push(path: string, input: pushInputType) { + if(!input.remote || !input.remote.name) { + input.remote = { name: await gitProxy.defaultRemoteName(path), url: '' } + } + let remoteRefString = '' + if(input.remoteRef && !input.remoteRef.name) { + remoteRefString = `:${input.remoteRef.name}` + } + const { stdout, stderr } = await execAsync(`git push ${input.force ? ' -f' : ''} ${input.remote.name}${remoteRefString} ${input.ref.name}`, { cwd: path }); }, - async pull(path: string, remote: string, src: string, branch: string) { - const { stdout, stderr } = await execAsync(`git pull ${remote} ${src}:${branch}`, { cwd: path }); + async pull(path: string, input: pullInputType) { + if(!input.remote || !input.remote.name) { + input.remote = { name: await gitProxy.defaultRemoteName(path), url: '' } + } + let remoteRefString = '' + if(input.remoteRef && !input.remoteRef.name) { + remoteRefString = `:${input.remoteRef.name}` + } + const { stdout, stderr } = await execAsync(`git pull ${input.remote.name} ${input.ref.name}${remoteRefString}`, { cwd: path }); }, - async fetch(path: string, remote: string, branch: string) { - const { stdout, stderr } = await execAsync(`git fetch ${remote} ${branch}`, { cwd: path }); + async fetch(path: string, input: fetchInputType) { + if(!input.remote || !input.remote.name) { + input.remote = { name: await gitProxy.defaultRemoteName(path), url: '' } + } + + try { + const { stdout, stderr } = await execAsync(`git fetch ${input.remote.name} ${(input.ref && input.ref.name) ? input.ref.name : ''}`, { cwd: path }); + if (stdout) { + console.log('stdout:', stdout); + } + if (stderr) { + console.error('stderr:', stderr); + } + } catch (error) { + console.error('Error during fetch:', error); + } + }, + + async checkout(path: string, input: checkoutInputType) { + let force = input.force ? ' -f' : ''; + const { stdout, stderr } = await execAsync(`git checkout ${force} ${input.ref}`, { cwd: path }); }, - async commit(path: string, message: string) { + async commit(path: string, input: commitInputType) { - await execAsync(`git commit -m '${message}'`, { cwd: path }); + await execAsync(`git commit -m '${input.message}'`, { cwd: path }); const { stdout, stderr } = await execAsync(`git rev-parse HEAD`, { cwd: path }); + console.log('stdout commit:', stdout); return stdout; }, async init(path: string) { - await execAsync(`git init`, { cwd: path }); + await execAsync(`git init --initial-branch=main`, { cwd: path }); + }, + + async updateSubmodules(path: string) { + const { stdout, stderr } = await execAsync(`git submodule update --init --recursive`, { cwd: path }); + if (stdout) { + console.log('stdout:', stdout); + } + if (stderr) { + console.error('stderr:', stderr); + } }, @@ -103,7 +161,7 @@ export const gitProxy = { return 0 }) - + console.log('files', files) return files }, diff --git a/apps/remixdesktop/src/types/index.ts b/apps/remixdesktop/src/types/index.ts index 8c0087b62e..e69de29bb2 100644 --- a/apps/remixdesktop/src/types/index.ts +++ b/apps/remixdesktop/src/types/index.ts @@ -1,9 +0,0 @@ -export type branch = { - name: string - remote: remote -} - -export type remote = { - name: string - url: string -} \ No newline at end of file diff --git a/apps/remixdesktop/src/utils/config.ts b/apps/remixdesktop/src/utils/config.ts index 4cbb17a3e0..df7b8c8d15 100644 --- a/apps/remixdesktop/src/utils/config.ts +++ b/apps/remixdesktop/src/utils/config.ts @@ -4,7 +4,7 @@ import path from 'path' export const cacheDir = path.join(os.homedir(), '.cache_remix_ide') -console.log('cacheDir', cacheDir) +console.log('cache dir is:', cacheDir) export const createDefaultConfigLocations = async() => { try { diff --git a/apps/remixdesktop/src/utils/matamo.ts b/apps/remixdesktop/src/utils/matamo.ts new file mode 100644 index 0000000000..a537e40afb --- /dev/null +++ b/apps/remixdesktop/src/utils/matamo.ts @@ -0,0 +1,51 @@ +import { screen } from 'electron'; +import { isPackaged, isE2E } from "../main"; + + +var MatomoTracker = require('matomo-tracker'); + +// Function to send events to Matomo +export function trackEvent(category: string, action: string, name: string, value: string | number, new_visit: number = 0): void { + var matomo = new MatomoTracker(35, 'http://ethereumfoundation.matomo.cloud/matomo.php'); + matomo.on('error', function (err: any) { + console.log('error tracking request: ', err); + }); + + + // Customize the user agent + const electronVersion = process.versions.electron; + const chromiumVersion = process.versions.chrome; + const os = process.platform; // 'darwin', 'win32', 'linux', etc. + const osVersion = process.getSystemVersion(); + + const ua = `Electron/${electronVersion} (Chromium/${chromiumVersion}) ${os} ${osVersion}`; + + + const res = `${screen.getPrimaryDisplay().size.width}x${screen.getPrimaryDisplay().size.height}`; + + if ((process.env.NODE_ENV === 'production' || isPackaged) && !isE2E) { + console.log('trackEvent', category, action, name, value, ua, new_visit); + matomo.track({ + e_c: category, + e_a: action, + e_n: name, + e_v: value, + ua, + new_visit, + res, + url: 'https://github.com/remix-project-org/remix-desktop' + // You can add other parameters if needed + }, (error: any) => { + if (error) { + console.error('Error tracking event:', error); + } else { + console.log('Event tracked successfully'); + } + }); + } else { + console.log('Matomo tracking is disabled'); + } + +} + + diff --git a/apps/remixdesktop/test/cache_dir/remixdesktop.json b/apps/remixdesktop/test/cache_dir/remixdesktop.json new file mode 100644 index 0000000000..a50cbdd2f5 --- /dev/null +++ b/apps/remixdesktop/test/cache_dir/remixdesktop.json @@ -0,0 +1,2 @@ +{"openedFolders":["/home/bunsen/Documents/remix-reward"], +"recentFolders":["/home/bunsen/Documents/remix-reward"]} \ No newline at end of file diff --git a/apps/remixdesktop/test/lib/git.ts b/apps/remixdesktop/test/lib/git.ts new file mode 100644 index 0000000000..2a47d54477 --- /dev/null +++ b/apps/remixdesktop/test/lib/git.ts @@ -0,0 +1,195 @@ +import { spawn, ChildProcess } from "child_process" + +export async function getBranches(path: string): Promise { + return new Promise((resolve, reject) => { + const git = spawn('git', ['branch'], { cwd: path }) + let branches = '' + git.stdout.on('data', function (data) { + console.log('stdout git branches', data.toString()) + branches += data.toString() + }) + git.stderr.on('data', function (data) { + console.log('stderr git branches', data.toString()) + reject(data.toString()) + }) + git.on('close', function () { + resolve(branches) + }) + }) +} + +export async function getGitLog(path: string): Promise { + return new Promise((resolve, reject) => { + const git = spawn('git', ['log'], { cwd: path }) + let logs = '' + git.stdout.on('data', function (data) { + logs += data.toString() + }) + git.stderr.on('err', function (data) { + reject(data.toString()) + }) + git.on('close', function () { + resolve(logs) + }) + }) +} + +export async function cloneOnServer(repo: string, path: string, name: string = 'bare') { + console.log('cloning', repo, path) + return new Promise((resolve, reject) => { + const git = spawn(`rm -rf ${name} && git`, ['clone', repo], { cwd: path, shell: true, detached: true }); + + git.stdout.on('data', function (data) { + console.log('stdout data cloning', data.toString()); + if (data.toString().includes('done')) { + resolve(git); + } + }); + + git.stderr.on('data', function (data) { + console.log('stderr data cloning', data.toString()); + if (data.toString().includes('into')) { + setTimeout(() => { + resolve(git); + }, 5000) + } + }); + + git.on('error', (error) => { + reject(`Process error: ${error.message}`); + }); + + git.on('exit', (code, signal) => { + if (code !== 0) { + reject(`Process exited with code: ${code} and signal: ${signal}`); + } + }); + }); +} + +export async function onLocalGitRepoAddFile(path: string, file: string) { + console.log('adding file', file) + return new Promise((resolve, reject) => { + const git = spawn('touch', [file], { cwd: path }); + + git.stdout.on('data', function (data) { + console.log('stdout data adding file', data.toString()); + if (data.toString().includes('done')) { + resolve(git); + } + }); + + git.stderr.on('data', function (data) { + console.error('stderr adding file', data.toString()); + reject(data.toString()); + }); + + git.on('error', (error) => { + reject(`Process error: ${error.message}`); + }); + + git.on('exit', (code, signal) => { + if (code !== 0) { + reject(`Process exited with code: ${code} and signal: ${signal}`); + } else { + resolve(git); + } + }); + }); +} + +export async function onLocalGitRepoPush(path: string, branch: string = 'master') { + console.log('pushing', path) + return new Promise((resolve, reject) => { + const git = spawn('git', ['push', 'origin', branch], { cwd: path, shell: true, detached: true }); + + git.stdout.on('data', function (data) { + console.log('stdout data pushing', data.toString()); + if (data.toString().includes('done')) { + resolve(git); + } + }); + + git.stderr.on('data', function (data) { + console.error('stderr data pushing', data.toString()); + if (data.toString().includes(branch)) { + resolve(git); + } + }); + + git.on('error', (error) => { + reject(`Process error: ${error.message}`); + }); + + git.on('exit', (code, signal) => { + if (code !== 0) { + reject(`Process exited with code: ${code} and signal: ${signal}`); + } else { + resolve(git); + } + }); + }); +} + + +export async function createCommitOnLocalServer(path: string, message: string) { + console.log('committing', message, path) + return new Promise((resolve, reject) => { + const git = spawn('git add . && git', ['commit', '-m', message], { cwd: path, shell: true, detached: true }); + + git.stdout.on('data', function (data) { + console.log('data stdout committing', data.toString()); + if (data.toString().includes(message)) { + setTimeout(() => { + resolve(git); + }, 1000) + } + }); + + git.stderr.on('data', function (data) { + console.error('data commiting', data.toString()); + reject(data.toString()); + }); + + git.on('error', (error) => { + console.error('error', error); + reject(`Process error: ${error.message}`); + }); + + git.on('exit', (code, signal) => { + if (code !== 0) { + console.error('exit', code, signal); + reject(`Process exited with code: ${code} and signal: ${signal}`); + } else { + resolve(git); + } + }); + }); +} + + +export async function spawnGitServer(path: string): Promise { + console.log(process.cwd()) + try { + const server = spawn('yarn && sh setup.sh && yarn start:server', [`${path}`], { cwd: process.cwd() + '/../remix-ide-e2e/src/githttpbackend/', shell: true, detached: true }) + console.log('spawned', server.stdout.closed, server.stderr.closed) + return new Promise((resolve, reject) => { + server.stdout.on('data', function (data) { + console.log(data.toString()) + if ( + data.toString().includes('is listening') + || data.toString().includes('address already in use') + ) { + console.log('resolving') + resolve(server) + } + }) + server.stderr.on('err', function (data) { + console.log(data.toString()) + reject(data.toString()) + }) + }) + } catch (e) { + console.log(e) + } +} \ No newline at end of file diff --git a/apps/remixdesktop/test/nighwatch.app.ts b/apps/remixdesktop/test/nighwatch.app.ts new file mode 100644 index 0000000000..77ff0f9b7f --- /dev/null +++ b/apps/remixdesktop/test/nighwatch.app.ts @@ -0,0 +1,104 @@ +import os from 'os'; +import fs from 'fs'; + + + +const useIsoGit = process.argv.includes('--use-isogit'); +const useOffline = process.argv.includes('--use-offline'); + +// Function to read JSON file synchronously +function readJSONFileSync(filename: string): any { + try { + const data = fs.readFileSync(filename, 'utf8'); + return JSON.parse(data); + } catch (err) { + throw err; + } +} + +const packageData: any = readJSONFileSync('package.json'); +const version = packageData.version; + +let channel: string = '' + +if (version.includes('beta')) { + channel = 'Beta'; +} else if (version.includes('alpha')) { + channel = 'Alpha'; +} else if (version.includes('insiders')) { + channel = 'Insiders'; +} + +// Determine if running on CircleCI or locally with --e2e-local +const isLocalE2E = process.argv.includes('--e2e-local') && !process.env.CIRCLECI; + +module.exports = { + src_folders: ['build-e2e/remixdesktop/test/tests/app'], + output_folder: './reports/tests', + custom_commands_path: ['build-e2e/remix-ide-e2e/src/commands'], + page_objects_path: '', + globals_path: '', + test_settings: { + default: { + enable_fail_fast: true, + selenium_port: 4444, + selenium_host: 'localhost', + globals: { + waitForConditionTimeout: 10000, + asyncHookTimeout: 100000 + }, + screenshots: { + enabled: true, + path: './reports/screenshots', + on_failure: true, + on_error: true + }, + webdriver: { + start_process: true, + timeout_options: { + timeout: 60000, + retry_attempts: 3 + } + }, + desiredCapabilities: { + browserName: 'chrome', + javascriptEnabled: true, + acceptSslCerts: true, + 'goog:chromeOptions': (() => { + const type = os.type(); + const arch = os.arch(); + let binaryPath = ""; + // Check if running on CircleCI or locally + let args = process.env.CIRCLECI ? ["--e2e"] : ["--e2e-local"]; + + if(useIsoGit) args = [...args, '--use-isogit']; + if(useOffline) args = [...args, '--use-offline']; + + // Set display size + const windowSize = "--window-size=1000,1000"; + args = [...args]; + + switch (type) { + case 'Windows_NT': + binaryPath = `./release/win-unpacked/Remix-Desktop-${channel}.exe`; + break; + case 'Darwin': + binaryPath = arch === 'x64' ? + `release/mac/Remix-Desktop-${channel}.app/Contents/MacOS/Remix-Desktop-${channel}` : + `release/mac-arm64/Remix-Desktop-${channel}.app/Contents/MacOS/Remix-Desktop-${channel}`; + break; + case 'Linux': + binaryPath = "release/linux-unpacked/remixdesktop"; + break; + } + + console.log('binaryPath', binaryPath); + return { + binary: binaryPath, + args: args + }; + })() + } + } + } +}; diff --git a/apps/remixdesktop/test/tests/app/compiler.test.ts b/apps/remixdesktop/test/tests/app/compiler.test.ts new file mode 100644 index 0000000000..2fce46320c --- /dev/null +++ b/apps/remixdesktop/test/tests/app/compiler.test.ts @@ -0,0 +1,37 @@ +import { NightwatchBrowser } from 'nightwatch' + + +module.exports = { + before: function (browser: NightwatchBrowser, done: VoidFunction) { + done() + }, + 'download compiler': function (browser: NightwatchBrowser) { + browser + .waitForElementVisible('*[data-id="remixIdeIconPanel"]', 10000) + .clickLaunchIcon('solidity') + .pause(1000) + .setSolidityCompilerVersion('soljson-v0.8.23+commit.f704f362.js') + .waitForElementVisible({ + selector: "//*[@data-id='selectedVersion' and contains(.,'0.8.23+commit.f704f362')]", + locateStrategy: 'xpath' + }) + .waitForElementContainsText('*[data-id="terminalJournal"]', 'Compiler downloaded from https://binaries.soliditylang.org/wasm/soljson-v0.8.23+commit.f704f362.js to soljson-v0.8.23+commit.f704f362.js', 10000) + .waitForElementPresent({ + selector: + "//a[@data-id='dropdown-item-soljson-v0.8.23+commit.f704f362.js']//*[contains(@class, 'fa-arrow-circle-down')]", + locateStrategy: 'xpath' + }) + + }, + 'refresh': function (browser: NightwatchBrowser) { + browser.refresh() + .clickLaunchIcon('solidity') + .waitForElementVisible('*[data-id="versionSelector"]') + .click('*[data-id="versionSelector"]') + .waitForElementPresent({ + selector: + "//a[@data-id='dropdown-item-soljson-v0.8.23+commit.f704f362.js']//*[contains(@class, 'fa-arrow-circle-down')]", + locateStrategy: 'xpath' + }) + } +} \ No newline at end of file diff --git a/apps/remixdesktop/test/tests/app/externaleditor.test.ts b/apps/remixdesktop/test/tests/app/externaleditor.test.ts new file mode 100644 index 0000000000..89e991fdcd --- /dev/null +++ b/apps/remixdesktop/test/tests/app/externaleditor.test.ts @@ -0,0 +1,122 @@ +import {NightwatchBrowser} from 'nightwatch' + +const testsBash = { + before: function (browser: NightwatchBrowser, done: VoidFunction) { + done() + }, + open: function (browser: NightwatchBrowser) { + browser.waitForElementVisible('*[data-id="openFolderButton"]', 10000).click('*[data-id="openFolderButton"]') + }, + 'open xterm linux and create a file': function (browser: NightwatchBrowser) { + browser + .waitForElementVisible('*[data-id="tabXTerm"]', 10000) + .click('*[data-id="tabXTerm"]') + .waitForElementVisible('*[data-type="remixUIXT"]', 10000) + .click('*[data-type="remixUIXT"]') + .perform(function () { + const actions = this.actions({async: true}) + return actions.sendKeys('mkdir dir && cd dir && echo "test" >> example.txt').sendKeys(this.Keys.ENTER) + }) + .waitForElementVisible('*[data-id="treeViewLitreeViewItemdir"]', 10000) + .openFile('dir') + .waitForElementVisible('*[data-id="treeViewLitreeViewItemdir/example.txt"]', 10000) + .openFile('dir/example.txt') + .getEditorValue((result) => { + browser.assert.equal(result, 'test\n') + }) + .waitForElementVisible('*[data-type="remixUIXT"]', 10000) + .click('*[data-type="remixUIXT"]') + .perform(function () { + const actions = this.actions({async: true}) + return actions.sendKeys('echo "123" >> example.txt').sendKeys(this.Keys.ENTER) + }) + .pause(1000) + .getEditorValue((result) => { + browser.assert.equal(result, 'test\n123\n') + }) + .setEditorValue('somethinginthere') + .pause(1000) + .perform(function () { + const actions = this.actions({async: true}) + return actions.sendKeys('cat example.txt').sendKeys(this.Keys.ENTER) + }) + .pause(1000) + .getText( + { + selector: "//*[@data-type='remixUIXT' and @data-active='1']", + timeout: 10000, + locateStrategy: 'xpath', + }, + function (result) { + console.log('Text content of the element:', result.value) + browser.assert.ok((result.value as string).includes('somethinginthere')) + } + ) + }, +} + +const testsWindows = { + before: function (browser: NightwatchBrowser, done: VoidFunction) { + done() + }, + open: function (browser: NightwatchBrowser) { + browser.waitForElementVisible('*[data-id="openFolderButton"]', 10000).click('*[data-id="openFolderButton"]') + }, + 'open xterm window and create a file': function (browser: NightwatchBrowser) { + browser + .waitForElementVisible('*[data-id="tabXTerm"]', 10000) + .click('*[data-id="tabXTerm"]') + .waitForElementVisible('*[data-id="select_shell"]') + .click('*[data-id="select_shell"]') + .waitForElementVisible('*[data-id="select_powershell.exe"]') + .click('*[data-id="select_powershell.exe"]') + .pause(3000) + .waitForElementVisible("[data-active='1'][data-type='remixUIXT']", 10000) + .click("[data-active='1'][data-type='remixUIXT']") + .pause(1000) + .perform(function () { + const actions = this.actions({async: true}) + return actions.sendKeys('New-Item -ItemType Directory -Name "dir" ; Set-Location -Path "./dir" ; Add-Content -Path "example.txt" -Value "test" -Encoding UTF8').sendKeys(this.Keys.ENTER) + }) + .pause(1000) + .waitForElementVisible('*[data-id="treeViewLitreeViewItemdir"]', 10000) + .openFile('dir') + .waitForElementVisible('*[data-id="treeViewLitreeViewItemdir/example.txt"]', 10000) + .openFile('dir/example.txt').pause(1000) + .getEditorValue((result) => { + browser.assert.equal(result, 'test\r\n') + }) + .pause(1000) + .waitForElementVisible("[data-active='1'][data-type='remixUIXT']", 10000) + .click("[data-active='1'][data-type='remixUIXT']") + .perform(function () { + const actions = this.actions({async: true}) + return actions.sendKeys('Add-Content -Path "example.txt" -Value "123" -Encoding UTF8').sendKeys(this.Keys.ENTER) + }) + .pause(1000) + .getEditorValue((result) => { + browser.assert.equal(result, 'test\r\n123\r\n') + }) + .setEditorValue('somethinginthere') + .pause(1000) + .perform(function () { + const actions = this.actions({async: true}) + return actions.sendKeys('Get-Content example.txt').sendKeys(this.Keys.ENTER) + }).pause(1000) + .getText( + { + selector: "//*[@data-type='remixUIXT' and @data-active='1']", + timeout: 10000, + locateStrategy: 'xpath', + }, + function (result) { + console.log('Text content of the element:', result.value) + browser.assert.ok((result.value as string).includes('somethinginthere')) + } + ) + } +} + +module.exports = { + ...process.platform.startsWith('win')?testsWindows:testsBash +} \ No newline at end of file diff --git a/apps/remixdesktop/test/tests/app/foundry.test.ts b/apps/remixdesktop/test/tests/app/foundry.test.ts new file mode 100644 index 0000000000..3aa370882a --- /dev/null +++ b/apps/remixdesktop/test/tests/app/foundry.test.ts @@ -0,0 +1,157 @@ +import { NightwatchBrowser } from 'nightwatch' +import { ChildProcess, spawn, execSync } from 'child_process' +import { homedir } from 'os' +import path from 'path' +import os from 'os' + +const projectDir = path.join('remix-desktop-test-' + Date.now().toString()) +const dir = '/tmp/' + projectDir + +const tests = { + before: function (browser: NightwatchBrowser, done: VoidFunction) { + done() + }, + installFoundry: function (browser: NightwatchBrowser) { + browser.perform(async (done) => { + await downloadFoundry() + await installFoundry() + await initFoundryProject() + done() + }) + }, + addScript: function (browser: NightwatchBrowser) { + // run script in console + browser.executeAsync(function (dir, done) { + (window as any).electronAPI.openFolderInSameWindow(dir + '/hello_foundry/').then(done) + }, [dir], () => { + console.log('done window opened') + }) + .waitForElementVisible('*[data-id="treeViewDivDraggableItemfoundry.toml"]', 10000) + }, + compile: function (browser: NightwatchBrowser) { + browser.perform(async (done) => { + console.log('generating compilation result') + await buildFoundryProject() + done() + }) + .expect.element('*[data-id="terminalJournal"]').text.to.contain('receiving compilation result from Foundry').before(60000) + + let contractAaddress + browser.clickLaunchIcon('filePanel') + .openFile('src') + .openFile('src/Counter.sol') + .clickLaunchIcon('udapp') + .selectContract('Counter') + .createContract('') + .getAddressAtPosition(0, (address) => { + console.log(contractAaddress) + contractAaddress = address + }) + .clickInstance(0) + .clickFunction('increment - transact (not payable)') + .perform((done) => { + browser.testConstantFunction(contractAaddress, 'number - call', null, '0:\nuint256: 1').perform(() => { + done() + }) + }) + } +} +async function downloadFoundry(): Promise { + console.log('downloadFoundry', process.cwd()) + try { + const server = spawn('curl -L https://foundry.paradigm.xyz | bash', [], { cwd: process.cwd(), shell: true, detached: true }) + return new Promise((resolve, reject) => { + server.stdout.on('data', function (data) { + console.log(data.toString()) + if ( + data.toString().includes("simply run 'foundryup' to install Foundry") + || data.toString().includes("foundryup: could not detect shell, manually add") + ) { + console.log('resolving') + resolve() + } + }) + server.stderr.on('err', function (data) { + console.log(data.toString()) + reject(data.toString()) + }) + }) + } catch (e) { + console.log(e) + } +} + +async function installFoundry(): Promise { + console.log('installFoundry', process.cwd()) + try { + const server = spawn('export PATH="' + homedir() + '/.foundry/bin:$PATH" && foundryup', [], { cwd: process.cwd(), shell: true, detached: true }) + return new Promise((resolve, reject) => { + server.stdout.on('data', function (data) { + console.log(data.toString()) + if ( + data.toString().includes("foundryup: done!") + ) { + console.log('resolving') + resolve() + } + }) + server.stderr.on('err', function (data) { + console.log(data.toString()) + reject(data.toString()) + }) + }) + } catch (e) { + console.log(e) + } +} + +async function initFoundryProject(): Promise { + console.log('initFoundryProject', homedir()) + try { + if (process.env.CIRCLECI) { + spawn('git config --global user.email \"you@example.com\"', [], { cwd: homedir(), shell: true, detached: true }) + spawn('git config --global user.name \"Your Name\"', [], { cwd: homedir(), shell: true, detached: true }) + } + spawn('mkdir ' + projectDir, [], { cwd: '/tmp/', shell: true, detached: true }) + const server = spawn('export PATH="' + homedir() + '/.foundry/bin:$PATH" && forge init hello_foundry', [], { cwd: dir, shell: true, detached: true }) + server.stdout.pipe(process.stdout) + return new Promise((resolve, reject) => { + server.on('exit', function (exitCode) { + console.log("Child exited with code: " + exitCode); + console.log('end') + resolve() + }) + server.stderr.on('err', function (data) { + console.log('err', data.toString()) + }) + server.stdout.on('data', function (data) { + console.log('data', data.toString()) + }) + }) + } catch (e) { + console.log(e) + } +} + +async function buildFoundryProject(): Promise { + console.log('buildFoundryProject', homedir()) + try { + const server = spawn('export PATH="' + homedir() + '/.foundry/bin:$PATH" && forge build', [], { cwd: dir + '/hello_foundry', shell: true, detached: true }) + server.stdout.pipe(process.stdout) + return new Promise((resolve, reject) => { + server.on('exit', function (exitCode) { + console.log("Child exited with code: " + exitCode); + console.log('end') + resolve() + }) + }) + } catch (e) { + console.log(e) + } +} + + + +module.exports = { + ...{}//...process.platform.startsWith('linux') ? tests : {} +} \ No newline at end of file diff --git a/apps/remixdesktop/test/tests/app/gist.test.ts b/apps/remixdesktop/test/tests/app/gist.test.ts new file mode 100644 index 0000000000..b53c741910 --- /dev/null +++ b/apps/remixdesktop/test/tests/app/gist.test.ts @@ -0,0 +1,36 @@ +import { NightwatchBrowser } from 'nightwatch' + +const gist_id = '02a847917a6a7ecaf4a7e0d4e68715bf' +const tests = { + before: function (browser: NightwatchBrowser, done: VoidFunction) { + done() + }, + 'start gist': function (browser: NightwatchBrowser) { + browser.end() + /* + browser + .waitForElementVisible('*[data-id="remixIdeIconPanel"]', 10000) + .waitForElementVisible('*[data-id="landingPageImportFromGist"]') + .click('*[data-id="landingPageImportFromGist"]') + .waitForElementVisible('*[data-id="gisthandlerModalDialogModalBody-react"] input[data-id="modalDialogCustomPromp"]') + .execute(function () { + (document.querySelector('*[data-id="gisthandlerModalDialogModalBody-react"] input[data-id="modalDialogCustomPromp"]') as any).focus() + }) + .setValue('*[data-id="gisthandlerModalDialogModalBody-react"] input[data-id="modalDialogCustomPromp"]', gist_id) + .modalFooterOKClick('gisthandler') + .pause(3000) + .windowHandles(function (result) { + console.log(result.value) + browser.switchWindow(result.value[1]) + .waitForElementVisible('*[data-id="treeViewDivtreeViewItemREADME.txt"]') + }) + .click('[data-id="treeViewLitreeViewItemcontracts"]') + .openFile('contracts/3_Ballot.sol') + .end() + */ + } +} + +module.exports = { + ...tests +} \ No newline at end of file diff --git a/apps/remixdesktop/test/tests/app/git-ui.test.ts b/apps/remixdesktop/test/tests/app/git-ui.test.ts new file mode 100644 index 0000000000..813c31da44 --- /dev/null +++ b/apps/remixdesktop/test/tests/app/git-ui.test.ts @@ -0,0 +1,203 @@ +import { ChildProcess, spawn } from "child_process" +import kill from 'tree-kill' +import { Nightwatch, NightwatchBrowser } from "nightwatch" +import { spawnGitServer, getGitLog, cloneOnServer, onLocalGitRepoAddFile, createCommitOnLocalServer, onLocalGitRepoPush, getBranches } from "../../lib/git" +let gitserver: ChildProcess + +/* +/ uses the git-http-backend package to create a git server ( if needed kill the server: kill -9 $(sudo lsof -t -i:6868) ) +/ GROUP 1: file operations PUSH PULL COMMIT SYNC FETCH CLONE ADD +/ GROUP 2: branch operations CREATE & PUBLISH +/ GROUP 3: file operations rename delete +*/ + +const tests = { + before: function (browser: NightwatchBrowser, done: VoidFunction) { + browser.hideToolTips() + done() + }, + after: function (browser: NightwatchBrowser) { + browser.perform((done) => { + console.log('kill server', gitserver.pid) + kill(gitserver.pid) + done() + }) + }, + + 'run server #group1 #group2 #group3': function (browser: NightwatchBrowser) { + browser.perform(async (done) => { + gitserver = await spawnGitServer('/tmp/') + console.log('working directory', process.cwd()) + done() + }) + }, + + 'clone a repo #group1 #group2 #group3': function (browser: NightwatchBrowser) { + browser + .clickLaunchIcon('dgit') + .pause(5000) + .waitForElementVisible('*[data-id="cloneButton"]') + .click('*[data-id="cloneButton"]') + .pause(1000) + .waitForElementVisible('[data-id="fileSystemModalDialogModalBody-react"]') + .click('[data-id="fileSystemModalDialogModalBody-react"]') + .waitForElementVisible('[data-id="modalDialogCustomPromptTextClone"]') + .setValue('*[data-id="modalDialogCustomPromptTextClone"]', 'http://localhost:6868/bare.git') + .click('[data-id="fileSystem-modal-footer-ok-react"]') + .pause(5000) + .windowHandles(function (result) { + console.log(result.value) + browser.switchWindow(result.value[1]) + .waitForElementVisible('*[data-id="treeViewLitreeViewItem.git"]') + .hideToolTips() + }) + .waitForElementVisible('*[data-id="treeViewLitreeViewItemREADME.md"]') + }, + 'Update settings for git #group1 #group2 #group3': function (browser: NightwatchBrowser) { + browser. + clickLaunchIcon('dgit') + .waitForElementVisible('*[data-id="github-panel"]') + .pause(1000) + .click('*[data-id="github-panel"]') + .pause(1000) + .setValue('*[data-id="gitubUsername"]', 'git') + .pause(1000) + .setValue('*[data-id="githubEmail"]', 'git@example.com') + .pause(1000) + .click('*[data-id="saveGitHubCredentials"]') + .modalFooterOKClick('github-credentials-error') + + }, + + // GROUP 1 + + 'check file added #group1 #group3': function (browser: NightwatchBrowser) { + browser + .addFile('test.txt', { content: 'hello world' }, 'README.md') + .clickLaunchIcon('dgit') + .pause(1000) + .click('*[data-id="sourcecontrol-panel"]') + .waitForElementVisible({ + selector: "//*[@data-status='new-untracked' and @data-file='/test.txt']", + locateStrategy: 'xpath' + }) + .waitForElementVisible('*[data-id="addToGitChangestest.txt"]') + .pause(1000) + .click('*[data-id="addToGitChangestest.txt"]') + .waitForElementVisible({ + selector: "//*[@data-status='added-staged' and @data-file='/test.txt']", + locateStrategy: 'xpath' + }) + .setValue('*[data-id="commitMessage"]', 'testcommit') + .click('*[data-id="commitButton"]') + }, + 'look at the commit #group1': function (browser: NightwatchBrowser) { + browser + .click('*[data-id="commits-panel"]') + .waitForElementPresent({ + selector: '//*[@data-id="commit-summary-testcommit-ahead"]', + locateStrategy: 'xpath' + }) + }, + 'sync the commit #group1': function (browser: NightwatchBrowser) { + browser + .pause(1000) + .waitForElementVisible('*[data-id="sourcecontrol-panel"]') + .click('*[data-id="sourcecontrol-panel"]') + + .waitForElementVisible('*[data-id="syncButton"]') + .click('*[data-id="syncButton"]') + .pause(2000) + .waitForElementVisible('*[data-id="commitButton"]') + .click('*[data-id="commits-panel"]') + .waitForElementPresent({ + selector: '//*[@data-id="commit-summary-testcommit-"]', + locateStrategy: 'xpath' + }) + }, + 'check the log #group1': async function (browser: NightwatchBrowser) { + const logs = await getGitLog('/tmp/git/bare.git') + console.log(logs) + browser.assert.ok(logs.includes('testcommit')) + }, + 'change a file #group1': function (browser: NightwatchBrowser) { + browser. + openFile('test.txt'). + pause(1000). + setEditorValue('changes', null) + }, + 'stage changed file #group1': function (browser: NightwatchBrowser) { + browser + .clickLaunchIcon('dgit') + .click('*[data-id="sourcecontrol-panel"]') + .waitForElementVisible({ + selector: "//*[@data-status='modified-unstaged' and @data-file='/test.txt']", + locateStrategy: 'xpath' + }) + .waitForElementVisible('*[data-id="addToGitChangestest.txt"]') + .click('*[data-id="addToGitChangestest.txt"]') + .waitForElementVisible({ + selector: "//*[@data-status='modified-staged' and @data-file='/test.txt']", + locateStrategy: 'xpath' + }) + .setValue('*[data-id="commitMessage"]', 'testcommit2') + .click('*[data-id="commitButton"]') + }, + 'push the commit #group1': function (browser: NightwatchBrowser) { + browser + .click('*[data-id="commands-panel"]') + .waitForElementVisible('*[data-id="sourcecontrol-push"]') + .click('*[data-id="sourcecontrol-push"]') + .pause(2000) + .click('*[data-id="commits-panel"]') + .waitForElementPresent({ + selector: '//*[@data-id="commit-summary-testcommit2-"]', + locateStrategy: 'xpath' + }).pause(2000) + }, + 'check the log for testcommit2 #group1': async function (browser: NightwatchBrowser) { + const logs = await getGitLog('/tmp/git/bare.git') + console.log(logs) + browser.assert.ok(logs.includes('testcommit2')) + }, + 'clone locally and add a file and push #group1': async function (browser: NightwatchBrowser) { + await cloneOnServer('http://localhost:6868/bare.git', '/tmp/') + await onLocalGitRepoAddFile('/tmp/bare/', 'test2.txt') + await createCommitOnLocalServer('/tmp/bare/', 'testlocal') + await onLocalGitRepoPush('/tmp/bare/', 'master') + }, + 'run a git fetch #group1': function (browser: NightwatchBrowser) { + browser + .pause(2000) + .click('*[data-id="commands-panel"]') + .waitForElementVisible('*[data-id="sourcecontrol-fetch-branch"]') + + .click('*[data-id="sourcecontrol-fetch-branch"]') + .pause(2000) + .click('*[data-id="commits-panel"]') + .waitForElementVisible('*[data-id="commits-panel-behind"]') + .click('*[data-id="commits-panel-behind"]') + .waitForElementPresent({ + selector: '//*[@data-id="commit-summary-testlocal-"]', + locateStrategy: 'xpath' + }) + }, + 'run pull from the header #group1': function (browser: NightwatchBrowser) { + browser. + click('*[data-id="sourcecontrol-button-pull"]') + .waitForElementNotPresent('*[data-id="commits-panel-behind"]') + }, + 'check if the file is added #group1': function (browser: NightwatchBrowser) { + browser + .clickLaunchIcon('filePanel') + .waitForElementVisible('*[data-id="treeViewLitreeViewItemtest2.txt"]') + }, +} +const useIsoGit = process.argv.includes('--use-isogit'); +if (process.platform.startsWith('win')) { + module.exports = {} +} +else + module.exports = { ...tests } + + diff --git a/apps/remixdesktop/test/tests/app/git-ui_2.test.ts b/apps/remixdesktop/test/tests/app/git-ui_2.test.ts new file mode 100644 index 0000000000..6a1f3b598b --- /dev/null +++ b/apps/remixdesktop/test/tests/app/git-ui_2.test.ts @@ -0,0 +1,181 @@ +import { ChildProcess, spawn } from "child_process" +import kill from 'tree-kill' +import { Nightwatch, NightwatchBrowser } from "nightwatch" +import { spawnGitServer, getGitLog, cloneOnServer, onLocalGitRepoAddFile, createCommitOnLocalServer, onLocalGitRepoPush, getBranches } from "../../lib/git" +let gitserver: ChildProcess + +/* +/ uses the git-http-backend package to create a git server ( if needed kill the server: kill -9 $(sudo lsof -t -i:6868) ) +/ GROUP 1: file operations PUSH PULL COMMIT SYNC FETCH CLONE ADD +/ GROUP 2: branch operations CREATE & PUBLISH +/ GROUP 3: file operations rename delete +*/ + +const tests = { + before: function (browser: NightwatchBrowser, done: VoidFunction) { + browser.hideToolTips() + done() + }, + after: function (browser: NightwatchBrowser) { + browser.perform((done) => { + console.log('kill server', gitserver.pid) + kill(gitserver.pid) + done() + }) + }, + + 'run server #group1 #group2 #group3': function (browser: NightwatchBrowser) { + browser.perform(async (done) => { + gitserver = await spawnGitServer('/tmp/') + console.log('working directory', process.cwd()) + done() + }) + }, + + 'clone a repo #group1 #group2 #group3': function (browser: NightwatchBrowser) { + browser + .clickLaunchIcon('dgit') + .pause(5000) + .waitForElementVisible('*[data-id="cloneButton"]') + .click('*[data-id="cloneButton"]') + .pause(1000) + .waitForElementVisible('[data-id="fileSystemModalDialogModalBody-react"]') + .click('[data-id="fileSystemModalDialogModalBody-react"]') + .waitForElementVisible('[data-id="modalDialogCustomPromptTextClone"]') + .setValue('*[data-id="modalDialogCustomPromptTextClone"]', 'http://localhost:6868/bare.git') + .click('[data-id="fileSystem-modal-footer-ok-react"]') + .pause(5000) + .windowHandles(function (result) { + console.log(result.value) + browser.switchWindow(result.value[1]) + .waitForElementVisible('*[data-id="treeViewLitreeViewItem.git"]') + .hideToolTips() + }) + .waitForElementVisible('*[data-id="treeViewLitreeViewItemREADME.md"]') + }, + 'Update settings for git #group1 #group2 #group3': function (browser: NightwatchBrowser) { + browser. + clickLaunchIcon('dgit') + .waitForElementVisible('*[data-id="github-panel"]') + .pause(1000) + .click('*[data-id="github-panel"]') + .pause(1000) + .setValue('*[data-id="gitubUsername"]', 'git') + .pause(1000) + .setValue('*[data-id="githubEmail"]', 'git@example.com') + .pause(1000) + .click('*[data-id="saveGitHubCredentials"]') + .modalFooterOKClick('github-credentials-error') + + }, + + // GROUP 2 + 'create a branch #group2': function (browser: NightwatchBrowser) { + browser + .click('*[data-id="branches-panel"]') + .waitForElementVisible('*[data-id="newbranchname"]') + .setValue('*[data-id="newbranchname"]', 'testbranch') + .click('*[data-id="sourcecontrol-create-branch"]') + .waitForElementVisible('*[data-id="branches-current-branch-testbranch"]') + .pause(1000) + }, + 'check if the branch is in the filePanel #group2': function (browser: NightwatchBrowser) { + browser + .clickLaunchIcon('filePanel') + .pause(1000) + .waitForElementVisible('*[data-id="workspaceGitBranchesDropdown"]') + .click('[data-id="workspaceGitBranchesDropdown"]') + .waitForElementVisible('*[data-id="workspaceGit-testbranch"]') + .expect.element('[data-id="workspaceGit-testbranch"]').text.to.contain('✓ ') + }, + 'publish the branch #group2': function (browser: NightwatchBrowser) { + browser + .clickLaunchIcon('dgit') + .waitForElementVisible('*[data-id="sourcecontrol-panel"]') + .click('*[data-id="sourcecontrol-panel"]') + .pause(1000) + .click('*[data-id="publishBranchButton"]') + .pause(2000) + .waitForElementNotVisible('*[data-id="publishBranchButton"]') + }, + 'check if the branch is published #group2': async function (browser: NightwatchBrowser) { + const branches = await getBranches('/tmp/git/bare.git') + browser.assert.ok(branches.includes('testbranch')) + }, + 'add file to new branch #group2': function (browser: NightwatchBrowser) { + browser + .pause(1000) + .addFile('test.txt', { content: 'hello world' }, 'README.md') + .clickLaunchIcon('dgit') + .pause(2000) + .waitForElementVisible({ + selector: "//*[@data-status='new-untracked' and @data-file='/test.txt']", + locateStrategy: 'xpath' + }) + .waitForElementVisible('*[data-id="addToGitChangestest.txt"]') + .pause(1000) + .click('*[data-id="addToGitChangestest.txt"]') + .waitForElementVisible({ + selector: "//*[@data-status='added-staged' and @data-file='/test.txt']", + locateStrategy: 'xpath' + }) + .setValue('*[data-id="commitMessage"]', 'testcommit') + .click('*[data-id="commitButton"]') + .pause(1000) + }, + 'check if the commit is ahead in the branches list #group2': function (browser: NightwatchBrowser) { + browser + .waitForElementVisible('*[data-id="branches-panel"]') + .click('*[data-id="branches-panel"]') + .waitForElementVisible('*[data-id="branches-current-branch-testbranch"]') + .click({ + selector: "//*[@data-id='branches-panel-content']//*[@data-id='branches-current-branch-testbranch']", + locateStrategy: 'xpath', + suppressNotFoundErrors: true + }) + .click({ + selector: "//*[@data-id='branches-panel-content']//*[@data-id='commits-panel-ahead']", + locateStrategy: 'xpath', + suppressNotFoundErrors: true + }) + .click({ + selector: "//*[@data-id='branches-panel-content']//*[@data-id='branchdifference-commits-testbranch-ahead']//*[@data-id='commit-summary-testcommit-ahead']", + locateStrategy: 'xpath', + }) + .click({ + selector: "//*[@data-id='branches-panel-content']//*[@data-id='branchdifference-commits-testbranch-ahead']//*[@data-id='commit-change-added-test.txt']", + locateStrategy: 'xpath', + }) + .click({ + selector: "//*[@data-id='branches-panel-content']//*[@data-id='local-branch-commits-testbranch']//*[@data-id='commit-summary-testcommit-ahead']", + locateStrategy: 'xpath', + }) + .waitForElementVisible({ + selector: "//*[@data-id='branches-panel-content']//*[@data-id='local-branch-commits-testbranch']//*[@data-id='commit-change-added-test.txt']", + locateStrategy: 'xpath', + }) + }, + 'switch back to master #group2': function (browser: NightwatchBrowser) { + browser + .click({ + selector: "//*[@data-id='branches-panel-content']//*[@data-id='branches-toggle-branch-master']", + locateStrategy: 'xpath', + }) + .waitForElementVisible({ + selector: "//*[@data-id='branches-panel-content']//*[@data-id='branches-toggle-current-branch-master']", + locateStrategy: 'xpath', + }) + }, + 'check if test file is gone #group2': function (browser: NightwatchBrowser) { + browser + .clickLaunchIcon('filePanel') + .waitForElementNotPresent('*[data-id="treeViewLitreeViewItemtest.txt"]') + } +} + +const useIsoGit = process.argv.includes('--useIsoGit'); +if (process.platform.startsWith('win')) { + module.exports = {} +} +else + module.exports = { ...tests } \ No newline at end of file diff --git a/apps/remixdesktop/test/tests/app/git-ui_3.test.ts b/apps/remixdesktop/test/tests/app/git-ui_3.test.ts new file mode 100644 index 0000000000..6fb96951ff --- /dev/null +++ b/apps/remixdesktop/test/tests/app/git-ui_3.test.ts @@ -0,0 +1,153 @@ +import { ChildProcess, spawn } from "child_process" +import kill from 'tree-kill' +import { Nightwatch, NightwatchBrowser } from "nightwatch" +import { spawnGitServer, getGitLog, cloneOnServer, onLocalGitRepoAddFile, createCommitOnLocalServer, onLocalGitRepoPush, getBranches } from "../../lib/git" +let gitserver: ChildProcess + +/* +/ uses the git-http-backend package to create a git server ( if needed kill the server: kill -9 $(sudo lsof -t -i:6868) ) +/ GROUP 1: file operations PUSH PULL COMMIT SYNC FETCH CLONE ADD +/ GROUP 2: branch operations CREATE & PUBLISH +/ GROUP 3: file operations rename delete +*/ + +const tests = { + before: function (browser: NightwatchBrowser, done: VoidFunction) { + browser.hideToolTips() + done() + }, + after: function (browser: NightwatchBrowser) { + browser.perform((done) => { + console.log('kill server', gitserver.pid) + kill(gitserver.pid) + done() + }) + }, + + 'run server #group1 #group2 #group3': function (browser: NightwatchBrowser) { + browser.perform(async (done) => { + gitserver = await spawnGitServer('/tmp/') + console.log('working directory', process.cwd()) + done() + }) + }, + + 'clone a repo #group1 #group2 #group3': function (browser: NightwatchBrowser) { + browser + .clickLaunchIcon('dgit') + .pause(5000) + .waitForElementVisible('*[data-id="cloneButton"]') + .click('*[data-id="cloneButton"]') + .pause(1000) + .waitForElementVisible('[data-id="fileSystemModalDialogModalBody-react"]') + .click('[data-id="fileSystemModalDialogModalBody-react"]') + .waitForElementVisible('[data-id="modalDialogCustomPromptTextClone"]') + .setValue('*[data-id="modalDialogCustomPromptTextClone"]', 'http://localhost:6868/bare.git') + .click('[data-id="fileSystem-modal-footer-ok-react"]') + .pause(5000) + .windowHandles(function (result) { + console.log(result.value) + browser.switchWindow(result.value[1]) + .waitForElementVisible('*[data-id="treeViewLitreeViewItem.git"]') + .hideToolTips() + }) + .waitForElementVisible('*[data-id="treeViewLitreeViewItemREADME.md"]') + }, + 'Update settings for git #group1 #group2 #group3': function (browser: NightwatchBrowser) { + browser. + clickLaunchIcon('dgit') + .saveScreenshot('./reports/screenshots/gitui.png') + .waitForElementVisible('*[data-id="github-panel"]') + .pause(1000) + .saveScreenshot('./reports/screenshots/gitui2.png') + .pause(1000) + .saveScreenshot('./reports/screenshots/gitui3.png') + .click('*[data-id="github-panel"]') + .pause(1000) + .setValue('*[data-id="gitubUsername"]', 'git') + .pause(1000) + .setValue('*[data-id="githubEmail"]', 'git@example.com') + .pause(1000) + .click('*[data-id="saveGitHubCredentials"]') + .pause(1000) + .modalFooterOKClick('github-credentials-error') + + }, + + 'check file added #group1 #group3': function (browser: NightwatchBrowser) { + browser + .addFile('test.txt', { content: 'hello world' }, 'README.md') + .clickLaunchIcon('dgit') + .pause(1000) + .click('*[data-id="sourcecontrol-panel"]') + .waitForElementVisible({ + selector: "//*[@data-status='new-untracked' and @data-file='/test.txt']", + locateStrategy: 'xpath' + }) + .waitForElementVisible('*[data-id="addToGitChangestest.txt"]') + .pause(1000) + .click('*[data-id="addToGitChangestest.txt"]') + .waitForElementVisible({ + selector: "//*[@data-status='added-staged' and @data-file='/test.txt']", + locateStrategy: 'xpath' + }) + .setValue('*[data-id="commitMessage"]', 'testcommit') + .click('*[data-id="commitButton"]') + }, + + // group 3 + 'rename a file #group3': function (browser: NightwatchBrowser) { + browser + .clickLaunchIcon('filePanel') + .waitForElementVisible('*[data-id="treeViewLitreeViewItemtest.txt"]') + .click('*[data-id="treeViewLitreeViewItemtest.txt"]') + .renamePath('test.txt', 'test_rename', 'test_rename.txt') + .waitForElementVisible('*[data-id="treeViewLitreeViewItemtest_rename.txt"]') + .pause(1000) + }, + 'stage renamed file #group3': function (browser: NightwatchBrowser) { + browser + .clickLaunchIcon('dgit') + .waitForElementVisible({ + selector: "//*[@data-status='deleted-unstaged' and @data-file='/test.txt']", + locateStrategy: 'xpath' + }) + .waitForElementVisible('*[data-id="addToGitChangestest.txt"]') + .waitForElementVisible({ + selector: "//*[@data-status='new-untracked' and @data-file='/test_rename.txt']", + locateStrategy: 'xpath' + }) + .pause(2000) + .click('*[data-id="sourcecontrol-add-all"]') + .waitForElementVisible({ + selector: "//*[@data-status='added-staged' and @data-file='/test_rename.txt']", + locateStrategy: 'xpath' + }) + }, + 'undo the rename #group3': function (browser: NightwatchBrowser) { + browser + .waitForElementVisible('*[data-id="unStageStagedtest_rename.txt"]') + .click('*[data-id="unStageStagedtest_rename.txt"]') + .pause(1000) + .click('*[data-id="unDoStagedtest.txt"]') + .pause(1000) + .waitForElementNotPresent({ + selector: "//*[@data-file='/test.txt']", + locateStrategy: 'xpath' + }) + }, + 'check if file is returned #group3': function (browser: NightwatchBrowser) { + browser + .clickLaunchIcon('filePanel') + .waitForElementVisible('*[data-id="treeViewLitreeViewItemtest.txt"]') + }, + + +} + +const useIsoGit = process.argv.includes('--use-isogit'); +if (process.platform.startsWith('win')) { + module.exports = {} +} +else + module.exports = { ...tests } \ No newline at end of file diff --git a/apps/remixdesktop/test/tests/app/git-ui_4.test.ts b/apps/remixdesktop/test/tests/app/git-ui_4.test.ts new file mode 100644 index 0000000000..521462122d --- /dev/null +++ b/apps/remixdesktop/test/tests/app/git-ui_4.test.ts @@ -0,0 +1,200 @@ +import { ChildProcess, spawn } from "child_process" +import kill from 'tree-kill' +import { Nightwatch, NightwatchBrowser } from "nightwatch" +import { spawnGitServer, getGitLog, cloneOnServer, onLocalGitRepoAddFile, createCommitOnLocalServer, onLocalGitRepoPush, getBranches } from "../../lib/git" +let gitserver: ChildProcess + +/* +/ uses the git-http-backend package to create a git server ( if needed kill the server: kill -9 $(sudo lsof -t -i:6868) ) +/ GROUP 1: file operations PUSH PULL COMMIT SYNC FETCH CLONE ADD +/ GROUP 2: branch operations CREATE & PUBLISH +/ GROUP 3: file operations rename delete +*/ + +const tests = { + before: function (browser: NightwatchBrowser, done: VoidFunction) { + browser.hideToolTips() + done() + }, + after: function (browser: NightwatchBrowser) { + browser.perform((done) => { + console.log('kill server', gitserver.pid) + kill(gitserver.pid) + done() + }) + }, + + 'run server #group1 #group2 #group3': function (browser: NightwatchBrowser) { + browser.perform(async (done) => { + gitserver = await spawnGitServer('/tmp/') + console.log('working directory', process.cwd()) + done() + }) + }, + + 'clone a repo #group1 #group2 #group3': function (browser: NightwatchBrowser) { + browser + .clickLaunchIcon('dgit') + .pause(5000) + .waitForElementVisible('*[data-id="cloneButton"]') + .click('*[data-id="cloneButton"]') + .pause(1000) + .waitForElementVisible('[data-id="fileSystemModalDialogModalBody-react"]') + .click('[data-id="fileSystemModalDialogModalBody-react"]') + .waitForElementVisible('[data-id="modalDialogCustomPromptTextClone"]') + .setValue('*[data-id="modalDialogCustomPromptTextClone"]', 'http://localhost:6868/bare.git') + .click('[data-id="fileSystem-modal-footer-ok-react"]') + .pause(5000) + .windowHandles(function (result) { + console.log(result.value) + browser.switchWindow(result.value[1]) + .waitForElementVisible('*[data-id="treeViewLitreeViewItem.git"]') + .hideToolTips() + }) + .waitForElementVisible('*[data-id="treeViewLitreeViewItemREADME.md"]') + }, + 'Update settings for git #group1 #group2 #group3': function (browser: NightwatchBrowser) { + browser. + clickLaunchIcon('dgit') + .waitForElementVisible('*[data-id="github-panel"]') + .pause(1000) + .click('*[data-id="github-panel"]') + .pause(1000) + .setValue('*[data-id="gitubUsername"]', 'git') + .pause(1000) + .setValue('*[data-id="githubEmail"]', 'git@example.com') + .pause(1000) + .click('*[data-id="saveGitHubCredentials"]') + .pause(1000) + .modalFooterOKClick('github-credentials-error') + + }, + + // GROUP 1 + + 'check file added #group1 #group3': function (browser: NightwatchBrowser) { + browser + .addFile('test.txt', { content: 'hello world' }, 'README.md') + .clickLaunchIcon('dgit') + .pause(1000) + .click('*[data-id="sourcecontrol-panel"]') + .waitForElementVisible({ + selector: "//*[@data-status='new-untracked' and @data-file='/test.txt']", + locateStrategy: 'xpath' + }) + .waitForElementVisible('*[data-id="addToGitChangestest.txt"]') + .pause(1000) + .click('*[data-id="addToGitChangestest.txt"]') + .waitForElementVisible({ + selector: "//*[@data-status='added-staged' and @data-file='/test.txt']", + locateStrategy: 'xpath' + }) + .setValue('*[data-id="commitMessage"]', 'testcommit') + .click('*[data-id="commitButton"]') + }, + 'look at the commit #group1': function (browser: NightwatchBrowser) { + browser + .click('*[data-id="commits-panel"]') + .waitForElementPresent({ + selector: '//*[@data-id="commit-summary-testcommit-ahead"]', + locateStrategy: 'xpath' + }) + }, + 'add second remote #group4': function (browser: NightwatchBrowser) { + browser + .pause(1000) + .click('*[data-id="remotes-panel"]') + .waitForElementVisible('*[data-id="add-manual-remoteurl"]') + .setValue('*[data-id="add-manual-remoteurl"]', 'http://localhost:6868/bare2.git') + .waitForElementVisible('*[data-id="add-manual-remotename"]') + .setValue('*[data-id="add-manual-remotename"]', 'origin2') + .waitForElementVisible('*[data-id="add-manual-remotebtn"]') + .click('*[data-id="add-manual-remotebtn"]') + }, + 'check the buttons #group4': function (browser: NightwatchBrowser) { + browser + .waitForElementVisible('*[data-id="default-remote-check-origin"]') + .waitForElementVisible('*[data-id="set-as-default-origin2"]') + }, + 'check the commands #group4': function (browser: NightwatchBrowser) { + browser + .click('*[data-id="commands-panel"]') + .waitForElementVisible({ + selector: "//div[@id='commands-remote-origin-select']//div[contains(@class, 'singleValue') and contains(text(), 'origin')]", + locateStrategy: 'xpath' + }) + }, + 'switch to origin2 #group4': function (browser: NightwatchBrowser) { + browser + .click('*[data-id="remotes-panel"]') + .waitForElementVisible('*[data-id="set-as-default-origin2"]') + .click('*[data-id="set-as-default-origin2"]') + }, + 'check the commands for origin2 #group4': function (browser: NightwatchBrowser) { + browser + .click('*[data-id="commands-panel"]') + .waitForElementVisible({ + selector: "//div[@id='commands-remote-origin-select']//div[contains(@class, 'singleValue') and contains(text(), 'origin2')]", + locateStrategy: 'xpath' + }) + }, + 'sync the commit #group4': function (browser: NightwatchBrowser) { + browser + .pause(1000) + .waitForElementVisible('*[data-id="sourcecontrol-panel"]') + .click('*[data-id="sourcecontrol-panel"]') + .waitForElementVisible('*[data-id="syncButton"]') + .click('*[data-id="syncButton"]') + .waitForElementVisible('*[data-id="commitButton"]') + .click('*[data-id="commits-panel"]') + .waitForElementPresent({ + selector: '//*[@data-id="commit-summary-testcommit-"]', + locateStrategy: 'xpath' + }) + }, + 'check the log #group4': async function (browser: NightwatchBrowser) { + const logs = await getGitLog('/tmp/git/bare2.git') + console.log(logs) + browser.assert.ok(logs.includes('testcommit')) + const logs2 = await getGitLog('/tmp/git/bare.git') + console.log(logs2) + console.log(logs2.includes('testcommit3')) + browser.assert.ok(logs2.includes('testcommit3')) + }, + 'switch to origin #group4': function (browser: NightwatchBrowser) { + browser + .pause(5000) + .click('*[data-id="remotes-panel"]') + .waitForElementVisible('*[data-id="set-as-default-origin"]') + .pause(1000) + .click('*[data-id="set-as-default-origin"]') + }, + 'check the commands for origin #group4': function (browser: NightwatchBrowser) { + browser + .click('*[data-id="commands-panel"]') + .waitForElementVisible({ + selector: "//div[@id='commands-remote-origin-select']//div[contains(@class, 'singleValue') and contains(text(), 'origin')]", + locateStrategy: 'xpath' + }) + }, + 'check the commit ahead #group4': function (browser: NightwatchBrowser) { + browser + .pause(1000) + .waitForElementVisible('*[data-id="sourcecontrol-panel"]') + .click('*[data-id="sourcecontrol-panel"]') + .waitForElementVisible('*[data-id="syncButton"]') + // do not sync + .click('*[data-id="commits-panel"]') + .waitForElementPresent({ + selector: '//*[@data-id="commit-summary-testcommit-ahead"]', + locateStrategy: 'xpath' + }) + }, +} + +const useIsoGit = process.argv.includes('--use-isogit'); +if (process.platform.startsWith('win')) { + module.exports = {} +} +else + module.exports = { ...tests } \ No newline at end of file diff --git a/apps/remixdesktop/test/tests/app/git.test.ts b/apps/remixdesktop/test/tests/app/git.test.ts new file mode 100644 index 0000000000..9cc26be3d0 --- /dev/null +++ b/apps/remixdesktop/test/tests/app/git.test.ts @@ -0,0 +1,28 @@ +import { NightwatchBrowser } from 'nightwatch' + + +module.exports = { + '@isogit': true, + before: function (browser: NightwatchBrowser, done: VoidFunction) { + done() + }, + 'clone a repo': function (browser: NightwatchBrowser) { + browser + .waitForElementVisible('*[data-id="remixIdeIconPanel"]', 10000) + .waitForElementVisible('button[data-id="landingPageImportFromGit"]') + .click('button[data-id="landingPageImportFromGit"]') + .pause(1000) + .waitForElementVisible('[data-id="fileSystemModalDialogModalBody-react"]') + .click('[data-id="fileSystemModalDialogModalBody-react"]') + .waitForElementVisible('[data-id="modalDialogCustomPromptTextClone"]') + .setValue('[data-id="modalDialogCustomPromptTextClone"]', 'https://github.com/ethereum/awesome-remix') + .click('[data-id="fileSystem-modal-footer-ok-react"]') + .pause(3000) + .windowHandles(function (result) { + console.log(result.value) + browser.switchWindow(result.value[1]) + .waitForElementVisible('*[data-id="treeViewLitreeViewItem.git"]') + }) + .end() + } +} \ No newline at end of file diff --git a/apps/remixdesktop/test/tests/app/github.test.ts b/apps/remixdesktop/test/tests/app/github.test.ts new file mode 100644 index 0000000000..612be7e02f --- /dev/null +++ b/apps/remixdesktop/test/tests/app/github.test.ts @@ -0,0 +1,255 @@ +import { NightwatchBrowser } from "nightwatch" + + +const tests = { + before: function (browser: NightwatchBrowser, done: VoidFunction) { + browser.hideToolTips() + done() + }, + + 'open default template': function (browser: NightwatchBrowser) { + browser + .waitForElementVisible('*[data-id="remixIdeIconPanel"]', 10000) + .waitForElementVisible('button[data-id="landingPageImportFromTemplate"]') + .click('button[data-id="landingPageImportFromTemplate"]') + .waitForElementPresent('*[data-id="create-remixDefault"]') + .scrollAndClick('*[data-id="create-remixDefault"]') + .waitForElementVisible('*[data-id="modalDialogCustomPromptTextCreate"]') + .waitForElementPresent('[data-id="TemplatesSelectionModalDialogContainer-react"] .modal-ok') + .click('[data-id="TemplatesSelectionModalDialogContainer-react"] .modal-ok') + .pause(3000) + .windowHandles(function (result) { + console.log(result.value) + browser.switchWindow(result.value[1]) + .waitForElementVisible('*[data-id="treeViewLitreeViewItemtests"]') + }) + + }, + 'Update settings for git #group1 #group2': function (browser: NightwatchBrowser) { + browser + .clickLaunchIcon('dgit') + .pause(1000) + .waitForElementVisible('*[data-id="initgit-btn"]') + .click('*[data-id="initgit-btn"]') + .waitForElementNotPresent('*[data-id="initgit-btn"]') + }, + 'launch github login via FE #group1 #group2': function (browser: NightwatchBrowser) { + browser + .clickLaunchIcon('filePanel') + .pause(1000) + .waitForElementVisible('*[data-id="filepanel-login-github"]') + .click('*[data-id="filepanel-login-github"]') + }, + 'login to github #group1 #group2': function (browser: NightwatchBrowser) { + browser + .waitForElementVisible('*[data-id="github-panel"]') + .waitForElementVisible('*[data-id="gitubUsername"]') + .setValue('*[data-id="githubToken"]', process.env.dgit_token) + .pause(1000) + .setValue('*[data-id="gitubUsername"]', 'git') + .pause(1000) + .setValue('*[data-id="githubEmail"]', 'git@example.com') + .pause(1000) + .click('*[data-id="saveGitHubCredentials"]') + }, + 'check if the settings are loaded #group1 #group2': function (browser: NightwatchBrowser) { + browser + .waitForElementVisible('*[data-id="connected-as-bunsenstraat"]') + .waitForElementVisible('*[data-id="connected-img-bunsenstraat"]') + .waitForElementVisible('*[data-id="connected-link-bunsenstraat"]') + .waitForElementVisible('*[data-id="remotes-panel"]') + }, + 'check the FE for the auth user #group1 #group2': function (browser: NightwatchBrowser) { + browser + .clickLaunchIcon('filePanel') + .waitForElementVisible('*[data-id="filepanel-connected-img-bunsenstraat"]') + }, + 'clone a repository #group1': function (browser: NightwatchBrowser) { + browser + .clickLaunchIcon('dgit') + .click('*[data-id="clone-panel"]') + .click({ + selector: '//*[@data-id="clone-panel-content"]//*[@data-id="fetch-repositories"]', + locateStrategy: 'xpath' + }) + .waitForElementVisible({ + selector: '//*[@data-id="clone-panel-content"]//*[@id="repository-select"]', + locateStrategy: 'xpath' + }) + .click({ + selector: '//*[@data-id="clone-panel-content"]//*[@id="repository-select"]', + locateStrategy: 'xpath' + }) + .waitForElementVisible({ + selector: '//*[@data-id="clone-panel-content"]//*[contains(text(), "awesome-remix")]', + locateStrategy: 'xpath' + }) + .click({ + selector: '//*[@data-id="clone-panel-content"]//*[contains(text(), "awesome-remix")]', + locateStrategy: 'xpath' + }) + .waitForElementVisible({ + selector: '//*[@data-id="clone-panel-content"]//*[@id="branch-select"]', + locateStrategy: 'xpath' + }) + .click({ + selector: '//*[@data-id="clone-panel-content"]//*[@id="branch-select"]', + locateStrategy: 'xpath' + }) + .click({ + selector: '//*[@data-id="clone-panel-content"]//*[contains(text(), "master")]', + locateStrategy: 'xpath' + }) + .waitForElementVisible({ + selector: '//*[@data-id="clone-panel-content"]//*[@data-id="clonebtn-ethereum/awesome-remix-master"]', + locateStrategy: 'xpath' + }) + .click({ + selector: '//*[@data-id="clone-panel-content"]//*[@data-id="clonebtn-ethereum/awesome-remix-master"]', + locateStrategy: 'xpath' + }) + .pause(5000) + .windowHandles(function (result) { + console.log(result.value) + browser.switchWindow(result.value[2]) + .pause(1000) + .waitForElementVisible('*[data-id="treeViewLitreeViewItem.git"]') + }) + }, + 'check if there is a README.md file #group1': function (browser: NightwatchBrowser) { + browser + .waitForElementVisible('*[data-id="treeViewLitreeViewItemREADME.md"]') + }, + 'check the commands panel #group1': function (browser: NightwatchBrowser) { + browser + .clickLaunchIcon('dgit') + .click('*[data-id="commands-panel"]') + .waitForElementVisible({ + selector: "//div[@id='commands-remote-branch-select']//div[contains(@class, 'singleValue') and contains(text(), 'master')]", + locateStrategy: 'xpath' + }) + .waitForElementVisible({ + selector: "//div[@id='commands-remote-origin-select']//div[contains(@class, 'singleValue') and contains(text(), 'origin')]", + locateStrategy: 'xpath' + }) + .waitForElementVisible({ + selector: "//div[@id='commands-local-branch-select']//div[contains(@class, 'singleValue') and contains(text(), 'master')]", + locateStrategy: 'xpath' + }) + }, + 'check the remotes #group1': function (browser: NightwatchBrowser) { + browser + + .click('*[data-id="remotes-panel"]') + .waitForElementVisible('*[data-id="remotes-panel-content"]') + .pause(2000) + .waitForElementVisible({ + selector: '//*[@data-id="remotes-panel-content"]//*[@data-id="remote-detail-origin-default"]', + locateStrategy: 'xpath' + }) + .waitForElementVisible({ + selector: '//*[@data-id="remotes-panel-content"]//*[@data-id="branches-current-branch-master"]', + locateStrategy: 'xpath' + }) + .click({ + selector: '//*[@data-id="remotes-panel-content"]//*[@data-id="remote-sync-origin"]', + locateStrategy: 'xpath' + }) + .waitForElementVisible({ + selector: '//*[@data-id="remotes-panel-content"]//*[@data-id="branches-branch-links"]', + locateStrategy: 'xpath', + timeout: 10000 + }) + + }, + 'check the commits of branch links #group1': function (browser: NightwatchBrowser) { + browser + .waitForElementVisible({ + selector: '//*[@data-id="remotes-panel-content"]//*[@data-id="branches-branch-links"]', + locateStrategy: 'xpath' + }) + .click({ + selector: '//*[@data-id="remotes-panel-content"]//*[@data-id="branches-branch-links"]', + locateStrategy: 'xpath' + }) + .waitForElementVisible({ + selector: '//*[@data-id="remotes-panel-content"]//*[@data-id="commit-summary-linking fixed-"]', + locateStrategy: 'xpath' + }) + }, + 'switch to branch links #group1': function (browser: NightwatchBrowser) { + browser + .click('*[data-id="branches-panel"]') + .waitForElementVisible({ + selector: '//*[@data-id="branches-panel-content-remote-branches"]//*[@data-id="branches-branch-links"]', + locateStrategy: 'xpath' + }) + .pause(1000) + .click({ + selector: '//*[@data-id="branches-panel-content-remote-branches"]//*[@data-id="branches-toggle-branch-links"]', + locateStrategy: 'xpath' + }) + .waitForElementVisible({ + selector: '//*[@data-id="branches-panel-content-remote-branches"]//*[@data-id="branches-toggle-current-branch-links"]', + locateStrategy: 'xpath' + }) + }, + 'check the local branches #group1': function (browser: NightwatchBrowser) { + browser + .waitForElementVisible({ + selector: '//*[@data-id="branches-panel-content-local-branches"]//*[@data-id="branches-toggle-current-branch-links"]', + locateStrategy: 'xpath' + }) + }, + 'check the local commits #group1': function (browser: NightwatchBrowser) { + browser + .click('*[data-id="commits-panel"]') + .pause(1000) + .waitForElementVisible({ + selector: '//*[@data-id="commits-current-branch-links"]//*[@data-id="commit-summary-linking fixed-"]', + locateStrategy: 'xpath' + }) + .click({ + selector: '//*[@data-id="commits-current-branch-links"]//*[@data-id="commit-summary-linking fixed-"]', + locateStrategy: 'xpath' + }) + .waitForElementVisible({ + selector: '//*[@data-id="commits-current-branch-links"]//*[@data-id="commit-change-modified-README.md"]', + locateStrategy: 'xpath' + }) + }, + 'check the commands panel for links #group1': function (browser: NightwatchBrowser) { + browser + .click('*[data-id="commands-panel"]') + .waitForElementVisible({ + selector: "//div[@id='commands-remote-branch-select']//div[contains(@class, 'singleValue') and contains(text(), 'links')]", + locateStrategy: 'xpath' + }) + .waitForElementVisible({ + selector: "//div[@id='commands-remote-origin-select']//div[contains(@class, 'singleValue') and contains(text(), 'origin')]", + locateStrategy: 'xpath' + }) + .waitForElementVisible({ + selector: "//div[@id='commands-local-branch-select']//div[contains(@class, 'singleValue') and contains(text(), 'links')]", + locateStrategy: 'xpath' + }) + }, + 'disconnect github #group1': function (browser: NightwatchBrowser) { + browser + .waitForElementVisible('*[data-id="github-panel"]') + .pause(1000) + .click('*[data-id="github-panel"]') + .waitForElementVisible('*[data-id="disconnect-github"]') + .pause(1000) + .click('*[data-id="disconnect-github"]') + .waitForElementNotPresent('*[data-id="connected-as-bunsenstraat"]') + }, + 'check the FE for the disconnected auth user #group1': function (browser: NightwatchBrowser) { + browser + .clickLaunchIcon('filePanel') + .waitForElementNotPresent('*[data-id="filepanel-connected-img-bunsenstraat"]') + .waitForElementVisible('*[data-id="filepanel-login-github"]') + }, +} + +module.exports = tests \ No newline at end of file diff --git a/apps/remixdesktop/test/tests/app/github_2.test.ts b/apps/remixdesktop/test/tests/app/github_2.test.ts new file mode 100644 index 0000000000..3b02b3746c --- /dev/null +++ b/apps/remixdesktop/test/tests/app/github_2.test.ts @@ -0,0 +1,190 @@ +import { NightwatchBrowser } from "nightwatch" + + +const tests = { + before: function (browser: NightwatchBrowser, done: VoidFunction) { + browser.hideToolTips() + done() + }, + + 'open default template': function (browser: NightwatchBrowser) { + browser + .waitForElementVisible('*[data-id="remixIdeIconPanel"]', 10000) + .waitForElementVisible('button[data-id="landingPageImportFromTemplate"]') + .click('button[data-id="landingPageImportFromTemplate"]') + .waitForElementPresent('*[data-id="create-remixDefault"]') + .scrollAndClick('*[data-id="create-remixDefault"]') + .waitForElementVisible('*[data-id="modalDialogCustomPromptTextCreate"]') + .waitForElementPresent('[data-id="TemplatesSelectionModalDialogContainer-react"] .modal-ok') + .click('[data-id="TemplatesSelectionModalDialogContainer-react"] .modal-ok') + .pause(3000) + .windowHandles(function (result) { + console.log(result.value) + browser.switchWindow(result.value[1]) + .waitForElementVisible('*[data-id="treeViewLitreeViewItemtests"]') + }) + + }, + 'Update settings for git #group1 #group2': function (browser: NightwatchBrowser) { + browser + .clickLaunchIcon('dgit') + .pause(1000) + .waitForElementVisible('*[data-id="initgit-btn"]') + .click('*[data-id="initgit-btn"]') + .waitForElementNotPresent('*[data-id="initgit-btn"]') + }, + 'launch github login via FE #group1 #group2': function (browser: NightwatchBrowser) { + browser + .clickLaunchIcon('filePanel') + .pause(1000) + .waitForElementVisible('*[data-id="filepanel-login-github"]') + .click('*[data-id="filepanel-login-github"]') + }, + 'login to github #group1 #group2': function (browser: NightwatchBrowser) { + browser + .waitForElementVisible('*[data-id="github-panel"]') + .waitForElementVisible('*[data-id="gitubUsername"]') + .setValue('*[data-id="githubToken"]', process.env.dgit_token) + .pause(1000) + .setValue('*[data-id="gitubUsername"]', 'git') + .pause(1000) + .setValue('*[data-id="githubEmail"]', 'git@example.com') + .pause(1000) + .click('*[data-id="saveGitHubCredentials"]') + }, + 'check if the settings are loaded #group1 #group2': function (browser: NightwatchBrowser) { + browser + .waitForElementVisible('*[data-id="connected-as-bunsenstraat"]') + .waitForElementVisible('*[data-id="connected-img-bunsenstraat"]') + .waitForElementVisible('*[data-id="connected-link-bunsenstraat"]') + .waitForElementVisible('*[data-id="remotes-panel"]') + }, + 'check the FE for the auth user #group1 #group2': function (browser: NightwatchBrowser) { + browser + .clickLaunchIcon('filePanel') + .waitForElementVisible('*[data-id="filepanel-connected-img-bunsenstraat"]') + }, + 'add a remote #group2': function (browser: NightwatchBrowser) { + browser + .pause(1000) + .clickLaunchIcon('dgit') + .waitForElementVisible('*[data-id="remotes-panel"]') + .click('*[data-id="remotes-panel"]') + .click({ + selector: '//*[@data-id="remotes-panel-content"]//*[@data-id="fetch-repositories"]', + locateStrategy: 'xpath' + }) + .waitForElementVisible({ + selector: '//*[@data-id="remotes-panel-content"]//*[@id="repository-select"]', + locateStrategy: 'xpath' + }) + .click({ + selector: '//*[@data-id="remotes-panel-content"]//*[@id="repository-select"]', + locateStrategy: 'xpath' + }) + .waitForElementVisible({ + selector: '//*[@data-id="remotes-panel-content"]//*[contains(text(), "awesome-remix")]', + locateStrategy: 'xpath' + }) + .click({ + selector: '//*[@data-id="remotes-panel-content"]//*[contains(text(), "awesome-remix")]', + locateStrategy: 'xpath' + }) + .waitForElementVisible({ + selector: '//*[@data-id="remotes-panel-content"]//*[@data-id="remote-panel-remotename"]', + locateStrategy: 'xpath' + }) + .setValue({ + selector: '//*[@data-id="remotes-panel-content"]//*[@data-id="remote-panel-remotename"]', + locateStrategy: 'xpath' + }, 'newremote') + .waitForElementVisible({ + selector: '//*[@data-id="remotes-panel-content"]//*[@data-id="remote-panel-addremote"]', + locateStrategy: 'xpath' + }) + .click({ + selector: '//*[@data-id="remotes-panel-content"]//*[@data-id="remote-panel-addremote"]', + locateStrategy: 'xpath' + }) + .waitForElementVisible({ + selector: '//*[@data-id="remotes-panel-content"]//*[@data-id="remote-detail-newremote-default"]', + locateStrategy: 'xpath' + }) + }, + 'check the commands panel for newremote #group2': function (browser: NightwatchBrowser) { + browser + .pause(1000) + .click('*[data-id="commands-panel"]') + .waitForElementVisible({ + selector: "//div[@id='commands-remote-branch-select']//div[contains(@class, 'singleValue') and contains(text(), 'main')]", + locateStrategy: 'xpath' + }) + .waitForElementVisible({ + selector: "//div[@id='commands-remote-origin-select']//div[contains(@class, 'singleValue') and contains(text(), 'newremote')]", + locateStrategy: 'xpath' + }) + .waitForElementVisible({ + selector: "//div[@id='commands-local-branch-select']//div[contains(@class, 'singleValue') and contains(text(), 'main')]", + locateStrategy: 'xpath' + }) + .pause(1000) + .getAttribute({ + selector: '//*[@data-id="sourcecontrol-pull"]', + locateStrategy: 'xpath' + }, 'disabled', (result) => { + if (result.value) { + browser.assert.fail('Button is disabled') + } else { + browser.assert.ok(true) + } + }) + }, + 'remove the remote #group2': function (browser: NightwatchBrowser) { + browser + .pause(1000) + .click('*[data-id="remotes-panel"]') + .waitForElementVisible({ + selector: '//*[@data-id="remotes-panel-content"]//*[@data-id="remote-rm-newremote"]', + locateStrategy: 'xpath' + }) + .pause(2000) + .click({ + selector: '//*[@data-id="remotes-panel-content"]//*[@data-id="remote-rm-newremote"]', + locateStrategy: 'xpath' + }) + .pause(1000) + .waitForElementNotPresent({ + selector: '//*[@data-id="remotes-panel-content"]//*[@data-id="remote-detail-newremote-default"]', + locateStrategy: 'xpath' + }) + }, + 'check the commands panel for removed remote #group2': function (browser: NightwatchBrowser) { + browser + .pause(1000) + .click('*[data-id="commands-panel"]') + .waitForElementVisible({ + selector: "//div[@id='commands-remote-branch-select']//div[contains(@class, 'singleValue') and contains(text(), 'main')]", + locateStrategy: 'xpath' + }) + .waitForElementNotPresent({ + selector: "//div[@id='commands-remote-origin-select']//div[contains(@class, 'singleValue') and contains(text(), 'newremote')]", + locateStrategy: 'xpath' + }) + .waitForElementVisible({ + selector: "//div[@id='commands-local-branch-select']//div[contains(@class, 'singleValue') and contains(text(), 'main')]", + locateStrategy: 'xpath' + }) + .getAttribute({ + selector: '//*[@data-id="sourcecontrol-pull"]', + locateStrategy: 'xpath' + }, 'disabled', (result) => { + if (result.value) { + browser.assert.ok(true) + } else { + browser.assert.fail('Button is not disabled') + } + }) + }, +} + +module.exports = tests \ No newline at end of file diff --git a/apps/remixdesktop/test/tests/app/github_3.test.ts b/apps/remixdesktop/test/tests/app/github_3.test.ts new file mode 100644 index 0000000000..12542bb86f --- /dev/null +++ b/apps/remixdesktop/test/tests/app/github_3.test.ts @@ -0,0 +1,180 @@ +import { NightwatchBrowser } from "nightwatch" + +const useIsoGit = process.argv.includes('--use-isogit'); +let commitCount = 0 +let branchCount = 0 +const tests = { + before: function (browser: NightwatchBrowser, done: VoidFunction) { + browser.hideToolTips() + done() + }, + + 'open default template': function (browser: NightwatchBrowser) { + browser + .waitForElementVisible('*[data-id="remixIdeIconPanel"]', 10000) + .waitForElementVisible('button[data-id="landingPageImportFromTemplate"]') + .click('button[data-id="landingPageImportFromTemplate"]') + .waitForElementPresent('*[data-id="create-remixDefault"]') + .scrollAndClick('*[data-id="create-remixDefault"]') + .waitForElementVisible('*[data-id="modalDialogCustomPromptTextCreate"]') + .waitForElementPresent('[data-id="TemplatesSelectionModalDialogContainer-react"] .modal-ok') + .click('[data-id="TemplatesSelectionModalDialogContainer-react"] .modal-ok') + .pause(3000) + .windowHandles(function (result) { + console.log(result.value) + browser.switchWindow(result.value[1]) + .waitForElementVisible('*[data-id="treeViewLitreeViewItemtests"]') + }) + + }, + 'Update settings for git #group1 #group2': function (browser: NightwatchBrowser) { + browser + .clickLaunchIcon('dgit') + .pause(1000) + .waitForElementVisible('*[data-id="initgit-btn"]') + .click('*[data-id="initgit-btn"]') + .waitForElementNotPresent('*[data-id="initgit-btn"]') + }, + 'launch github login via FE #group1 #group2': function (browser: NightwatchBrowser) { + browser + .clickLaunchIcon('filePanel') + .pause(1000) + .waitForElementVisible('*[data-id="filepanel-login-github"]') + .click('*[data-id="filepanel-login-github"]') + }, + 'login to github #group1 #group2': function (browser: NightwatchBrowser) { + browser + .waitForElementVisible('*[data-id="github-panel"]') + .waitForElementVisible('*[data-id="gitubUsername"]') + .setValue('*[data-id="githubToken"]', process.env.dgit_token) + .pause(1000) + .setValue('*[data-id="gitubUsername"]', 'git') + .pause(1000) + .setValue('*[data-id="githubEmail"]', 'git@example.com') + .pause(1000) + .click('*[data-id="saveGitHubCredentials"]') + }, + 'check if the settings are loaded #group1 #group2': function (browser: NightwatchBrowser) { + browser + .waitForElementVisible('*[data-id="connected-as-bunsenstraat"]') + .waitForElementVisible('*[data-id="connected-img-bunsenstraat"]') + .waitForElementVisible('*[data-id="connected-link-bunsenstraat"]') + .waitForElementVisible('*[data-id="remotes-panel"]') + }, + 'check the FE for the auth user #group1 #group2': function (browser: NightwatchBrowser) { + browser + .clickLaunchIcon('filePanel') + .waitForElementVisible('*[data-id="filepanel-connected-img-bunsenstraat"]') + }, + // pagination test + 'clone repo #group3': function (browser: NightwatchBrowser) { + browser + .clickLaunchIcon('dgit') + .waitForElementVisible('*[data-id="clone-panel"]') + .click('*[data-id="clone-panel"]') + .waitForElementVisible('*[data-id="clone-url"]') + .setValue('*[data-id="clone-url"]', 'https://github.com/yann300/remix-reward') + .waitForElementVisible('*[data-id="clone-branch"]') + .setValue('*[data-id="clone-branch"]', 'master') + .waitForElementVisible('*[data-id="clone-btn"]') + .click('*[data-id="clone-btn"]') + .clickLaunchIcon('filePanel') + .pause(5000) + .windowHandles(function (result) { + console.log(result.value) + browser.switchWindow(result.value[2]) + .pause(1000) + .waitForElementVisible('*[data-id="treeViewLitreeViewItem.git"]') + }) + }, + 'Update settings for git #group3': function (browser: NightwatchBrowser) { + browser. + clickLaunchIcon('dgit') + .waitForElementVisible('*[data-id="github-panel"]') + .pause(1000) + .click('*[data-id="github-panel"]') + .pause(1000) + .setValue('*[data-id="githubToken"]', 'invalidtoken') + .pause(1000) + .setValue('*[data-id="gitubUsername"]', 'git') + .pause(1000) + .setValue('*[data-id="githubEmail"]', 'git@example.com') + .pause(1000) + .click('*[data-id="saveGitHubCredentials"]') + .pause(1000) + .modalFooterOKClick('github-credentials-error') + }, + 'check the commits panel for pagination #group3': function (browser: NightwatchBrowser) { + browser + .waitForElementVisible('*[data-id="commits-panel"]') + .click('*[data-id="commits-panel"]') + .elements('xpath', '//*[@data-id="commits-current-branch-master"]//*[@data-type="commit-summary"]', function (result) { + console.log('Number of commit-summary elements:', (result.value as any).length); + if (useIsoGit) { + commitCount = (result.value as any).length + browser.assert.ok((result.value as any).length == 1) + } else { + commitCount = (result.value as any).length + browser.assert.ok((result.value as any).length > 2) + } + }) + + }, + 'load more commits #group3': function (browser: NightwatchBrowser) { + console.log('commitCount:', commitCount) + browser + .waitForElementVisible('*[data-id="load-more-commits"]') + .click('*[data-id="load-more-commits"]') + .waitForElementVisible('*[data-id="loader-indicator"]') + .waitForElementNotPresent('*[data-id="loader-indicator"]') + .pause(2000) + .elements('xpath', '//*[@data-id="commits-current-branch-master"]//*[@data-type="commit-summary"]', function (result) { + console.log('Number of commit-summary elements:', (result.value as any).length); + browser.assert.ok((result.value as any).length > commitCount) + }) + }, + 'load more branches from remote #group3': function (browser: NightwatchBrowser) { + + browser + .click('*[data-id="branches-panel"]') + .waitForElementVisible({ + selector: '//*[@data-id="branches-panel-content-remote-branches"]', + locateStrategy: 'xpath' + }) + .elements('xpath', '//*[@data-id="branches-panel-content-remote-branches"]//*[@data-type="branches-branch"]', function (result) { + console.log('Number of branches elements:', (result.value as any).length); + if (useIsoGit) { + branchCount = (result.value as any).length + browser.assert.ok((result.value as any).length == 1) + } else { + branchCount = (result.value as any).length + browser.assert.ok((result.value as any).length > 2) + } + }) + + + if (useIsoGit) { + + browser.waitForElementVisible('*[data-id="remote-sync-origin"]') + .click('*[data-id="remote-sync-origin"]') + .waitForElementVisible('*[data-id="loader-indicator"]') + .waitForElementNotPresent('*[data-id="loader-indicator"]') + .pause(2000) + .elements('xpath', '//*[@data-id="branches-panel-content-remote-branches"]//*[@data-type="branches-branch"]', function (result) { + console.log('Number of branches elements:', (result.value as any).length); + browser.assert.ok((result.value as any).length > branchCount) + }) + } else { + browser.waitForElementVisible('*[data-id="show-more-branches-on-remote"]') + .click('*[data-id="show-more-branches-on-remote"]') + .pause(1000) + .elements('xpath', '//*[@data-id="branches-panel-content-remote-branches"]//*[@data-type="branches-branch"]', function (result) { + console.log('Number of branches elements:', (result.value as any).length); + browser.assert.ok((result.value as any).length > branchCount) + }) + } + + } +} + +module.exports = tests \ No newline at end of file diff --git a/apps/remixdesktop/test/tests/app/hardhat.test.ts b/apps/remixdesktop/test/tests/app/hardhat.test.ts new file mode 100644 index 0000000000..f8c093102e --- /dev/null +++ b/apps/remixdesktop/test/tests/app/hardhat.test.ts @@ -0,0 +1,90 @@ +import { NightwatchBrowser } from 'nightwatch' +import { ChildProcess, spawn, execSync } from 'child_process' +import { homedir } from 'os' +import path from 'path' +import os from 'os' + +const dir = path.join('remix-desktop-test-' + Date.now().toString()) + +const tests = { + before: function (browser: NightwatchBrowser, done: VoidFunction) { + done() + }, + setuphardhat: function (browser: NightwatchBrowser) { + browser.perform(async (done) => { + await setupHardhatProject() + done() + }) + }, + addScript: function (browser: NightwatchBrowser) { + // run script in console + browser.executeAsync(function (dir, done) { + (window as any).electronAPI.openFolderInSameWindow('/tmp/' + dir).then(done) + }, [dir], () => { + console.log('done window opened') + }) + .waitForElementVisible('*[data-id="treeViewDivDraggableItemhardhat.config.js"]', 10000) + }, + compile: function (browser: NightwatchBrowser) { + browser.perform(async (done) => { + console.log('generating compilation result') + await compileHardhatProject() + done() + }) + .expect.element('*[data-id="terminalJournal"]').text.to.contain('receiving compilation result from Hardhat').before(60000) + let addressRef + browser.clickLaunchIcon('filePanel') + .openFile('contracts') + .openFile('contracts/Token.sol') + .clickLaunchIcon('udapp') + .selectAccount('0xCA35b7d915458EF540aDe6068dFe2F44E8fa733c') + .selectContract('Token') + .createContract('') + .clickInstance(0) + .clickFunction('balanceOf - call', { types: 'address account', values: '0xCA35b7d915458EF540aDe6068dFe2F44E8fa733c' }) + .getAddressAtPosition(0, (address) => { + addressRef = address + }) + .perform((done) => { + browser.verifyCallReturnValue(addressRef, ['0:uint256: 1000000']) + .perform(() => done()) + }) + } +} + +async function compileHardhatProject(): Promise { + console.log(process.cwd()) + try { + const server = spawn('npx hardhat compile', [], { cwd: '/tmp/' + dir, shell: true, detached: true }) + return new Promise((resolve, reject) => { + server.on('exit', function (exitCode) { + console.log("Child exited with code: " + exitCode); + console.log('end') + resolve() + }) + }) + } catch (e) { + console.log(e) + } +} + +async function setupHardhatProject(): Promise { + console.log('setup hardhat project', dir) + try { + const server = spawn(`git clone https://github.com/NomicFoundation/hardhat-boilerplate ${dir} && cd ${dir} && yarn install && yarn add "@typechain/ethers-v5@^10.1.0" && yarn add "@typechain/hardhat@^6.1.2" && yarn add "typechain@^8.1.0" && echo "END"`, [], { cwd: '/tmp/', shell: true, detached: true }) + return new Promise((resolve, reject) => { + server.on('exit', function (exitCode) { + console.log("Child exited with code: " + exitCode); + console.log('end') + resolve() + }) + }) + } catch (e) { + console.log(e) + } +} + + +module.exports = { + ...tests +} \ No newline at end of file diff --git a/apps/remixdesktop/test/tests/app/offline.test.ts b/apps/remixdesktop/test/tests/app/offline.test.ts new file mode 100644 index 0000000000..284d44991a --- /dev/null +++ b/apps/remixdesktop/test/tests/app/offline.test.ts @@ -0,0 +1,48 @@ +import { NightwatchBrowser } from 'nightwatch' + + +module.exports = { + '@offline': true, + before: function (browser: NightwatchBrowser, done: VoidFunction) { + done() + }, + 'open default template': function (browser: NightwatchBrowser) { + browser + .waitForElementVisible('*[data-id="remixIdeIconPanel"]', 10000) + .waitForElementVisible('button[data-id="landingPageImportFromTemplate"]') + .click('button[data-id="landingPageImportFromTemplate"]') + .waitForElementPresent('*[data-id="create-remixDefault"]') + .scrollAndClick('*[data-id="create-remixDefault"]') + .waitForElementVisible('*[data-id="modalDialogCustomPromptTextCreate"]') + .waitForElementPresent('[data-id="TemplatesSelectionModalDialogContainer-react"] .modal-ok') + .click('[data-id="TemplatesSelectionModalDialogContainer-react"] .modal-ok') + .pause(3000) + .windowHandles(function (result) { + console.log(result.value) + browser.switchWindow(result.value[1]) + .waitForElementVisible('*[data-id="treeViewLitreeViewItemtests"]') + .click('*[data-id="treeViewLitreeViewItemtests"]') + .waitForElementVisible('*[data-id="treeViewLitreeViewItemcontracts"]') + .click('*[data-id="treeViewLitreeViewItemcontracts"]') + .waitForElementVisible('[data-id="treeViewLitreeViewItemcontracts/1_Storage.sol"]') + .openFile('contracts/1_Storage.sol') + .waitForElementVisible('*[id="editorView"]', 10000) + .getEditorValue((content) => { + browser.assert.ok(content.includes('function retrieve() public view returns (uint256){')) + }) + }) + }, + 'compile storage': function (browser: NightwatchBrowser) { + browser + .clickLaunchIcon('solidity') + .pause(1000) + .waitForElementVisible('*[data-id="compilerContainerCompileBtn"]') + .click('[data-id="compilerContainerCompileBtn"]') + .clickLaunchIcon('filePanel') + .clickLaunchIcon('solidity') + .pause(5000) + .waitForElementPresent('*[data-id="compiledContracts"] option', 60000) + .click('*[data-id="compilation-details"]') + .waitForElementVisible('*[data-id="remixui_treeviewitem_metadata"]') + } +} \ No newline at end of file diff --git a/apps/remixdesktop/test/tests/app/search.test.ts b/apps/remixdesktop/test/tests/app/search.test.ts new file mode 100644 index 0000000000..30f1593bdc --- /dev/null +++ b/apps/remixdesktop/test/tests/app/search.test.ts @@ -0,0 +1,269 @@ +import { NightwatchBrowser } from 'nightwatch' + + +module.exports = { + before: function (browser: NightwatchBrowser, done: VoidFunction) { + done() + }, + 'open default template': function (browser: NightwatchBrowser) { + browser + .waitForElementVisible('*[data-id="remixIdeIconPanel"]', 10000) + .waitForElementVisible('button[data-id="landingPageImportFromTemplate"]') + .click('button[data-id="landingPageImportFromTemplate"]') + .waitForElementPresent('*[data-id="create-remixDefault"]') + .scrollAndClick('*[data-id="create-remixDefault"]') + .waitForElementVisible('*[data-id="modalDialogCustomPromptTextCreate"]') + .waitForElementPresent('[data-id="TemplatesSelectionModalDialogContainer-react"] .modal-ok') + .click('[data-id="TemplatesSelectionModalDialogContainer-react"] .modal-ok') + .pause(3000) + .windowHandles(function (result) { + console.log(result.value) + browser.switchWindow(result.value[1]) + .waitForElementVisible('*[data-id="treeViewLitreeViewItemtests"]') + .click('*[data-id="treeViewLitreeViewItemtests"]') + .waitForElementVisible('*[data-id="treeViewLitreeViewItemcontracts"]') + .click('*[data-id="treeViewLitreeViewItemcontracts"]') + .waitForElementVisible('[data-id="treeViewLitreeViewItemcontracts/1_Storage.sol"]') + .openFile('contracts/1_Storage.sol') + .waitForElementVisible('*[id="editorView"]', 10000) + .getEditorValue((content) => { + browser.assert.ok(content.includes('function retrieve() public view returns (uint256){')) + }) + }) + }, + 'Should find text #group1': function (browser: NightwatchBrowser) { + browser.waitForElementVisible('*[data-id="remixIdeSidePanel"]') + .click('*[plugin="search"]').waitForElementVisible('*[id="search_input"]') + .waitForElementVisible('*[id="search_include"]') + .setValue('*[id="search_include"]', ', *.*').pause(2000) + .setValue('*[id="search_input"]', 'read').sendKeys('*[id="search_input"]', browser.Keys.ENTER) + .pause(1000) + .waitForElementContainsText('*[data-id="search_results"]', '3_BALLOT.SOL', 60000) + .waitForElementContainsText('*[data-id="search_results"]', 'contracts', 60000) + .waitForElementContainsText('*[data-id="search_results"]', 'README.TXT', 60000) + .waitForElementContainsText('*[data-id="search_results"]', 'file must') + .waitForElementContainsText('*[data-id="search_results"]', 'be compiled') + .waitForElementContainsText('*[data-id="search_results"]', 'that person al') + .waitForElementContainsText('*[data-id="search_results"]', 'sender.voted') + .waitForElementContainsText('*[data-id="search_results"]', 'read') + .elements('css selector', '.search_plugin_search_line', (res) => { + Array.isArray(res.value) && browser.assert.equal(res.value.length, 6) + }) + }, 'Should find text with exclude #group1': function (browser: NightwatchBrowser) { + browser + .clearValue('*[id="search_input"]') + .setValue('*[id="search_input"]', 'contract').pause(1000) + .clearValue('*[id="search_include"]').pause(2000) + .setValue('*[id="search_include"]', '**').sendKeys('*[id="search_include"]', browser.Keys.ENTER).pause(4000) + .elements('css selector', '.search_plugin_search_line', (res) => { + Array.isArray(res.value) && browser.assert.equal(res.value.length, 62) + }) + .setValue('*[id="search_exclude"]', ',contracts/**').sendKeys('*[id="search_exclude"]', browser.Keys.ENTER).pause(4000) + .elements('css selector', '.search_plugin_search_line', (res) => { + Array.isArray(res.value) && browser.assert.equal(res.value.length, 56) + }) + .clearValue('*[id="search_include"]').setValue('*[id="search_include"]', '*.sol, *.js, *.txt') + .clearValue('*[id="search_exclude"]').setValue('*[id="search_exclude"]', '.*/**/*') + }, + 'Should find regex #group1': function (browser: NightwatchBrowser) { + browser + .waitForElementVisible('*[id="search_input"]') + .clearValue('*[id="search_input"]').pause(2000) + .setValue('*[id="search_input"]', '^contract').sendKeys('*[id="search_input"]', browser.Keys.ENTER).pause(3000) + .waitForElementVisible('*[data-id="search_use_regex"]').click('*[data-id="search_use_regex"]').pause(3000) + .waitForElementContainsText('*[data-id="search_results"]', '3_BALLOT.SOL', 60000) + .waitForElementContainsText('*[data-id="search_results"]', '2_OWNER.SOL', 60000) + .waitForElementContainsText('*[data-id="search_results"]', '1_STORAGE.SOL', 60000) + .waitForElementContainsText('*[data-id="search_results"]', 'BALLOT_TEST.SOL', 60000) + .waitForElementContainsText('*[data-id="search_results"]', 'tests', 60000) + .elements('css selector', '.search_plugin_search_line', (res) => { + Array.isArray(res.value) && browser.assert.equal(res.value.length, 4) + }) + }, + 'Should find matchcase #group1': function (browser: NightwatchBrowser) { + browser + .waitForElementVisible('*[data-id="search_use_regex"]').click('*[data-id="search_use_regex"]') + .waitForElementVisible('*[data-id="search_case_sensitive"]').click('*[data-id="search_case_sensitive"]').pause(4000) + .elements('css selector', '.search_plugin_search_line', (res) => { + Array.isArray(res.value) && browser.assert.equal(res.value.length, 0) + }) + .clearValue('*[id="search_input"]') + .setValue('*[id="search_input"]', 'Contract').sendKeys('*[id="search_input"]', browser.Keys.ENTER).pause(3000) + .elements('css selector', '.search_plugin_search_line', (res) => { + Array.isArray(res.value) && browser.assert.equal(res.value.length, 3) + }) + .waitForElementContainsText('*[data-id="search_results"]', 'STORAGE.TEST.JS', 60000) + }, + 'Should find matchword #group1': function (browser: NightwatchBrowser) { + browser + .waitForElementVisible('*[data-id="search_case_sensitive"]').click('*[data-id="search_case_sensitive"]') + .waitForElementVisible('*[data-id="search_whole_word"]').click('*[data-id="search_whole_word"]').pause(2000) + .clearValue('*[id="search_input"]') + .setValue('*[id="search_input"]', 'contract').sendKeys('*[id="search_input"]', browser.Keys.ENTER).pause(4000) + .elements('css selector', '.search_plugin_search_line', (res) => { + Array.isArray(res.value) && browser.assert.equal(res.value.length, 15) + }) + }, + 'Should replace text #group1': function (browser: NightwatchBrowser) { + browser + .waitForElementVisible('*[data-id="toggle_replace"]').click('*[data-id="toggle_replace"]') + .waitForElementVisible('*[id="search_replace"]') + .clearValue('*[id="search_include"]').setValue('*[id="search_include"]', 'contracts/2_*.sol') + .setValue('*[id="search_replace"]', 'replacing').sendKeys('*[id="search_include"]', browser.Keys.ENTER).pause(1000) + .waitForElementVisible('*[data-id="contracts/2_Owner.sol-33-71"]') + .moveToElement('*[data-id="contracts/2_Owner.sol-33-71"]', 10, 10) + .waitForElementVisible('*[data-id="replace-contracts/2_Owner.sol-33-71"]') + .click('*[data-id="replace-contracts/2_Owner.sol-33-71"]').pause(2000). + modalFooterOKClick('confirmreplace').pause(2000). + getEditorValue((content) => { + browser.assert.ok(content.includes('replacing deployer for a constructor'), 'should replace text ok') + }) + }, + 'Should replace text without confirmation #group1': function (browser: NightwatchBrowser) { + browser.click('*[data-id="confirm_replace_label"]').pause(500) + .clearValue('*[id="search_input"]') + .setValue('*[id="search_input"]', 'replacing').sendKeys('*[id="search_input"]', browser.Keys.ENTER).pause(1000) + .setValue('*[id="search_replace"]', 'replacing2').pause(1000) + .waitForElementVisible('*[data-id="contracts/2_Owner.sol-33-71"]') + .moveToElement('*[data-id="contracts/2_Owner.sol-33-71"]', 10, 10) + .waitForElementVisible('*[data-id="replace-contracts/2_Owner.sol-33-71"]') + .click('*[data-id="replace-contracts/2_Owner.sol-33-71"]').pause(2000). + getEditorValue((content) => { + browser.assert.ok(content.includes('replacing2 deployer for a constructor'), 'should replace text ok') + }) + }, + 'Should replace all & undo #group1': function (browser: NightwatchBrowser) { + browser + .clearValue('*[id="search_input"]') + .clearValue('*[id="search_include"]').setValue('*[id="search_include"]', 'contracts/1_*.sol') + .setValue('*[id="search_input"]', 'storage').sendKeys('*[id="search_include"]', browser.Keys.ENTER) + .clearValue('*[id="search_replace"]') + .setValue('*[id="search_replace"]', '123test').pause(1000) + .waitForElementVisible('*[data-id="replace-all-contracts/1_Storage.sol"]') + .click('*[data-id="replace-all-contracts/1_Storage.sol"]').pause(2000) + .getEditorValue((content) => { + browser.assert.ok(content.includes('contract 123test'), 'should replace text ok') + browser.assert.ok(content.includes('title 123test'), 'should replace text ok') + }) + .waitForElementVisible('*[data-id="undo-replace-contracts/1_Storage.sol"]') + .click('*[data-id="undo-replace-contracts/1_Storage.sol"]').pause(2000) + .getEditorValue((content) => { + browser.assert.ok(content.includes('contract Storage'), 'should undo text ok') + browser.assert.ok(content.includes('title Storage'), 'should undo text ok') + }) + }, + 'Should replace all & undo & switch between files #group1': function (browser: NightwatchBrowser) { + browser.waitForElementVisible('*[id="search_input"]') + .clearValue('*[id="search_input"]') + .clearValue('*[id="search_include"]').setValue('*[id="search_include"]', '*.sol, *.js, *.txt') + .setValue('*[id="search_input"]', 'storage').sendKeys('*[id="search_include"]', browser.Keys.ENTER) + .clearValue('*[id="search_replace"]') + .setValue('*[id="search_replace"]', '123test').pause(1000) + .waitForElementVisible('*[data-id="replace-all-contracts/1_Storage.sol"]') + .click('*[data-id="replace-all-contracts/1_Storage.sol"]').pause(2000) + .getEditorValue((content) => { + browser.assert.ok(content.includes('contract 123test'), 'should replace text ok') + browser.assert.ok(content.includes('title 123test'), 'should replace text ok') + }) + .waitForElementVisible('*[data-id="undo-replace-contracts/1_Storage.sol"]') + .openFile('README.txt') + .click('*[plugin="search"]').pause(2000) + .waitForElementNotPresent('*[data-id="undo-replace-contracts/1_Storage.sol"]') + .waitForElementVisible('*[data-id="replace-all-README.txt"]') + .click('*[data-id="replace-all-README.txt"]').pause(2000) + .getEditorValue((content) => { + browser.assert.ok(content.includes("123test' contract"), 'should replace text ok') + }) + .waitForElementVisible('*[data-id="undo-replace-README.txt"]') + .click('div[data-path="/contracts/1_Storage.sol"]').pause(2000) + .waitForElementVisible('*[data-id="undo-replace-contracts/1_Storage.sol"]') + .click('*[data-id="undo-replace-contracts/1_Storage.sol"]').pause(2000) + .getEditorValue((content) => { + browser.assert.ok(content.includes('contract Storage'), 'should undo text ok') + browser.assert.ok(content.includes('title Storage'), 'should undo text ok') + }) + .click('div[data-path="/README.txt"]').pause(2000) + .waitForElementVisible('*[data-id="undo-replace-README.txt"]') + .click('*[data-id="undo-replace-README.txt"]').pause(2000) + .getEditorValue((content) => { + browser.assert.ok(content.includes("Storage' contract"), 'should replace text ok') + }) + }, + 'Should hide button when edited content is the same #group2': function (browser: NightwatchBrowser) { + browser.refresh() + .waitForElementVisible('*[data-id="remixIdeSidePanel"]') + .addFile('test.sol', { content: '123' }) + .pause(4000) + .click('*[plugin="search"]') + .waitForElementVisible('*[id="search_input"]') + .waitForElementVisible('*[data-id="toggle_replace"]') + .click('*[data-id="toggle_replace"]') + .clearValue('*[id="search_input"]') + .setValue('*[id="search_input"]', '123') + .sendKeys('*[id="search_input"]', browser.Keys.ENTER) + .waitForElementVisible('*[id="search_replace"]') + .clearValue('*[id="search_replace"]') + .setValue('*[id="search_replace"]', '456').pause(1000) + .click('*[data-id="confirm_replace_label"]').pause(500) + .waitForElementVisible('*[data-id="replace-all-test.sol"]') + .click('*[data-id="replace-all-test.sol"]').pause(2000) + .getEditorValue((content) => { + browser.assert.ok(content.includes('456'), 'should replace text ok') + } + ) + .setEditorValue('123') + .getEditorValue((content) => { + browser.assert.ok(content.includes('123'), 'should have text ok') + } + ).pause(5000) + .waitForElementNotPresent('*[data-id="undo-replace-test.sol"]') + }, + 'Should disable/enable button when edited content changed #group2': function (browser: NightwatchBrowser) { + browser + .waitForElementVisible('*[id="search_input"]') + .clearValue('*[id="search_input"]') + .clearValue('*[id="search_input"]') + .setValue('*[id="search_input"]', '123').sendKeys('*[id="search_input"]', browser.Keys.ENTER) + .clearValue('*[id="search_replace"]') + .setValue('*[id="search_replace"]', 'replaced').pause(1000) + .waitForElementVisible('*[data-id="replace-all-test.sol"]') + .click('*[data-id="replace-all-test.sol"]').pause(2000) + .getEditorValue((content) => { + browser.assert.ok(content.includes('replaced'), 'should replace text ok') + } + ) + .setEditorValue('changed') + .getEditorValue((content) => { + browser.assert.ok(content.includes('changed'), 'should have text ok') + } + ).pause(5000) + .waitForElementVisible('*[data-id="undo-replace-test.sol"]') + .getAttribute('[data-id="undo-replace-test.sol"]', 'disabled', (result) => { + browser.assert.equal(result.value, 'true', 'should be disabled') + }) + .setEditorValue('replaced') + .getEditorValue((content) => { + browser.assert.ok(content.includes('replaced'), 'should have text ok') + } + ).pause(1000) + .waitForElementVisible('*[data-id="undo-replace-test.sol"]') + .getAttribute('[data-id="undo-replace-test.sol"]', 'disabled', (result) => { + browser.assert.equal(result.value, null, 'should not be disabled') + }) + .click('*[data-id="undo-replace-test.sol"]').pause(2000) + .getEditorValue((content) => { + browser.assert.ok(content.includes('123'), 'should have text ok') + }) + .waitForElementNotPresent('*[data-id="undo-replace-test.sol"]') + }, + + 'should clear search #group2': function (browser: NightwatchBrowser) { + browser + .waitForElementVisible('*[id="search_input"]') + .setValue('*[id="search_input"]', 'nodata').sendKeys('*[id="search_input"]', browser.Keys.ENTER).pause(1000) + .elements('css selector', '.search_plugin_search_line', (res) => { + Array.isArray(res.value) && browser.assert.equal(res.value.length, 0) + }) + } + +} \ No newline at end of file diff --git a/apps/remixdesktop/test/tests/app/slitherlinux.test.ts b/apps/remixdesktop/test/tests/app/slitherlinux.test.ts new file mode 100644 index 0000000000..21b3f38ea5 --- /dev/null +++ b/apps/remixdesktop/test/tests/app/slitherlinux.test.ts @@ -0,0 +1,107 @@ +import {NightwatchBrowser} from 'nightwatch' +import { ChildProcess, spawn, execSync } from 'child_process' +import { homedir } from 'os' +const tests = { + before: function (browser: NightwatchBrowser, done: VoidFunction) { + done() + }, + open: function (browser: NightwatchBrowser) { + browser.waitForElementVisible('*[data-id="openFolderButton"]', 10000).click('*[data-id="openFolderButton"]') + }, + + 'open default template': function (browser: NightwatchBrowser) { + browser + .waitForElementVisible('*[data-id="remixIdeIconPanel"]', 10000) + .waitForElementVisible('button[data-id="landingPageImportFromTemplate"]') + .click('button[data-id="landingPageImportFromTemplate"]') + .waitForElementPresent('*[data-id="create-remixDefault"]') + .scrollAndClick('*[data-id="create-remixDefault"]') + .waitForElementVisible('*[data-id="modalDialogCustomPromptTextCreate"]') + .waitForElementPresent('[data-id="TemplatesSelectionModalDialogContainer-react"] .modal-ok') + .click('[data-id="TemplatesSelectionModalDialogContainer-react"] .modal-ok') + .pause(3000) + .windowHandles(function (result) { + console.log(result.value) + browser.switchWindow(result.value[1]) + .waitForElementVisible('*[data-id="treeViewLitreeViewItemtests"]') + .click('*[data-id="treeViewLitreeViewItemtests"]') + .waitForElementVisible('*[data-id="treeViewLitreeViewItemcontracts"]') + .click('*[data-id="treeViewLitreeViewItemcontracts"]') + .waitForElementVisible('[data-id="treeViewLitreeViewItemcontracts/1_Storage.sol"]') + .openFile('contracts/1_Storage.sol') + .waitForElementVisible('*[id="editorView"]', 10000) + .getEditorValue((content) => { + browser.assert.ok(content.includes('function retrieve() public view returns (uint256){')) + }) + }) + }, + 'Should install slither #group6': function (browser: NightwatchBrowser) { + browser.perform(async (done) => { + await installSlither() + done() + }) + }, + 'run slither': function (browser: NightwatchBrowser) { + browser + .click('[data-id="verticalIconsKindpluginManager"]') + .scrollAndClick('[data-id="pluginManagerComponentActivateButtonsolidityStaticAnalysis"]') + .clickLaunchIcon('solidity').click('*[data-id="compilerContainerCompileBtn"]') + .pause(1000) + .clickLaunchIcon('solidityStaticAnalysis') + .useXpath() + .click('//*[@id="staticAnalysisRunBtn"]') + .waitForElementPresent('//*[@id="staticanalysisresult"]', 5000) + .waitForElementVisible({ + selector: "//*[@data-id='nolibslitherwarnings'][contains(text(), '1')]", + locateStrategy: 'xpath', + timeout: 5000 + }) + .waitForElementVisible({ + selector: "//div[@data-id='block']/span[contains(text(), '1 warnings found.')]", + locateStrategy: 'xpath', + timeout: 5000 + }) + }, + + after: function (browser: NightwatchBrowser) { + browser.end() + }, +} + +async function installSlither(): Promise { + console.log('installSlither', process.cwd()) + try { + try { + const solcVersion = '0.8.15' + console.log('\x1b[32m%s\x1b[0m', `[Slither Installation]: requires Python3.6+ (pip3) to be installed on your system`) + console.log('\x1b[32m%s\x1b[0m', `[Slither Installation]: solc-select will be installed along with Slither to set different solc compiler versions.`) + console.log('\x1b[32m%s\x1b[0m', `[Slither Installation]: checking pip3 availability ...`) + const pip3OP = execSync('pip3 --version') + console.log('\x1b[32m%s\x1b[0m', `[Slither Installation]: pip3 found: ${pip3OP.toString()}`) + console.log('\x1b[32m%s\x1b[0m', `[Slither Installation]: installing slither...`) + const slitherOP = execSync('pip3 install slither-analyzer') + console.log('\x1b[32m%s\x1b[0m', `[Slither Installation]: slither installation output: ${slitherOP.toString()}`) + console.log('\x1b[32m%s\x1b[0m', `[Slither Installation]: installing solc-select...`) + const solcSelectOP = execSync('pip3 install solc-select') + console.log('\x1b[32m%s\x1b[0m', `[Slither Installation]: solc-select installation output: ${solcSelectOP.toString()}`) + console.log('\x1b[32m%s\x1b[0m', `[Slither Installation]: installing solc ${solcVersion}...`) + const solcInstallOP = execSync(`solc-select install ${solcVersion}`) + console.log('\x1b[32m%s\x1b[0m', `[Slither Installation]: solc installation output: ${solcInstallOP.toString()}`) + console.log('\x1b[32m%s\x1b[0m', `[Slither Installation]: setting solc version to ${solcVersion}...`) + const solcUseOP = execSync(`solc-select use ${solcVersion}`) + console.log('\x1b[32m%s\x1b[0m', `[Slither Installation]: solc setting installation output: ${solcUseOP.toString()}`) + console.log('\x1b[32m%s\x1b[0m', `[Slither Installation]: Slither is ready to use!`) + } catch (err) { + console.log('\x1b[31m%s\x1b[0m', `[Slither Installation]: Error occurred: ${err}`) + } + } catch (e) { + console.log(e) + } + } + + + + +module.exports = { + ...process.platform.startsWith('linux')?tests:{} +} \ No newline at end of file diff --git a/apps/remixdesktop/test/tests/app/templates.test.ts b/apps/remixdesktop/test/tests/app/templates.test.ts new file mode 100644 index 0000000000..86528458e9 --- /dev/null +++ b/apps/remixdesktop/test/tests/app/templates.test.ts @@ -0,0 +1,35 @@ +import { NightwatchBrowser } from 'nightwatch' + + +module.exports = { + before: function (browser: NightwatchBrowser, done: VoidFunction) { + done() + }, + 'open default template': function (browser: NightwatchBrowser) { + browser + .waitForElementVisible('*[data-id="remixIdeIconPanel"]', 10000) + .waitForElementVisible('button[data-id="landingPageImportFromTemplate"]') + .click('button[data-id="landingPageImportFromTemplate"]') + .waitForElementPresent('*[data-id="create-remixDefault"]') + .scrollAndClick('*[data-id="create-remixDefault"]') + .waitForElementVisible('*[data-id="modalDialogCustomPromptTextCreate"]') + .waitForElementPresent('[data-id="TemplatesSelectionModalDialogContainer-react"] .modal-ok') + .click('[data-id="TemplatesSelectionModalDialogContainer-react"] .modal-ok') + .pause(3000) + .windowHandles(function (result) { + console.log(result.value) + browser.switchWindow(result.value[1]) + .waitForElementVisible('*[data-id="treeViewLitreeViewItemtests"]') + .click('*[data-id="treeViewLitreeViewItemtests"]') + .waitForElementVisible('*[data-id="treeViewLitreeViewItemcontracts"]') + .click('*[data-id="treeViewLitreeViewItemcontracts"]') + .waitForElementVisible('[data-id="treeViewLitreeViewItemcontracts/1_Storage.sol"]') + .openFile('contracts/1_Storage.sol') + .waitForElementVisible('*[id="editorView"]', 10000) + .getEditorValue((content) => { + browser.assert.ok(content.includes('function retrieve() public view returns (uint256){')) + }) + }) + .end() + } +} \ No newline at end of file diff --git a/apps/remixdesktop/test/tests/app/xterm.test.ts b/apps/remixdesktop/test/tests/app/xterm.test.ts new file mode 100644 index 0000000000..df238fbcc9 --- /dev/null +++ b/apps/remixdesktop/test/tests/app/xterm.test.ts @@ -0,0 +1,246 @@ +import {NightwatchBrowser} from 'nightwatch' + + + + +const tests = { + before: function (browser: NightwatchBrowser, done: VoidFunction) { + done() + }, + open: function (browser: NightwatchBrowser) { + browser.waitForElementVisible('*[data-id="openFolderButton"]', 10000).click('*[data-id="openFolderButton"]') + }, + 'open xterm linux and create a file': function (browser: NightwatchBrowser) { + browser + .waitForElementVisible('*[data-id="tabXTerm"]', 10000) + .click('*[data-id="tabXTerm"]') + .waitForElementVisible('*[data-type="remixUIXT"]', 10000) + .click('*[data-type="remixUIXT"]') + .perform(function () { + const actions = this.actions({async: true}) + return actions.sendKeys('echo test > example.txt').sendKeys(this.Keys.ENTER) + }) + .waitForElementVisible('*[data-id="treeViewLitreeViewItemexample.txt"]', 10000) + }, + 'rename that file': function (browser: NightwatchBrowser) { + browser + .perform(function () { + const actions = this.actions({async: true}) + return actions.sendKeys('mv example.txt newExample.txt').sendKeys(this.Keys.ENTER) + }) + .waitForElementVisible('*[data-id="treeViewLitreeViewItemnewExample.txt"]', 10000) + }, + 'create a file and delete it': function (browser: NightwatchBrowser) { + browser + .perform(function () { + const actions = this.actions({async: true}) + return actions.sendKeys('touch newExample2.txt').sendKeys(this.Keys.ENTER) + }) + .waitForElementVisible('*[data-id="treeViewLitreeViewItemnewExample2.txt"]', 10000) + .perform(function () { + const actions = this.actions({async: true}) + return actions.sendKeys('rm newExample2.txt').sendKeys(this.Keys.ENTER) + }) + .waitForElementNotPresent('*[data-id="treeViewLitreeViewItemnewExample2.txt"]', 10000) + }, + 'run a git clone command': function (browser: NightwatchBrowser) { + browser + .perform(function () { + const actions = this.actions({async: true}) + return actions.sendKeys('git clone https://github.com/ethereum/awesome-remix').sendKeys(this.Keys.ENTER) + }) + .waitForElementVisible('*[data-id="treeViewLitreeViewItemawesome-remix"]', 10000) + .click('*[data-id="treeViewLitreeViewItemawesome-remix"]') + .waitForElementVisible('*[data-id="treeViewLitreeViewItemawesome-remix/README.md"]', 10000) + }, + 'remove the cloned repo': function (browser: NightwatchBrowser) { + browser + .waitForElementVisible('*[data-type="remixUIXT"]', 10000) + .click('*[data-type="remixUIXT"]') + .perform(function () { + const actions = this.actions({async: true}) + return actions.sendKeys('rm -rf awesome-remix').sendKeys(this.Keys.ENTER) + }) + .waitForElementNotPresent('*[data-id="treeViewLitreeViewItemawesome-remix"]', 10000) + }, + 'list files': function (browser: NightwatchBrowser) { + browser + .pause(2000) + .waitForElementVisible({ + selector: "//*[@data-type='remixUIXT' and @data-active='1']", + timeout: 10000, + locateStrategy: 'xpath', + }) + .click({ + selector: "//*[@data-type='remixUIXT' and @data-active='1']", + timeout: 10000, + locateStrategy: 'xpath', + }) + .perform(function () { + const actions = this.actions({async: true}) + return actions.sendKeys('ls').sendKeys(this.Keys.ENTER) + }).pause(3000) + .getText( + { + selector: "//*[@data-type='remixUIXT' and @data-active='1']", + timeout: 10000, + locateStrategy: 'xpath', + }, + function (result) { + console.log('Text content of the element:', result.value) + browser.assert.ok((result.value as string).includes('newExample.txt')) + } + ) + }, + 'switch to a new terminal': function (browser: NightwatchBrowser) { + browser + .waitForElementVisible('*[data-id="createTerminalButton"]', 10000) + .click('*[data-id="createTerminalButton"]') + .elements('css selector', '[data-type="remixUIXTSideButton"]', function (result) { + browser.assert.ok((result.value as any).length === 2) + }) + .getText( + { + selector: "//*[@data-type='remixUIXT' and @data-active='1']", + timeout: 10000, + locateStrategy: 'xpath', + }, + function (result) { + console.log('Text content of the element:', result.value) + browser.assert.ok(!(result.value as string).includes('newExample.txt')) + } + ) + }, + 'switch to a third terminal': function (browser: NightwatchBrowser) { + browser + .waitForElementVisible('*[data-id="createTerminalButton"]', 10000) + .click('*[data-id="createTerminalButton"]') + .waitForElementVisible( + { + selector: "//*[@data-type='remixUIXT' and @data-active='1']", + timeout: 10000, + locateStrategy: 'xpath', + }, + 10000 + ) + .click({ + selector: "//*[@data-type='remixUIXT' and @data-active='1']", + timeout: 10000, + locateStrategy: 'xpath', + }) + .elements('css selector', '[data-type="remixUIXTSideButton"]', function (result) { + browser.assert.ok((result.value as any).length === 3) + }) + .perform(function () { + const actions = this.actions({async: true}) + return actions.sendKeys('echo thirdterminal').sendKeys(this.Keys.ENTER) + }) + }, + 'switch back to the second terminal': function (browser: NightwatchBrowser) { + browser + .elements('css selector', '[data-type="remixUIXTSideButton"]', function (result) { + browser.elementIdClick(Object.values((result.value as any)[1])[0] as any) + }) + .getText( + { + selector: "//*[@data-type='remixUIXT' and @data-active='1']", + timeout: 10000, + locateStrategy: 'xpath', + }, + function (result) { + console.log('Text content of the element:', result.value) + browser.assert.ok(!(result.value as string).includes('newExample.txt')) + } + ) + }, + 'close the second terminal': function (browser: NightwatchBrowser) { + browser + .waitForElementVisible('*[data-id="closeTerminalButton"]', 10000) + .click('*[data-id="closeTerminalButton"]') + .elements('css selector', '[data-type="remixUIXTSideButton"]', function (result) { + browser.assert.ok((result.value as any).length === 2) + }) + }, + 'switch back to the first terminal': function (browser: NightwatchBrowser) { + browser + .elements('css selector', '[data-type="remixUIXTSideButton"]', function (result) { + browser.elementIdClick(Object.values((result.value as any)[0])[0] as any) + }) + .getText( + { + selector: "//*[@data-type='remixUIXT' and @data-active='1']", + timeout: 10000, + locateStrategy: 'xpath', + }, + function (result) { + console.log('Text content of the element:', result.value) + browser.assert.ok((result.value as string).includes('newExample.txt')) + } + ) + }, + 'switch to the output panel': function (browser: NightwatchBrowser) { + browser.waitForElementVisible('*[data-id="tabOutput"]', 10000).click('*[data-id="tabOutput"]').waitForElementNotPresent('*[data-id="createTerminalButton"]', 10000) + }, + 'switch back to xterminal': function (browser: NightwatchBrowser) { + browser + .waitForElementVisible('*[data-id="tabXTerm"]', 10000) + .click('*[data-id="tabXTerm"]') + .waitForElementVisible('*[data-type="remixUIXT"]', 10000) + .click('*[data-type="remixUIXT"]') + .getText( + { + selector: "//*[@data-type='remixUIXT' and @data-active='1']", + timeout: 10000, + locateStrategy: 'xpath', + }, + function (result) { + console.log('Text content of the element:', result.value) + browser.assert.ok((result.value as string).includes('newExample.txt')) + } + ) + }, + 'clear the terminal and type exit': function (browser: NightwatchBrowser) { + browser + .pause(1000) + .waitForElementVisible('*[data-id="clearTerminalButton"]', 10000) + .click('*[data-id="clearTerminalButton"]') + .getText( + { + selector: "//*[@data-type='remixUIXT' and @data-active='1']", + timeout: 10000, + locateStrategy: 'xpath', + }, + function (result) { + console.log('Text content of the element:', result.value) + browser.assert.ok(!(result.value as string).includes('newExample.txt')) + .waitForElementVisible( + { + selector: "//*[@data-type='remixUIXT' and @data-active='1']", + timeout: 10000, + locateStrategy: 'xpath', + }, + 10000 + ) + .click({ + selector: "//*[@data-type='remixUIXT' and @data-active='1']", + timeout: 10000, + locateStrategy: 'xpath', + }) + .pause(1000) + .perform(function () { + const actions = this.actions({async: true}) + return actions.sendKeys('exit').sendKeys(this.Keys.ENTER) + }) + .pause(1000) + .elements('css selector', '[data-type="remixUIXTSideButton"]', function (result) { + browser.assert.ok((result.value as any).length === 1) + }).end() + } + ).pause(3000) + }, +} + + +module.exports = { + ...process.platform.startsWith('win')?{}:tests +} \ No newline at end of file diff --git a/apps/remixdesktop/test/tests/app/xtermwin.test.ts b/apps/remixdesktop/test/tests/app/xtermwin.test.ts new file mode 100644 index 0000000000..cf7b1e5be4 --- /dev/null +++ b/apps/remixdesktop/test/tests/app/xtermwin.test.ts @@ -0,0 +1,249 @@ +import {NightwatchBrowser} from 'nightwatch' + +const tests = { + before: function (browser: NightwatchBrowser, done: VoidFunction) { + done() + }, + open: function (browser: NightwatchBrowser) { + browser.waitForElementVisible('*[data-id="openFolderButton"]', 10000).click('*[data-id="openFolderButton"]') + }, + 'open xterm window and create a file': function (browser: NightwatchBrowser) { + browser + .waitForElementVisible('*[data-id="tabXTerm"]', 10000) + .click('*[data-id="tabXTerm"]') + .waitForElementVisible('*[data-id="select_shell"]') + .click('*[data-id="select_shell"]') + .waitForElementVisible('*[data-id="select_powershell.exe"]') + .click('*[data-id="select_powershell.exe"]') + .pause(3000) + .waitForElementVisible("[data-active='1'][data-type='remixUIXT']", 10000) + .click("[data-active='1'][data-type='remixUIXT']") + .pause(1000) + .perform(function () { + const actions = this.actions({async: true}) + return actions.sendKeys('"test" | Out-File -FilePath example.txt').sendKeys(this.Keys.ENTER) + }) + .waitForElementVisible('*[data-id="treeViewLitreeViewItemexample.txt"]', 10000) + }, + 'rename that file': function (browser: NightwatchBrowser) { + browser + .perform(function () { + const actions = this.actions({async: true}) + return actions.sendKeys('Move-Item -Path example.txt -Destination newExample.txt').sendKeys(this.Keys.ENTER) + }) + .waitForElementVisible('*[data-id="treeViewLitreeViewItemnewExample.txt"]', 10000) + }, + 'create a file and delete it': function (browser: NightwatchBrowser) { + browser + .perform(function () { + const actions = this.actions({async: true}) + return actions.sendKeys('touch newExample2.txt').sendKeys(this.Keys.ENTER) + }) + .waitForElementVisible('*[data-id="treeViewLitreeViewItemnewExample2.txt"]', 10000) + .perform(function () { + const actions = this.actions({async: true}) + return actions.sendKeys('Remove-Item -Path newExample2.txt').sendKeys(this.Keys.ENTER) + }) + .waitForElementNotPresent('*[data-id="treeViewLitreeViewItemnewExample2.txt"]', 10000) + }, + 'run a git clone command': function (browser: NightwatchBrowser) { + browser + .perform(function () { + const actions = this.actions({async: true}) + return actions.sendKeys('git clone https://github.com/ethereum/awesome-remix').sendKeys(this.Keys.ENTER) + }) + .waitForElementVisible('*[data-id="treeViewLitreeViewItemawesome-remix"]', 10000) + .click('*[data-id="treeViewLitreeViewItemawesome-remix"]') + .waitForElementVisible('*[data-id="treeViewLitreeViewItemawesome-remix/README.md"]', 10000) + }, + 'remove the cloned repo': function (browser: NightwatchBrowser) { + browser + .waitForElementVisible("[data-active='1'][data-type='remixUIXT']", 10000) + .click("[data-active='1'][data-type='remixUIXT']") + .perform(function () { + const actions = this.actions({async: true}) + return actions.sendKeys('Remove-Item -Path awesome-remix -Recurse -Force').sendKeys(this.Keys.ENTER) + }) + .waitForElementNotPresent('*[data-id="treeViewLitreeViewItemawesome-remix"]', 10000) + }, + 'list files': function (browser: NightwatchBrowser) { + browser + .pause(3000) + .waitForElementVisible("[data-active='1'][data-type='remixUIXT']", 10000) + .click("[data-active='1'][data-type='remixUIXT']") + .saveScreenshot('./reports/screenshots/list-files.png') + .perform(function () { + const actions = this.actions({async: true}) + return actions.sendKeys('ls').sendKeys(this.Keys.ENTER) + }) + .saveScreenshot('./reports/screenshots/list-files-after.png') + .waitForElementVisible({ + selector: "//*[@data-type='remixUIXT' and @data-active='1']", + timeout: 10000, + locateStrategy: 'xpath', + }) + .pause(2000) + .getText( + { + selector: "//*[@data-type='remixUIXT' and @data-active='1']", + timeout: 10000, + locateStrategy: 'xpath', + }, + function (result) { + console.log('Text content of the element:', result.value) + browser.assert.ok((result.value as string).includes('newExample')) + } + ) + }, + 'switch to a new terminal': function (browser: NightwatchBrowser) { + browser + .waitForElementVisible('*[data-id="select_shell"]') + .click('*[data-id="select_shell"]') + .waitForElementVisible('*[data-id="select_powershell.exe"]') + .click('*[data-id="select_powershell.exe"]') + .pause(3000) + .elements('css selector', '[data-type="remixUIXTSideButton"]', function (result) { + console.log(result) + browser.assert.ok((result.value as any).length === 3) + }) + .getText( + { + selector: "//*[@data-type='remixUIXT' and @data-active='1']", + timeout: 10000, + locateStrategy: 'xpath', + }, + function (result) { + console.log('Text content of the element:', result.value) + browser.assert.ok(!(result.value as string).includes('newExample')) + } + ) + }, + 'switch to a third terminal': function (browser: NightwatchBrowser) { + browser + .waitForElementVisible('*[data-id="select_shell"]') + .click('*[data-id="select_shell"]') + .waitForElementVisible('*[data-id="select_powershell.exe"]') + .click('*[data-id="select_powershell.exe"]') + .pause(3000) + .waitForElementVisible( + { + selector: "//*[@data-type='remixUIXT' and @data-active='1']", + timeout: 10000, + locateStrategy: 'xpath', + }, + 10000 + ) + .click({ + selector: "//*[@data-type='remixUIXT' and @data-active='1']", + timeout: 10000, + locateStrategy: 'xpath', + }) + .elements('css selector', '[data-type="remixUIXTSideButton"]', function (result) { + browser.assert.ok((result.value as any).length === 4) + }) + .perform(function () { + const actions = this.actions({async: true}) + return actions.sendKeys('echo thirdterminal').sendKeys(this.Keys.ENTER) + }) + }, + 'switch back to the second terminal': function (browser: NightwatchBrowser) { + browser + .elements('css selector', '[data-type="remixUIXTSideButton"]', function (result) { + browser.elementIdClick(Object.values((result.value as any)[2])[0] as any) + }) + .getText( + { + selector: "//*[@data-type='remixUIXT' and @data-active='1']", + timeout: 10000, + locateStrategy: 'xpath', + }, + function (result) { + console.log('Text content of the element:', result.value) + browser.assert.ok(!(result.value as string).includes('newExample')) + } + ) + }, + 'close the second terminal': function (browser: NightwatchBrowser) { + browser + .waitForElementVisible('*[data-id="closeTerminalButton"]', 10000) + .click('*[data-id="closeTerminalButton"]') + .pause(1000) + .elements('css selector', '[data-type="remixUIXTSideButton"]', function (result) { + browser.assert.ok((result.value as any).length === 3) + }) + }, + 'switch back to the first terminal': function (browser: NightwatchBrowser) { + browser + .elements('css selector', '[data-type="remixUIXTSideButton"]', function (result) { + browser.elementIdClick(Object.values((result.value as any)[1])[0] as any) + }) + .getText( + { + selector: "//*[@data-type='remixUIXT' and @data-active='1']", + timeout: 10000, + locateStrategy: 'xpath', + }, + function (result) { + console.log('Text content of the element:', result.value) + browser.assert.ok((result.value as string).includes('newExample')) + } + ) + }, + 'switch to the output panel': function (browser: NightwatchBrowser) { + browser.waitForElementVisible('*[data-id="tabOutput"]', 10000).click('*[data-id="tabOutput"]').waitForElementNotPresent('*[data-id="createTerminalButton"]', 10000) + }, + 'switch back to xterminal': function (browser: NightwatchBrowser) { + browser + .waitForElementVisible('*[data-id="tabXTerm"]', 10000) + .click('*[data-id="tabXTerm"]') + .waitForElementVisible("[data-active='1'][data-type='remixUIXT']", 10000) + .click("[data-active='1'][data-type='remixUIXT']") + .getText( + { + selector: "//*[@data-type='remixUIXT' and @data-active='1']", + timeout: 10000, + locateStrategy: 'xpath', + }, + function (result) { + console.log('Text content of the element:', result.value) + browser.assert.ok((result.value as string).includes('newExample')) + } + ) + }, + 'clear the terminal': function (browser: NightwatchBrowser) { + browser + .waitForElementVisible('*[data-id="clearTerminalButton"]', 10000) + .click('*[data-id="clearTerminalButton"]') + .getText( + { + selector: "//*[@data-type='remixUIXT' and @data-active='1']", + timeout: 10000, + locateStrategy: 'xpath', + }, + function (result) { + console.log('Text content of the element:', result.value) + browser.assert.ok(!(result.value as string).includes('newExample')) + } + ) + }, + 'close all terminals': function (browser: NightwatchBrowser) { + browser + .waitForElementVisible('*[data-id="closeTerminalButton"]', 10000) + .click('*[data-id="closeTerminalButton"]') + .pause(3000) + .click('*[data-id="closeTerminalButton"]') + .pause(3000) + .click('*[data-id="closeTerminalButton"]') + .pause(3000) + .elements('css selector', '[data-type="remixUIXTSideButton"]', function (result) { + browser.assert.ok((result.value as any).length === 0) + }).end() + }, + after: function (browser: NightwatchBrowser) { + browser.end() + }, +} + +module.exports = { + ...process.platform.startsWith('win')?tests:{} +} \ No newline at end of file diff --git a/apps/remixdesktop/test/types/index.d.ts b/apps/remixdesktop/test/types/index.d.ts new file mode 100644 index 0000000000..faf3a89d54 --- /dev/null +++ b/apps/remixdesktop/test/types/index.d.ts @@ -0,0 +1,108 @@ +// Merge custom command types with nightwatch types +/* eslint-disable no-use-before-define */ +import {NightwatchBrowser} from 'nightwatch' // eslint-disable-line @typescript-eslint/no-unused-vars +export type callbackCheckVerifyCallReturnValue = (values: string[]) => {message: string; pass: boolean} + +declare module 'nightwatch' { + export interface NightwatchCustomCommands { + clickLaunchIcon(icon: string): NightwatchBrowser + switchBrowserTab(index: number): NightwatchBrowser + scrollAndClick(target: string): NightwatchBrowser + scrollInto(target: string): NightwatchBrowser + testContracts(fileName: string, contractCode: NightwatchContractContent, compiledContractNames: string[]): NightwatchBrowser + setEditorValue(value: string, callback?: () => void): NightwatchBrowser + addFile(name: string, content: NightwatchContractContent, readMeFile?: string): NightwatchBrowser + verifyContracts(compiledContractNames: string[], opts?: {wait: number; version?: string; runs?: string}): NightwatchBrowser + selectAccount(account?: string): NightwatchBrowser + clickFunction(fnFullName: string, expectedInput?: NightwatchClickFunctionExpectedInput): NightwatchBrowser + testFunction(txHash: string, expectedInput: NightwatchTestFunctionExpectedInput): NightwatchBrowser + goToVMTraceStep(step: number, incr?: number): NightwatchBrowser + checkVariableDebug(id: string, debugValue: NightwatchCheckVariableDebugValue): NightwatchBrowser + addAtAddressInstance(address: string, isValidFormat: boolean, isValidChecksum: boolean, isAbi?: boolean): NightwatchBrowser + modalFooterOKClick(id?: string): NightwatchBrowser + clickInstance(index: number): NightwatchBrowser + journalLastChildIncludes(val: string): NightwatchBrowser + executeScriptInTerminal(script: string): NightwatchBrowser + clearEditableContent(cssSelector: string): NightwatchBrowser + journalChildIncludes(val: string, opts = {shouldHaveOnlyOneOccurence: boolean}): NightwatchBrowser + debugTransaction(index: number): NightwatchBrowser + checkElementStyle(cssSelector: string, styleProperty: string, expectedResult: string): NightwatchBrowser + openFile(name: string): NightwatchBrowser + refreshPage(): NightwatchBrowser + verifyLoad(): NightwatchBrowser + renamePath(path: string, newFileName: string, renamedPath: string): NightwatchBrowser + rightClickCustom(cssSelector: string): NightwatchBrowser + scrollToLine(line: number): NightwatchBrowser + waitForElementContainsText(id: string, value: string, timeout?: number): NightwatchBrowser + getModalBody(callback: (value: string, cb: VoidFunction) => void): NightwatchBrowser + modalFooterCancelClick(id?: string): NightwatchBrowser + selectContract(contractName: string): NightwatchBrowser + createContract(inputParams: string): NightwatchBrowser + getAddressAtPosition(index: number, cb: (pos: string) => void): NightwatchBrowser + testConstantFunction(address: string, fnFullName: string, expectedInput: NightwatchTestConstantFunctionExpectedInput | null, expectedOutput: string): NightwatchBrowser + getEditorValue(callback: (content: string) => void): NightwatchBrowser + getInstalledPlugins(cb: (plugins: string[]) => void): NightwatchBrowser + verifyCallReturnValue(address: string, checks: string[] | callbackCheckVerifyCallReturnValue): NightwatchBrowser + testEditorValue(testvalue: string): NightwatchBrowser + removeFile(path: string, workspace: string): NightwatchBrowser + switchBrowserWindow(url: string, windowName: string, cb: (browser: NightwatchBrowser, window?: NightwatchCallbackResult) => void): NightwatchBrowser + setupMetamask(passphrase: string, password: string): NightwatchBrowser + signMessage(msg: string, callback: (hash: {value: string}, signature: {value: string}) => void): NightwatchBrowser + setSolidityCompilerVersion(version: string): NightwatchBrowser + clickElementAtPosition(cssSelector: string, index: number, opt?: {forceSelectIfUnselected: boolean}): NightwatchBrowser + notContainsText(cssSelector: string, text: string): NightwatchBrowser + sendLowLevelTx(address: string, value: string, callData: string): NightwatchBrowser + journalLastChild(val: string): NightwatchBrowser + checkTerminalFilter(filter: string, test: string): NightwatchBrowser + noWorkerErrorFor(version: string): NightwatchBrowser + validateValueInput(selector: string, valueTosSet: string[], expectedValue: string): NightwatchBrowser + checkAnnotations(type: string): NightwatchBrowser + checkAnnotationsNotPresent(type: string): NightwatchBrowser + getLastTransactionHash(callback: (hash: string) => void) + currentWorkspaceIs(name: string): NightwatchBrowser + addLocalPlugin(this: NightwatchBrowser, profile: Profile & LocationProfile & ExternalProfile): NightwatchBrowser + acceptAndRemember(this: NightwatchBrowser, remember: boolean, accept: boolean): NightwatchBrowser + clearConsole(this: NightwatchBrowser): NightwatchBrowser + clearTransactions(this: NightwatchBrowser): NightwatchBrowser + getBrowserLogs(this: NightwatchBrowser): NightwatchBrowser + currentSelectedFileIs(name: string): NightwatchBrowser + switchWorkspace: (workspaceName: string) => NightwatchBrowser + switchEnvironment: (provider: string) => NightwatchBrowser + connectToExternalHttpProvider: (url: string, identifier: string) => NightwatchBrowser + waitForElementNotContainsText: (id: string, value: string, timeout: number = 10000) => NightwatchBrowser + hideToolTips: (this: NightwatchBrowser) => NightwatchBrowser + enableClipBoard: () => NightwatchBrowser + } + + export interface NightwatchBrowser { + api: this + emit: (status: string) => void + fullscreenWindow: (result?: any) => this + keys(keysToSend: string, callback?: (this: NightwatchAPI, result: NightwatchCallbackResult) => void): NightwatchBrowser + sendKeys: (selector: string, inputValue: string | string[], callback?: (this: NightwatchAPI, result: NightwatchCallbackResult) => void) => NightwatchBrowser + } + + export interface NightwatchAPI { + keys(keysToSend: string, callback?: (this: NightwatchAPI, result: NightwatchCallbackResult) => void): NightwatchAPI + } + + export interface NightwatchContractContent { + content: string + } + + export interface NightwatchClickFunctionExpectedInput { + types: string + values: string + } + + export interface NightwatchTestFunctionExpectedInput { + [key: string]: any + } + + export interface NightwatchTestConstantFunctionExpectedInput { + types: string + values: string + } + + export type NightwatchCheckVariableDebugValue = NightwatchTestFunctionExpectedInput +} diff --git a/apps/remixdesktop/tsconfig.e2e.json b/apps/remixdesktop/tsconfig.e2e.json new file mode 100644 index 0000000000..b63b0a2f36 --- /dev/null +++ b/apps/remixdesktop/tsconfig.e2e.json @@ -0,0 +1,8 @@ +{ + "extends": "./tsconfig.json", + "compilerOptions": { + "outDir": "build-e2e", + "target": "ES6" + }, + "include": ["test/**/*.ts", "test/**/*.js", "../remix-ide-e2e/src/commands"] + } \ No newline at end of file diff --git a/apps/remixdesktop/tsconfig.json b/apps/remixdesktop/tsconfig.json index 63acb26bd4..ef1cbf789f 100644 --- a/apps/remixdesktop/tsconfig.json +++ b/apps/remixdesktop/tsconfig.json @@ -1,17 +1,35 @@ { "compilerOptions": { - "target": "es6", - "module": "commonjs", + "target": "ES2018", + "allowJs": true, + "module": "CommonJS", "skipLibCheck": true, "esModuleInterop": true, - "noImplicitAny": true, - "allowSyntheticDefaultImports": true, + "noImplicitAny": false, "sourceMap": true, - "strictPropertyInitialization": false, - "strict": true, - "outDir": "build", - "rootDir": "./src/", - "noEmitOnError": true, - "typeRoots": ["node_modules/@types", "./types"] - } + "baseUrl": ".", + "outDir": "./build", + "moduleResolution": "node", + "resolveJsonModule": true, + "paths": { + "*": [ + "node_modules/*" + ], + "@remix-api": [ + "../../libs/remix-api/src/lib/types/git.ts" + ], + "@remix-git": [ + "../../libs/remix-git/" + ], + }, + "typeRoots": [ + "src/**/*.d.ts", + "node_modules/@types", + "test/**/*.d.ts", + "../remix-ide-e2e/src/**/*.d.ts" + ] + }, + "include": [ + "src/**/*", + ] } \ No newline at end of file diff --git a/apps/remixdesktop/webpack.config.js b/apps/remixdesktop/webpack.config.js new file mode 100644 index 0000000000..de122e7e1e --- /dev/null +++ b/apps/remixdesktop/webpack.config.js @@ -0,0 +1,44 @@ +const path = require('path'); +const nodeExternals = require('webpack-node-externals'); +const TsconfigPathsPlugin = require('tsconfig-paths-webpack-plugin'); +const mode = process.env.NODE_ENV || 'development'; +const webpack = require('webpack'); +module.exports = { + mode, + entry: { + main: './src/main.ts', + preload: './src/preload.ts', + }, + target: 'electron-main', + externals: [nodeExternals()], + module: { + rules: [ + { + test: /\.ts$/, + include: /src/, + use: [{ loader: 'ts-loader' }] + }, + { + test: /\.node$/, + use: 'node-loader' + } + ] + }, + resolve: { + extensions: ['.ts', '.js'], + plugins: [new TsconfigPathsPlugin({ configFile: './tsconfig.json' })] + }, + plugins: [ + new webpack.DefinePlugin({ + 'process.env.NODE_ENV': JSON.stringify(process.env.NODE_ENV || mode) + }) + ], + output: { + path: path.resolve(__dirname, 'build'), + filename: '[name].js' + }, + node: { + __dirname: false, + __filename: false + } +} diff --git a/apps/remixdesktop/yarn.lock b/apps/remixdesktop/yarn.lock index caa85e0eb9..83d6645f63 100644 --- a/apps/remixdesktop/yarn.lock +++ b/apps/remixdesktop/yarn.lock @@ -2,10 +2,10 @@ # yarn lockfile v1 -"7zip-bin@~5.1.1": - version "5.1.1" - resolved "https://registry.npmjs.org/7zip-bin/-/7zip-bin-5.1.1.tgz" - integrity sha512-sAP4LldeWNz0lNzmTird3uWfFDWWTeg6V/MsmyyLR9X1idwKBWIgt/ZvinqQldJm3LecKEs1emkbquO6PCiLVQ== +"7zip-bin@~5.2.0": + version "5.2.0" + resolved "https://registry.yarnpkg.com/7zip-bin/-/7zip-bin-5.2.0.tgz#7a03314684dd6572b7dfa89e68ce31d60286854d" + integrity sha512-ukTPVhqG4jNzMro2qA9HSCSSVJN3aN7tlb+hfqYCt3ER0yWroeA2VR38MNrOHLQ/cVj+DaIMad0kFCtWWowh/A== "@babel/runtime@^7.8.3": version "7.23.2" @@ -22,6 +22,21 @@ ajv "^6.12.0" ajv-keywords "^3.4.1" +"@discoveryjs/json-ext@^0.5.0": + version "0.5.7" + resolved "https://registry.yarnpkg.com/@discoveryjs/json-ext/-/json-ext-0.5.7.tgz#1d572bfbbe14b7704e0ba0f39b74815b84870d70" + integrity sha512-dBVuXR082gk3jsFp7Rd/JI4kytwGHecnCoTtXFb7DB6CNHp4rg5k1bhg0nWdLGLnOV71lmDzGQaLMy8iPLY0pw== + +"@electron/asar@^3.2.1": + version "3.2.13" + resolved "https://registry.yarnpkg.com/@electron/asar/-/asar-3.2.13.tgz#56565ea423ead184465adfa72663b2c70d9835f2" + integrity sha512-pY5z2qQSwbFzJsBdgfJIzXf5ElHTVMutC2dxh0FD60njknMu3n1NnTABOcQwbb5/v5soqE79m9UjaJryBf3epg== + dependencies: + "@types/glob" "^7.1.0" + commander "^5.0.0" + glob "^7.1.6" + minimatch "^3.0.4" + "@electron/get@^2.0.0": version "2.0.2" resolved "https://registry.npmjs.org/@electron/get/-/get-2.0.2.tgz" @@ -37,34 +52,45 @@ optionalDependencies: global-agent "^3.0.0" -"@electron/rebuild@^3.2.13": - version "3.2.13" - resolved "https://registry.npmjs.org/@electron/rebuild/-/rebuild-3.2.13.tgz" - integrity sha512-DH9Ol4JCnHDYVOD0fKWq+Qqbn/0WU1O6QR0mIpMXEVU4YFM4PlaqNC9K36mGShNBxxGFotZCMDrB1wl/iHM12g== +"@electron/notarize@2.1.0": + version "2.1.0" + resolved "https://registry.yarnpkg.com/@electron/notarize/-/notarize-2.1.0.tgz#76aaec10c8687225e8d0a427cc9df67611c46ff3" + integrity sha512-Q02xem1D0sg4v437xHgmBLxI2iz/fc0D4K7fiVWHa/AnW8o7D751xyKNXgziA6HrTOme9ul1JfWN5ark8WH1xA== + dependencies: + debug "^4.1.1" + fs-extra "^9.0.1" + promise-retry "^2.0.1" + +"@electron/notarize@^2.3.0": + version "2.4.0" + resolved "https://registry.yarnpkg.com/@electron/notarize/-/notarize-2.4.0.tgz#efa35dbd86b25d97b41d4a70cf19d1800f6e4603" + integrity sha512-ArHnRPIJJGrmV+uWNQSINAht+cM4gAo3uA3WFI54bYF93mzmD15gzhPQ0Dd+v/fkMhnRiiIO8NNkGdn87Vsy0g== dependencies: - "@malept/cross-spawn-promise" "^2.0.0" - chalk "^4.0.0" debug "^4.1.1" - detect-libc "^2.0.1" + fs-extra "^9.0.1" + promise-retry "^2.0.1" + +"@electron/osx-sign@1.0.5": + version "1.0.5" + resolved "https://registry.yarnpkg.com/@electron/osx-sign/-/osx-sign-1.0.5.tgz#0af7149f2fce44d1a8215660fd25a9fb610454d8" + integrity sha512-k9ZzUQtamSoweGQDV2jILiRIHUu7lYlJ3c6IEmjv1hC17rclE+eb9U+f6UFlOOETo0JzY1HNlXy4YOlCvl+Lww== + dependencies: + compare-version "^0.1.2" + debug "^4.3.4" fs-extra "^10.0.0" - got "^11.7.0" - node-abi "^3.0.0" - node-api-version "^0.1.4" - node-gyp "^9.0.0" - ora "^5.1.0" - semver "^7.3.5" - tar "^6.0.5" - yargs "^17.0.1" - -"@electron/universal@1.2.1": - version "1.2.1" - resolved "https://registry.yarnpkg.com/@electron/universal/-/universal-1.2.1.tgz#3c2c4ff37063a4e9ab1e6ff57db0bc619bc82339" - integrity sha512-7323HyMh7KBAl/nPDppdLsC87G6RwRU02dy5FPeGB1eS7rUePh55+WNWiDPLhFQqqVPHzh77M69uhmoT8XnwMQ== + isbinaryfile "^4.0.8" + minimist "^1.2.6" + plist "^3.0.5" + +"@electron/universal@1.4.1": + version "1.4.1" + resolved "https://registry.yarnpkg.com/@electron/universal/-/universal-1.4.1.tgz#3fbda2a5ed9ff9f3304c8e8316b94c1e3a7b3785" + integrity sha512-lE/U3UNw1YHuowNbTmKNs9UlS3En3cPgwM5MI+agIgr/B1hSze9NdOP0qn7boZaI9Lph8IDv3/24g9IxnJP7aQ== dependencies: + "@electron/asar" "^3.2.1" "@malept/cross-spawn-promise" "^1.1.0" - asar "^3.1.0" debug "^4.3.1" - dir-compare "^2.4.0" + dir-compare "^3.0.0" fs-extra "^9.0.1" minimatch "^3.0.4" plist "^3.0.4" @@ -87,6 +113,126 @@ dependencies: "@babel/runtime" "^7.8.3" +"@esbuild/aix-ppc64@0.23.1": + version "0.23.1" + resolved "https://registry.yarnpkg.com/@esbuild/aix-ppc64/-/aix-ppc64-0.23.1.tgz#51299374de171dbd80bb7d838e1cfce9af36f353" + integrity sha512-6VhYk1diRqrhBAqpJEdjASR/+WVRtfjpqKuNw11cLiaWpAT/Uu+nokB+UJnevzy/P9C/ty6AOe0dwueMrGh/iQ== + +"@esbuild/android-arm64@0.23.1": + version "0.23.1" + resolved "https://registry.yarnpkg.com/@esbuild/android-arm64/-/android-arm64-0.23.1.tgz#58565291a1fe548638adb9c584237449e5e14018" + integrity sha512-xw50ipykXcLstLeWH7WRdQuysJqejuAGPd30vd1i5zSyKK3WE+ijzHmLKxdiCMtH1pHz78rOg0BKSYOSB/2Khw== + +"@esbuild/android-arm@0.23.1": + version "0.23.1" + resolved "https://registry.yarnpkg.com/@esbuild/android-arm/-/android-arm-0.23.1.tgz#5eb8c652d4c82a2421e3395b808e6d9c42c862ee" + integrity sha512-uz6/tEy2IFm9RYOyvKl88zdzZfwEfKZmnX9Cj1BHjeSGNuGLuMD1kR8y5bteYmwqKm1tj8m4cb/aKEorr6fHWQ== + +"@esbuild/android-x64@0.23.1": + version "0.23.1" + resolved "https://registry.yarnpkg.com/@esbuild/android-x64/-/android-x64-0.23.1.tgz#ae19d665d2f06f0f48a6ac9a224b3f672e65d517" + integrity sha512-nlN9B69St9BwUoB+jkyU090bru8L0NA3yFvAd7k8dNsVH8bi9a8cUAUSEcEEgTp2z3dbEDGJGfP6VUnkQnlReg== + +"@esbuild/darwin-arm64@0.23.1": + version "0.23.1" + resolved "https://registry.yarnpkg.com/@esbuild/darwin-arm64/-/darwin-arm64-0.23.1.tgz#05b17f91a87e557b468a9c75e9d85ab10c121b16" + integrity sha512-YsS2e3Wtgnw7Wq53XXBLcV6JhRsEq8hkfg91ESVadIrzr9wO6jJDMZnCQbHm1Guc5t/CdDiFSSfWP58FNuvT3Q== + +"@esbuild/darwin-x64@0.23.1": + version "0.23.1" + resolved "https://registry.yarnpkg.com/@esbuild/darwin-x64/-/darwin-x64-0.23.1.tgz#c58353b982f4e04f0d022284b8ba2733f5ff0931" + integrity sha512-aClqdgTDVPSEGgoCS8QDG37Gu8yc9lTHNAQlsztQ6ENetKEO//b8y31MMu2ZaPbn4kVsIABzVLXYLhCGekGDqw== + +"@esbuild/freebsd-arm64@0.23.1": + version "0.23.1" + resolved "https://registry.yarnpkg.com/@esbuild/freebsd-arm64/-/freebsd-arm64-0.23.1.tgz#f9220dc65f80f03635e1ef96cfad5da1f446f3bc" + integrity sha512-h1k6yS8/pN/NHlMl5+v4XPfikhJulk4G+tKGFIOwURBSFzE8bixw1ebjluLOjfwtLqY0kewfjLSrO6tN2MgIhA== + +"@esbuild/freebsd-x64@0.23.1": + version "0.23.1" + resolved "https://registry.yarnpkg.com/@esbuild/freebsd-x64/-/freebsd-x64-0.23.1.tgz#69bd8511fa013b59f0226d1609ac43f7ce489730" + integrity sha512-lK1eJeyk1ZX8UklqFd/3A60UuZ/6UVfGT2LuGo3Wp4/z7eRTRYY+0xOu2kpClP+vMTi9wKOfXi2vjUpO1Ro76g== + +"@esbuild/linux-arm64@0.23.1": + version "0.23.1" + resolved "https://registry.yarnpkg.com/@esbuild/linux-arm64/-/linux-arm64-0.23.1.tgz#8050af6d51ddb388c75653ef9871f5ccd8f12383" + integrity sha512-/93bf2yxencYDnItMYV/v116zff6UyTjo4EtEQjUBeGiVpMmffDNUyD9UN2zV+V3LRV3/on4xdZ26NKzn6754g== + +"@esbuild/linux-arm@0.23.1": + version "0.23.1" + resolved "https://registry.yarnpkg.com/@esbuild/linux-arm/-/linux-arm-0.23.1.tgz#ecaabd1c23b701070484990db9a82f382f99e771" + integrity sha512-CXXkzgn+dXAPs3WBwE+Kvnrf4WECwBdfjfeYHpMeVxWE0EceB6vhWGShs6wi0IYEqMSIzdOF1XjQ/Mkm5d7ZdQ== + +"@esbuild/linux-ia32@0.23.1": + version "0.23.1" + resolved "https://registry.yarnpkg.com/@esbuild/linux-ia32/-/linux-ia32-0.23.1.tgz#3ed2273214178109741c09bd0687098a0243b333" + integrity sha512-VTN4EuOHwXEkXzX5nTvVY4s7E/Krz7COC8xkftbbKRYAl96vPiUssGkeMELQMOnLOJ8k3BY1+ZY52tttZnHcXQ== + +"@esbuild/linux-loong64@0.23.1": + version "0.23.1" + resolved "https://registry.yarnpkg.com/@esbuild/linux-loong64/-/linux-loong64-0.23.1.tgz#a0fdf440b5485c81b0fbb316b08933d217f5d3ac" + integrity sha512-Vx09LzEoBa5zDnieH8LSMRToj7ir/Jeq0Gu6qJ/1GcBq9GkfoEAoXvLiW1U9J1qE/Y/Oyaq33w5p2ZWrNNHNEw== + +"@esbuild/linux-mips64el@0.23.1": + version "0.23.1" + resolved "https://registry.yarnpkg.com/@esbuild/linux-mips64el/-/linux-mips64el-0.23.1.tgz#e11a2806346db8375b18f5e104c5a9d4e81807f6" + integrity sha512-nrFzzMQ7W4WRLNUOU5dlWAqa6yVeI0P78WKGUo7lg2HShq/yx+UYkeNSE0SSfSure0SqgnsxPvmAUu/vu0E+3Q== + +"@esbuild/linux-ppc64@0.23.1": + version "0.23.1" + resolved "https://registry.yarnpkg.com/@esbuild/linux-ppc64/-/linux-ppc64-0.23.1.tgz#06a2744c5eaf562b1a90937855b4d6cf7c75ec96" + integrity sha512-dKN8fgVqd0vUIjxuJI6P/9SSSe/mB9rvA98CSH2sJnlZ/OCZWO1DJvxj8jvKTfYUdGfcq2dDxoKaC6bHuTlgcw== + +"@esbuild/linux-riscv64@0.23.1": + version "0.23.1" + resolved "https://registry.yarnpkg.com/@esbuild/linux-riscv64/-/linux-riscv64-0.23.1.tgz#65b46a2892fc0d1af4ba342af3fe0fa4a8fe08e7" + integrity sha512-5AV4Pzp80fhHL83JM6LoA6pTQVWgB1HovMBsLQ9OZWLDqVY8MVobBXNSmAJi//Csh6tcY7e7Lny2Hg1tElMjIA== + +"@esbuild/linux-s390x@0.23.1": + version "0.23.1" + resolved "https://registry.yarnpkg.com/@esbuild/linux-s390x/-/linux-s390x-0.23.1.tgz#e71ea18c70c3f604e241d16e4e5ab193a9785d6f" + integrity sha512-9ygs73tuFCe6f6m/Tb+9LtYxWR4c9yg7zjt2cYkjDbDpV/xVn+68cQxMXCjUpYwEkze2RcU/rMnfIXNRFmSoDw== + +"@esbuild/linux-x64@0.23.1": + version "0.23.1" + resolved "https://registry.yarnpkg.com/@esbuild/linux-x64/-/linux-x64-0.23.1.tgz#d47f97391e80690d4dfe811a2e7d6927ad9eed24" + integrity sha512-EV6+ovTsEXCPAp58g2dD68LxoP/wK5pRvgy0J/HxPGB009omFPv3Yet0HiaqvrIrgPTBuC6wCH1LTOY91EO5hQ== + +"@esbuild/netbsd-x64@0.23.1": + version "0.23.1" + resolved "https://registry.yarnpkg.com/@esbuild/netbsd-x64/-/netbsd-x64-0.23.1.tgz#44e743c9778d57a8ace4b72f3c6b839a3b74a653" + integrity sha512-aevEkCNu7KlPRpYLjwmdcuNz6bDFiE7Z8XC4CPqExjTvrHugh28QzUXVOZtiYghciKUacNktqxdpymplil1beA== + +"@esbuild/openbsd-arm64@0.23.1": + version "0.23.1" + resolved "https://registry.yarnpkg.com/@esbuild/openbsd-arm64/-/openbsd-arm64-0.23.1.tgz#05c5a1faf67b9881834758c69f3e51b7dee015d7" + integrity sha512-3x37szhLexNA4bXhLrCC/LImN/YtWis6WXr1VESlfVtVeoFJBRINPJ3f0a/6LV8zpikqoUg4hyXw0sFBt5Cr+Q== + +"@esbuild/openbsd-x64@0.23.1": + version "0.23.1" + resolved "https://registry.yarnpkg.com/@esbuild/openbsd-x64/-/openbsd-x64-0.23.1.tgz#2e58ae511bacf67d19f9f2dcd9e8c5a93f00c273" + integrity sha512-aY2gMmKmPhxfU+0EdnN+XNtGbjfQgwZj43k8G3fyrDM/UdZww6xrWxmDkuz2eCZchqVeABjV5BpildOrUbBTqA== + +"@esbuild/sunos-x64@0.23.1": + version "0.23.1" + resolved "https://registry.yarnpkg.com/@esbuild/sunos-x64/-/sunos-x64-0.23.1.tgz#adb022b959d18d3389ac70769cef5a03d3abd403" + integrity sha512-RBRT2gqEl0IKQABT4XTj78tpk9v7ehp+mazn2HbUeZl1YMdaGAQqhapjGTCe7uw7y0frDi4gS0uHzhvpFuI1sA== + +"@esbuild/win32-arm64@0.23.1": + version "0.23.1" + resolved "https://registry.yarnpkg.com/@esbuild/win32-arm64/-/win32-arm64-0.23.1.tgz#84906f50c212b72ec360f48461d43202f4c8b9a2" + integrity sha512-4O+gPR5rEBe2FpKOVyiJ7wNDPA8nGzDuJ6gN4okSA1gEOYZ67N8JPk58tkWtdtPeLz7lBnY6I5L3jdsr3S+A6A== + +"@esbuild/win32-ia32@0.23.1": + version "0.23.1" + resolved "https://registry.yarnpkg.com/@esbuild/win32-ia32/-/win32-ia32-0.23.1.tgz#5e3eacc515820ff729e90d0cb463183128e82fac" + integrity sha512-BcaL0Vn6QwCwre3Y717nVHZbAa4UBEigzFm6VdsVdT/MbZ38xoj1X9HPkZhbmaBGUD1W8vxAfffbDe8bA6AKnQ== + +"@esbuild/win32-x64@0.23.1": + version "0.23.1" + resolved "https://registry.yarnpkg.com/@esbuild/win32-x64/-/win32-x64-0.23.1.tgz#81fd50d11e2c32b2d6241470e3185b70c7b30699" + integrity sha512-BHpFFeslkWrXWyUPnbKm+xYYVYruCinGcftSBaa8zoF9hZO4BcSCFUvHVTtzpIY6YzUnYtuEhZ+C9iEXjxnasg== + "@ethereumjs/common@2.6.5", "@ethereumjs/common@^2.6.4": version "2.6.5" resolved "https://registry.yarnpkg.com/@ethereumjs/common/-/common-2.6.5.tgz#0a75a22a046272579d91919cb12d84f2756e8d30" @@ -461,7 +607,7 @@ "@isaacs/cliui@^8.0.2": version "8.0.2" - resolved "https://registry.npmjs.org/@isaacs/cliui/-/cliui-8.0.2.tgz" + resolved "https://registry.yarnpkg.com/@isaacs/cliui/-/cliui-8.0.2.tgz#b37667b7bc181c168782259bab42474fbf52b550" integrity sha512-O8jcjabXaleOG9DQ0+ARXWZBTfnP4WNAqzuiJK7ll44AmxGKv/J2M4TPjxjY3znBCfvBXFzucm1twdyFybFqEA== dependencies: string-width "^5.1.2" @@ -471,20 +617,53 @@ wrap-ansi "^8.1.0" wrap-ansi-cjs "npm:wrap-ansi@^7.0.0" +"@jridgewell/gen-mapping@^0.3.5": + version "0.3.5" + resolved "https://registry.yarnpkg.com/@jridgewell/gen-mapping/-/gen-mapping-0.3.5.tgz#dcce6aff74bdf6dad1a95802b69b04a2fcb1fb36" + integrity sha512-IzL8ZoEDIBRWEzlCcRhOaCupYyN5gdIK+Q6fbFdPDg6HqX6jpkItn7DFIpW9LQzXG6Df9sA7+OKnq0qlz/GaQg== + dependencies: + "@jridgewell/set-array" "^1.2.1" + "@jridgewell/sourcemap-codec" "^1.4.10" + "@jridgewell/trace-mapping" "^0.3.24" + +"@jridgewell/resolve-uri@^3.1.0": + version "3.1.2" + resolved "https://registry.yarnpkg.com/@jridgewell/resolve-uri/-/resolve-uri-3.1.2.tgz#7a0ee601f60f99a20c7c7c5ff0c80388c1189bd6" + integrity sha512-bRISgCIjP20/tbWSPWMEi54QVPRZExkuD9lJL+UIxUKtwVJA8wW1Trb1jMs1RFXo1CBTNZ/5hpC9QvmKWdopKw== + +"@jridgewell/set-array@^1.2.1": + version "1.2.1" + resolved "https://registry.yarnpkg.com/@jridgewell/set-array/-/set-array-1.2.1.tgz#558fb6472ed16a4c850b889530e6b36438c49280" + integrity sha512-R8gLRTZeyp03ymzP/6Lil/28tGeGEzhx1q2k703KGWRAI1VdvPIXdG70VJc2pAMw3NA6JKL5hhFu1sJX0Mnn/A== + +"@jridgewell/source-map@^0.3.3": + version "0.3.6" + resolved "https://registry.yarnpkg.com/@jridgewell/source-map/-/source-map-0.3.6.tgz#9d71ca886e32502eb9362c9a74a46787c36df81a" + integrity sha512-1ZJTZebgqllO79ue2bm3rIGud/bOe0pP5BjSRCRxxYkEZS8STV7zN84UBbiYu7jy+eCKSnVIUgoWWE/tt+shMQ== + dependencies: + "@jridgewell/gen-mapping" "^0.3.5" + "@jridgewell/trace-mapping" "^0.3.25" + +"@jridgewell/sourcemap-codec@^1.4.10", "@jridgewell/sourcemap-codec@^1.4.14": + version "1.4.15" + resolved "https://registry.yarnpkg.com/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.4.15.tgz#d7c6e6755c78567a951e04ab52ef0fd26de59f32" + integrity sha512-eF2rxCRulEKXHTRiDrDy6erMYWqNw4LPdQ8UQA4huuxaQsVeRPFl2oM8oDGxMFhJUWZf9McpLtJasDDZb/Bpeg== + +"@jridgewell/trace-mapping@^0.3.20", "@jridgewell/trace-mapping@^0.3.24", "@jridgewell/trace-mapping@^0.3.25": + version "0.3.25" + resolved "https://registry.yarnpkg.com/@jridgewell/trace-mapping/-/trace-mapping-0.3.25.tgz#15f190e98895f3fc23276ee14bc76b675c2e50f0" + integrity sha512-vNk6aEwybGtawWmy/PzwnGDOjCkLWSD2wqvjGGAgOAwCGWySYXfYoxt00IJkTF+8Lb57DwOb3Aa0o9CApepiYQ== + dependencies: + "@jridgewell/resolve-uri" "^3.1.0" + "@jridgewell/sourcemap-codec" "^1.4.14" + "@malept/cross-spawn-promise@^1.1.0": version "1.1.1" - resolved "https://registry.npmjs.org/@malept/cross-spawn-promise/-/cross-spawn-promise-1.1.1.tgz" + resolved "https://registry.yarnpkg.com/@malept/cross-spawn-promise/-/cross-spawn-promise-1.1.1.tgz#504af200af6b98e198bce768bc1730c6936ae01d" integrity sha512-RTBGWL5FWQcg9orDOCcp4LvItNzUPcyEU9bwaeJX0rJ1IQxzucC48Y0/sQLp/g6t99IQgAlGIaesJS+gTn7tVQ== dependencies: cross-spawn "^7.0.1" -"@malept/cross-spawn-promise@^2.0.0": - version "2.0.0" - resolved "https://registry.npmjs.org/@malept/cross-spawn-promise/-/cross-spawn-promise-2.0.0.tgz" - integrity sha512-1DpKU0Z5ThltBwjNySMC14g0CkbyhCaz9FkhxqNsZI6uAPJXFS8cMXlBKo26FJ8ZuW6S9GCMcR9IO5k2X5/9Fg== - dependencies: - cross-spawn "^7.0.1" - "@malept/flatpak-bundler@^0.4.0": version "0.4.0" resolved "https://registry.npmjs.org/@malept/flatpak-bundler/-/flatpak-bundler-0.4.0.tgz" @@ -495,6 +674,18 @@ lodash "^4.17.15" tmp-promise "^3.0.2" +"@nightwatch/chai@5.0.2": + version "5.0.2" + resolved "https://registry.yarnpkg.com/@nightwatch/chai/-/chai-5.0.2.tgz#86b20908fc090dffd5c9567c0392bc6a494cc2e6" + integrity sha512-yzILJFCcE75OPoRfBlJ80Y3Ky06ljsdrK4Ld92yhmM477vxO2GEguwnd+ldl7pdSYTcg1gSJ1bPPQrA+/Hrn+A== + dependencies: + assertion-error "1.1.0" + check-error "1.0.2" + deep-eql "4.0.1" + loupe "2.3.4" + pathval "1.1.1" + type-detect "4.0.8" + "@noble/curves@1.1.0", "@noble/curves@~1.1.0": version "1.1.0" resolved "https://registry.yarnpkg.com/@noble/curves/-/curves-1.1.0.tgz#f13fc667c89184bc04cccb9b11e8e7bae27d8c3d" @@ -512,12 +703,247 @@ resolved "https://registry.yarnpkg.com/@noble/hashes/-/hashes-1.3.2.tgz#6f26dbc8fbc7205873ce3cee2f690eba0d421b39" integrity sha512-MVC8EAQp7MvEcm30KWENFjgR+Mkmf+D189XJTkFIlwohU5hcBbn1ZkKq7KVTi2Hme3PMGF390DaL52beVrIihQ== -"@npmcli/fs@^3.1.0": - version "3.1.0" - resolved "https://registry.npmjs.org/@npmcli/fs/-/fs-3.1.0.tgz" - integrity sha512-7kZUAaLscfgbwBQRbvdMYaZOWyMEcPTH/tJjnyAWJ/dvvs9Ef+CERx/qJb9GExJpl1qipaDGn7KqHnFGGixd0w== +"@octokit/app@^14.0.2": + version "14.1.0" + resolved "https://registry.yarnpkg.com/@octokit/app/-/app-14.1.0.tgz#2d491dc70746773b83f61edf5c56817dd7d3854b" + integrity sha512-g3uEsGOQCBl1+W1rgfwoRFUIR6PtvB2T1E4RpygeUU5LrLvlOqcxrt5lfykIeRpUPpupreGJUYl70fqMDXdTpw== + dependencies: + "@octokit/auth-app" "^6.0.0" + "@octokit/auth-unauthenticated" "^5.0.0" + "@octokit/core" "^5.0.0" + "@octokit/oauth-app" "^6.0.0" + "@octokit/plugin-paginate-rest" "^9.0.0" + "@octokit/types" "^12.0.0" + "@octokit/webhooks" "^12.0.4" + +"@octokit/auth-app@^6.0.0": + version "6.1.1" + resolved "https://registry.yarnpkg.com/@octokit/auth-app/-/auth-app-6.1.1.tgz#758a5d2e0324c750f7463b10398fd99c52b2eb89" + integrity sha512-VrTtzRpyuT5nYGUWeGWQqH//hqEZDV+/yb6+w5wmWpmmUA1Tx950XsAc2mBBfvusfcdF2E7w8jZ1r1WwvfZ9pA== + dependencies: + "@octokit/auth-oauth-app" "^7.1.0" + "@octokit/auth-oauth-user" "^4.1.0" + "@octokit/request" "^8.3.1" + "@octokit/request-error" "^5.1.0" + "@octokit/types" "^13.1.0" + deprecation "^2.3.1" + lru-cache "^10.0.0" + universal-github-app-jwt "^1.1.2" + universal-user-agent "^6.0.0" + +"@octokit/auth-oauth-app@^7.0.0", "@octokit/auth-oauth-app@^7.1.0": + version "7.1.0" + resolved "https://registry.yarnpkg.com/@octokit/auth-oauth-app/-/auth-oauth-app-7.1.0.tgz#d0f74e19ebd5a4829cb780c107cedd6c894f20fc" + integrity sha512-w+SyJN/b0l/HEb4EOPRudo7uUOSW51jcK1jwLa+4r7PA8FPFpoxEnHBHMITqCsc/3Vo2qqFjgQfz/xUUvsSQnA== + dependencies: + "@octokit/auth-oauth-device" "^6.1.0" + "@octokit/auth-oauth-user" "^4.1.0" + "@octokit/request" "^8.3.1" + "@octokit/types" "^13.0.0" + "@types/btoa-lite" "^1.0.0" + btoa-lite "^1.0.0" + universal-user-agent "^6.0.0" + +"@octokit/auth-oauth-device@^6.1.0": + version "6.1.0" + resolved "https://registry.yarnpkg.com/@octokit/auth-oauth-device/-/auth-oauth-device-6.1.0.tgz#f868213a3db05fe27e68d1fc607502a322379dd9" + integrity sha512-FNQ7cb8kASufd6Ej4gnJ3f1QB5vJitkoV1O0/g6e6lUsQ7+VsSNRHRmFScN2tV4IgKA12frrr/cegUs0t+0/Lw== + dependencies: + "@octokit/oauth-methods" "^4.1.0" + "@octokit/request" "^8.3.1" + "@octokit/types" "^13.0.0" + universal-user-agent "^6.0.0" + +"@octokit/auth-oauth-user@^4.0.0", "@octokit/auth-oauth-user@^4.1.0": + version "4.1.0" + resolved "https://registry.yarnpkg.com/@octokit/auth-oauth-user/-/auth-oauth-user-4.1.0.tgz#32e5529f8bd961af9839a1f8c6ab0c8ad2184eee" + integrity sha512-FrEp8mtFuS/BrJyjpur+4GARteUCrPeR/tZJzD8YourzoVhRics7u7we/aDcKv+yywRNwNi/P4fRi631rG/OyQ== + dependencies: + "@octokit/auth-oauth-device" "^6.1.0" + "@octokit/oauth-methods" "^4.1.0" + "@octokit/request" "^8.3.1" + "@octokit/types" "^13.0.0" + btoa-lite "^1.0.0" + universal-user-agent "^6.0.0" + +"@octokit/auth-token@^4.0.0": + version "4.0.0" + resolved "https://registry.yarnpkg.com/@octokit/auth-token/-/auth-token-4.0.0.tgz#40d203ea827b9f17f42a29c6afb93b7745ef80c7" + integrity sha512-tY/msAuJo6ARbK6SPIxZrPBms3xPbfwBrulZe0Wtr/DIY9lje2HeV1uoebShn6mx7SjCHif6EjMvoREj+gZ+SA== + +"@octokit/auth-unauthenticated@^5.0.0": + version "5.0.1" + resolved "https://registry.yarnpkg.com/@octokit/auth-unauthenticated/-/auth-unauthenticated-5.0.1.tgz#d8032211728333068b2e07b53997c29e59a03507" + integrity sha512-oxeWzmBFxWd+XolxKTc4zr+h3mt+yofn4r7OfoIkR/Cj/o70eEGmPsFbueyJE2iBAGpjgTnEOKM3pnuEGVmiqg== + dependencies: + "@octokit/request-error" "^5.0.0" + "@octokit/types" "^12.0.0" + +"@octokit/core@^5.0.0": + version "5.2.0" + resolved "https://registry.yarnpkg.com/@octokit/core/-/core-5.2.0.tgz#ddbeaefc6b44a39834e1bb2e58a49a117672a7ea" + integrity sha512-1LFfa/qnMQvEOAdzlQymH0ulepxbxnCYAKJZfMci/5XJyIHWgEYnDmgnKakbTh7CH2tFQ5O60oYDvns4i9RAIg== + dependencies: + "@octokit/auth-token" "^4.0.0" + "@octokit/graphql" "^7.1.0" + "@octokit/request" "^8.3.1" + "@octokit/request-error" "^5.1.0" + "@octokit/types" "^13.0.0" + before-after-hook "^2.2.0" + universal-user-agent "^6.0.0" + +"@octokit/endpoint@^9.0.1": + version "9.0.5" + resolved "https://registry.yarnpkg.com/@octokit/endpoint/-/endpoint-9.0.5.tgz#e6c0ee684e307614c02fc6ac12274c50da465c44" + integrity sha512-ekqR4/+PCLkEBF6qgj8WqJfvDq65RH85OAgrtnVp1mSxaXF03u2xW/hUdweGS5654IlC0wkNYC18Z50tSYTAFw== + dependencies: + "@octokit/types" "^13.1.0" + universal-user-agent "^6.0.0" + +"@octokit/graphql@^7.1.0": + version "7.1.0" + resolved "https://registry.yarnpkg.com/@octokit/graphql/-/graphql-7.1.0.tgz#9bc1c5de92f026648131f04101cab949eeffe4e0" + integrity sha512-r+oZUH7aMFui1ypZnAvZmn0KSqAUgE1/tUXIWaqUCa1758ts/Jio84GZuzsvUkme98kv0WFY8//n0J1Z+vsIsQ== + dependencies: + "@octokit/request" "^8.3.0" + "@octokit/types" "^13.0.0" + universal-user-agent "^6.0.0" + +"@octokit/oauth-app@^6.0.0": + version "6.1.0" + resolved "https://registry.yarnpkg.com/@octokit/oauth-app/-/oauth-app-6.1.0.tgz#22c276f6ad2364c6999837bfdd5d9c1092838726" + integrity sha512-nIn/8eUJ/BKUVzxUXd5vpzl1rwaVxMyYbQkNZjHrF7Vk/yu98/YDF/N2KeWO7uZ0g3b5EyiFXFkZI8rJ+DH1/g== + dependencies: + "@octokit/auth-oauth-app" "^7.0.0" + "@octokit/auth-oauth-user" "^4.0.0" + "@octokit/auth-unauthenticated" "^5.0.0" + "@octokit/core" "^5.0.0" + "@octokit/oauth-authorization-url" "^6.0.2" + "@octokit/oauth-methods" "^4.0.0" + "@types/aws-lambda" "^8.10.83" + universal-user-agent "^6.0.0" + +"@octokit/oauth-authorization-url@^6.0.2": + version "6.0.2" + resolved "https://registry.yarnpkg.com/@octokit/oauth-authorization-url/-/oauth-authorization-url-6.0.2.tgz#cc82ca29cc5e339c9921672f39f2b3f5c8eb6ef2" + integrity sha512-CdoJukjXXxqLNK4y/VOiVzQVjibqoj/xHgInekviUJV73y/BSIcwvJ/4aNHPBPKcPWFnd4/lO9uqRV65jXhcLA== + +"@octokit/oauth-methods@^4.0.0", "@octokit/oauth-methods@^4.1.0": + version "4.1.0" + resolved "https://registry.yarnpkg.com/@octokit/oauth-methods/-/oauth-methods-4.1.0.tgz#1403ac9c4d4e277922fddc4c89fa8a782f8f791b" + integrity sha512-4tuKnCRecJ6CG6gr0XcEXdZtkTDbfbnD5oaHBmLERTjTMZNi2CbfEHZxPU41xXLDG4DfKf+sonu00zvKI9NSbw== + dependencies: + "@octokit/oauth-authorization-url" "^6.0.2" + "@octokit/request" "^8.3.1" + "@octokit/request-error" "^5.1.0" + "@octokit/types" "^13.0.0" + btoa-lite "^1.0.0" + +"@octokit/openapi-types@^20.0.0": + version "20.0.0" + resolved "https://registry.yarnpkg.com/@octokit/openapi-types/-/openapi-types-20.0.0.tgz#9ec2daa0090eeb865ee147636e0c00f73790c6e5" + integrity sha512-EtqRBEjp1dL/15V7WiX5LJMIxxkdiGJnabzYx5Apx4FkQIFgAfKumXeYAqqJCj1s+BMX4cPFIFC4OLCR6stlnA== + +"@octokit/openapi-types@^22.2.0": + version "22.2.0" + resolved "https://registry.yarnpkg.com/@octokit/openapi-types/-/openapi-types-22.2.0.tgz#75aa7dcd440821d99def6a60b5f014207ae4968e" + integrity sha512-QBhVjcUa9W7Wwhm6DBFu6ZZ+1/t/oYxqc2tp81Pi41YNuJinbFRx8B133qVOrAaBbF7D/m0Et6f9/pZt9Rc+tg== + +"@octokit/plugin-paginate-graphql@^4.0.0": + version "4.0.1" + resolved "https://registry.yarnpkg.com/@octokit/plugin-paginate-graphql/-/plugin-paginate-graphql-4.0.1.tgz#9c0b1145b93a2b8635943f497c127969d54512fc" + integrity sha512-R8ZQNmrIKKpHWC6V2gum4x9LG2qF1RxRjo27gjQcG3j+vf2tLsEfE7I/wRWEPzYMaenr1M+qDAtNcwZve1ce1A== + +"@octokit/plugin-paginate-rest@11.3.1": + version "11.3.1" + resolved "https://registry.yarnpkg.com/@octokit/plugin-paginate-rest/-/plugin-paginate-rest-11.3.1.tgz#fe92d04b49f134165d6fbb716e765c2f313ad364" + integrity sha512-ryqobs26cLtM1kQxqeZui4v8FeznirUsksiA+RYemMPJ7Micju0WSkv50dBksTuZks9O5cg4wp+t8fZ/cLY56g== + dependencies: + "@octokit/types" "^13.5.0" + +"@octokit/plugin-paginate-rest@^9.0.0": + version "9.2.1" + resolved "https://registry.yarnpkg.com/@octokit/plugin-paginate-rest/-/plugin-paginate-rest-9.2.1.tgz#2e2a2f0f52c9a4b1da1a3aa17dabe3c459b9e401" + integrity sha512-wfGhE/TAkXZRLjksFXuDZdmGnJQHvtU/joFQdweXUgzo1XwvBCD4o4+75NtFfjfLK5IwLf9vHTfSiU3sLRYpRw== + dependencies: + "@octokit/types" "^12.6.0" + +"@octokit/plugin-rest-endpoint-methods@13.2.2": + version "13.2.2" + resolved "https://registry.yarnpkg.com/@octokit/plugin-rest-endpoint-methods/-/plugin-rest-endpoint-methods-13.2.2.tgz#af8e5dd2cddfea576f92ffaf9cb84659f302a638" + integrity sha512-EI7kXWidkt3Xlok5uN43suK99VWqc8OaIMktY9d9+RNKl69juoTyxmLoWPIZgJYzi41qj/9zU7G/ljnNOJ5AFA== + dependencies: + "@octokit/types" "^13.5.0" + +"@octokit/plugin-retry@^6.0.0": + version "6.0.1" + resolved "https://registry.yarnpkg.com/@octokit/plugin-retry/-/plugin-retry-6.0.1.tgz#3257404f7cc418e1c1f13a7f2012c1db848b7693" + integrity sha512-SKs+Tz9oj0g4p28qkZwl/topGcb0k0qPNX/i7vBKmDsjoeqnVfFUquqrE/O9oJY7+oLzdCtkiWSXLpLjvl6uog== + dependencies: + "@octokit/request-error" "^5.0.0" + "@octokit/types" "^12.0.0" + bottleneck "^2.15.3" + +"@octokit/plugin-throttling@^8.0.0": + version "8.2.0" + resolved "https://registry.yarnpkg.com/@octokit/plugin-throttling/-/plugin-throttling-8.2.0.tgz#9ec3ea2e37b92fac63f06911d0c8141b46dc4941" + integrity sha512-nOpWtLayKFpgqmgD0y3GqXafMFuKcA4tRPZIfu7BArd2lEZeb1988nhWhwx4aZWmjDmUfdgVf7W+Tt4AmvRmMQ== + dependencies: + "@octokit/types" "^12.2.0" + bottleneck "^2.15.3" + +"@octokit/request-error@^5.0.0", "@octokit/request-error@^5.1.0": + version "5.1.0" + resolved "https://registry.yarnpkg.com/@octokit/request-error/-/request-error-5.1.0.tgz#ee4138538d08c81a60be3f320cd71063064a3b30" + integrity sha512-GETXfE05J0+7H2STzekpKObFe765O5dlAKUTLNGeH+x47z7JjXHfsHKo5z21D/o/IOZTUEI6nyWyR+bZVP/n5Q== + dependencies: + "@octokit/types" "^13.1.0" + deprecation "^2.0.0" + once "^1.4.0" + +"@octokit/request@^8.3.0", "@octokit/request@^8.3.1": + version "8.4.0" + resolved "https://registry.yarnpkg.com/@octokit/request/-/request-8.4.0.tgz#7f4b7b1daa3d1f48c0977ad8fffa2c18adef8974" + integrity sha512-9Bb014e+m2TgBeEJGEbdplMVWwPmL1FPtggHQRkV+WVsMggPtEkLKPlcVYm/o8xKLkpJ7B+6N8WfQMtDLX2Dpw== + dependencies: + "@octokit/endpoint" "^9.0.1" + "@octokit/request-error" "^5.1.0" + "@octokit/types" "^13.1.0" + universal-user-agent "^6.0.0" + +"@octokit/types@^12.0.0", "@octokit/types@^12.2.0", "@octokit/types@^12.6.0": + version "12.6.0" + resolved "https://registry.yarnpkg.com/@octokit/types/-/types-12.6.0.tgz#8100fb9eeedfe083aae66473bd97b15b62aedcb2" + integrity sha512-1rhSOfRa6H9w4YwK0yrf5faDaDTb+yLyBUKOCV4xtCDB5VmIPqd/v9yr9o6SAzOAlRxMiRiCic6JVM1/kunVkw== + dependencies: + "@octokit/openapi-types" "^20.0.0" + +"@octokit/types@^13.0.0", "@octokit/types@^13.1.0", "@octokit/types@^13.5.0": + version "13.5.0" + resolved "https://registry.yarnpkg.com/@octokit/types/-/types-13.5.0.tgz#4796e56b7b267ebc7c921dcec262b3d5bfb18883" + integrity sha512-HdqWTf5Z3qwDVlzCrP8UJquMwunpDiMPt5er+QjGzL4hqr/vBVY/MauQgS1xWxCDT1oMx1EULyqxncdCY/NVSQ== + dependencies: + "@octokit/openapi-types" "^22.2.0" + +"@octokit/webhooks-methods@^4.1.0": + version "4.1.0" + resolved "https://registry.yarnpkg.com/@octokit/webhooks-methods/-/webhooks-methods-4.1.0.tgz#681a6c86c9b21d4ec9e29108fb053ae7512be033" + integrity sha512-zoQyKw8h9STNPqtm28UGOYFE7O6D4Il8VJwhAtMHFt2C4L0VQT1qGKLeefUOqHNs1mNRYSadVv7x0z8U2yyeWQ== + +"@octokit/webhooks-types@7.4.0": + version "7.4.0" + resolved "https://registry.yarnpkg.com/@octokit/webhooks-types/-/webhooks-types-7.4.0.tgz#7ed15c75908683a34e0079c80f261fe568b87395" + integrity sha512-FE2V+QZ2UYlh+9wWd5BPLNXG+J/XUD/PPq0ovS+nCcGX4+3qVbi3jYOmCTW48hg9SBBLtInx9+o7fFt4H5iP0Q== + +"@octokit/webhooks@^12.0.4": + version "12.2.0" + resolved "https://registry.yarnpkg.com/@octokit/webhooks/-/webhooks-12.2.0.tgz#ea1ee2d9d9c5a4b7b53ff8bc64a9feb0dac94161" + integrity sha512-CyuLJ0/P7bKZ+kIYw+fnkeVdhUzNuDKgNSI7pU/m7Nod0T7kP+s4s2f0pNmG9HL8/RZN1S0ZWTDll3VTMrFLAw== dependencies: - semver "^7.3.5" + "@octokit/request-error" "^5.0.0" + "@octokit/webhooks-methods" "^4.1.0" + "@octokit/webhooks-types" "7.4.0" + aggregate-error "^3.1.0" "@openzeppelin/contracts@^4.7.3": version "4.9.6" @@ -533,7 +959,7 @@ "@pkgjs/parseargs@^0.11.0": version "0.11.0" - resolved "https://registry.npmjs.org/@pkgjs/parseargs/-/parseargs-0.11.0.tgz" + resolved "https://registry.yarnpkg.com/@pkgjs/parseargs/-/parseargs-0.11.0.tgz#a77ea742fab25775145434eb1d2328cf5013ac33" integrity sha512-+1VkjdD0QBLPodGrJUeqarH8VAIvQODIbwh9XpP5Syisf7YoQgsJKPNFoqqLQlu+VQ/tVSshMR6loPMn8U+dPg== "@remix-project/remix-url-resolver@^0.0.65": @@ -556,68 +982,68 @@ ethers "^5.4.2" web3 "^1.5.1" -"@remixproject/engine-electron@0.3.41": - version "0.3.41" - resolved "https://registry.yarnpkg.com/@remixproject/engine-electron/-/engine-electron-0.3.41.tgz#a354d4a4dd43ade644ea27636cfc0aa63c5155b2" - integrity sha512-fF2l3LkDVK1KjkIHll7mOo6AkjUg4hgbHG2jDzHZW6m1jYr6SGxauVoYlOQvlfTe283dpsGxWEdU7TOC8Kne7w== +"@remixproject/engine-electron@0.3.43": + version "0.3.43" + resolved "https://registry.yarnpkg.com/@remixproject/engine-electron/-/engine-electron-0.3.43.tgz#37fe98c6ef2deb6de80db60882608714d6e25274" + integrity sha512-k1Lcg67tlPiBFJwKhBRT9bDMyZuYWDdUXZOHKX8BGPZ0lS1ZQDrH4uN2QE2EFGIiCxeArcNzQ7MZ5iEo763eUA== dependencies: - "@remixproject/engine" "0.3.41" - "@remixproject/plugin-api" "0.3.41" - "@remixproject/plugin-utils" "0.3.41" + "@remixproject/engine" "0.3.43" + "@remixproject/plugin-api" "0.3.43" + "@remixproject/plugin-utils" "0.3.43" -"@remixproject/engine@0.3.41": - version "0.3.41" - resolved "https://registry.yarnpkg.com/@remixproject/engine/-/engine-0.3.41.tgz#71b447d07dd52ec7645c6538f64caa638f3d9702" - integrity sha512-5ppAEana+I9FvSOjdNoLkLFbBTIpLoN5DAKsw+efyZ076i/67OsZ6oHXZqzGoHTOr4s4aS0wHmCBJPSla8GUBA== +"@remixproject/engine@0.3.43": + version "0.3.43" + resolved "https://registry.yarnpkg.com/@remixproject/engine/-/engine-0.3.43.tgz#deceb8398a034d33f741f9de38b233ab616720a4" + integrity sha512-BKmLVdtkPUQ56yZuRsU7CxS0TgJe4b7P9RoqdBW0Udy1w8oUJsWmlmKchCLXD+/t+12jPyk4sulRN8N9YOFBAw== dependencies: - "@remixproject/plugin-api" "0.3.41" - "@remixproject/plugin-utils" "0.3.41" + "@remixproject/plugin-api" "0.3.43" + "@remixproject/plugin-utils" "0.3.43" -"@remixproject/plugin-api@0.3.41": - version "0.3.41" - resolved "https://registry.yarnpkg.com/@remixproject/plugin-api/-/plugin-api-0.3.41.tgz#9a60d92332af608a871366bec6097bda2d2d1658" - integrity sha512-+gZOzJH4KUMVOEYFFW4LwwCWbojACqxvLM9FJRRkHehohue07Y7ojIbFoYk4EPWkdBtOXOsIR2zjdUIUlzzrTg== +"@remixproject/plugin-api@0.3.43": + version "0.3.43" + resolved "https://registry.yarnpkg.com/@remixproject/plugin-api/-/plugin-api-0.3.43.tgz#68ce6799a8e6e22961b82f46a7a52b1d7a4a765c" + integrity sha512-qgwq3UQAW9JKsFv47m0E7plNNEWL4CFbqoLGbfsfwuZTd/V7HhaMc1my5dxOObW+RKExyvFNFSEvEp7HoHFsWg== dependencies: - "@remixproject/plugin-utils" "0.3.41" + "@remixproject/plugin-utils" "0.3.43" -"@remixproject/plugin-api@^0.3.38": - version "0.3.38" - resolved "https://registry.yarnpkg.com/@remixproject/plugin-api/-/plugin-api-0.3.38.tgz#7dcff37483451b654fc51290157992fff3fbd8b7" - integrity sha512-GLXAnV7TMYV2KlXTml+W0H6s0m5EkVb5w610Jh9k4PLFVrocl9xDEG4VlZ8BF/uv+yjXRi4dn++8zWMRe5375Q== +"@remixproject/plugin-api@^0.3.43": + version "0.3.208" + resolved "https://registry.yarnpkg.com/@remixproject/plugin-api/-/plugin-api-0.3.208.tgz#28505b84ec06c84e04ca1bf7cfa51109c178c06b" + integrity sha512-11hFxABBrEzE4fgcDblWqxLAh5ARH2tBADgh9KNk+y7LUV7aQ7OZf4KiZ2US+uKiSC6497iu/uLHbWBTeRqlVA== dependencies: - "@remixproject/plugin-utils" "0.3.38" + "@remixproject/plugin-utils" "0.3.208" -"@remixproject/plugin-electron@0.3.41": - version "0.3.41" - resolved "https://registry.yarnpkg.com/@remixproject/plugin-electron/-/plugin-electron-0.3.41.tgz#6f736dfa5146bdf41fe0c452ab0b78e7f914fda1" - integrity sha512-E/rmKSbUa4rZKq02C+HD6WQDTS2CH6+Gqc6Z9p5wxQwbbJoMD/WVtWUvOFr1p2PSp0Nwpc4qWfOoQC6EmaugOg== +"@remixproject/plugin-electron@0.3.43": + version "0.3.43" + resolved "https://registry.yarnpkg.com/@remixproject/plugin-electron/-/plugin-electron-0.3.43.tgz#6c621c413745ce785f9973baea109debe3def00a" + integrity sha512-uv44xjmkTsC/o4xnMEBml6NxrMeq95aOR3FFY8MnZkKvnWOKC94SE5AYuHOAvt+FBrnar2f58+IYpBJAIkYyaQ== dependencies: - "@remixproject/engine" "0.3.41" - "@remixproject/plugin" "0.3.41" - "@remixproject/plugin-api" "0.3.41" - "@remixproject/plugin-utils" "0.3.41" + "@remixproject/engine" "0.3.43" + "@remixproject/plugin" "0.3.43" + "@remixproject/plugin-api" "0.3.43" + "@remixproject/plugin-utils" "0.3.43" -"@remixproject/plugin-utils@0.3.38": - version "0.3.38" - resolved "https://registry.yarnpkg.com/@remixproject/plugin-utils/-/plugin-utils-0.3.38.tgz#402adbef700a9392fbeae7d536ba020b7cfbdfaa" - integrity sha512-DpbB+BFfWvZ/pKWlXY0Ms3mqp/ajWxBI+TUiJor2AkLtCSBS1+Uk7BWG++jNSqgjdvVKxxWa4kJygFwUPtUYXA== +"@remixproject/plugin-utils@0.3.208": + version "0.3.208" + resolved "https://registry.yarnpkg.com/@remixproject/plugin-utils/-/plugin-utils-0.3.208.tgz#8ec1339af9177358c09a7dd7a39396f52c4cad27" + integrity sha512-PjEK+ty6X14ud3h2U/XH8BBbqwLF3CwduOxHCXfCG0KarR4FwuSfocWQfGlASeDFmPzyV1aMGn//U6xZ03O42Q== dependencies: tslib "2.0.1" -"@remixproject/plugin-utils@0.3.41": - version "0.3.41" - resolved "https://registry.yarnpkg.com/@remixproject/plugin-utils/-/plugin-utils-0.3.41.tgz#6de4d016084cf54fbf710ed717c9c1efc0a990de" - integrity sha512-pyqewxfQwr35YkFoZItH5E9qiIZRlpwxLuGBCMXzo6fmPm2YybhpblLaefppsdbqY1yEVsqakQa6U6d6vJRSNQ== +"@remixproject/plugin-utils@0.3.43": + version "0.3.43" + resolved "https://registry.yarnpkg.com/@remixproject/plugin-utils/-/plugin-utils-0.3.43.tgz#53206666135a360c88bfde11568c31341c9d961f" + integrity sha512-FB2Dz0/+TQ+D9AdINfsu38qHEsUVIDpaDCaXY76suDkSUudoHcGrC5TbpaV/xMUbMMma2dcLp629vBNnA5Cd0w== dependencies: tslib "2.0.1" -"@remixproject/plugin@0.3.41": - version "0.3.41" - resolved "https://registry.yarnpkg.com/@remixproject/plugin/-/plugin-0.3.41.tgz#fc82d0afd08ba659d09ee7714fa91af92cdb8e72" - integrity sha512-GqBaxExtNGQHNHwPwx/2RKX7vinEBJe9KzxzkzR2BGuBZD963+il2WsMu+QYyHjTxJ8kHZF9exqUSYJd9jZ+Yw== +"@remixproject/plugin@0.3.43": + version "0.3.43" + resolved "https://registry.yarnpkg.com/@remixproject/plugin/-/plugin-0.3.43.tgz#c7397b8e44ab6627a290c3716985439482eb4f4a" + integrity sha512-uO0wQ9kP982QTJIlGUXXeOjLG1qG64UN5kDopTcMbplzT5vXlMRV64FY8zEqSXtl+sdqKBFLXrwmb+AUNU0MTA== dependencies: - "@remixproject/plugin-api" "0.3.41" - "@remixproject/plugin-utils" "0.3.41" + "@remixproject/plugin-api" "0.3.43" + "@remixproject/plugin-utils" "0.3.43" events "3.2.0" "@scure/base@~1.1.0": @@ -661,11 +1087,21 @@ dependencies: defer-to-connect "^2.0.1" +"@testim/chrome-version@^1.1.3": + version "1.1.4" + resolved "https://registry.yarnpkg.com/@testim/chrome-version/-/chrome-version-1.1.4.tgz#86e04e677cd6c05fa230dd15ac223fa72d1d7090" + integrity sha512-kIhULpw9TrGYnHp/8VfdcneIcxKnLixmADtukQRtJUmsVlMg0niMkwV0xZmi8hqa57xqilIHjWFA0GKvEjVU5g== + "@tootallnate/once@2": version "2.0.0" resolved "https://registry.npmjs.org/@tootallnate/once/-/once-2.0.0.tgz" integrity sha512-XCuKFP5PS55gnMVu3dty8KPatLqUoy/ZYzDzAGCQ8JNFCkLXzmI7vNHCR+XpbZaMWQK/vQubr7PkYq8g470J/A== +"@types/aws-lambda@^8.10.83": + version "8.10.141" + resolved "https://registry.yarnpkg.com/@types/aws-lambda/-/aws-lambda-8.10.141.tgz#f4d2fddf2bda51c4b2885b1abc3d1e9a1d6d2a7a" + integrity sha512-SMWlRBukG9KV8ZNjwemp2AzDibp/czIAeKKTw09nCPbWxVskIxactCJCGOp4y6I1hCMY7T7UGfySvBLXNeUbEw== + "@types/bn.js@^5.1.0", "@types/bn.js@^5.1.1": version "5.1.3" resolved "https://registry.yarnpkg.com/@types/bn.js/-/bn.js-5.1.3.tgz#0857f00da3bf888a26a44b4a477c7819b17dacc5" @@ -681,6 +1117,11 @@ "@types/connect" "*" "@types/node" "*" +"@types/btoa-lite@^1.0.0": + version "1.0.2" + resolved "https://registry.yarnpkg.com/@types/btoa-lite/-/btoa-lite-1.0.2.tgz#82bb6aab00abf7cff3ca2825abe010c0cd536ae5" + integrity sha512-ZYbcE2x7yrvNFJiU7xJGrpF/ihpkM7zKgw8bha3LNJSesvTtUNxbpzaT7WXBIryf6jovisrxTBvymxMeLLj1Mg== + "@types/byline@^4.2.35": version "4.2.35" resolved "https://registry.npmjs.org/@types/byline/-/byline-4.2.35.tgz" @@ -698,6 +1139,11 @@ "@types/node" "*" "@types/responselike" "^1.0.0" +"@types/chai@*": + version "4.3.11" + resolved "https://registry.yarnpkg.com/@types/chai/-/chai-4.3.11.tgz#e95050bf79a932cb7305dd130254ccdf9bde671c" + integrity sha512-qQR1dr2rGIHYlJulmr8Ioq3De0Le9E4MJ5AiaeAETJJpndT1uUNHsGFK3L/UIu+rbkQSdj8J/w2bCsBZc/Y5fQ== + "@types/connect@*": version "3.4.38" resolved "https://registry.yarnpkg.com/@types/connect/-/connect-3.4.38.tgz#5ba7f3bc4fbbdeaff8dded952e5ff2cc53f8d858" @@ -712,6 +1158,11 @@ dependencies: "@types/ms" "*" +"@types/estree@^1.0.5": + version "1.0.5" + resolved "https://registry.yarnpkg.com/@types/estree/-/estree-1.0.5.tgz#a6ce3e556e00fd9895dd872dd172ad0d4bd687f4" + integrity sha512-/kYRxGDLWzHOB7q+wtSUQlFrtcdUccpfy+X+9iMBpHK8QLLhx2wIPYuS5DYtR9Wa/YlZAbIovy7qVdB1Aq6Lyw== + "@types/express-serve-static-core@^4.17.33": version "4.17.41" resolved "https://registry.yarnpkg.com/@types/express-serve-static-core/-/express-serve-static-core-4.17.41.tgz#5077defa630c2e8d28aa9ffc2c01c157c305bef6" @@ -732,14 +1183,14 @@ "@types/qs" "*" "@types/serve-static" "*" -"@types/fs-extra@^9.0.11": +"@types/fs-extra@9.0.13", "@types/fs-extra@^9.0.11": version "9.0.13" resolved "https://registry.yarnpkg.com/@types/fs-extra/-/fs-extra-9.0.13.tgz#7594fbae04fe7f1918ce8b3d213f74ff44ac1f45" integrity sha512-nEnwB++1u5lVDM2UI4c1+5R+FYaKfaAzS4OococimjVm3nQw3TuzH5UNsocrcTBbhnerblyHj4A49qXbIiZdpA== dependencies: "@types/node" "*" -"@types/glob@^7.1.1": +"@types/glob@^7.1.0": version "7.2.0" resolved "https://registry.yarnpkg.com/@types/glob/-/glob-7.2.0.tgz#bc1b5bf3aa92f25bd5dd39f35c57361bdce5b2eb" integrity sha512-ZUxbzKl0IfJILTS6t7ip5fQQM/J3TJYubDm3nMbgubNNYS62eXeUpoLUC8/7fJNiFYHTrGPQn7hspDUzIHX3UA== @@ -757,6 +1208,18 @@ resolved "https://registry.yarnpkg.com/@types/http-errors/-/http-errors-2.0.4.tgz#7eb47726c391b7345a6ec35ad7f4de469cf5ba4f" integrity sha512-D0CFMMtydbJAegzOyHjtiKPLlvnm3iTZyZRSZoLq2mRhDdmLfIWOCYPfQJ4cu2erKghU++QvjcUjp/5h7hESpA== +"@types/json-schema@^7.0.8": + version "7.0.15" + resolved "https://registry.yarnpkg.com/@types/json-schema/-/json-schema-7.0.15.tgz#596a1747233694d50f6ad8a7869fcb6f56cf5841" + integrity sha512-5+fP8P8MFNC+AyZCDxrB2pkZFPGzqQWUzpSeuuVLvm8VMcorNYavBqoFcxK8bQz4Qsbn4oUEEem4wDLfcysGHA== + +"@types/jsonwebtoken@^9.0.0": + version "9.0.6" + resolved "https://registry.yarnpkg.com/@types/jsonwebtoken/-/jsonwebtoken-9.0.6.tgz#d1af3544d99ad992fb6681bbe60676e06b032bd3" + integrity sha512-/5hndP5dCjloafCXns6SZyESp3Ldq7YjH3zwzwczYnjxIT0Fqzk5ROSYVGfFyczIue7IUEj8hkvLbPoLQ18vQw== + dependencies: + "@types/node" "*" + "@types/keyv@^3.1.4": version "3.1.4" resolved "https://registry.npmjs.org/@types/keyv/-/keyv-3.1.4.tgz" @@ -784,6 +1247,15 @@ resolved "https://registry.npmjs.org/@types/ms/-/ms-0.7.31.tgz" integrity sha512-iiUgKzV9AuaEkZqkOLDIvlQiL6ltuZd9tGcW3gwpnX8JbuiuhFlEGmmFXEXkN50Cvq7Os88IY2v0dkDqXYWVgA== +"@types/nightwatch@^2.3.23": + version "2.3.30" + resolved "https://registry.yarnpkg.com/@types/nightwatch/-/nightwatch-2.3.30.tgz#bb342bf21bc6cd0a7134681523ba42eeefe73c4d" + integrity sha512-TiVGKR9mORwx0nN3ylonXp2IobpQoZxwV63IjABYkxsEpNauHL8GU9kmceEThjqDUigKaeh6aPOqepwC4bwCfA== + dependencies: + "@types/chai" "*" + "@types/selenium-webdriver" "*" + devtools-protocol "^0.0.1025565" + "@types/node@*": version "20.3.2" resolved "https://registry.npmjs.org/@types/node/-/node-20.3.2.tgz" @@ -795,9 +1267,11 @@ integrity sha512-J8xLz7q2OFulZ2cyGTLE1TbbZcjpno7FaN6zdJNrgAdrJ+DZzh/uFR6YrTb4C+nXakvud8Q4+rbhoIWlYQbUFQ== "@types/node@^18.11.18": - version "18.16.18" - resolved "https://registry.npmjs.org/@types/node/-/node-18.16.18.tgz" - integrity sha512-/aNaQZD0+iSBAGnvvN2Cx92HqE5sZCPZtx2TsK+4nvV23fFe09jVDvpArXr2j9DnYlzuU9WuoykDDc6wqvpNcw== + version "18.19.50" + resolved "https://registry.yarnpkg.com/@types/node/-/node-18.19.50.tgz#8652b34ee7c0e7e2004b3f08192281808d41bf5a" + integrity sha512-xonK+NRrMBRtkL1hVCc3G+uXtjh1Al4opBLjqVmipe5ZAaBYWW6cNAiBVZ1BvmkBhep698rP3UM3aRAdSALuhg== + dependencies: + undici-types "~5.26.4" "@types/pbkdf2@^3.0.0": version "3.1.1" @@ -838,6 +1312,13 @@ dependencies: "@types/node" "*" +"@types/selenium-webdriver@*": + version "4.1.21" + resolved "https://registry.yarnpkg.com/@types/selenium-webdriver/-/selenium-webdriver-4.1.21.tgz#79fe31faf9953a4143c3e32944d98d5146bbe185" + integrity sha512-QGURnImvxYlIQz5DVhvHdqpYNLBjhJ2Vm+cnQI2G9QZzkWlZm0LkLcvDcHp+qE6N2KBz4CeuvXgPO7W3XQ0Tyw== + dependencies: + "@types/ws" "*" + "@types/send@*": version "0.17.4" resolved "https://registry.yarnpkg.com/@types/send/-/send-0.17.4.tgz#6619cd24e7270793702e4e6a4b958a9010cfc57a" @@ -860,17 +1341,12 @@ resolved "https://registry.npmjs.org/@types/verror/-/verror-1.10.6.tgz" integrity sha512-NNm+gdePAX1VGvPcGZCDKQZKYSiAWigKhKaz5KF94hG6f2s8de9Ow5+7AbXoeKxL8gavZfk4UquSAygOF2duEQ== -"@types/yargs-parser@*": - version "21.0.3" - resolved "https://registry.yarnpkg.com/@types/yargs-parser/-/yargs-parser-21.0.3.tgz#815e30b786d2e8f0dcd85fd5bcf5e1a04d008f15" - integrity sha512-I4q9QU9MQv4oEOz4tAHJtNz1cwuLxn2F3xcc2iV5WdqLPpUnj30aUuxt1mAxYTG+oe8CZMV/+6rU4S4gRDzqtQ== - -"@types/yargs@^17.0.1": - version "17.0.31" - resolved "https://registry.yarnpkg.com/@types/yargs/-/yargs-17.0.31.tgz#8fd0089803fd55d8a285895a18b88cb71a99683c" - integrity sha512-bocYSx4DI8TmdlvxqGpVNXOgCNR1Jj0gNPhhAY+iz1rgKDAaYrAYdFYnhDV1IFuiuVc9HkOwyDcFxaTElF3/wg== +"@types/ws@*": + version "8.5.10" + resolved "https://registry.yarnpkg.com/@types/ws/-/ws-8.5.10.tgz#4acfb517970853fa6574a3a6886791d04a396787" + integrity sha512-vmQSUcfalpIq0R9q7uTo2lXs6eGIpt9wtnLdMv9LVpIjCA/+ufZRozlVoVelIYixx1ugCBKDhn89vnsEGOCx9A== dependencies: - "@types/yargs-parser" "*" + "@types/node" "*" "@types/yauzl@^2.9.1": version "2.10.0" @@ -879,23 +1355,170 @@ dependencies: "@types/node" "*" +"@ungap/promise-all-settled@1.1.2": + version "1.1.2" + resolved "https://registry.yarnpkg.com/@ungap/promise-all-settled/-/promise-all-settled-1.1.2.tgz#aa58042711d6e3275dd37dc597e5d31e8c290a44" + integrity sha512-sL/cEvJWAnClXw0wHk85/2L0G6Sj8UB0Ctc1TEMbKSsmpRosqhwj9gWgFRZSrBr2f9tiXISwNhCPmlfqUqyb9Q== + "@vscode/ripgrep@^1.15.6": - version "1.15.6" - resolved "https://registry.npmjs.org/@vscode/ripgrep/-/ripgrep-1.15.6.tgz" - integrity sha512-mCtfHqZ/g+75qDDeIPB9ST1xyJDaJornaSujuRKkB0SMZ6FMVtuKUdvvvOITR+DcKo5KOwUVuOUUpt75jOY+Yw== + version "1.15.9" + resolved "https://registry.yarnpkg.com/@vscode/ripgrep/-/ripgrep-1.15.9.tgz#92279f7f28e1e49ad9a89603e10b17a4c7f9f5f1" + integrity sha512-4q2PXRvUvr3bF+LsfrifmUZgSPmCNcUZo6SbEAZgArIChchkezaxLoIeQMJe/z3CCKStvaVKpBXLxN3Z8lQjFQ== dependencies: https-proxy-agent "^7.0.2" proxy-from-env "^1.1.0" + yauzl "^2.9.2" + +"@webassemblyjs/ast@1.12.1", "@webassemblyjs/ast@^1.12.1": + version "1.12.1" + resolved "https://registry.yarnpkg.com/@webassemblyjs/ast/-/ast-1.12.1.tgz#bb16a0e8b1914f979f45864c23819cc3e3f0d4bb" + integrity sha512-EKfMUOPRRUTy5UII4qJDGPpqfwjOmZ5jeGFwid9mnoqIFK+e0vqoi1qH56JpmZSzEL53jKnNzScdmftJyG5xWg== + dependencies: + "@webassemblyjs/helper-numbers" "1.11.6" + "@webassemblyjs/helper-wasm-bytecode" "1.11.6" + +"@webassemblyjs/floating-point-hex-parser@1.11.6": + version "1.11.6" + resolved "https://registry.yarnpkg.com/@webassemblyjs/floating-point-hex-parser/-/floating-point-hex-parser-1.11.6.tgz#dacbcb95aff135c8260f77fa3b4c5fea600a6431" + integrity sha512-ejAj9hfRJ2XMsNHk/v6Fu2dGS+i4UaXBXGemOfQ/JfQ6mdQg/WXtwleQRLLS4OvfDhv8rYnVwH27YJLMyYsxhw== + +"@webassemblyjs/helper-api-error@1.11.6": + version "1.11.6" + resolved "https://registry.yarnpkg.com/@webassemblyjs/helper-api-error/-/helper-api-error-1.11.6.tgz#6132f68c4acd59dcd141c44b18cbebbd9f2fa768" + integrity sha512-o0YkoP4pVu4rN8aTJgAyj9hC2Sv5UlkzCHhxqWj8butaLvnpdc2jOwh4ewE6CX0txSfLn/UYaV/pheS2Txg//Q== + +"@webassemblyjs/helper-buffer@1.12.1": + version "1.12.1" + resolved "https://registry.yarnpkg.com/@webassemblyjs/helper-buffer/-/helper-buffer-1.12.1.tgz#6df20d272ea5439bf20ab3492b7fb70e9bfcb3f6" + integrity sha512-nzJwQw99DNDKr9BVCOZcLuJJUlqkJh+kVzVl6Fmq/tI5ZtEyWT1KZMyOXltXLZJmDtvLCDgwsyrkohEtopTXCw== + +"@webassemblyjs/helper-numbers@1.11.6": + version "1.11.6" + resolved "https://registry.yarnpkg.com/@webassemblyjs/helper-numbers/-/helper-numbers-1.11.6.tgz#cbce5e7e0c1bd32cf4905ae444ef64cea919f1b5" + integrity sha512-vUIhZ8LZoIWHBohiEObxVm6hwP034jwmc9kuq5GdHZH0wiLVLIPcMCdpJzG4C11cHoQ25TFIQj9kaVADVX7N3g== + dependencies: + "@webassemblyjs/floating-point-hex-parser" "1.11.6" + "@webassemblyjs/helper-api-error" "1.11.6" + "@xtuc/long" "4.2.2" + +"@webassemblyjs/helper-wasm-bytecode@1.11.6": + version "1.11.6" + resolved "https://registry.yarnpkg.com/@webassemblyjs/helper-wasm-bytecode/-/helper-wasm-bytecode-1.11.6.tgz#bb2ebdb3b83aa26d9baad4c46d4315283acd51e9" + integrity sha512-sFFHKwcmBprO9e7Icf0+gddyWYDViL8bpPjJJl0WHxCdETktXdmtWLGVzoHbqUcY4Be1LkNfwTmXOJUFZYSJdA== + +"@webassemblyjs/helper-wasm-section@1.12.1": + version "1.12.1" + resolved "https://registry.yarnpkg.com/@webassemblyjs/helper-wasm-section/-/helper-wasm-section-1.12.1.tgz#3da623233ae1a60409b509a52ade9bc22a37f7bf" + integrity sha512-Jif4vfB6FJlUlSbgEMHUyk1j234GTNG9dBJ4XJdOySoj518Xj0oGsNi59cUQF4RRMS9ouBUxDDdyBVfPTypa5g== + dependencies: + "@webassemblyjs/ast" "1.12.1" + "@webassemblyjs/helper-buffer" "1.12.1" + "@webassemblyjs/helper-wasm-bytecode" "1.11.6" + "@webassemblyjs/wasm-gen" "1.12.1" + +"@webassemblyjs/ieee754@1.11.6": + version "1.11.6" + resolved "https://registry.yarnpkg.com/@webassemblyjs/ieee754/-/ieee754-1.11.6.tgz#bb665c91d0b14fffceb0e38298c329af043c6e3a" + integrity sha512-LM4p2csPNvbij6U1f19v6WR56QZ8JcHg3QIJTlSwzFcmx6WSORicYj6I63f9yU1kEUtrpG+kjkiIAkevHpDXrg== + dependencies: + "@xtuc/ieee754" "^1.2.0" + +"@webassemblyjs/leb128@1.11.6": + version "1.11.6" + resolved "https://registry.yarnpkg.com/@webassemblyjs/leb128/-/leb128-1.11.6.tgz#70e60e5e82f9ac81118bc25381a0b283893240d7" + integrity sha512-m7a0FhE67DQXgouf1tbN5XQcdWoNgaAuoULHIfGFIEVKA6tu/edls6XnIlkmS6FrXAquJRPni3ZZKjw6FSPjPQ== + dependencies: + "@xtuc/long" "4.2.2" + +"@webassemblyjs/utf8@1.11.6": + version "1.11.6" + resolved "https://registry.yarnpkg.com/@webassemblyjs/utf8/-/utf8-1.11.6.tgz#90f8bc34c561595fe156603be7253cdbcd0fab5a" + integrity sha512-vtXf2wTQ3+up9Zsg8sa2yWiQpzSsMyXj0qViVP6xKGCUT8p8YJ6HqI7l5eCnWx1T/FYdsv07HQs2wTFbbof/RA== + +"@webassemblyjs/wasm-edit@^1.12.1": + version "1.12.1" + resolved "https://registry.yarnpkg.com/@webassemblyjs/wasm-edit/-/wasm-edit-1.12.1.tgz#9f9f3ff52a14c980939be0ef9d5df9ebc678ae3b" + integrity sha512-1DuwbVvADvS5mGnXbE+c9NfA8QRcZ6iKquqjjmR10k6o+zzsRVesil54DKexiowcFCPdr/Q0qaMgB01+SQ1u6g== + dependencies: + "@webassemblyjs/ast" "1.12.1" + "@webassemblyjs/helper-buffer" "1.12.1" + "@webassemblyjs/helper-wasm-bytecode" "1.11.6" + "@webassemblyjs/helper-wasm-section" "1.12.1" + "@webassemblyjs/wasm-gen" "1.12.1" + "@webassemblyjs/wasm-opt" "1.12.1" + "@webassemblyjs/wasm-parser" "1.12.1" + "@webassemblyjs/wast-printer" "1.12.1" + +"@webassemblyjs/wasm-gen@1.12.1": + version "1.12.1" + resolved "https://registry.yarnpkg.com/@webassemblyjs/wasm-gen/-/wasm-gen-1.12.1.tgz#a6520601da1b5700448273666a71ad0a45d78547" + integrity sha512-TDq4Ojh9fcohAw6OIMXqiIcTq5KUXTGRkVxbSo1hQnSy6lAM5GSdfwWeSxpAo0YzgsgF182E/U0mDNhuA0tW7w== + dependencies: + "@webassemblyjs/ast" "1.12.1" + "@webassemblyjs/helper-wasm-bytecode" "1.11.6" + "@webassemblyjs/ieee754" "1.11.6" + "@webassemblyjs/leb128" "1.11.6" + "@webassemblyjs/utf8" "1.11.6" + +"@webassemblyjs/wasm-opt@1.12.1": + version "1.12.1" + resolved "https://registry.yarnpkg.com/@webassemblyjs/wasm-opt/-/wasm-opt-1.12.1.tgz#9e6e81475dfcfb62dab574ac2dda38226c232bc5" + integrity sha512-Jg99j/2gG2iaz3hijw857AVYekZe2SAskcqlWIZXjji5WStnOpVoat3gQfT/Q5tb2djnCjBtMocY/Su1GfxPBg== + dependencies: + "@webassemblyjs/ast" "1.12.1" + "@webassemblyjs/helper-buffer" "1.12.1" + "@webassemblyjs/wasm-gen" "1.12.1" + "@webassemblyjs/wasm-parser" "1.12.1" + +"@webassemblyjs/wasm-parser@1.12.1", "@webassemblyjs/wasm-parser@^1.12.1": + version "1.12.1" + resolved "https://registry.yarnpkg.com/@webassemblyjs/wasm-parser/-/wasm-parser-1.12.1.tgz#c47acb90e6f083391e3fa61d113650eea1e95937" + integrity sha512-xikIi7c2FHXysxXe3COrVUPSheuBtpcfhbpFj4gmu7KRLYOzANztwUU0IbsqvMqzuNK2+glRGWCEqZo1WCLyAQ== + dependencies: + "@webassemblyjs/ast" "1.12.1" + "@webassemblyjs/helper-api-error" "1.11.6" + "@webassemblyjs/helper-wasm-bytecode" "1.11.6" + "@webassemblyjs/ieee754" "1.11.6" + "@webassemblyjs/leb128" "1.11.6" + "@webassemblyjs/utf8" "1.11.6" + +"@webassemblyjs/wast-printer@1.12.1": + version "1.12.1" + resolved "https://registry.yarnpkg.com/@webassemblyjs/wast-printer/-/wast-printer-1.12.1.tgz#bcecf661d7d1abdaf989d8341a4833e33e2b31ac" + integrity sha512-+X4WAlOisVWQMikjbcvY2e0rwPsKQ9F688lksZhBcPycBBuii3O7m8FACbDMWDojpAqvjIncrG8J0XHKyQfVeA== + dependencies: + "@webassemblyjs/ast" "1.12.1" + "@xtuc/long" "4.2.2" + +"@webpack-cli/configtest@^2.1.1": + version "2.1.1" + resolved "https://registry.yarnpkg.com/@webpack-cli/configtest/-/configtest-2.1.1.tgz#3b2f852e91dac6e3b85fb2a314fb8bef46d94646" + integrity sha512-wy0mglZpDSiSS0XHrVR+BAdId2+yxPSoJW8fsna3ZpYSlufjvxnP4YbKTCBZnNIcGN4r6ZPXV55X4mYExOfLmw== + +"@webpack-cli/info@^2.0.2": + version "2.0.2" + resolved "https://registry.yarnpkg.com/@webpack-cli/info/-/info-2.0.2.tgz#cc3fbf22efeb88ff62310cf885c5b09f44ae0fdd" + integrity sha512-zLHQdI/Qs1UyT5UBdWNqsARasIA+AaF8t+4u2aS2nEpBQh2mWIVb8qAklq0eUENnC5mOItrIB4LiS9xMtph18A== + +"@webpack-cli/serve@^2.0.5": + version "2.0.5" + resolved "https://registry.yarnpkg.com/@webpack-cli/serve/-/serve-2.0.5.tgz#325db42395cd49fe6c14057f9a900e427df8810e" + integrity sha512-lqaoKnRYBdo1UgDX8uF24AfGMifWK19TxPmM5FHc2vAGxrJ/qtyUyFBWoY1tISZdelsQ5fBcOusifo5o5wSJxQ== "@xmldom/xmldom@^0.8.8": version "0.8.10" resolved "https://registry.yarnpkg.com/@xmldom/xmldom/-/xmldom-0.8.10.tgz#a1337ca426aa61cef9fe15b5b28e340a72f6fa99" integrity sha512-2WALfTl4xo2SkGCYRt6rDTFfk9R1czmBvUQy12gK2KuRKIpWEhcbbzy8EZXtz/jkRqHX8bFEc6FC1HjX4TUWYw== -abbrev@^1.0.0: - version "1.1.1" - resolved "https://registry.npmjs.org/abbrev/-/abbrev-1.1.1.tgz" - integrity sha512-nne9/IiQ/hzIhY6pdDnbBtz7DjPTKrY00P/zvPSm5pOFkl6xuGrGnXn/VtTNNfNtAfZ9/1RtehkszU9qcTii0Q== +"@xtuc/ieee754@^1.2.0": + version "1.2.0" + resolved "https://registry.yarnpkg.com/@xtuc/ieee754/-/ieee754-1.2.0.tgz#eef014a3145ae477a1cbc00cd1e552336dceb790" + integrity sha512-DX8nKgqcGwsc0eJSqYt5lwP4DH5FlHnmuWWBRy7X0NcaGR0ZtuyeESgMwTYVEtxmsNGY+qit4QYT/MIYTOTPeA== + +"@xtuc/long@4.2.2": + version "4.2.2" + resolved "https://registry.yarnpkg.com/@xtuc/long/-/long-4.2.2.tgz#d291c6a4e97989b5c61d9acf396ae4fe133a718d" + integrity sha512-NuHqBY1PB/D8xU6s/thBgOAiAP7HOYDQ32+BFZILJ8ivkUkAHQnWfn6WhL79Owj1qmUnoN/YPhktdIoucipkAQ== abortcontroller-polyfill@^1.7.5: version "1.7.5" @@ -910,6 +1533,16 @@ accepts@~1.3.8: mime-types "~2.1.34" negotiator "0.6.3" +acorn-import-attributes@^1.9.5: + version "1.9.5" + resolved "https://registry.yarnpkg.com/acorn-import-attributes/-/acorn-import-attributes-1.9.5.tgz#7eb1557b1ba05ef18b5ed0ec67591bfab04688ef" + integrity sha512-n02Vykv5uA3eHGM/Z2dQrcD56kL8TyDb2p1+0P83PClMnC/nc+anbQRhIOWnSq4Ke/KvDPrY3C9hDtC/A3eHnQ== + +acorn@^8.7.1, acorn@^8.8.2: + version "8.12.1" + resolved "https://registry.yarnpkg.com/acorn/-/acorn-8.12.1.tgz#71616bdccbe25e27a54439e0046e89ca76df2248" + integrity sha512-tcpGyI9zbizT9JbV6oYE477V6mTlXvvi0T0G3SNIYE2apm/G5huBa1+K89VGeovbg+jycCrfhl3ADxErOuO6Jg== + add@^2.0.6: version "2.0.6" resolved "https://registry.yarnpkg.com/add/-/add-2.0.6.tgz#248f0a9f6e5a528ef2295dbeec30532130ae2235" @@ -920,7 +1553,7 @@ aes-js@3.0.0: resolved "https://registry.yarnpkg.com/aes-js/-/aes-js-3.0.0.tgz#e21df10ad6c2053295bcbb8dab40b09dbea87e4d" integrity sha512-H7wUZRn8WpTq9jocdxQ2c8x2sKo9ZVmzfRE13GiNJXfp7NcKYEdvl3vspKjXox6RIG2VtaRe4JFvxG4rqp2Zuw== -agent-base@6, agent-base@^6.0.2: +agent-base@6: version "6.0.2" resolved "https://registry.npmjs.org/agent-base/-/agent-base-6.0.2.tgz" integrity sha512-RZNwNclF7+MS/8bDg70amg32dyeZGZxiDuQmZxKLAlQjr3jGyLx+4Kkk58UO7D2QdgFIQCovuSuZESne6RG6XQ== @@ -934,29 +1567,20 @@ agent-base@^7.0.2: dependencies: debug "^4.3.4" -agentkeepalive@^4.2.1: - version "4.3.0" - resolved "https://registry.npmjs.org/agentkeepalive/-/agentkeepalive-4.3.0.tgz" - integrity sha512-7Epl1Blf4Sy37j4v9f9FjICCh4+KAQOyXgHEwlyBiAQLbhKdq/i2QQU3amQalS/wPhdPzDXPL5DMR5bkn+YeWg== - dependencies: - debug "^4.1.0" - depd "^2.0.0" - humanize-ms "^1.2.1" - -aggregate-error@^3.0.0: +aggregate-error@^3.1.0: version "3.1.0" - resolved "https://registry.npmjs.org/aggregate-error/-/aggregate-error-3.1.0.tgz" + resolved "https://registry.yarnpkg.com/aggregate-error/-/aggregate-error-3.1.0.tgz#92670ff50f5359bdb7a3e0d40d0ec30c5737687a" integrity sha512-4I7Td01quW/RpocfNayFdFVk1qSuoh0E7JrbRJ16nH01HhKFQ88INq9Sd+nd72zqRySlr9BmDA8xlEJ6vJMrYA== dependencies: clean-stack "^2.0.0" indent-string "^4.0.0" -ajv-keywords@^3.4.1: +ajv-keywords@^3.4.1, ajv-keywords@^3.5.2: version "3.5.2" resolved "https://registry.npmjs.org/ajv-keywords/-/ajv-keywords-3.5.2.tgz" integrity sha512-5p6WTN0DdTGVQk6VjcEju19IgaHudalcfabD7yhDGeA6bcQnmL+CpveLJq/3hvfwd1aof6L386Ougkx6RfyMIQ== -ajv@^6.10.0, ajv@^6.12.0, ajv@^6.12.3: +ajv@^6.10.0, ajv@^6.12.0, ajv@^6.12.3, ajv@^6.12.5: version "6.12.6" resolved "https://registry.npmjs.org/ajv/-/ajv-6.12.6.tgz" integrity sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g== @@ -966,6 +1590,18 @@ ajv@^6.10.0, ajv@^6.12.0, ajv@^6.12.3: json-schema-traverse "^0.4.1" uri-js "^4.2.2" +ansi-align@^3.0.0: + version "3.0.1" + resolved "https://registry.yarnpkg.com/ansi-align/-/ansi-align-3.0.1.tgz#0cdf12e111ace773a86e9a1fad1225c43cb19a59" + integrity sha512-IOfwwBF5iczOjp/WeY4YxyjqAFMQoZufdQWDd19SEExbVLNXqvpzSJ/M7Za4/sCPmQ0+GRquoA7bGcINcxew6w== + dependencies: + string-width "^4.1.0" + +ansi-colors@4.1.1: + version "4.1.1" + resolved "https://registry.yarnpkg.com/ansi-colors/-/ansi-colors-4.1.1.tgz#cbb9ae256bf750af1eab344f229aa27fe94ba348" + integrity sha512-JoX0apGbHaUJBNl6yF+p6JAFYZ666/hhCGKN5t9QFjbJQKUU/g8MNbFDbvfrgKXvI1QpZplPOnwIo99lX/AAmA== + ansi-regex@^5.0.1: version "5.0.1" resolved "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz" @@ -973,7 +1609,7 @@ ansi-regex@^5.0.1: ansi-regex@^6.0.1: version "6.0.1" - resolved "https://registry.npmjs.org/ansi-regex/-/ansi-regex-6.0.1.tgz" + resolved "https://registry.yarnpkg.com/ansi-regex/-/ansi-regex-6.0.1.tgz#3183e38fae9a65d7cb5e53945cd5897d0260a06a" integrity sha512-n5M855fKb2SsfMIiFFoVrABHJC8QtHwVx+mHWP3QcEqBHYienj5dHSgjbxtC0WEZXYt4wcD6zrQElDPhFuZgfA== ansi-styles@^4.0.0, ansi-styles@^4.1.0: @@ -985,9 +1621,16 @@ ansi-styles@^4.0.0, ansi-styles@^4.1.0: ansi-styles@^6.1.0: version "6.2.1" - resolved "https://registry.npmjs.org/ansi-styles/-/ansi-styles-6.2.1.tgz" + resolved "https://registry.yarnpkg.com/ansi-styles/-/ansi-styles-6.2.1.tgz#0e62320cf99c21afff3b3012192546aacbfb05c5" integrity sha512-bN798gFfQX+viw3R7yrGWRqnrN2oRkEkUjjl4JNn4E8GxxbjtG3FbrEIIY3l8/hrwUwIeCZvi4QuOTP4MErVug== +ansi-to-html@0.7.2: + version "0.7.2" + resolved "https://registry.yarnpkg.com/ansi-to-html/-/ansi-to-html-0.7.2.tgz#a92c149e4184b571eb29a0135ca001a8e2d710cb" + integrity sha512-v6MqmEpNlxF+POuyhKkidusCHWWkaLcGRURzivcU3I9tv7k4JVhFcnukrM5Rlk2rUywdZuzYAZ+kbZqWCnfN3g== + dependencies: + entities "^2.2.0" + anymatch@~3.1.2: version "3.1.3" resolved "https://registry.npmjs.org/anymatch/-/anymatch-3.1.3.tgz" @@ -998,54 +1641,43 @@ anymatch@~3.1.2: app-builder-bin@4.0.0: version "4.0.0" - resolved "https://registry.npmjs.org/app-builder-bin/-/app-builder-bin-4.0.0.tgz" + resolved "https://registry.yarnpkg.com/app-builder-bin/-/app-builder-bin-4.0.0.tgz#1df8e654bd1395e4a319d82545c98667d7eed2f0" integrity sha512-xwdG0FJPQMe0M0UA4Tz0zEB8rBJTRA5a476ZawAqiBkMv16GRK5xpXThOjMaEOFnZ6zabejjG4J3da0SXG63KA== -app-builder-lib@23.6.0: - version "23.6.0" - resolved "https://registry.yarnpkg.com/app-builder-lib/-/app-builder-lib-23.6.0.tgz#03cade02838c077db99d86212d61c5fc1d6da1a8" - integrity sha512-dQYDuqm/rmy8GSCE6Xl/3ShJg6Ab4bZJMT8KaTKGzT436gl1DN4REP3FCWfXoh75qGTJ+u+WsdnnpO9Jl8nyMA== +app-builder-lib@24.9.1: + version "24.9.1" + resolved "https://registry.yarnpkg.com/app-builder-lib/-/app-builder-lib-24.9.1.tgz#bf3568529298b4de8595ed1acbb351fe27db5ba4" + integrity sha512-Q1nYxZcio4r+W72cnIRVYofEAyjBd3mG47o+zms8HlD51zWtA/YxJb01Jei5F+jkWhge/PTQK+uldsPh6d0/4g== dependencies: - "7zip-bin" "~5.1.1" + "7zip-bin" "~5.2.0" "@develar/schema-utils" "~2.6.5" - "@electron/universal" "1.2.1" + "@electron/notarize" "2.1.0" + "@electron/osx-sign" "1.0.5" + "@electron/universal" "1.4.1" "@malept/flatpak-bundler" "^0.4.0" + "@types/fs-extra" "9.0.13" async-exit-hook "^2.0.1" bluebird-lst "^1.0.9" - builder-util "23.6.0" - builder-util-runtime "9.1.1" + builder-util "24.8.1" + builder-util-runtime "9.2.3" chromium-pickle-js "^0.2.0" debug "^4.3.4" - ejs "^3.1.7" - electron-osx-sign "^0.6.0" - electron-publish "23.6.0" + ejs "^3.1.8" + electron-publish "24.8.1" form-data "^4.0.0" fs-extra "^10.1.0" hosted-git-info "^4.1.0" is-ci "^3.0.0" - isbinaryfile "^4.0.10" + isbinaryfile "^5.0.0" js-yaml "^4.1.0" lazy-val "^1.0.5" - minimatch "^3.1.2" - read-config-file "6.2.0" + minimatch "^5.1.1" + read-config-file "6.3.2" sanitize-filename "^1.6.3" - semver "^7.3.7" - tar "^6.1.11" + semver "^7.3.8" + tar "^6.1.12" temp-file "^3.4.0" -"aproba@^1.0.3 || ^2.0.0": - version "2.0.0" - resolved "https://registry.npmjs.org/aproba/-/aproba-2.0.0.tgz" - integrity sha512-lYe4Gx7QT+MKGbDsA+Z+he/Wtef0BiwDOlK/XkBrdfsh9J/jPPXbX0tE9x9cl27Tmu5gg3QUbUrQYa/y+KOHPQ== - -are-we-there-yet@^3.0.0: - version "3.0.1" - resolved "https://registry.npmjs.org/are-we-there-yet/-/are-we-there-yet-3.0.1.tgz" - integrity sha512-QZW4EDmGwlYur0Yyf/b2uGucHQMa8aFUP7eu9ddR73vvhFyt4V0Vl3QHPcTNJ8l6qYOBdxgXdnBXQrHilfRQBg== - dependencies: - delegates "^1.0.0" - readable-stream "^3.6.0" - argparse@^2.0.1: version "2.0.1" resolved "https://registry.npmjs.org/argparse/-/argparse-2.0.1.tgz" @@ -1087,17 +1719,10 @@ arraybuffer.prototype.slice@^1.0.2: is-array-buffer "^3.0.2" is-shared-array-buffer "^1.0.2" -asar@^3.1.0: - version "3.2.0" - resolved "https://registry.yarnpkg.com/asar/-/asar-3.2.0.tgz#e6edb5edd6f627ebef04db62f771c61bea9c1221" - integrity sha512-COdw2ZQvKdFGFxXwX3oYh2/sOsJWJegrdJCGxnN4MZ7IULgRBp9P6665aqj9z1v9VwP4oP1hRBojRDQ//IGgAg== - dependencies: - chromium-pickle-js "^0.2.0" - commander "^5.0.0" - glob "^7.1.6" - minimatch "^3.0.4" - optionalDependencies: - "@types/glob" "^7.1.1" +arrify@^2.0.1: + version "2.0.1" + resolved "https://registry.yarnpkg.com/arrify/-/arrify-2.0.1.tgz#c9655e9331e0abcd588d2a7cad7e9956f66701fa" + integrity sha512-3duEwti880xqi4eAMN8AyR4a0ByT90zoYdLlevfrvU43vb0YZwZVfxOgxWrLXXXpyugL0hNZc9G6BiB5B3nUug== asn1@~0.2.3: version "0.2.6" @@ -1111,6 +1736,11 @@ assert-plus@1.0.0, assert-plus@^1.0.0: resolved "https://registry.npmjs.org/assert-plus/-/assert-plus-1.0.0.tgz" integrity sha512-NfJ4UzBCcQGLDlQq7nHxH+tv3kyZ0hHQqF5BO6J7tNJeP5do1llPr8dZ8zHonfhAu0PHAdMkSo+8o0wxg9lZWw== +assertion-error@1.1.0: + version "1.1.0" + resolved "https://registry.yarnpkg.com/assertion-error/-/assertion-error-1.1.0.tgz#e60b6b0e8f301bd97e5375215bda406c85118c0b" + integrity sha512-jgsaNduz+ndvGyFt3uSuWqvy4lCnIJiovtouQN5JZHOKCS2QuhEdbcQHFhVksz2N2U9hXJo8odG7ETyWlEeuDw== + astral-regex@^2.0.0: version "2.0.0" resolved "https://registry.npmjs.org/astral-regex/-/astral-regex-2.0.0.tgz" @@ -1161,6 +1791,11 @@ aws4@^1.8.0: resolved "https://registry.yarnpkg.com/aws4/-/aws4-1.12.0.tgz#ce1c9d143389679e253b314241ea9aa5cec980d3" integrity sha512-NmWvPnx0F1SfrQbYwOi7OeaNGokp9XhzNioJ/CSBs8Qa4vxug81mhJEAVZwxXuBmYB5KDRfMq/F3RR0BIU7sWg== +axe-core@^4.4.3: + version "4.8.3" + resolved "https://registry.yarnpkg.com/axe-core/-/axe-core-4.8.3.tgz#205df863dd9917d5979e9435dab4d47692759051" + integrity sha512-d5ZQHPSPkF9Tw+yfyDcRoUOc4g/8UloJJe5J8m4L5+c7AtDdjDLRxew/knnI4CxvtdxEUVgWz4x3OIQUIFiMfw== + axios@1.2.2: version "1.2.2" resolved "https://registry.yarnpkg.com/axios/-/axios-1.2.2.tgz#72681724c6e6a43a9fea860fc558127dbe32f9f1" @@ -1170,6 +1805,23 @@ axios@1.2.2: form-data "^4.0.0" proxy-from-env "^1.1.0" +axios@^0.27.2: + version "0.27.2" + resolved "https://registry.yarnpkg.com/axios/-/axios-0.27.2.tgz#207658cc8621606e586c85db4b41a750e756d972" + integrity sha512-t+yRIyySRTp/wua5xEr+z1q60QmLq8ABsS5O9Me1AsE5dfKqgnCFzwiCZZ/cGNd1lq4/7akDWMxdhVlucjmnOQ== + dependencies: + follow-redirects "^1.14.9" + form-data "^4.0.0" + +axios@^1.4.0: + version "1.6.8" + resolved "https://registry.yarnpkg.com/axios/-/axios-1.6.8.tgz#66d294951f5d988a00e87a0ffb955316a619ea66" + integrity sha512-v/ZHtJDU39mDpyBoFVkETcd/uNdxrWRrg3bKpOKzXFA6Bvqopts6ALSMU3y6ijYxbw2B+wPrIv46egTzJXCLGQ== + dependencies: + follow-redirects "^1.15.6" + form-data "^4.0.0" + proxy-from-env "^1.1.0" + axios@^1.7.4: version "1.7.4" resolved "https://registry.yarnpkg.com/axios/-/axios-1.7.4.tgz#4c8ded1b43683c8dd362973c393f3ede24052aa2" @@ -1179,6 +1831,11 @@ axios@^1.7.4: form-data "^4.0.0" proxy-from-env "^1.1.0" +b4a@^1.6.4: + version "1.6.4" + resolved "https://registry.yarnpkg.com/b4a/-/b4a-1.6.4.tgz#ef1c1422cae5ce6535ec191baeed7567443f36c9" + integrity sha512-fpWrvyVHEKyeEvbKZTVOeZF3VSKKWtJxFIxX/jaVPf+cLbGUSitjb49pHLqPV2BUNNZ0LcoeEGfE/YCpyDYHIw== + balanced-match@^1.0.0: version "1.0.2" resolved "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz" @@ -1208,6 +1865,16 @@ bech32@1.1.4: resolved "https://registry.yarnpkg.com/bech32/-/bech32-1.1.4.tgz#e38c9f37bf179b8eb16ae3a772b40c356d4832e9" integrity sha512-s0IrSOzLlbvX7yp4WBfPITzpAU8sqQcpsmwXDiKwrG4r491vwCO/XpejasRNl0piBMe/DvP4Tz0mIS/X1DPJBQ== +before-after-hook@^2.2.0: + version "2.2.3" + resolved "https://registry.yarnpkg.com/before-after-hook/-/before-after-hook-2.2.3.tgz#c51e809c81a4e354084422b9b26bad88249c517c" + integrity sha512-NzUnlZexiaH/46WDhANlyR2bXRopNg4F/zuSA3OpZnllCUgRaOF2znDioDWrmbNVsuZk6l9pMquQB38cfBZwkQ== + +big.js@^5.2.2: + version "5.2.2" + resolved "https://registry.yarnpkg.com/big.js/-/big.js-5.2.2.tgz#65f0af382f578bcdc742bd9c281e9cb2d7768328" + integrity sha512-vyL2OymJxmarO8gxMr0mhChsO9QGwhynfuu4+MHTAW6czfq9humCB7rKpUjDd9YUiDPU4mzpyupFSvOClAwbmQ== + bignumber.js@^9.0.0: version "9.1.2" resolved "https://registry.yarnpkg.com/bignumber.js/-/bignumber.js-9.1.2.tgz#b7c4242259c008903b13707983b5f4bbd31eda0c" @@ -1282,6 +1949,25 @@ boolean@^3.0.1: resolved "https://registry.npmjs.org/boolean/-/boolean-3.2.0.tgz" integrity sha512-d0II/GO9uf9lfUHH2BQsjxzRJZBdsjgsBiW4BvhWk/3qoKwQFjIDVN19PfX8F2D/r9PCMTtLWjYVCFrpeYUzsw== +bottleneck@^2.15.3: + version "2.19.5" + resolved "https://registry.yarnpkg.com/bottleneck/-/bottleneck-2.19.5.tgz#5df0b90f59fd47656ebe63c78a98419205cadd91" + integrity sha512-VHiNCbI1lKdl44tGrhNfU3lup0Tj/ZBMJB5/2ZbNXRCPuRCO7ed2mgcK4r17y+KB2EfuYuRaVlwNbAeaWGSpbw== + +boxen@5.1.2: + version "5.1.2" + resolved "https://registry.yarnpkg.com/boxen/-/boxen-5.1.2.tgz#788cb686fc83c1f486dfa8a40c68fc2b831d2b50" + integrity sha512-9gYgQKXx+1nP8mP7CzFyaUARhg7D3n1dF/FnErWmu9l6JvGpNUN278h0aSb+QjoiKSWG+iZ3uHrcqk0qrY9RQQ== + dependencies: + ansi-align "^3.0.0" + camelcase "^6.2.0" + chalk "^4.1.0" + cli-boxes "^2.2.1" + string-width "^4.2.2" + type-fest "^0.20.2" + widest-line "^3.1.0" + wrap-ansi "^7.0.0" + brace-expansion@^1.1.7: version "1.1.11" resolved "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz" @@ -1297,7 +1983,7 @@ brace-expansion@^2.0.1: dependencies: balanced-match "^1.0.0" -braces@~3.0.2: +braces@^3.0.3, braces@~3.0.2: version "3.0.3" resolved "https://registry.yarnpkg.com/braces/-/braces-3.0.3.tgz#490332f40919452272d55a8480adc0c441358789" integrity sha512-yQbXgO/OSZVD2IsiLlro+7Hf6Q18EJrKSEsdoMzKePKXct3gvD8oLcOQdIzGupr5Fj+EDe8gO/lxc1BzfMpxvA== @@ -1309,6 +1995,11 @@ brorand@^1.1.0: resolved "https://registry.yarnpkg.com/brorand/-/brorand-1.1.0.tgz#12c25efe40a45e3c323eb8675a0a0ce57b22371f" integrity sha512-cKV8tMCEpQs4hK/ik71d6LrPOnpkpGBR0wzxqr68g2m/LB2GxVYQroAjMJZRVM1Y4BCjCKc3vAamxSzOY2RP+w== +browser-stdout@1.3.1: + version "1.3.1" + resolved "https://registry.yarnpkg.com/browser-stdout/-/browser-stdout-1.3.1.tgz#baa559ee14ced73452229bad7326467c61fabd60" + integrity sha512-qhAVI1+Av2X7qelOfAIYwXONood6XlZE/fXaBSmW/T5SzLAmCgzi+eiWE7fUvbHaeNBQH13UftjpXxsfLkMpgw== + browserify-aes@^1.2.0: version "1.2.0" resolved "https://registry.yarnpkg.com/browserify-aes/-/browserify-aes-1.2.0.tgz#326734642f403dabc3003209853bb70ad428ef48" @@ -1321,6 +2012,16 @@ browserify-aes@^1.2.0: inherits "^2.0.1" safe-buffer "^5.0.1" +browserslist@^4.21.10: + version "4.23.1" + resolved "https://registry.yarnpkg.com/browserslist/-/browserslist-4.23.1.tgz#ce4af0534b3d37db5c1a4ca98b9080f985041e96" + integrity sha512-TUfofFo/KsK/bWZ9TWQ5O26tsWW4Uhmt8IYklbnUa70udB6P2wA7w7o4PY4muaEPBQaAX+CEnmmIA41NVHtPVw== + dependencies: + caniuse-lite "^1.0.30001629" + electron-to-chromium "^1.4.796" + node-releases "^2.0.14" + update-browserslist-db "^1.0.16" + bs58@^4.0.0: version "4.0.1" resolved "https://registry.yarnpkg.com/bs58/-/bs58-4.0.1.tgz#be161e76c354f6f788ae4071f63f34e8c4f0a42a" @@ -1337,33 +2038,25 @@ bs58check@^2.1.2: create-hash "^1.1.0" safe-buffer "^5.1.2" -buffer-alloc-unsafe@^1.1.0: - version "1.1.0" - resolved "https://registry.yarnpkg.com/buffer-alloc-unsafe/-/buffer-alloc-unsafe-1.1.0.tgz#bd7dc26ae2972d0eda253be061dba992349c19f0" - integrity sha512-TEM2iMIEQdJ2yjPJoSIsldnleVaAk1oW3DBVUykyOLsEsFmEc9kn+SFFPz+gl54KQNxlDnAwCXosOS9Okx2xAg== - -buffer-alloc@^1.2.0: - version "1.2.0" - resolved "https://registry.yarnpkg.com/buffer-alloc/-/buffer-alloc-1.2.0.tgz#890dd90d923a873e08e10e5fd51a57e5b7cce0ec" - integrity sha512-CFsHQgjtW1UChdXgbyJGtnm+O/uLQeZdtbDo8mfUgYXCHSM1wgrVxXm6bSyrUuErEb+4sYVGCzASBRot7zyrow== - dependencies: - buffer-alloc-unsafe "^1.1.0" - buffer-fill "^1.0.0" +btoa-lite@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/btoa-lite/-/btoa-lite-1.0.0.tgz#337766da15801210fdd956c22e9c6891ab9d0337" + integrity sha512-gvW7InbIyF8AicrqWoptdW08pUxuhq8BEgowNajy9RhiE86fmGAGl+bLKo6oB8QP0CkqHLowfN0oJdKC/J6LbA== buffer-crc32@~0.2.3: version "0.2.13" resolved "https://registry.npmjs.org/buffer-crc32/-/buffer-crc32-0.2.13.tgz" integrity sha512-VO9Ht/+p3SN7SKWqcrgEzjGbRSJYTx+Q1pTQC0wrWqHx0vpJraQ6GtHx8tvcg1rlK1byhU5gccxgOgj7B0TDkQ== -buffer-equal@1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/buffer-equal/-/buffer-equal-1.0.0.tgz#59616b498304d556abd466966b22eeda3eca5fbe" - integrity sha512-tcBWO2Dl4e7Asr9hTGcpVrCe+F7DubpmqWCTbj4FHLmjqO2hIaC383acQubWtRJhdceqs5uBHs6Es+Sk//RKiQ== +buffer-equal-constant-time@1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/buffer-equal-constant-time/-/buffer-equal-constant-time-1.0.1.tgz#f8e71132f7ffe6e01a5c9697a4c6f3e48d5cc819" + integrity sha512-zRpUiDwd/xk6ADqPMATG8vc9VPrkck7T07OIx0gnjmJAnHnTVXNQG3vfvWNuiZIkwu9KrKdA1iJKfsfTVxE6NA== -buffer-fill@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/buffer-fill/-/buffer-fill-1.0.0.tgz#f8f78b76789888ef39f205cd637f68e702122b2c" - integrity sha512-T7zexNBwiiaCOGDg9xNX9PBmjrubblRkENuptryuI64URkXDFum9il/JGL8Lm8wYfAXpredVXXZz7eMHilimiQ== +buffer-equal@^1.0.0: + version "1.0.1" + resolved "https://registry.yarnpkg.com/buffer-equal/-/buffer-equal-1.0.1.tgz#2f7651be5b1b3f057fcd6e7ee16cf34767077d90" + integrity sha512-QoV3ptgEaQpvVwbXdSO39iqPQTCxSF7A5U99AxbHYqUdCizL/lH2Z0A2y6nbZucxMEOtNyZfG2s6gsVugGpKkg== buffer-from@^1.0.0: version "1.1.2" @@ -1395,31 +2088,38 @@ bufferutil@^4.0.1: dependencies: node-gyp-build "^4.3.0" -builder-util-runtime@9.1.1: - version "9.1.1" - resolved "https://registry.yarnpkg.com/builder-util-runtime/-/builder-util-runtime-9.1.1.tgz#2da7b34e78a64ad14ccd070d6eed4662d893bd60" - integrity sha512-azRhYLEoDvRDR8Dhis4JatELC/jUvYjm4cVSj7n9dauGTOM2eeNn9KS0z6YA6oDsjI1xphjNbY6PZZeHPzzqaw== +builder-util-runtime@9.2.3: + version "9.2.3" + resolved "https://registry.yarnpkg.com/builder-util-runtime/-/builder-util-runtime-9.2.3.tgz#0a82c7aca8eadef46d67b353c638f052c206b83c" + integrity sha512-FGhkqXdFFZ5dNC4C+yuQB9ak311rpGAw+/ASz8ZdxwODCv1GGMWgLDeofRkdi0F3VCHQEWy/aXcJQozx2nOPiw== + dependencies: + debug "^4.3.4" + sax "^1.2.4" + +builder-util-runtime@9.2.5: + version "9.2.5" + resolved "https://registry.yarnpkg.com/builder-util-runtime/-/builder-util-runtime-9.2.5.tgz#0afdffa0adb5c84c14926c7dd2cf3c6e96e9be83" + integrity sha512-HjIDfhvqx/8B3TDN4GbABQcgpewTU4LMRTQPkVpKYV3lsuxEJoIfvg09GyWTNmfVNSUAYf+fbTN//JX4TH20pg== dependencies: debug "^4.3.4" sax "^1.2.4" -builder-util@23.6.0: - version "23.6.0" - resolved "https://registry.yarnpkg.com/builder-util/-/builder-util-23.6.0.tgz#1880ec6da7da3fd6fa19b8bd71df7f39e8d17dd9" - integrity sha512-QiQHweYsh8o+U/KNCZFSvISRnvRctb8m/2rB2I1JdByzvNKxPeFLlHFRPQRXab6aYeXc18j9LpsDLJ3sGQmWTQ== +builder-util@24.8.1: + version "24.8.1" + resolved "https://registry.yarnpkg.com/builder-util/-/builder-util-24.8.1.tgz#594d45b0c86d1d17f5c7bebbb77405080b2571c2" + integrity sha512-ibmQ4BnnqCnJTNrdmdNlnhF48kfqhNzSeqFMXHLIl+o9/yhn6QfOaVrloZ9YUu3m0k3rexvlT5wcki6LWpjTZw== dependencies: - "7zip-bin" "~5.1.1" + "7zip-bin" "~5.2.0" "@types/debug" "^4.1.6" - "@types/fs-extra" "^9.0.11" app-builder-bin "4.0.0" bluebird-lst "^1.0.9" - builder-util-runtime "9.1.1" - chalk "^4.1.1" + builder-util-runtime "9.2.3" + chalk "^4.1.2" cross-spawn "^7.0.3" debug "^4.3.4" - fs-extra "^10.0.0" + fs-extra "^10.1.0" http-proxy-agent "^5.0.0" - https-proxy-agent "^5.0.0" + https-proxy-agent "^5.0.1" is-ci "^3.0.0" js-yaml "^4.1.0" source-map-support "^0.5.19" @@ -1436,24 +2136,6 @@ bytes@3.1.2: resolved "https://registry.yarnpkg.com/bytes/-/bytes-3.1.2.tgz#8b0beeb98605adf1b128fa4386403c009e0221a5" integrity sha512-/Nf7TyzTx6S3yRJObOAV7956r8cr2+Oj8AC5dt8wSP3BQAoeX58NoHyCU8P8zGkNXStjTSi6fzO6F0pBdcYbEg== -cacache@^17.0.0: - version "17.1.3" - resolved "https://registry.npmjs.org/cacache/-/cacache-17.1.3.tgz" - integrity sha512-jAdjGxmPxZh0IipMdR7fK/4sDSrHMLUV0+GvVUsjwyGNKHsh79kW/otg+GkbXwl6Uzvy9wsvHOX4nUoWldeZMg== - dependencies: - "@npmcli/fs" "^3.1.0" - fs-minipass "^3.0.0" - glob "^10.2.2" - lru-cache "^7.7.1" - minipass "^5.0.0" - minipass-collect "^1.0.2" - minipass-flush "^1.0.5" - minipass-pipeline "^1.2.4" - p-map "^4.0.0" - ssri "^10.0.0" - tar "^6.1.11" - unique-filename "^3.0.0" - cacheable-lookup@^5.0.3: version "5.0.4" resolved "https://registry.npmjs.org/cacheable-lookup/-/cacheable-lookup-5.0.4.tgz" @@ -1497,20 +2179,47 @@ call-bind@^1.0.7: get-intrinsic "^1.2.4" set-function-length "^1.2.1" +camelcase@^6.0.0, camelcase@^6.2.0: + version "6.3.0" + resolved "https://registry.yarnpkg.com/camelcase/-/camelcase-6.3.0.tgz#5685b95eb209ac9c0c177467778c9c84df58ba9a" + integrity sha512-Gmy6FhYlCY7uOElZUSbxo2UCDH8owEk996gkbrpsgGtrJLM3J7jGxl9Ic7Qwwj4ivOE5AWZWRMecDdF7hqGjFA== + +caniuse-lite@^1.0.30001629: + version "1.0.30001640" + resolved "https://registry.yarnpkg.com/caniuse-lite/-/caniuse-lite-1.0.30001640.tgz#32c467d4bf1f1a0faa63fc793c2ba81169e7652f" + integrity sha512-lA4VMpW0PSUrFnkmVuEKBUovSWKhj7puyCg8StBChgu298N1AtuF1sKWEvfDuimSEDbhlb/KqPKC3fs1HbuQUA== + caseless@~0.12.0: version "0.12.0" resolved "https://registry.yarnpkg.com/caseless/-/caseless-0.12.0.tgz#1b681c21ff84033c826543090689420d187151dc" integrity sha512-4tYFyifaFfGacoiObjJegolkwSU4xQNGbVgUiNYVUxbQ2x2lUsFvY4hVgVzGiIe6WLOPqycWXA40l+PWsxthUw== -chalk@^4.0.0, chalk@^4.0.2, chalk@^4.1.0, chalk@^4.1.1: +chai-nightwatch@0.5.3: + version "0.5.3" + resolved "https://registry.yarnpkg.com/chai-nightwatch/-/chai-nightwatch-0.5.3.tgz#980ecf63dde5a04e7f3524370682c7ff01178ffb" + integrity sha512-38ixH/mqpY6IwnZkz6xPqx8aB5/KVR+j6VPugcir3EGOsphnWXrPH/mUt8Jp+ninL6ghY0AaJDQ10hSfCPGy/g== + dependencies: + assertion-error "1.1.0" + +chalk@^4.0.0, chalk@^4.0.2, chalk@^4.1.0, chalk@^4.1.2: version "4.1.2" - resolved "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz" + resolved "https://registry.yarnpkg.com/chalk/-/chalk-4.1.2.tgz#aac4e2b7734a740867aeb16bf02aad556a1e7a01" integrity sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA== dependencies: ansi-styles "^4.1.0" supports-color "^7.1.0" -chokidar@^3.5.3: +charenc@0.0.2: + version "0.0.2" + resolved "https://registry.yarnpkg.com/charenc/-/charenc-0.0.2.tgz#c0a1d2f3a7092e03774bfa83f14c0fc5790a8667" + integrity sha512-yrLQ/yVUFXkzg7EDQsPieE/53+0RlaWTs+wBrvW36cyilJ2SaDWfl4Yj7MtLTXleV9uEKefbAGUPv2/iWSooRA== + +check-error@1.0.2: + version "1.0.2" + resolved "https://registry.yarnpkg.com/check-error/-/check-error-1.0.2.tgz#574d312edd88bb5dd8912e9286dd6c0aed4aac82" + integrity sha512-BrgHpW9NURQgzoNyjfq0Wu6VFO6D7IZEmJNdtgNqpzGG8RuNFHt2jQxWlAs4HMe119chBnv+34syEZtc6IhLtA== + +chokidar@3.5.3, chokidar@^3.5.3: version "3.5.3" resolved "https://registry.npmjs.org/chokidar/-/chokidar-3.5.3.tgz" integrity sha512-Dr3sfKRP6oTcjf2JmUmFJfeVMvXBdegxB0iVQ5eb2V10uFJUCAS8OByZdVAyVb8xXNz3GjjTgj9kLWsZTqE6kw== @@ -1535,11 +2244,34 @@ chownr@^2.0.0: resolved "https://registry.npmjs.org/chownr/-/chownr-2.0.0.tgz" integrity sha512-bIomtDF5KGpdogkLd9VspvFzk9KfpyyGlS8YFVZl7TGPBHL5snIOnxeshwVgPteQ9b4Eydl+pVbIyE1DcvCWgQ== +chrome-trace-event@^1.0.2: + version "1.0.4" + resolved "https://registry.yarnpkg.com/chrome-trace-event/-/chrome-trace-event-1.0.4.tgz#05bffd7ff928465093314708c93bdfa9bd1f0f5b" + integrity sha512-rNjApaLzuwaOTjCiT8lSDdGN1APCiqkChLMJxJPWLunPAt5fy8xgU9/jNOchV84wfIxrA0lRQB7oCT8jrn/wrQ== + +chromedriver@116: + version "116.0.0" + resolved "https://registry.yarnpkg.com/chromedriver/-/chromedriver-116.0.0.tgz#3f5d07b5427953270461791651d7b68cb6afe9fe" + integrity sha512-/TQaRn+RUAYnVqy5Vx8VtU8DvtWosU8QLM2u7BoNM5h55PRQPXF/onHAehEi8Sj/CehdKqH50NFdiumQAUr0DQ== + dependencies: + "@testim/chrome-version" "^1.1.3" + axios "^1.4.0" + compare-versions "^6.0.0" + extract-zip "^2.0.1" + https-proxy-agent "^5.0.1" + proxy-from-env "^1.1.0" + tcp-port-used "^1.0.1" + chromium-pickle-js@^0.2.0: version "0.2.0" resolved "https://registry.npmjs.org/chromium-pickle-js/-/chromium-pickle-js-0.2.0.tgz" integrity sha512-1R5Fho+jBq0DDydt+/vHWj5KJNJCKdARKOCwZUen84I5BreWoLqRLANH1U87eJy1tiASPtMnGqJJq0ZsLoRPOw== +ci-info@3.3.0: + version "3.3.0" + resolved "https://registry.yarnpkg.com/ci-info/-/ci-info-3.3.0.tgz#b4ed1fb6818dea4803a55c623041f9165d2066b2" + integrity sha512-riT/3vI5YpVH6/qomlDnJow6TBee2PBKSEpx3O32EGPYbWGIRsIlGRms3Sm74wYE1JMo8RnO04Hb12+v1J5ICw== + ci-info@^3.2.0: version "3.8.0" resolved "https://registry.npmjs.org/ci-info/-/ci-info-3.8.0.tgz" @@ -1576,20 +2308,25 @@ clean-git-ref@^2.0.1: clean-stack@^2.0.0: version "2.2.0" - resolved "https://registry.npmjs.org/clean-stack/-/clean-stack-2.2.0.tgz" + resolved "https://registry.yarnpkg.com/clean-stack/-/clean-stack-2.2.0.tgz#ee8472dbb129e727b31e8a10a427dee9dfe4008b" integrity sha512-4diC9HaTE+KRAMWhDhrGOECgWZxoevMc5TlkObMqNSsVU62PYzXZ/SMTjzyGAFF1YusgxGcSWTEXBhp0CPwQ1A== +cli-boxes@^2.2.1: + version "2.2.1" + resolved "https://registry.yarnpkg.com/cli-boxes/-/cli-boxes-2.2.1.tgz#ddd5035d25094fce220e9cab40a45840a440318f" + integrity sha512-y4coMcylgSCdVinjiDBuR8PCC2bLjyGTwEmPb9NHR/QaNU6EUOXcTY/s6VjGMD6ENSEaeQYHCY0GNGS5jfMwPw== + cli-cursor@^3.1.0: version "3.1.0" - resolved "https://registry.npmjs.org/cli-cursor/-/cli-cursor-3.1.0.tgz" + resolved "https://registry.yarnpkg.com/cli-cursor/-/cli-cursor-3.1.0.tgz#264305a7ae490d1d03bf0c9ba7c925d1753af307" integrity sha512-I/zHAwsKf9FqGoXM4WWRACob9+SNukZTd94DWF57E4toouRulbCxcUh6RKUEOQlYTHJnzkPMySvPNaaSLNfLZw== dependencies: restore-cursor "^3.1.0" cli-spinners@^2.5.0: - version "2.9.0" - resolved "https://registry.npmjs.org/cli-spinners/-/cli-spinners-2.9.0.tgz" - integrity sha512-4/aL9X3Wh0yiMQlE+eeRhWP6vclO3QRtw1JHKIT0FFUs5FjpFmESqtMvYZ0+lbzBw900b95mS0hohy+qn2VK/g== + version "2.9.2" + resolved "https://registry.yarnpkg.com/cli-spinners/-/cli-spinners-2.9.2.tgz#1773a8f4b9c4d6ac31563df53b3fc1d79462fe41" + integrity sha512-ywqV+5MmyL4E7ybXgKys4DugZbX0FC6LnwrhjuykIjnK9k8OQacQ7axGKnjDXWNhns0xot3bZI5h55H8yo9cJg== cli-truncate@^2.1.0: version "2.1.0" @@ -1599,6 +2336,15 @@ cli-truncate@^2.1.0: slice-ansi "^3.0.0" string-width "^4.2.0" +cliui@^7.0.2: + version "7.0.4" + resolved "https://registry.yarnpkg.com/cliui/-/cliui-7.0.4.tgz#a0265ee655476fc807aea9df3df8df7783808b4f" + integrity sha512-OcRE68cOsVMXp1Yvonl/fzkQOyjLSu/8bhPDfQt0e0/Eb283TKP20Fs2MqoPsr9SwA595rRCA+QMzYc9nBP+JQ== + dependencies: + string-width "^4.2.0" + strip-ansi "^6.0.0" + wrap-ansi "^7.0.0" + cliui@^8.0.1: version "8.0.1" resolved "https://registry.npmjs.org/cliui/-/cliui-8.0.1.tgz" @@ -1608,6 +2354,15 @@ cliui@^8.0.1: strip-ansi "^6.0.1" wrap-ansi "^7.0.0" +clone-deep@^4.0.1: + version "4.0.1" + resolved "https://registry.yarnpkg.com/clone-deep/-/clone-deep-4.0.1.tgz#c19fd9bdbbf85942b4fd979c84dcf7d5f07c2387" + integrity sha512-neHB9xuzh/wk0dIHweyAXv2aPGZIVk3pLMe+/RNzINf17fe0OG96QroktYAUm7SM1PBnzTabaLboqqxDyMU+SQ== + dependencies: + is-plain-object "^2.0.4" + kind-of "^6.0.2" + shallow-clone "^3.0.0" + clone-response@^1.0.2: version "1.0.3" resolved "https://registry.npmjs.org/clone-response/-/clone-response-1.0.3.tgz" @@ -1617,7 +2372,7 @@ clone-response@^1.0.2: clone@^1.0.2: version "1.0.4" - resolved "https://registry.npmjs.org/clone/-/clone-1.0.4.tgz" + resolved "https://registry.yarnpkg.com/clone/-/clone-1.0.4.tgz#da309cc263df15994c688ca902179ca3c7cd7c7e" integrity sha512-JQHZ2QMW6l3aH/j6xCqQThY/9OH4D/9ls34cgkUBiEeocRTU04tHfKPBsUK1PqZCUQM7GiA0IIXJSuXHI64Kbg== color-convert@^2.0.1: @@ -1632,15 +2387,10 @@ color-name@~1.1.4: resolved "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz" integrity sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA== -color-support@^1.1.3: - version "1.1.3" - resolved "https://registry.npmjs.org/color-support/-/color-support-1.1.3.tgz" - integrity sha512-qiBjkpbMLO/HL68y+lh4q0/O1MZFj2RX6X/KmMa3+gJD3z+WwI1ZzDHysvqHGS3mP6mznPckpXmw1nI9cJjyRg== - -colors@1.0.3: - version "1.0.3" - resolved "https://registry.yarnpkg.com/colors/-/colors-1.0.3.tgz#0433f44d809680fdeb60ed260f1b0c262e82a40b" - integrity sha512-pFGrxThWcWQ2MsAz6RtgeWe4NK2kUE1WfsrvvlctdII745EW9I0yflqhe7++M5LEc7bV2c/9/5zc8sFcpL0Drw== +colorette@^2.0.14: + version "2.0.20" + resolved "https://registry.yarnpkg.com/colorette/-/colorette-2.0.20.tgz#9eb793e6833067f7235902fcd3b09917a000a95a" + integrity sha512-IfEDxwoWIjkeXL1eXcDiow4UbKjhLdq6/EuSVR9GMN7KVH3r9gQ83e73hsz1Nd1T3ijd5xv1wcWRYO+D6kCI2w== combined-stream@^1.0.6, combined-stream@^1.0.8, combined-stream@~1.0.6: version "1.0.8" @@ -1649,32 +2399,48 @@ combined-stream@^1.0.6, combined-stream@^1.0.8, combined-stream@~1.0.6: dependencies: delayed-stream "~1.0.0" -commander@2.9.0: - version "2.9.0" - resolved "https://registry.yarnpkg.com/commander/-/commander-2.9.0.tgz#9c99094176e12240cb22d6c5146098400fe0f7d4" - integrity sha512-bmkUukX8wAOjHdN26xj5c4ctEV22TQ7dQYhSmuckKhToXrkUn0iIaolHdIxYYqD55nhpSPA9zPQ1yP57GdXP2A== - dependencies: - graceful-readlink ">= 1.0.0" +commander@^10.0.1: + version "10.0.1" + resolved "https://registry.yarnpkg.com/commander/-/commander-10.0.1.tgz#881ee46b4f77d1c1dccc5823433aa39b022cbe06" + integrity sha512-y4Mg2tXshplEbSGzx7amzPwKKOCGuoSRP/CjEdwwk0FOGlUbq6lKuoyDZTNZkmxHdJtp54hdfY/JUrdL7Xfdug== + +commander@^2.20.0: + version "2.20.3" + resolved "https://registry.yarnpkg.com/commander/-/commander-2.20.3.tgz#fd485e84c03eb4881c20722ba48035e8531aeb33" + integrity sha512-GpVkmM8vF2vQUkj2LvZmD35JxeJOLCwJ9cUkugyk2nuhbv3+mJvpLYYt+0+USMxE+oj+ey/lJEnhZw75x/OMcQ== -commander@^5.0.0: +commander@^5.0.0, commander@^5.1.0: version "5.1.0" resolved "https://registry.npmjs.org/commander/-/commander-5.1.0.tgz" integrity sha512-P0CysNDQ7rtVw4QIQtm+MRxV66vKFSvlsQvGYXZWR3qFU0jlMKHZZZgw8e+8DSah4UDKMqnknRDQz+xuQXQ/Zg== +commander@^8.3.0: + version "8.3.0" + resolved "https://registry.yarnpkg.com/commander/-/commander-8.3.0.tgz#4837ea1b2da67b9c616a67afbb0fafee567bca66" + integrity sha512-OkTL9umf+He2DZkUq8f8J9of7yL6RJKI24dVITBmNfZBmri9zYZQrKkuXiKhyfPSu8tUhnVBB1iKXevvnlR4Ww== + compare-version@^0.1.2: version "0.1.2" resolved "https://registry.npmjs.org/compare-version/-/compare-version-0.1.2.tgz" integrity sha512-pJDh5/4wrEnXX/VWRZvruAGHkzKdr46z11OlTPN+VrATlWWhSKewNCJ1futCO5C7eJB3nPMFZA1LeYtcFboZ2A== +compare-versions@^6.0.0: + version "6.1.0" + resolved "https://registry.yarnpkg.com/compare-versions/-/compare-versions-6.1.0.tgz#3f2131e3ae93577df111dba133e6db876ffe127a" + integrity sha512-LNZQXhqUvqUTotpZ00qLSaify3b4VFD588aRr8MKFw4CMUr98ytzCW5wDH5qx/DEY5kCDXcbcRuCqL0szEf2tg== + concat-map@0.0.1: version "0.0.1" resolved "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz" integrity sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg== -console-control-strings@^1.1.0: - version "1.1.0" - resolved "https://registry.npmjs.org/console-control-strings/-/console-control-strings-1.1.0.tgz" - integrity sha512-ty/fTekppD2fIwRvnZAVdeOiGd1c7YXEixbgJTNzqcxJWKQnjJ/V1bNEEE6hygpM3WjwHFUVK6HTjWSzV4a8sQ== +config-file-ts@^0.2.4: + version "0.2.6" + resolved "https://registry.yarnpkg.com/config-file-ts/-/config-file-ts-0.2.6.tgz#b424ff74612fb37f626d6528f08f92ddf5d22027" + integrity sha512-6boGVaglwblBgJqGyxm4+xCmEGcWgnWHSWHY5jad58awQhB6gftq0G8HbzU39YqCIYHMLAiL1yjwiZ36m/CL8w== + dependencies: + glob "^10.3.10" + typescript "^5.3.3" content-disposition@0.5.4: version "0.5.4" @@ -1783,6 +2549,11 @@ cross-spawn@^7.0.0, cross-spawn@^7.0.1, cross-spawn@^7.0.3: shebang-command "^2.0.0" which "^2.0.1" +crypt@0.0.2: + version "0.0.2" + resolved "https://registry.yarnpkg.com/crypt/-/crypt-0.0.2.tgz#88d7ff7ec0dfb86f713dc87bbb42d044d3e6c41b" + integrity sha512-mCxBlsHFYh9C+HVpiEacem8FEBnMXgU9gy4zmNC+SXAZNB/1idgp/aulFJ4FgCi7GPEVbfyng092GqL2k2rmow== + d@1, d@^1.0.1: version "1.0.1" resolved "https://registry.yarnpkg.com/d/-/d-1.0.1.tgz#8698095372d58dbee346ffd0c7093f99f8f9eb5a" @@ -1798,20 +2569,39 @@ dashdash@^1.12.0: dependencies: assert-plus "^1.0.0" -debug@2.6.9, debug@^2.2.0, debug@^2.6.8: +debug@2.6.9, debug@^2.2.0: version "2.6.9" resolved "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz" integrity sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA== dependencies: ms "2.0.0" -debug@4, debug@^4.1.0, debug@^4.1.1, debug@^4.3.1, debug@^4.3.3, debug@^4.3.4: +debug@4, debug@^4.1.0, debug@^4.1.1, debug@^4.3.1, debug@^4.3.4: version "4.3.4" resolved "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz" integrity sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ== dependencies: ms "2.1.2" +debug@4.3.1: + version "4.3.1" + resolved "https://registry.yarnpkg.com/debug/-/debug-4.3.1.tgz#f0d229c505e0c6d8c49ac553d1b13dc183f6b2ee" + integrity sha512-doEwdvm4PCeK4K3RQN2ZC2BYUBaxwLARCqZmMjtF8a51J2Rb0xpVloFRnCODwqjpwnAoao4pelN8l3RJdv3gRQ== + dependencies: + ms "2.1.2" + +debug@4.3.3: + version "4.3.3" + resolved "https://registry.yarnpkg.com/debug/-/debug-4.3.3.tgz#04266e0b70a98d4462e6e288e38259213332b664" + integrity sha512-/zxw5+vh1Tfv+4Qn7a5nsbcJKPaSvCDhojn6FEl9vupwK2VCSDtEiEtqr8DFtzYFOdz63LBkxec7DYuc2jon6Q== + dependencies: + ms "2.1.2" + +decamelize@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/decamelize/-/decamelize-4.0.0.tgz#aa472d7bf660eb15f3494efd531cab7f2a709837" + integrity sha512-9iE1PgSik9HeIIw2JO94IidnE3eBoQrFJ3w7sFuzSX4DpmZ3v5sZpUiV5Swcf6mQEF+Y0ru8Neo+p+nyh2J+hQ== + decode-uri-component@^0.2.0: version "0.2.2" resolved "https://registry.yarnpkg.com/decode-uri-component/-/decode-uri-component-0.2.2.tgz#e69dbe25d37941171dd540e024c444cd5188e1e9" @@ -1831,15 +2621,51 @@ decompress-response@^6.0.0: dependencies: mimic-response "^3.1.0" -defaults@^1.0.3: - version "1.0.4" - resolved "https://registry.npmjs.org/defaults/-/defaults-1.0.4.tgz" - integrity sha512-eFuaLoy/Rxalv2kr+lqMlUnrDWV+3j4pljOIJgLIhI058IQfWJ7vXhyEIHu+HtC738klGALYxOKDO0bQP3tg8A== +deep-eql@4.0.1: + version "4.0.1" + resolved "https://registry.yarnpkg.com/deep-eql/-/deep-eql-4.0.1.tgz#2b65bc89491d193780c452edee2144a91bb0a445" + integrity sha512-D/Oxqobjr+kxaHsgiQBZq9b6iAWdEj5W/JdJm8deNduAPc9CwXQ3BJJCuEqlrPXcy45iOMkGPZ0T81Dnz7UDCA== dependencies: - clone "^1.0.2" + type-detect "^4.0.0" -defer-to-connect@^2.0.0, defer-to-connect@^2.0.1: - version "2.0.1" +deep-equal@^2.2.3: + version "2.2.3" + resolved "https://registry.yarnpkg.com/deep-equal/-/deep-equal-2.2.3.tgz#af89dafb23a396c7da3e862abc0be27cf51d56e1" + integrity sha512-ZIwpnevOurS8bpT4192sqAowWM76JDKSHYzMLty3BZGSswgq6pBaH3DhCSW5xVAZICZyKdOBPjwww5wfgT/6PA== + dependencies: + array-buffer-byte-length "^1.0.0" + call-bind "^1.0.5" + es-get-iterator "^1.1.3" + get-intrinsic "^1.2.2" + is-arguments "^1.1.1" + is-array-buffer "^3.0.2" + is-date-object "^1.0.5" + is-regex "^1.1.4" + is-shared-array-buffer "^1.0.2" + isarray "^2.0.5" + object-is "^1.1.5" + object-keys "^1.1.1" + object.assign "^4.1.4" + regexp.prototype.flags "^1.5.1" + side-channel "^1.0.4" + which-boxed-primitive "^1.0.2" + which-collection "^1.0.1" + which-typed-array "^1.1.13" + +deep-is@^0.1.3: + version "0.1.4" + resolved "https://registry.yarnpkg.com/deep-is/-/deep-is-0.1.4.tgz#a6f2dce612fadd2ef1f519b73551f17e85199831" + integrity sha512-oIPzksmTg4/MriiaYGO+okXDT7ztn/w3Eptv/+gSIdMdKsJo0u4CfYNFJPy+4SKMuCqGw2wxnA+URMg3t8a/bQ== + +defaults@^1.0.3: + version "1.0.4" + resolved "https://registry.yarnpkg.com/defaults/-/defaults-1.0.4.tgz#b0b02062c1e2aa62ff5d9528f0f98baa90978d7a" + integrity sha512-eFuaLoy/Rxalv2kr+lqMlUnrDWV+3j4pljOIJgLIhI058IQfWJ7vXhyEIHu+HtC738klGALYxOKDO0bQP3tg8A== + dependencies: + clone "^1.0.2" + +defer-to-connect@^2.0.0, defer-to-connect@^2.0.1: + version "2.0.1" resolved "https://registry.npmjs.org/defer-to-connect/-/defer-to-connect-2.0.1.tgz" integrity sha512-4tvttepXG1VaYGrRibk5EwJd1t4udunSOVMdLSAL6mId1ix438oPwPZMALY41FCijukO1L0twNcGsdzS7dHgDg== @@ -1861,6 +2687,11 @@ define-data-property@^1.1.4: es-errors "^1.3.0" gopd "^1.0.1" +define-lazy-prop@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/define-lazy-prop/-/define-lazy-prop-2.0.0.tgz#3f7ae421129bcaaac9bc74905c98a0009ec9ee7f" + integrity sha512-Ds09qNh8yw3khSjiJjiUInaGX9xlqZDY7JVryGxdxV7NPeuqQfplOpQ66yJFZut3jLa5zOwkXw1g9EI2uKh4Og== + define-properties@^1.1.3: version "1.2.0" resolved "https://registry.npmjs.org/define-properties/-/define-properties-1.2.0.tgz" @@ -1869,7 +2700,7 @@ define-properties@^1.1.3: has-property-descriptors "^1.0.0" object-keys "^1.1.1" -define-properties@^1.1.4, define-properties@^1.2.0: +define-properties@^1.1.4, define-properties@^1.2.0, define-properties@^1.2.1: version "1.2.1" resolved "https://registry.yarnpkg.com/define-properties/-/define-properties-1.2.1.tgz#10781cc616eb951a80a034bafcaa7377f6af2b6c" integrity sha512-8QmQKqEASLd5nx0U1B1okLElbUuuttJ/AnYmRXbbbGDWh6uS208EjD4Xqq/I9wK7u0v6O08XhTWnt5XtEbR6Dg== @@ -1883,55 +2714,63 @@ delayed-stream@~1.0.0: resolved "https://registry.npmjs.org/delayed-stream/-/delayed-stream-1.0.0.tgz" integrity sha512-ZySD7Nf91aLB0RxL4KGrKHBXl7Eds1DAmEdcoVawXnLD7SDhpNgtuII2aAkg7a7QS41jxPSZ17p4VdGnMHk3MQ== -delegates@^1.0.0: - version "1.0.0" - resolved "https://registry.npmjs.org/delegates/-/delegates-1.0.0.tgz" - integrity sha512-bd2L678uiWATM6m5Z1VzNCErI3jiGzt6HGY8OVICs40JQq/HALfbyNJmp0UDakEY4pMMaN0Ly5om/B1VI/+xfQ== - -depd@2.0.0, depd@^2.0.0: +depd@2.0.0: version "2.0.0" resolved "https://registry.npmjs.org/depd/-/depd-2.0.0.tgz" integrity sha512-g7nH6P6dyDioJogAAGprGpCtVImJhpPk/roCzdb3fIh61/s/nPsfR6onyMwkCAR/OlC3yBC0lESvUoQEAssIrw== +deprecation@^2.0.0, deprecation@^2.3.1: + version "2.3.1" + resolved "https://registry.yarnpkg.com/deprecation/-/deprecation-2.3.1.tgz#6368cbdb40abf3373b525ac87e4a260c3a700919" + integrity sha512-xmHIy4F3scKVwMsQ4WnVaS8bHOx0DmVwRywosKhaILI0ywMDWPtBSku2HNxRvF7jtwDRsoEwYQSfbxj8b7RlJQ== + destroy@1.2.0: version "1.2.0" resolved "https://registry.yarnpkg.com/destroy/-/destroy-1.2.0.tgz#4803735509ad8be552934c67df614f94e66fa015" integrity sha512-2sJGJTaXIIaR1w4iJSNoN0hnMY7Gpc/n8D4qSCJw8QqFWXf7cuAgnEHxBpweaVcPevC2l3KpjYCx3NypQQgaJg== -detect-libc@^2.0.1: - version "2.0.1" - resolved "https://registry.npmjs.org/detect-libc/-/detect-libc-2.0.1.tgz" - integrity sha512-463v3ZeIrcWtdgIg6vI6XUncguvr2TnGl4SzDXinkt9mSLpBJKXT3mW6xT3VQdDN11+WVs29pgvivTc4Lp8v+w== - detect-node@^2.0.4: version "2.1.0" resolved "https://registry.npmjs.org/detect-node/-/detect-node-2.1.0.tgz" integrity sha512-T0NIuQpnTvFDATNuHN5roPwSBG83rFsuO+MXXH9/3N1eFbn4wcPjttvjMLEPWJ0RGUYgQE7cGgS3tNxbqCGM7g== +devtools-protocol@^0.0.1025565: + version "0.0.1025565" + resolved "https://registry.yarnpkg.com/devtools-protocol/-/devtools-protocol-0.0.1025565.tgz#0b3da0d3714c556aad06b0ec60f4fde68a701a90" + integrity sha512-0s5sbGQR/EfYQhd8EpZgphpndsv+CufTlaeUyA6vYXCA0H5kMAsHCS/cHtUFWoKJCO125hpoKicQCfpxRj4oqw== + +didyoumean@1.2.2: + version "1.2.2" + resolved "https://registry.yarnpkg.com/didyoumean/-/didyoumean-1.2.2.tgz#989346ffe9e839b4555ecf5666edea0d3e8ad037" + integrity sha512-gxtyfqMg7GKyhQmb056K7M3xszy/myH8w+B4RT+QXBQsvAOdc3XymqDDPHx1BgPgsdAA5SIifona89YtRATDzw== + diff3@0.0.3: version "0.0.3" resolved "https://registry.npmjs.org/diff3/-/diff3-0.0.3.tgz" integrity sha512-iSq8ngPOt0K53A6eVr4d5Kn6GNrM2nQZtC740pzIriHtn4pOQ2lyzEXQMBeVcWERN0ye7fhBsk9PbLLQOnUx/g== -dir-compare@^2.4.0: - version "2.4.0" - resolved "https://registry.yarnpkg.com/dir-compare/-/dir-compare-2.4.0.tgz#785c41dc5f645b34343a4eafc50b79bac7f11631" - integrity sha512-l9hmu8x/rjVC9Z2zmGzkhOEowZvW7pmYws5CWHutg8u1JgvsKWMx7Q/UODeu4djLZ4FgW5besw5yvMQnBHzuCA== - dependencies: - buffer-equal "1.0.0" - colors "1.0.3" - commander "2.9.0" - minimatch "3.0.4" - -dmg-builder@23.6.0: - version "23.6.0" - resolved "https://registry.yarnpkg.com/dmg-builder/-/dmg-builder-23.6.0.tgz#d39d3871bce996f16c07d2cafe922d6ecbb2a948" - integrity sha512-jFZvY1JohyHarIAlTbfQOk+HnceGjjAdFjVn3n8xlDWKsYNqbO4muca6qXEZTfGXeQMG7TYim6CeS5XKSfSsGA== - dependencies: - app-builder-lib "23.6.0" - builder-util "23.6.0" - builder-util-runtime "9.1.1" - fs-extra "^10.0.0" +diff@5.0.0: + version "5.0.0" + resolved "https://registry.yarnpkg.com/diff/-/diff-5.0.0.tgz#7ed6ad76d859d030787ec35855f5b1daf31d852b" + integrity sha512-/VTCrvm5Z0JGty/BWHljh+BAiw3IK+2j87NGMu8Nwc/f48WoDAC395uomO9ZD117ZOBaHmkX1oyLvkVM/aIT3w== + +dir-compare@^3.0.0: + version "3.3.0" + resolved "https://registry.yarnpkg.com/dir-compare/-/dir-compare-3.3.0.tgz#2c749f973b5c4b5d087f11edaae730db31788416" + integrity sha512-J7/et3WlGUCxjdnD3HAAzQ6nsnc0WL6DD7WcwJb7c39iH1+AWfg+9OqzJNaI6PkBwBvm1mhZNL9iY/nRiZXlPg== + dependencies: + buffer-equal "^1.0.0" + minimatch "^3.0.4" + +dmg-builder@24.9.1: + version "24.9.1" + resolved "https://registry.yarnpkg.com/dmg-builder/-/dmg-builder-24.9.1.tgz#04bf6c0dcd235f6214511f2358a78ed2b9379421" + integrity sha512-huC+O6hvHd24Ubj3cy2GMiGLe2xGFKN3klqVMLAdcbB6SWMd1yPSdZvV8W1O01ICzCCRlZDHiv4VrNUgnPUfbQ== + dependencies: + app-builder-lib "24.9.1" + builder-util "24.8.1" + builder-util-runtime "9.2.3" + fs-extra "^10.1.0" iconv-lite "^0.6.2" js-yaml "^4.1.0" optionalDependencies: @@ -1958,17 +2797,22 @@ dom-walk@^0.1.0: dotenv-expand@^5.1.0: version "5.1.0" - resolved "https://registry.npmjs.org/dotenv-expand/-/dotenv-expand-5.1.0.tgz" + resolved "https://registry.yarnpkg.com/dotenv-expand/-/dotenv-expand-5.1.0.tgz#3fbaf020bfd794884072ea26b1e9791d45a629f0" integrity sha512-YXQl1DSa4/PQyRfgrv6aoNjhasp/p4qs9FjJ4q4cQk+8m4r6k4ZSiEyytKG8f8W9gi8WsQtIObNmKd+tMzNTmA== +dotenv@10.0.0: + version "10.0.0" + resolved "https://registry.yarnpkg.com/dotenv/-/dotenv-10.0.0.tgz#3d4227b8fb95f81096cdd2b66653fb2c7085ba81" + integrity sha512-rlBi9d8jpv9Sf1klPjNfFAuWDjKLwTIJJ/VxtoTwIR6hnZxcEOQCZg2oIL3MWBYw5GpUDKOEnND7LXTbIpQ03Q== + dotenv@^9.0.2: version "9.0.2" - resolved "https://registry.npmjs.org/dotenv/-/dotenv-9.0.2.tgz" + resolved "https://registry.yarnpkg.com/dotenv/-/dotenv-9.0.2.tgz#dacc20160935a37dea6364aa1bef819fb9b6ab05" integrity sha512-I9OvvrHp4pIARv4+x9iuewrWycX6CcZtoAu1XrzPxc5UygMJXJZYmBsynku8IkrJwgypE5DGNjDPmPRhDCptUg== eastasianwidth@^0.2.0: version "0.2.0" - resolved "https://registry.npmjs.org/eastasianwidth/-/eastasianwidth-0.2.0.tgz" + resolved "https://registry.yarnpkg.com/eastasianwidth/-/eastasianwidth-0.2.0.tgz#696ce2ec0aa0e6ea93a397ffcf24aa7840c827cb" integrity sha512-I88TYZWc9XiYHRQ4/3c5rjjfgkjhLyW2luGIheGERbNQ6OY7yTybanSpDXZa8y7VUP9YmDcYa+eyq4ca7iLqWA== ecc-jsbn@~0.1.1: @@ -1979,35 +2823,48 @@ ecc-jsbn@~0.1.1: jsbn "~0.1.0" safer-buffer "^2.1.0" +ecdsa-sig-formatter@1.0.11: + version "1.0.11" + resolved "https://registry.yarnpkg.com/ecdsa-sig-formatter/-/ecdsa-sig-formatter-1.0.11.tgz#ae0f0fa2d85045ef14a817daa3ce9acd0489e5bf" + integrity sha512-nagl3RYrbNv6kQkeJIpt6NJZy8twLB/2vtz6yN9Z4vRKHN4/QZJIEbqohALSgwKdnksuY3k5Addp5lg8sVoVcQ== + dependencies: + safe-buffer "^5.0.1" + ee-first@1.1.1: version "1.1.1" resolved "https://registry.yarnpkg.com/ee-first/-/ee-first-1.1.1.tgz#590c61156b0ae2f4f0255732a158b266bc56b21d" integrity sha512-WMwm9LhRUo+WUaRN+vRuETqG89IgZphVSNkdFgeb6sS/E4OrDIN7t48CAewSHXc6C8lefD8KKfr5vY61brQlow== -ejs@^3.1.7: +ejs@3.1.8: + version "3.1.8" + resolved "https://registry.yarnpkg.com/ejs/-/ejs-3.1.8.tgz#758d32910c78047585c7ef1f92f9ee041c1c190b" + integrity sha512-/sXZeMlhS0ArkfX2Aw780gJzXSMPnKjtspYZv+f3NiKLlubezAHDU5+9xz6gd3/NhG3txQCo6xlglmTS+oTGEQ== + dependencies: + jake "^10.8.5" + +ejs@^3.1.8: version "3.1.9" resolved "https://registry.yarnpkg.com/ejs/-/ejs-3.1.9.tgz#03c9e8777fe12686a9effcef22303ca3d8eeb361" integrity sha512-rC+QVNMJWv+MtPgkt0y+0rVEIdbtxVADApW9JXrUVlzHetgcyczP/E7DJmWJ4fJCZF2cPcBk0laWO9ZHMG3DmQ== dependencies: jake "^10.8.5" -electron-builder@^23.6.0: - version "23.6.0" - resolved "https://registry.yarnpkg.com/electron-builder/-/electron-builder-23.6.0.tgz#c79050cbdce90ed96c5feb67c34e9e0a21b5331b" - integrity sha512-y8D4zO+HXGCNxFBV/JlyhFnoQ0Y0K7/sFH+XwIbj47pqaW8S6PGYQbjoObolKBR1ddQFPt4rwp4CnwMJrW3HAw== - dependencies: - "@types/yargs" "^17.0.1" - app-builder-lib "23.6.0" - builder-util "23.6.0" - builder-util-runtime "9.1.1" - chalk "^4.1.1" - dmg-builder "23.6.0" - fs-extra "^10.0.0" +electron-builder@24.9.1: + version "24.9.1" + resolved "https://registry.yarnpkg.com/electron-builder/-/electron-builder-24.9.1.tgz#4aee03947963b829a7f48a850fe02c219311ef63" + integrity sha512-v7BuakDuY6sKMUYM8mfQGrwyjBpZ/ObaqnenU0H+igEL10nc6ht049rsCw2HghRBdEwJxGIBuzs3jbEhNaMDmg== + dependencies: + app-builder-lib "24.9.1" + builder-util "24.8.1" + builder-util-runtime "9.2.3" + chalk "^4.1.2" + dmg-builder "24.9.1" + fs-extra "^10.1.0" is-ci "^3.0.0" lazy-val "^1.0.5" - read-config-file "6.2.0" - simple-update-notifier "^1.0.7" - yargs "^17.5.1" + read-config-file "6.3.2" + simple-update-notifier "2.0.0" + yargs "^17.6.2" electron-devtools-installer@^3.2.0: version "3.2.0" @@ -2019,35 +2876,42 @@ electron-devtools-installer@^3.2.0: tslib "^2.1.0" unzip-crx-3 "^0.2.0" -electron-osx-sign@^0.6.0: - version "0.6.0" - resolved "https://registry.yarnpkg.com/electron-osx-sign/-/electron-osx-sign-0.6.0.tgz#9b69c191d471d9458ef5b1e4fdd52baa059f1bb8" - integrity sha512-+hiIEb2Xxk6eDKJ2FFlpofCnemCbjbT5jz+BKGpVBrRNT3kWTGs4DfNX6IzGwgi33hUcXF+kFs9JW+r6Wc1LRg== - dependencies: - bluebird "^3.5.0" - compare-version "^0.1.2" - debug "^2.6.8" - isbinaryfile "^3.0.2" - minimist "^1.2.0" - plist "^3.0.1" - -electron-publish@23.6.0: - version "23.6.0" - resolved "https://registry.yarnpkg.com/electron-publish/-/electron-publish-23.6.0.tgz#ac9b469e0b07752eb89357dd660e5fb10b3d1ce9" - integrity sha512-jPj3y+eIZQJF/+t5SLvsI5eS4mazCbNYqatv5JihbqOstIM13k0d1Z3vAWntvtt13Itl61SO6seicWdioOU5dg== +electron-publish@24.8.1: + version "24.8.1" + resolved "https://registry.yarnpkg.com/electron-publish/-/electron-publish-24.8.1.tgz#4216740372bf4297a429543402a1a15ce8c3560b" + integrity sha512-IFNXkdxMVzUdweoLJNXSupXkqnvgbrn3J4vognuOY06LaS/m0xvfFYIf+o1CM8if6DuWYWoQFKPcWZt/FUjZPw== dependencies: "@types/fs-extra" "^9.0.11" - builder-util "23.6.0" - builder-util-runtime "9.1.1" - chalk "^4.1.1" - fs-extra "^10.0.0" + builder-util "24.8.1" + builder-util-runtime "9.2.3" + chalk "^4.1.2" + fs-extra "^10.1.0" lazy-val "^1.0.5" mime "^2.5.2" -electron@^25.0.1: - version "25.9.5" - resolved "https://registry.yarnpkg.com/electron/-/electron-25.9.5.tgz#c030368ebe1b40580e781d89fa8ce7ef19202692" - integrity sha512-gM7GXUSd3JVRcYbBnNOtZeNnE5MCJjtZTT8QyIxJvpQ0Dh9dz3hTuEL62dOwnMFW/l47ACQ6es/8qi01P4QGZA== +electron-to-chromium@^1.4.796: + version "1.4.820" + resolved "https://registry.yarnpkg.com/electron-to-chromium/-/electron-to-chromium-1.4.820.tgz#1195660c157535392a09442540a08ee63fea8c40" + integrity sha512-kK/4O/YunacfboFEk/BDf7VO1HoPmDudLTJAU9NmXIOSjsV7qVIX3OrI4REZo0VmdqhcpUcncQc6N8Q3aEXlHg== + +electron-updater@^6.1.8: + version "6.3.4" + resolved "https://registry.yarnpkg.com/electron-updater/-/electron-updater-6.3.4.tgz#3934bc89875bb524c2cbbd11041114e97c0c2496" + integrity sha512-uZUo7p1Y53G4tl6Cgw07X1yF8Jlz6zhaL7CQJDZ1fVVkOaBfE2cWtx80avwDVi8jHp+I/FWawrMgTAeCCNIfAg== + dependencies: + builder-util-runtime "9.2.5" + 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.6.3" + tiny-typed-emitter "^2.1.0" + +electron@^26.0.0: + version "26.6.10" + resolved "https://registry.yarnpkg.com/electron/-/electron-26.6.10.tgz#01ca7610bd662033ed3ceb70804cbf940c7e6756" + integrity sha512-pV2SD0RXzAiNRb/2yZrsVmVkBOMrf+DVsPulIgRjlL0+My9BL5spFuhHVMQO9yHl9tFpWtuRpQv0ofM/i9P8xg== dependencies: "@electron/get" "^2.0.0" "@types/node" "^18.11.18" @@ -2073,9 +2937,14 @@ emoji-regex@^8.0.0: emoji-regex@^9.2.2: version "9.2.2" - resolved "https://registry.npmjs.org/emoji-regex/-/emoji-regex-9.2.2.tgz" + resolved "https://registry.yarnpkg.com/emoji-regex/-/emoji-regex-9.2.2.tgz#840c8803b0d8047f4ff0cf963176b32d4ef3ed72" integrity sha512-L18DaJsXSUk2+42pv8mLs5jJT2hqFkFE4j21wOmgbUqsZ2hL72NsUU785g9RXgo3s0ZNgVl42TiHp3ZtOv/Vyg== +emojis-list@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/emojis-list/-/emojis-list-3.0.0.tgz#5570662046ad29e2e916e71aae260abdff4f6a78" + integrity sha512-/kyM18EfinwXZbno9FyUGeFh87KC8HRQBQGildHZbEuRyWFOmv1U10o9BBp8XVZDVNNuQKyIGIu5ZYAAXJ0V2Q== + encodeurl@~1.0.2: version "1.0.2" resolved "https://registry.yarnpkg.com/encodeurl/-/encodeurl-1.0.2.tgz#ad3ff4c86ec2d029322f5a02c3a9a606c95b3f59" @@ -2086,13 +2955,6 @@ encodeurl@~2.0.0: resolved "https://registry.yarnpkg.com/encodeurl/-/encodeurl-2.0.0.tgz#7b8ea898077d7e409d3ac45474ea38eaf0857a58" integrity sha512-Q0n9HRi4m6JuGIV1eFlmvJB7ZEVxu93IrMyiMsGC0lrMJMWzRgx6WGquyfQgZVb31vhGgXnfmPNNXmxnOkRBrg== -encoding@^0.1.13: - version "0.1.13" - resolved "https://registry.npmjs.org/encoding/-/encoding-0.1.13.tgz" - integrity sha512-ETBauow1T35Y/WZMkio9jiM0Z5xjHHmJ4XmjZOq1l/dXz3lr2sRn87nJy20RupqSh1F2m3HHPSp8ShIPQJrJ3A== - dependencies: - iconv-lite "^0.6.2" - end-of-stream@^1.1.0, end-of-stream@^1.4.1: version "1.4.4" resolved "https://registry.npmjs.org/end-of-stream/-/end-of-stream-1.4.4.tgz" @@ -2100,14 +2962,45 @@ end-of-stream@^1.1.0, end-of-stream@^1.4.1: dependencies: once "^1.4.0" +enhanced-resolve@^5.0.0, enhanced-resolve@^5.7.0: + version "5.17.0" + resolved "https://registry.yarnpkg.com/enhanced-resolve/-/enhanced-resolve-5.17.0.tgz#d037603789dd9555b89aaec7eb78845c49089bc5" + integrity sha512-dwDPwZL0dmye8Txp2gzFmA6sxALaSvdRDjPH0viLcKrtlOL3tw62nWWweVD1SdILDTJrbrL6tdWVN58Wo6U3eA== + dependencies: + graceful-fs "^4.2.4" + tapable "^2.2.0" + +enhanced-resolve@^5.17.1: + version "5.17.1" + resolved "https://registry.yarnpkg.com/enhanced-resolve/-/enhanced-resolve-5.17.1.tgz#67bfbbcc2f81d511be77d686a90267ef7f898a15" + integrity sha512-LMHl3dXhTcfv8gM4kEzIUeTQ+7fpdA0l2tUf34BddXPkz2A5xJ5L/Pchd5BL6rdccM9QGvu0sWZzK1Z1t4wwyg== + dependencies: + graceful-fs "^4.2.4" + tapable "^2.2.0" + +entities@^2.2.0: + version "2.2.0" + resolved "https://registry.yarnpkg.com/entities/-/entities-2.2.0.tgz#098dc90ebb83d8dffa089d55256b351d34c4da55" + integrity sha512-p92if5Nz619I0w+akJrLZH0MX0Pb5DX39XOwQTtXSdQQOaYH03S1uIQp4mhOZtAXrxq4ViO67YTiLBo2638o9A== + env-paths@^2.2.0: version "2.2.1" resolved "https://registry.npmjs.org/env-paths/-/env-paths-2.2.1.tgz" integrity sha512-+h1lkLKhZMTYjog1VEpJNG7NZJWcuc2DDk/qsqSTRRCOXiLjeQ1d1/udrUGhqMxUgAlwKNZ0cf2uqan5GLuS2A== +envinfo@7.8.1: + version "7.8.1" + resolved "https://registry.yarnpkg.com/envinfo/-/envinfo-7.8.1.tgz#06377e3e5f4d379fea7ac592d5ad8927e0c4d475" + integrity sha512-/o+BXHmB7ocbHEAs6F2EnG0ogybVVUdkRunTT2glZU9XAaGmhqskrvKwqXuDfNjEO0LZKWdejEEpnq8aM0tOaw== + +envinfo@^7.7.3: + version "7.13.0" + resolved "https://registry.yarnpkg.com/envinfo/-/envinfo-7.13.0.tgz#81fbb81e5da35d74e814941aeab7c325a606fb31" + integrity sha512-cvcaMr7KqXVh4nyzGTVqTum+gAiL265x5jUWQIDLq//zOGbW+gSW/C+OWLleY/rs9Qole6AZLMXPbtIFQbqu+Q== + err-code@^2.0.2: version "2.0.3" - resolved "https://registry.npmjs.org/err-code/-/err-code-2.0.3.tgz" + resolved "https://registry.yarnpkg.com/err-code/-/err-code-2.0.3.tgz#23c2f3b756ffdfc608d30e27c9a941024807e7f9" integrity sha512-2bmlRpNKBxT/CRmPOlyISQpNj+qSeYvcym/uT0Jx2bMOlKLtSy1ZmLuVxSEKKyor/N5yhvp/ZiG1oE3DEYMSFA== es-abstract@^1.22.1: @@ -2167,6 +3060,26 @@ es-errors@^1.3.0: resolved "https://registry.yarnpkg.com/es-errors/-/es-errors-1.3.0.tgz#05f75a25dab98e4fb1dcd5e1472c0546d5057c8f" integrity sha512-Zf5H2Kxt2xjTvbJvP2ZWLEICxA6j+hAmMzIlypy4xcBg1vKVnx89Wy0GbS+kf5cwCVFFzdCFh2XSCFNULS6csw== +es-get-iterator@^1.1.3: + version "1.1.3" + resolved "https://registry.yarnpkg.com/es-get-iterator/-/es-get-iterator-1.1.3.tgz#3ef87523c5d464d41084b2c3c9c214f1199763d6" + integrity sha512-sPZmqHBe6JIiTfN5q2pEi//TwxmAFHwj/XEuYjTuse78i8KxaqMTTzxPoFKuzRpDpTJ+0NAbpfenkmH2rePtuw== + dependencies: + call-bind "^1.0.2" + get-intrinsic "^1.1.3" + has-symbols "^1.0.3" + is-arguments "^1.1.1" + is-map "^2.0.2" + is-set "^2.0.2" + is-string "^1.0.7" + isarray "^2.0.5" + stop-iteration-iterator "^1.0.0" + +es-module-lexer@^1.2.1: + version "1.5.4" + resolved "https://registry.yarnpkg.com/es-module-lexer/-/es-module-lexer-1.5.4.tgz#a8efec3a3da991e60efa6b633a7cad6ab8d26b78" + integrity sha512-MVNK56NiMrOwitFB7cqDwq0CQutbw+0BvLshJSse0MUNU+y1FC3bUS/AQg7oUng+/wKrrki7JfmwtVHkVfPLlw== + es-set-tostringtag@^2.0.1: version "2.0.2" resolved "https://registry.yarnpkg.com/es-set-tostringtag/-/es-set-tostringtag-2.0.2.tgz#11f7cc9f63376930a5f20be4915834f4bc74f9c9" @@ -2229,21 +3142,64 @@ es6-symbol@^3.1.1, es6-symbol@^3.1.3: d "^1.0.1" ext "^1.1.2" +esbuild@^0.23.1: + version "0.23.1" + resolved "https://registry.yarnpkg.com/esbuild/-/esbuild-0.23.1.tgz#40fdc3f9265ec0beae6f59824ade1bd3d3d2dab8" + integrity sha512-VVNz/9Sa0bs5SELtn3f7qhJCDPCF5oMEl5cO9/SSinpE9hbPVvxbd572HH5AKiP7WD8INO53GgfDDhRjkylHEg== + optionalDependencies: + "@esbuild/aix-ppc64" "0.23.1" + "@esbuild/android-arm" "0.23.1" + "@esbuild/android-arm64" "0.23.1" + "@esbuild/android-x64" "0.23.1" + "@esbuild/darwin-arm64" "0.23.1" + "@esbuild/darwin-x64" "0.23.1" + "@esbuild/freebsd-arm64" "0.23.1" + "@esbuild/freebsd-x64" "0.23.1" + "@esbuild/linux-arm" "0.23.1" + "@esbuild/linux-arm64" "0.23.1" + "@esbuild/linux-ia32" "0.23.1" + "@esbuild/linux-loong64" "0.23.1" + "@esbuild/linux-mips64el" "0.23.1" + "@esbuild/linux-ppc64" "0.23.1" + "@esbuild/linux-riscv64" "0.23.1" + "@esbuild/linux-s390x" "0.23.1" + "@esbuild/linux-x64" "0.23.1" + "@esbuild/netbsd-x64" "0.23.1" + "@esbuild/openbsd-arm64" "0.23.1" + "@esbuild/openbsd-x64" "0.23.1" + "@esbuild/sunos-x64" "0.23.1" + "@esbuild/win32-arm64" "0.23.1" + "@esbuild/win32-ia32" "0.23.1" + "@esbuild/win32-x64" "0.23.1" + escalade@^3.1.1: version "3.1.1" resolved "https://registry.npmjs.org/escalade/-/escalade-3.1.1.tgz" integrity sha512-k0er2gUkLf8O0zKJiAhmkTnJlTvINGv7ygDNPbeIsX/TJjGJZHuh9B2UxbsaEkmlEo9MfhrSzmhIlhRlI2GXnw== +escalade@^3.1.2: + version "3.1.2" + resolved "https://registry.yarnpkg.com/escalade/-/escalade-3.1.2.tgz#54076e9ab29ea5bf3d8f1ed62acffbb88272df27" + integrity sha512-ErCHMCae19vR8vQGe50xIsVomy19rg6gFu3+r3jkEO46suLMWBksvVyoGgQV+jOfl84ZSOSlmv6Gxa89PmTGmA== + escape-html@~1.0.3: version "1.0.3" resolved "https://registry.yarnpkg.com/escape-html/-/escape-html-1.0.3.tgz#0258eae4d3d0c0974de1c169188ef0051d1d1988" integrity sha512-NiSupZ4OeuGwr68lGIeym/ksIZMJodUGOSCZ/FSnTxcrekbvqrgdUxlJOMpijaKZVjAJrWrGs/6Jy8OMuyj9ow== -escape-string-regexp@^4.0.0: +escape-string-regexp@4.0.0, escape-string-regexp@^4.0.0: version "4.0.0" resolved "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-4.0.0.tgz" integrity sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA== +eslint-scope@5.1.1: + version "5.1.1" + resolved "https://registry.yarnpkg.com/eslint-scope/-/eslint-scope-5.1.1.tgz#e786e59a66cb92b3f6c1fb0d508aab174848f48c" + integrity sha512-2NxwbF/hZ0KpepYN0cNbo+FN6XoK7GaHlQhgx/hIZl6Va0bF45RQOOwhLIy8lQDbuCiadSLCBnH2CFYquit5bw== + dependencies: + esrecurse "^4.3.0" + estraverse "^4.1.1" + esniff@^2.0.1: version "2.0.1" resolved "https://registry.yarnpkg.com/esniff/-/esniff-2.0.1.tgz#a4d4b43a5c71c7ec51c51098c1d8a29081f9b308" @@ -2254,6 +3210,23 @@ esniff@^2.0.1: event-emitter "^0.3.5" type "^2.7.2" +esrecurse@^4.3.0: + version "4.3.0" + resolved "https://registry.yarnpkg.com/esrecurse/-/esrecurse-4.3.0.tgz#7ad7964d679abb28bee72cec63758b1c5d2c9921" + integrity sha512-KmfKL3b6G+RXvP8N1vr3Tq1kL/oCFgn2NYXEtqP8/L3pKapUA4G8cFVaoF3SU323CD4XypR/ffioHmkti6/Tag== + dependencies: + estraverse "^5.2.0" + +estraverse@^4.1.1: + version "4.3.0" + resolved "https://registry.yarnpkg.com/estraverse/-/estraverse-4.3.0.tgz#398ad3f3c5a24948be7725e83d11a7de28cdbd1d" + integrity sha512-39nnKffWz8xN1BU/2c79n9nB9HDzo0niYUqx6xyqUnyoAnQyyWpOTdZEeiCch8BBu515t4wp9ZmgVfVhn9EBpw== + +estraverse@^5.2.0: + version "5.3.0" + resolved "https://registry.yarnpkg.com/estraverse/-/estraverse-5.3.0.tgz#2eea5290702f26ab8fe5370370ff86c965d21123" + integrity sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA== + etag@~1.8.1: version "1.8.1" resolved "https://registry.yarnpkg.com/etag/-/etag-1.8.1.tgz#41ae2eeb65efa62268aebfea83ac7d79299b0887" @@ -2399,6 +3372,11 @@ events@3.2.0: resolved "https://registry.npmjs.org/events/-/events-3.2.0.tgz" integrity sha512-/46HWwbfCX2xTawVfkKLGxMifJYQBWMwY1mjywRtb4c9x8l5NP3KoJtnIOiL1hfdRkIuYhETxQlo62IF8tcnlg== +events@^3.2.0: + version "3.3.0" + resolved "https://registry.yarnpkg.com/events/-/events-3.3.0.tgz#31a95ad0a924e2d2c419a813aeb2c4e878ea7400" + integrity sha512-mQw+2fkQbALzQ7V0MY0IqdnXNOeTtP4r0lN9z7AAawCXgqea7bDii20AYrIBrFd/Hx0M2Ocz6S111CaFkUcb0Q== + evp_bytestokey@^1.0.3: version "1.0.3" resolved "https://registry.yarnpkg.com/evp_bytestokey/-/evp_bytestokey-1.0.3.tgz#7fcbdb198dc71959432efe13842684e0525acb02" @@ -2407,10 +3385,36 @@ evp_bytestokey@^1.0.3: md5.js "^1.3.4" safe-buffer "^5.1.1" -exponential-backoff@^3.1.1: - version "3.1.1" - resolved "https://registry.npmjs.org/exponential-backoff/-/exponential-backoff-3.1.1.tgz" - integrity sha512-dX7e/LHVJ6W3DE1MHWi9S1EYzDESENfLrYohG2G++ovZrYOkm4Knwa0mc1cn84xJOR4KEU0WSchhLbd0UklbHw== +execa@^3.3.0: + version "3.4.0" + resolved "https://registry.yarnpkg.com/execa/-/execa-3.4.0.tgz#c08ed4550ef65d858fac269ffc8572446f37eb89" + integrity sha512-r9vdGQk4bmCuK1yKQu1KTwcT2zwfWdbdaXfCtAh+5nU/4fSX+JAb7vZGvI5naJrQlvONrEB20jeruESI69530g== + dependencies: + cross-spawn "^7.0.0" + get-stream "^5.0.0" + human-signals "^1.1.1" + is-stream "^2.0.0" + merge-stream "^2.0.0" + npm-run-path "^4.0.0" + onetime "^5.1.0" + p-finally "^2.0.0" + signal-exit "^3.0.2" + strip-final-newline "^2.0.0" + +execa@^5.0.0, execa@^5.1.1: + version "5.1.1" + resolved "https://registry.yarnpkg.com/execa/-/execa-5.1.1.tgz#f80ad9cbf4298f7bd1d4c9555c21e93741c411dd" + integrity sha512-8uSpZZocAZRBAPIEINJj3Lo9HyGitllczc27Eh5YYojjMFMn8yHMDMaUHE2Jqfq05D/wucwI4JGURyXt1vchyg== + dependencies: + cross-spawn "^7.0.3" + get-stream "^6.0.0" + human-signals "^2.1.0" + is-stream "^2.0.0" + merge-stream "^2.0.0" + npm-run-path "^4.0.1" + onetime "^5.1.2" + signal-exit "^3.0.3" + strip-final-newline "^2.0.0" express@^4.14.0, express@^4.20.0: version "4.20.0" @@ -2487,11 +3491,21 @@ fast-deep-equal@^3.1.1: resolved "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz" integrity sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q== +fast-fifo@^1.1.0, fast-fifo@^1.2.0: + version "1.3.2" + resolved "https://registry.yarnpkg.com/fast-fifo/-/fast-fifo-1.3.2.tgz#286e31de96eb96d38a97899815740ba2a4f3640c" + integrity sha512-/d9sfos4yxzpwkDkuN7k2SqFKtYNmCTzgfEpz82x34IM9/zc8KGxQoXg1liNC/izpRM/MBdt44Nmx41ZWqk+FQ== + fast-json-stable-stringify@^2.0.0: version "2.1.0" resolved "https://registry.npmjs.org/fast-json-stable-stringify/-/fast-json-stable-stringify-2.1.0.tgz" integrity sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw== +fastest-levenshtein@^1.0.12: + version "1.0.16" + resolved "https://registry.yarnpkg.com/fastest-levenshtein/-/fastest-levenshtein-1.0.16.tgz#210e61b6ff181de91ea9b3d1b84fdedd47e034e5" + integrity sha512-eRnCtTTtGZFpQCwhJiUOuxPQWRXVKYDn0b2PeHfXL6/Zi53SLAzAHfVhVWK2AryC/WH05kGfxhFIPvTF0SXQzg== + fd-slicer@~1.1.0: version "1.1.0" resolved "https://registry.npmjs.org/fd-slicer/-/fd-slicer-1.1.0.tgz" @@ -2526,6 +3540,54 @@ finalhandler@1.2.0: statuses "2.0.1" unpipe "~1.0.0" +find-process@^1.4.7: + version "1.4.7" + resolved "https://registry.yarnpkg.com/find-process/-/find-process-1.4.7.tgz#8c76962259216c381ef1099371465b5b439ea121" + integrity sha512-/U4CYp1214Xrp3u3Fqr9yNynUrr5Le4y0SsJh2lMDDSbpwYSz3M2SMWQC+wqcx79cN8PQtHQIL8KnuY9M66fdg== + dependencies: + chalk "^4.0.0" + commander "^5.1.0" + debug "^4.1.1" + +find-up@5.0.0: + version "5.0.0" + resolved "https://registry.yarnpkg.com/find-up/-/find-up-5.0.0.tgz#4c92819ecb7083561e4f4a240a86be5198f536fc" + integrity sha512-78/PXT1wlLLDgTzDs7sjq9hzz0vXD+zn+7wypEe4fXQxCmdmqfGsEPQxmiCSQI3ajFV91bVSsvNtrJRiW6nGng== + dependencies: + locate-path "^6.0.0" + path-exists "^4.0.0" + +find-up@^4.0.0: + version "4.1.0" + resolved "https://registry.yarnpkg.com/find-up/-/find-up-4.1.0.tgz#97afe7d6cdc0bc5928584b7c8d7b16e8a9aa5d19" + integrity sha512-PpOwAdQ/YlXQ2vj8a3h8IipDuYRi3wceVQQGYWxNINccq40Anw7BlsEXCMbt1Zt+OLA6Fq9suIpIWD0OsnISlw== + dependencies: + locate-path "^5.0.0" + path-exists "^4.0.0" + +fkill@^7.2.1: + version "7.2.1" + resolved "https://registry.yarnpkg.com/fkill/-/fkill-7.2.1.tgz#7036200cd2edd28a6bc40f0defc1e159d9e24e64" + integrity sha512-eN9cmsIlRdq06wu3m01OOEgQf5Xh/M7REm0jfZ4eL3V3XisjXzfRq3iyqtKS+FhO6wB36FvWRiRGdeSx5KpLAQ== + dependencies: + aggregate-error "^3.1.0" + arrify "^2.0.1" + execa "^5.0.0" + pid-port "^0.1.0" + process-exists "^4.0.0" + ps-list "^7.2.0" + taskkill "^3.1.0" + +flat@^5.0.2: + version "5.0.2" + resolved "https://registry.yarnpkg.com/flat/-/flat-5.0.2.tgz#8ca6fe332069ffa9d324c327198c598259ceb241" + integrity sha512-b6suED+5/3rTpUBdG1gupIl8MPFCAMA0QXwmljLhvCUKcUvdE4gWky9zpuGCcXHOsz4J9wPGNWq6OKpmIzz3hQ== + +follow-redirects@^1.14.9: + version "1.15.4" + resolved "https://registry.yarnpkg.com/follow-redirects/-/follow-redirects-1.15.4.tgz#cdc7d308bf6493126b17ea2191ea0ccf3e535adf" + integrity sha512-Cr4D/5wlrb0z9dgERpUL3LrmPKVDsETIJhaCMeDfuFYcqa5bldGV6wBsAN6X/vxlXQtFBMrXdXxdL8CbDTGniw== + follow-redirects@^1.15.0, follow-redirects@^1.15.6: version "1.15.6" resolved "https://registry.yarnpkg.com/follow-redirects/-/follow-redirects-1.15.6.tgz#7f815c0cda4249c74ff09e95ef97c23b5fd0399b" @@ -2540,7 +3602,7 @@ for-each@^0.3.3: foreground-child@^3.1.0: version "3.1.1" - resolved "https://registry.npmjs.org/foreground-child/-/foreground-child-3.1.1.tgz" + resolved "https://registry.yarnpkg.com/foreground-child/-/foreground-child-3.1.1.tgz#1d173e776d75d2772fed08efe4a0de1ea1b12d0d" integrity sha512-TMKDUnIte6bfb5nWv7V/caI169OHgvwjb7V4WkeUvbQQdjr5rWKqHFiKWb/fcOwB+CzBT+qbWjvj+DVwRskpIg== dependencies: cross-spawn "^7.0.0" @@ -2649,13 +3711,6 @@ fs-minipass@^2.0.0: dependencies: minipass "^3.0.0" -fs-minipass@^3.0.0: - version "3.0.2" - resolved "https://registry.npmjs.org/fs-minipass/-/fs-minipass-3.0.2.tgz" - integrity sha512-2GAfyfoaCDRrM6jaOS3UsBts8yJ55VioXdWcOL7dK9zdAuKT71+WBA4ifnNYqVjYv+4SsPxjK0JT4yIIn4cA/g== - dependencies: - minipass "^5.0.0" - fs.realpath@^1.0.0: version "1.0.0" resolved "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz" @@ -2691,25 +3746,16 @@ functions-have-names@^1.2.3: resolved "https://registry.yarnpkg.com/functions-have-names/-/functions-have-names-1.2.3.tgz#0404fe4ee2ba2f607f0e0ec3c80bae994133b834" integrity sha512-xckBUXyTIqT97tq2x2AMb+g163b5JFysYk0x4qxNFwbfQkmNZoiRHb6sPzI9/QV33WeuvVYBUIiD4NzNIyqaRQ== -gauge@^4.0.3: - version "4.0.4" - resolved "https://registry.npmjs.org/gauge/-/gauge-4.0.4.tgz" - integrity sha512-f9m+BEN5jkg6a0fZjleidjN51VE1X+mPFQ2DJ0uv1V39oCLCbsGe6yjbBnp7eK7z/+GAon99a3nHuqbuuthyPg== - dependencies: - aproba "^1.0.3 || ^2.0.0" - color-support "^1.1.3" - console-control-strings "^1.1.0" - has-unicode "^2.0.1" - signal-exit "^3.0.7" - string-width "^4.2.3" - strip-ansi "^6.0.1" - wide-align "^1.1.5" - get-caller-file@^2.0.5: version "2.0.5" resolved "https://registry.npmjs.org/get-caller-file/-/get-caller-file-2.0.5.tgz" integrity sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg== +get-func-name@^2.0.0: + version "2.0.2" + resolved "https://registry.yarnpkg.com/get-func-name/-/get-func-name-2.0.2.tgz#0d7cf20cd13fda808669ffa88f4ffc7a3943fc41" + integrity sha512-8vXOvuE167CtIc3OyItco7N/dpRtBbYOsPsXCz7X/PMnlGjYjSGuZJgM1Y7mmew7BKf9BqvLX2tnOVy1BBUsxQ== + get-intrinsic@^1.0.2, get-intrinsic@^1.1.3, get-intrinsic@^1.2.0, get-intrinsic@^1.2.1, get-intrinsic@^1.2.2: version "1.2.2" resolved "https://registry.yarnpkg.com/get-intrinsic/-/get-intrinsic-1.2.2.tgz#281b7622971123e1ef4b3c90fd7539306da93f3b" @@ -2741,14 +3787,14 @@ get-intrinsic@^1.2.4: has-symbols "^1.0.3" hasown "^2.0.0" -get-stream@^5.1.0: +get-stream@^5.0.0, get-stream@^5.1.0: version "5.2.0" resolved "https://registry.npmjs.org/get-stream/-/get-stream-5.2.0.tgz" integrity sha512-nBF+F1rAZVCu/p7rjzgA+Yb4lfYXrpl7a6VmJrU8wF9I1CKvP/QwPNZHnOlwbTkY6dvtFIzFMSyQXbLoTQPRpA== dependencies: pump "^3.0.0" -get-stream@^6.0.1: +get-stream@^6.0.0, get-stream@^6.0.1: version "6.0.1" resolved "https://registry.yarnpkg.com/get-stream/-/get-stream-6.0.1.tgz#a262d8eef67aced57c2852ad6167526a43cbf7b7" integrity sha512-ts6Wi+2j3jQjqi70w5AlN8DFnkSwC+MqmxEzdEALB2qXZYV3X/b1CTfgPLGJNMeAWxdPfU8FO1ms3NUfaHCPYg== @@ -2775,18 +3821,36 @@ glob-parent@~5.1.2: dependencies: is-glob "^4.0.1" -glob@^10.2.2: - version "10.3.0" - resolved "https://registry.npmjs.org/glob/-/glob-10.3.0.tgz" - integrity sha512-AQ1/SB9HH0yCx1jXAT4vmCbTOPe5RQ+kCurjbel5xSCGhebumUv+GJZfa1rEqor3XIViqwSEmlkZCQD43RWrBg== +glob-to-regexp@^0.4.1: + version "0.4.1" + resolved "https://registry.yarnpkg.com/glob-to-regexp/-/glob-to-regexp-0.4.1.tgz#c75297087c851b9a578bd217dd59a92f59fe546e" + integrity sha512-lkX1HJXwyMcprw/5YUZc2s7DrpAiHB21/V+E1rHUrVNokkvB6bqMzT0VfV6/86ZNabt1k14YOIaT7nDvOX3Iiw== + +glob@7.2.0: + version "7.2.0" + resolved "https://registry.yarnpkg.com/glob/-/glob-7.2.0.tgz#d15535af7732e02e948f4c41628bd910293f6023" + integrity sha512-lmLf6gtyrPq8tTjSmrO94wBeQbFR3HbLHbuyD69wuyQkImp2hWqMGB47OX65FBkPffO641IP9jWa1z4ivqG26Q== + dependencies: + fs.realpath "^1.0.0" + inflight "^1.0.4" + inherits "2" + minimatch "^3.0.4" + once "^1.3.0" + path-is-absolute "^1.0.0" + +glob@^10.3.10: + version "10.4.5" + resolved "https://registry.yarnpkg.com/glob/-/glob-10.4.5.tgz#f4d9f0b90ffdbab09c9d77f5f29b4262517b0956" + integrity sha512-7Bv8RF0k6xjo7d4A/PxYLbUCfb6c+Vpd2/mB2yRDlew7Jb5hEXiCD9ibfO7wpk8i4sevK6DFny9h7EYbM3/sHg== dependencies: foreground-child "^3.1.0" - jackspeak "^2.0.3" - minimatch "^9.0.1" - minipass "^5.0.0 || ^6.0.2" - path-scurry "^1.7.0" + jackspeak "^3.1.2" + minimatch "^9.0.4" + minipass "^7.1.2" + package-json-from-dist "^1.0.0" + path-scurry "^1.11.1" -glob@^7.1.3, glob@^7.1.4, glob@^7.1.6: +glob@^7.1.3, glob@^7.1.6, glob@^7.2.3: version "7.2.3" resolved "https://registry.npmjs.org/glob/-/glob-7.2.3.tgz" integrity sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q== @@ -2851,9 +3915,9 @@ got@12.1.0: p-cancelable "^3.0.0" responselike "^2.0.0" -got@^11.7.0, got@^11.8.5: +got@^11.8.5, got@^11.8.6: version "11.8.6" - resolved "https://registry.npmjs.org/got/-/got-11.8.6.tgz" + resolved "https://registry.yarnpkg.com/got/-/got-11.8.6.tgz#276e827ead8772eddbcfc97170590b841823233a" integrity sha512-6tfZ91bOr7bOXnK7PRDCGBLa1H4U080YHNaAQ2KsMGlLEzRbk44nsZF2E1IeRc3vtJHPVbKCYgdFbaGO2ljd8g== dependencies: "@sindresorhus/is" "^4.0.0" @@ -2868,15 +3932,15 @@ got@^11.7.0, got@^11.8.5: p-cancelable "^2.0.0" responselike "^2.0.0" -graceful-fs@^4.1.2, graceful-fs@^4.1.6, graceful-fs@^4.2.0, graceful-fs@^4.2.6: +graceful-fs@^4.1.2, graceful-fs@^4.1.6, graceful-fs@^4.2.0, graceful-fs@^4.2.11, graceful-fs@^4.2.4: 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== -"graceful-readlink@>= 1.0.0": - version "1.0.1" - resolved "https://registry.yarnpkg.com/graceful-readlink/-/graceful-readlink-1.0.1.tgz#4cafad76bc62f02fa039b2f94e9a3dd3a391a725" - integrity sha512-8tLu60LgxF6XpdbK8OW3FA+IfTNBn1ZHGHKF4KQbEeSkajYw5PlYJcKluntgegDPTg8UkHjpet1T82vk6TQ68w== +growl@1.10.5: + version "1.10.5" + resolved "https://registry.yarnpkg.com/growl/-/growl-1.10.5.tgz#f2735dc2283674fa67478b10181059355c369e5e" + integrity sha512-qBr4OuELkhPenW6goKVXiv47US3clb3/IbuWF9KNKEijAy9oeHxU9IgzjvJhHkUzhaj7rOUD7+YGWqUjLp5oSA== har-schema@^2.0.0: version "2.0.0" @@ -2932,11 +3996,6 @@ has-tostringtag@^1.0.0: dependencies: has-symbols "^1.0.2" -has-unicode@^2.0.1: - version "2.0.1" - resolved "https://registry.npmjs.org/has-unicode/-/has-unicode-2.0.1.tgz" - integrity sha512-8Rf9Y83NBReMnx0gFzA8JImQACstCYWUplepDa9xprwwtmgEZUF0h/i5xSA625zB/I37EtrswSST6OXxwaaIJQ== - has@^1.0.3: version "1.0.3" resolved "https://registry.npmjs.org/has/-/has-1.0.3.tgz" @@ -2968,6 +4027,18 @@ hasown@^2.0.0: dependencies: function-bind "^1.1.2" +hasown@^2.0.2: + version "2.0.2" + resolved "https://registry.yarnpkg.com/hasown/-/hasown-2.0.2.tgz#003eaf91be7adc372e84ec59dc37252cedb80003" + integrity sha512-0hJU9SCPvmMzIBdZFqNPXWa6dqh7WdH0cII9y+CyS8rG3nL48Bclra9HmKhVVUHyPWNH5Y7xDwAB7bfgSjkUMQ== + dependencies: + function-bind "^1.1.2" + +he@1.2.0: + version "1.2.0" + resolved "https://registry.yarnpkg.com/he/-/he-1.2.0.tgz#84ae65fa7eafb165fddb61566ae14baf05664f0f" + integrity sha512-F/1DnUGPopORZi0ni+CvrCgHQ5FyEAHRLSApuYWMmrbSwoN2Mn/7k+Gl38gJnR7yyDZk6WLXwiGod1JOWNDKGw== + hmac-drbg@^1.0.1: version "1.0.1" resolved "https://registry.yarnpkg.com/hmac-drbg/-/hmac-drbg-1.0.1.tgz#d2745701025a6c775a6c545793ed502fc0c649a1" @@ -2984,7 +4055,7 @@ hosted-git-info@^4.1.0: dependencies: lru-cache "^6.0.0" -http-cache-semantics@^4.0.0, http-cache-semantics@^4.1.1: +http-cache-semantics@^4.0.0: version "4.1.1" resolved "https://registry.npmjs.org/http-cache-semantics/-/http-cache-semantics-4.1.1.tgz" integrity sha512-er295DKPVsV82j5kw1Gjt+ADA/XYHsajl82cGNQG2eyoPkvgUhX+nDIyelzhIWbbsXP39EHcI6l5tYs2FYqYXQ== @@ -3039,9 +4110,9 @@ http2-wrapper@^2.1.10: quick-lru "^5.1.1" resolve-alpn "^1.2.0" -https-proxy-agent@^5.0.0: +https-proxy-agent@^5.0.1: version "5.0.1" - resolved "https://registry.npmjs.org/https-proxy-agent/-/https-proxy-agent-5.0.1.tgz" + resolved "https://registry.yarnpkg.com/https-proxy-agent/-/https-proxy-agent-5.0.1.tgz#c59ef224a04fe8b754f3db0063a25ea30d0005d6" integrity sha512-dFcAjpTQFgoLMzC2VwU+C/CbS7uRL0lWmxDITmqm7C+7F0Odmj6s9l6alZc6AELXhrnggM2CeWSXHGOdX2YtwA== dependencies: agent-base "6" @@ -3055,12 +4126,15 @@ https-proxy-agent@^7.0.2: agent-base "^7.0.2" debug "4" -humanize-ms@^1.2.1: - version "1.2.1" - resolved "https://registry.npmjs.org/humanize-ms/-/humanize-ms-1.2.1.tgz" - integrity sha512-Fl70vYtsAFb/C06PTS9dZBo7ihau+Tu/DNCk/OyHhea07S+aeMWpFFkUaXRa8fI+ScZbEI8dfSxwY7gxZ9SAVQ== - dependencies: - ms "^2.0.0" +human-signals@^1.1.1: + version "1.1.1" + resolved "https://registry.yarnpkg.com/human-signals/-/human-signals-1.1.1.tgz#c5b1cd14f50aeae09ab6c59fe63ba3395fe4dfa3" + integrity sha512-SEQu7vl8KjNL2eoGBLF3+wAjpsNfA9XMlXAYj/3EdaNfAlxKthD1xjEQfGOUhllCGGJVNY34bRr6lPINhNjyZw== + +human-signals@^2.1.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/human-signals/-/human-signals-2.1.0.tgz#dc91fcba42e4d06e4abaed33b3e7a3c02f514ea0" + integrity sha512-B4FFZ6q/T2jhhksgkbEW3HBvWIfDW85snkQgawt07S7J5QXTk6BkNV+0yAeZrM5QpMAdYlocGoljn0sJ/WQkFw== iconv-corefoundation@^1.1.7: version "1.1.7" @@ -3106,14 +4180,17 @@ immediate@~3.0.5: resolved "https://registry.yarnpkg.com/immediate/-/immediate-3.0.6.tgz#9db1dbd0faf8de6fbe0f5dd5e56bb606280de69b" integrity sha512-XXOFtyqDjNDAQxVfYxuF7g9Il/IbWmmlQg2MYKOH8ExIT1qg6xc4zyS3HaEEATgs1btfzxq15ciUiY7gjSXRGQ== -imurmurhash@^0.1.4: - version "0.1.4" - resolved "https://registry.npmjs.org/imurmurhash/-/imurmurhash-0.1.4.tgz" - integrity sha512-JmXMZ6wuvDmLiHEml9ykzqO6lwFbof0GG4IkcGaENdCRDDmMVnny7s5HsIgHCbaq0w2MyPhDqkhTUgS2LU2PHA== +import-local@^3.0.2: + version "3.1.0" + resolved "https://registry.yarnpkg.com/import-local/-/import-local-3.1.0.tgz#b4479df8a5fd44f6cdce24070675676063c95cb4" + integrity sha512-ASB07uLtnDs1o6EHjKpX34BKYDSqnFerfTOJL2HvMqF70LnxpjkzDB8J44oT9pu4AMPkQwf8jl6szgvNd2tRIg== + dependencies: + pkg-dir "^4.2.0" + resolve-cwd "^3.0.0" indent-string@^4.0.0: version "4.0.0" - resolved "https://registry.npmjs.org/indent-string/-/indent-string-4.0.0.tgz" + resolved "https://registry.yarnpkg.com/indent-string/-/indent-string-4.0.0.tgz#624f8f4497d619b2d9768531d58f4122854d7251" integrity sha512-EdDDZu4A2OyIK7Lr/2zG+w5jmbuk1DVBnEwREQvBzspBJkCEbRa8GxU1lghYcaGJCnRWibjDXlq779X1/y5xwg== inflight@^1.0.4: @@ -3129,6 +4206,15 @@ inherits@2, inherits@2.0.4, inherits@^2.0.1, inherits@^2.0.3, inherits@^2.0.4, i resolved "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz" integrity sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ== +internal-slot@^1.0.4: + version "1.0.7" + resolved "https://registry.yarnpkg.com/internal-slot/-/internal-slot-1.0.7.tgz#c06dcca3ed874249881007b0a5523b172a190802" + integrity sha512-NGnrKwXzSms2qUUih/ILZ5JBqNTSa1+ZmP6flaIp6KmSElgE9qdndzS3cqjrDovwFdmwsGsLdeFgB6suw+1e9g== + dependencies: + es-errors "^1.3.0" + hasown "^2.0.0" + side-channel "^1.0.4" + internal-slot@^1.0.5: version "1.0.6" resolved "https://registry.yarnpkg.com/internal-slot/-/internal-slot-1.0.6.tgz#37e756098c4911c5e912b8edbf71ed3aa116f930" @@ -3138,17 +4224,22 @@ internal-slot@^1.0.5: hasown "^2.0.0" side-channel "^1.0.4" -ip@^2.0.0: - version "2.0.1" - resolved "https://registry.yarnpkg.com/ip/-/ip-2.0.1.tgz#e8f3595d33a3ea66490204234b77636965307105" - integrity sha512-lJUL9imLTNi1ZfXT+DU6rBBdbiKGBuay9B6xGSPVjUeQwaH1RIGqef8RZkUtHioLmSNpPR5M4HVKJGm1j8FWVQ== +interpret@^3.1.1: + version "3.1.1" + resolved "https://registry.yarnpkg.com/interpret/-/interpret-3.1.1.tgz#5be0ceed67ca79c6c4bc5cf0d7ee843dcea110c4" + integrity sha512-6xwYfHbajpoF0xLW+iwLkhwgvLoZDfjYfoFNu8ftMoXINzwuymNLd9u/KmwtdT2GbR+/Cz66otEGEVVUHX9QLQ== + +ip-regex@^4.1.0: + version "4.3.0" + resolved "https://registry.yarnpkg.com/ip-regex/-/ip-regex-4.3.0.tgz#687275ab0f57fa76978ff8f4dddc8a23d5990db5" + integrity sha512-B9ZWJxHHOHUhUjCPrMpLD4xEq35bUTClHM1S6CBU5ixQnkZmwipwgc96vAd7AAGM9TGHvJR+Uss+/Ak6UphK+Q== ipaddr.js@1.9.1: version "1.9.1" resolved "https://registry.yarnpkg.com/ipaddr.js/-/ipaddr.js-1.9.1.tgz#bff38543eeb8984825079ff3a2a8e6cbd46781b3" integrity sha512-0KI/607xoxSToH7GjN1FfSbLoU0+btTicjsQSWQlh/hZykN8KpmMf7uYwPW3R+akZ6R/w18ZlXSHBYXiYUPO3g== -is-arguments@^1.0.4: +is-arguments@^1.0.4, is-arguments@^1.1.1: version "1.1.1" resolved "https://registry.yarnpkg.com/is-arguments/-/is-arguments-1.1.1.tgz#15b3f88fda01f2a97fec84ca761a560f123efa9b" integrity sha512-8Q7EARjzEnKpt/PCD7e1cgUS0a6X8u5tdSiMqXhojOdoV9TsMsiO+9VLC5vAmO8N7/GmXn7yjR8qnA6bVAEzfA== @@ -3187,6 +4278,11 @@ is-boolean-object@^1.1.0: call-bind "^1.0.2" has-tostringtag "^1.0.0" +is-buffer@~1.1.6: + version "1.1.6" + resolved "https://registry.yarnpkg.com/is-buffer/-/is-buffer-1.1.6.tgz#efaa2ea9daa0d7ab2ea13a97b2b8ad51fefbe8be" + integrity sha512-NcdALwpXkTm5Zvvbk7owOUSvVvBKDgKP5/ewfXEznmQFfs4ZRmanOeKBTjRVjka3QFoN6XJ+9F3USqfHqTaU5w== + is-callable@^1.1.3, is-callable@^1.1.4, is-callable@^1.2.7: version "1.2.7" resolved "https://registry.yarnpkg.com/is-callable/-/is-callable-1.2.7.tgz#3bc2a85ea742d9e36205dcacdd72ca1fdc51b055" @@ -3199,13 +4295,25 @@ is-ci@^3.0.0: dependencies: ci-info "^3.2.0" -is-date-object@^1.0.1: +is-core-module@^2.13.0: + version "2.14.0" + resolved "https://registry.yarnpkg.com/is-core-module/-/is-core-module-2.14.0.tgz#43b8ef9f46a6a08888db67b1ffd4ec9e3dfd59d1" + integrity sha512-a5dFJih5ZLYlRtDc0dZWP7RiKr6xIKzmn/oAYCDvdLThadVgyJwlaoQPmRtMSpz+rk0OGAgIu+TcM9HUF0fk1A== + dependencies: + hasown "^2.0.2" + +is-date-object@^1.0.1, is-date-object@^1.0.5: version "1.0.5" resolved "https://registry.yarnpkg.com/is-date-object/-/is-date-object-1.0.5.tgz#0841d5536e724c25597bf6ea62e1bd38298df31f" integrity sha512-9YQaSxsAiSwcvS33MBk3wTCVnWK+HhF8VZR2jRxehM16QcVOdHqPn4VPHmRK4lSr38n9JriurInLcP90xsYNfQ== dependencies: has-tostringtag "^1.0.0" +is-docker@^2.0.0, is-docker@^2.1.1: + version "2.2.1" + resolved "https://registry.yarnpkg.com/is-docker/-/is-docker-2.2.1.tgz#33eeabe23cfe86f14bde4408a02c0cfb853acdaa" + integrity sha512-F+i2BKsFrH66iaUFc0woD8sLy8getkwTwtOBjvs56Cx4CgJDeKQeqfz8wAYiSb8JOprWhHH5p77PbmYCvvUuXQ== + is-extglob@^2.1.1: version "2.1.1" resolved "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz" @@ -3242,13 +4350,13 @@ is-hex-prefixed@1.0.0: is-interactive@^1.0.0: version "1.0.0" - resolved "https://registry.npmjs.org/is-interactive/-/is-interactive-1.0.0.tgz" + resolved "https://registry.yarnpkg.com/is-interactive/-/is-interactive-1.0.0.tgz#cea6e6ae5c870a7b0a0004070b7b587e0252912e" integrity sha512-2HvIEKRoqS62guEC+qBjpvRubdX910WCMuJTZ+I9yvqKU2/12eSL549HMwtabb4oupdj2sMP50k+XJfB/8JE6w== -is-lambda@^1.0.1: - version "1.0.1" - resolved "https://registry.npmjs.org/is-lambda/-/is-lambda-1.0.1.tgz" - integrity sha512-z7CMFGNrENq5iFB9Bqo64Xk6Y9sg+epq1myIcdHaGnbMTYOxvzsEtdYqQUylB7LxfkvgrrjP32T6Ywciio9UIQ== +is-map@^2.0.2, is-map@^2.0.3: + version "2.0.3" + resolved "https://registry.yarnpkg.com/is-map/-/is-map-2.0.3.tgz#ede96b7fe1e270b3c4465e3a465658764926d62e" + integrity sha512-1Qed0/Hr2m+YqxnM09CjA2d/i6YZNfF6R2oRAOj36eUdS6qIV/huPJNSEpKbupewFs+ZsJlxsjjPbc0/afW6Lw== is-negative-zero@^2.0.2: version "2.0.2" @@ -3267,6 +4375,23 @@ is-number@^7.0.0: resolved "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz" integrity sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng== +is-plain-obj@^2.1.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/is-plain-obj/-/is-plain-obj-2.1.0.tgz#45e42e37fccf1f40da8e5f76ee21515840c09287" + integrity sha512-YWnfyRwxL/+SsrWYfOpUtz5b3YD+nyfkHvjbcanzk8zgyO4ASD67uVMRt8k5bM4lLMDnXfriRhOpemw+NfT1eA== + +is-plain-object@^2.0.4: + version "2.0.4" + resolved "https://registry.yarnpkg.com/is-plain-object/-/is-plain-object-2.0.4.tgz#2c163b3fafb1b606d9d17928f05c2a1c38e07677" + integrity sha512-h5PpgXkWitc38BBMYawTYMWJHFZJVnBquFE57xFpjB8pJFiF6gZ+bU+WyI/yqXiFR5mdLsgYNaPe8uao6Uv9Og== + dependencies: + isobject "^3.0.1" + +is-port-reachable@^3.0.0: + version "3.1.0" + resolved "https://registry.yarnpkg.com/is-port-reachable/-/is-port-reachable-3.1.0.tgz#f6668d3bca9c36b07f737c48a8f875ab0653cd2b" + integrity sha512-vjc0SSRNZ32s9SbZBzGaiP6YVB+xglLShhgZD/FHMZUXBvQWaV9CtzgeVhjccFJrI6RAMV+LX7NYxueW/A8W5A== + is-regex@^1.1.4: version "1.1.4" resolved "https://registry.yarnpkg.com/is-regex/-/is-regex-1.1.4.tgz#eef5663cd59fa4c0ae339505323df6854bb15958" @@ -3275,6 +4400,11 @@ is-regex@^1.1.4: call-bind "^1.0.2" has-tostringtag "^1.0.0" +is-set@^2.0.2, is-set@^2.0.3: + version "2.0.3" + resolved "https://registry.yarnpkg.com/is-set/-/is-set-2.0.3.tgz#8ab209ea424608141372ded6e0cb200ef1d9d01d" + integrity sha512-iPAjerrse27/ygGLxw+EBR9agv9Y6uLeYVJMu+QNCoouJ1/1ri0mGrcWpfCqFZuzzx3WjtwxG098X+n4OuRkPg== + is-shared-array-buffer@^1.0.2: version "1.0.2" resolved "https://registry.yarnpkg.com/is-shared-array-buffer/-/is-shared-array-buffer-1.0.2.tgz#8f259c573b60b6a32d4058a1a07430c0a7344c79" @@ -3282,6 +4412,11 @@ is-shared-array-buffer@^1.0.2: dependencies: call-bind "^1.0.2" +is-stream@^2.0.0: + version "2.0.1" + resolved "https://registry.yarnpkg.com/is-stream/-/is-stream-2.0.1.tgz#fac1e3d53b97ad5a9d0ae9cef2389f5810a5c077" + integrity sha512-hFoiJiTl63nn+kstHGBtewWSKnQLpyb155KHheA1l39uvtO9nWIop1p3udqPcUd/xbF1VLMO4n7OI6p7RbngDg== + is-string@^1.0.5, is-string@^1.0.7: version "1.0.7" resolved "https://registry.yarnpkg.com/is-string/-/is-string-1.0.7.tgz#0dd12bf2006f255bb58f695110eff7491eebc0fd" @@ -3310,9 +4445,19 @@ is-typedarray@^1.0.0, is-typedarray@~1.0.0: is-unicode-supported@^0.1.0: version "0.1.0" - resolved "https://registry.npmjs.org/is-unicode-supported/-/is-unicode-supported-0.1.0.tgz" + resolved "https://registry.yarnpkg.com/is-unicode-supported/-/is-unicode-supported-0.1.0.tgz#3f26c76a809593b52bfa2ecb5710ed2779b522a7" integrity sha512-knxG2q4UC3u8stRGyAVJCOdxFmv5DZiRcdlIaAQXAbSfJya+OhopNotLQrstBhququ4ZpuKbDc/8S6mgXgPFPw== +is-url@^1.2.4: + version "1.2.4" + resolved "https://registry.yarnpkg.com/is-url/-/is-url-1.2.4.tgz#04a4df46d28c4cff3d73d01ff06abeb318a1aa52" + integrity sha512-ITvGim8FhRiYe4IQ5uHSkj7pVaPDrCTkNd3yq3cV7iZAcJdHTUMPMEHcqSOy9xZ9qFenQCvi+2wjH9a1nXqHww== + +is-weakmap@^2.0.2: + version "2.0.2" + resolved "https://registry.yarnpkg.com/is-weakmap/-/is-weakmap-2.0.2.tgz#bf72615d649dfe5f699079c54b83e47d1ae19cfd" + integrity sha512-K5pXYOm9wqY1RgjpL3YTkF39tni1XajUIkawTLUo9EZEVUFga5gSQJF8nNS7ZwJQ02y+1YCNYcMh+HIf1ZqE+w== + is-weakref@^1.0.2: version "1.0.2" resolved "https://registry.yarnpkg.com/is-weakref/-/is-weakref-1.0.2.tgz#9529f383a9338205e89765e0392efc2f100f06f2" @@ -3320,6 +4465,30 @@ is-weakref@^1.0.2: dependencies: call-bind "^1.0.2" +is-weakset@^2.0.3: + version "2.0.3" + resolved "https://registry.yarnpkg.com/is-weakset/-/is-weakset-2.0.3.tgz#e801519df8c0c43e12ff2834eead84ec9e624007" + integrity sha512-LvIm3/KWzS9oRFHugab7d+M/GcBXuXX5xZkzPmN+NxihdQlZUQ4dWuSV1xR/sq6upL1TJEDrfBgRepHFdBtSNQ== + dependencies: + call-bind "^1.0.7" + get-intrinsic "^1.2.4" + +is-wsl@^2.2.0: + version "2.2.0" + resolved "https://registry.yarnpkg.com/is-wsl/-/is-wsl-2.2.0.tgz#74a4c76e77ca9fd3f932f290c17ea326cd157271" + integrity sha512-fKzAra0rGJUUBwGBgNkHZuToZcn+TtXHpeCgmkMJMMYx1sQDYaCSyjJBSCa2nH1DGm7s3n1oBnohoVTBaN7Lww== + dependencies: + is-docker "^2.0.0" + +is2@^2.0.6: + version "2.0.9" + resolved "https://registry.yarnpkg.com/is2/-/is2-2.0.9.tgz#ff63b441f90de343fa8fac2125ee170da8e8240d" + integrity sha512-rZkHeBn9Zzq52sd9IUIV3a5mfwBY+o2HePMh0wkGBM4z4qjvy2GwVxQ6nNXSfw6MmVP6gf1QIlWjiOavhM3x5g== + dependencies: + deep-is "^0.1.3" + ip-regex "^4.1.0" + is-url "^1.2.4" + isarray@^2.0.5: version "2.0.5" resolved "https://registry.yarnpkg.com/isarray/-/isarray-2.0.5.tgz#8af1e4c1221244cc62459faf38940d4e644a5723" @@ -3330,23 +4499,26 @@ isarray@~1.0.0: resolved "https://registry.yarnpkg.com/isarray/-/isarray-1.0.0.tgz#bb935d48582cba168c06834957a54a3e07124f11" integrity sha512-VLghIWNM6ELQzo7zwmcg0NmTVyWKYjvIeM83yjp0wRDTmUnrM678fQbcKBo6n2CJEF0szoG//ytg+TKla89ALQ== -isbinaryfile@^3.0.2: - version "3.0.3" - resolved "https://registry.yarnpkg.com/isbinaryfile/-/isbinaryfile-3.0.3.tgz#5d6def3edebf6e8ca8cae9c30183a804b5f8be80" - integrity sha512-8cJBL5tTd2OS0dM4jz07wQd5g0dCCqIhUxPIGtZfa5L6hWlvV5MHTITy/DBAsF+Oe2LS1X3krBUhNwaGUWpWxw== - dependencies: - buffer-alloc "^1.2.0" - -isbinaryfile@^4.0.10: +isbinaryfile@^4.0.8: version "4.0.10" resolved "https://registry.yarnpkg.com/isbinaryfile/-/isbinaryfile-4.0.10.tgz#0c5b5e30c2557a2f06febd37b7322946aaee42b3" integrity sha512-iHrqe5shvBUcFbmZq9zOQHBoeOhZJu6RQGrDpBgenUm/Am+F3JM2MgQj+rK3Z601fzrL5gLZWtAPH2OBaSVcyw== +isbinaryfile@^5.0.0: + version "5.0.0" + resolved "https://registry.yarnpkg.com/isbinaryfile/-/isbinaryfile-5.0.0.tgz#034b7e54989dab8986598cbcea41f66663c65234" + integrity sha512-UDdnyGvMajJUWCkib7Cei/dvyJrrvo4FIrsvSFWdPpXSUorzXrDJ0S+X5Q4ZlasfPjca4yqCNNsjbCeiy8FFeg== + isexe@^2.0.0: version "2.0.0" resolved "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz" integrity sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw== +isobject@^3.0.1: + version "3.0.1" + resolved "https://registry.yarnpkg.com/isobject/-/isobject-3.0.1.tgz#4e431e92b11a9731636aa1f9c8d1ccbcfdab78df" + integrity sha512-WhB9zCku7EGTj/HQQRz5aUQEUeoQZH2bWcltRErOpymJ4boYE6wL9Tbr23krRPSZ+C5zqNSrSw+Cc7sZZ4b7vg== + isomorphic-git@^1.24.2: version "1.24.2" resolved "https://registry.npmjs.org/isomorphic-git/-/isomorphic-git-1.24.2.tgz" @@ -3369,10 +4541,10 @@ isstream@~0.1.2: resolved "https://registry.yarnpkg.com/isstream/-/isstream-0.1.2.tgz#47e63f7af55afa6f92e1500e690eb8b8529c099a" integrity sha512-Yljz7ffyPbrLpLngrMtZ7NduUgVvi6wG9RJ9IUcyCd59YQ911PBJphODUcbOVbqYfxe1wuYf/LJ8PauMRwsM/g== -jackspeak@^2.0.3: - version "2.2.1" - resolved "https://registry.npmjs.org/jackspeak/-/jackspeak-2.2.1.tgz" - integrity sha512-MXbxovZ/Pm42f6cDIDkl3xpwv1AGwObKwfmjs2nQePiy85tP3fatofl3FC1aBsOtP/6fq5SbtgHwWcMsLP+bDw== +jackspeak@^3.1.2: + version "3.4.3" + resolved "https://registry.yarnpkg.com/jackspeak/-/jackspeak-3.4.3.tgz#8833a9d89ab4acde6188942bd1c53b6390ed5a8a" + integrity sha512-OGlZQpz2yfahA/Rd1Y8Cd9SIEsqvXkLVoSw/cgwhnhFMDbsQFeZYoJJ7bIZBS9BcamUW96asq/npPWugM+RQBw== dependencies: "@isaacs/cliui" "^8.0.2" optionalDependencies: @@ -3388,6 +4560,15 @@ jake@^10.8.5: filelist "^1.0.4" minimatch "^3.1.2" +jest-worker@^27.4.5: + version "27.5.1" + resolved "https://registry.yarnpkg.com/jest-worker/-/jest-worker-27.5.1.tgz#8d146f0900e8973b106b6f73cc1e9a8cb86f8db0" + integrity sha512-7vuh85V5cdDofPyxn58nrPjBktZo0u9x1g8WtjQol+jZDaE+fhN+cIvTj11GndBnMnyfrUOG1sZQxCdjKh+DKg== + dependencies: + "@types/node" "*" + merge-stream "^2.0.0" + supports-color "^8.0.0" + js-sha3@0.8.0, js-sha3@^0.8.0: version "0.8.0" resolved "https://registry.yarnpkg.com/js-sha3/-/js-sha3-0.8.0.tgz#b9b7a5da73afad7dedd0f8c463954cbde6818840" @@ -3398,7 +4579,7 @@ js-sha3@^0.5.7: resolved "https://registry.yarnpkg.com/js-sha3/-/js-sha3-0.5.7.tgz#0d4ffd8002d5333aabaf4a23eed2f6374c9f28e7" integrity sha512-GII20kjaPX0zJ8wzkTbNDYMY7msuZcTWk8S5UOh6806Jq/wz1J8/bnr8uGU0DAUmYDjj2Mr4X1cW8v/GLYnR+g== -js-yaml@^4.1.0: +js-yaml@4.1.0, js-yaml@^4.1.0: version "4.1.0" resolved "https://registry.npmjs.org/js-yaml/-/js-yaml-4.1.0.tgz" integrity sha512-wpxZs9NoxZaJESJGIZTyDEaYpl0FKSA+FB9aJiyemKhMwkxQg63h4T1KJgUGHpTqPDNRcmmYLugrRjJlBtWvRA== @@ -3415,6 +4596,11 @@ json-buffer@3.0.1: resolved "https://registry.npmjs.org/json-buffer/-/json-buffer-3.0.1.tgz" integrity sha512-4bV5BfR2mqfQTJm+V5tPPdf+ZpuhiIvTuAB5g8kcrXOZpTT/QwwVRWBywX1ozr6lEuPdbHxwaJlm9G6mI2sfSQ== +json-parse-even-better-errors@^2.3.1: + version "2.3.1" + resolved "https://registry.yarnpkg.com/json-parse-even-better-errors/-/json-parse-even-better-errors-2.3.1.tgz#7c47805a94319928e05777405dc12e1f7a4ee02d" + integrity sha512-xyFwyhro/JEof6Ghe2iz2NcXoj2sloNsWr/XsERDK/oiPCfaNhl5ONfp+jQdAZRQQ0IJWNzH9zIZF7li91kh2w== + json-schema-traverse@^0.4.1: version "0.4.1" resolved "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz" @@ -3430,9 +4616,9 @@ json-stringify-safe@^5.0.1, json-stringify-safe@~5.0.1: resolved "https://registry.npmjs.org/json-stringify-safe/-/json-stringify-safe-5.0.1.tgz" integrity sha512-ZClg6AaYvamvYEE82d3Iyd3vSSIjQ+odgjaTzRuO3s7toCdFKczob2i0zCh7JE8kWn17yvAWhUVxvqGwUalsRA== -json5@^2.2.0: +json5@^2.1.2, json5@^2.2.0, json5@^2.2.2: version "2.2.3" - resolved "https://registry.npmjs.org/json5/-/json5-2.2.3.tgz" + resolved "https://registry.yarnpkg.com/json5/-/json5-2.2.3.tgz#78cd6f1a19bdc12b73db5ad0c61efd66c1e29283" integrity sha512-XmOWe7eyHYH14cLdVPoyg+GOH3rYX++KpzrylJwSW98t3Nk+U8XOl8FWKOgwtzdb8lXGf6zYwDUzeHMWfxasyg== jsonfile@^4.0.0: @@ -3451,6 +4637,22 @@ jsonfile@^6.0.1: optionalDependencies: graceful-fs "^4.1.6" +jsonwebtoken@^9.0.2: + version "9.0.2" + resolved "https://registry.yarnpkg.com/jsonwebtoken/-/jsonwebtoken-9.0.2.tgz#65ff91f4abef1784697d40952bb1998c504caaf3" + integrity sha512-PRp66vJ865SSqOlgqS8hujT5U4AOgMfhrwYIuIhfKaoSCZcirrmASQr8CX7cUg+RMih+hgznrjp99o+W4pJLHQ== + dependencies: + jws "^3.2.2" + lodash.includes "^4.3.0" + lodash.isboolean "^3.0.3" + lodash.isinteger "^4.0.4" + lodash.isnumber "^3.0.3" + lodash.isplainobject "^4.0.6" + lodash.isstring "^4.0.1" + lodash.once "^4.0.0" + ms "^2.1.1" + semver "^7.5.4" + jsprim@^1.2.2: version "1.4.2" resolved "https://registry.yarnpkg.com/jsprim/-/jsprim-1.4.2.tgz#712c65533a15c878ba59e9ed5f0e26d5b77c5feb" @@ -3461,7 +4663,7 @@ jsprim@^1.2.2: json-schema "0.4.0" verror "1.10.0" -jszip@^3.1.0: +jszip@^3.1.0, jszip@^3.10.0: version "3.10.1" resolved "https://registry.yarnpkg.com/jszip/-/jszip-3.10.1.tgz#34aee70eb18ea1faec2f589208a157d1feb091c2" integrity sha512-xXDvecyTpGLrqFrvkrUSoxxfJI5AH7U8zxxtVclpsUtMCq4JQ290LY8AW5c7Ggnr/Y/oK+bQMbqK2qmtk3pN4g== @@ -3471,6 +4673,23 @@ jszip@^3.1.0: readable-stream "~2.3.6" setimmediate "^1.0.5" +jwa@^1.4.1: + version "1.4.1" + resolved "https://registry.yarnpkg.com/jwa/-/jwa-1.4.1.tgz#743c32985cb9e98655530d53641b66c8645b039a" + integrity sha512-qiLX/xhEEFKUAJ6FiBMbes3w9ATzyk5W7Hvzpa/SLYdxNtng+gcurvrI7TbACjIXlsJyr05/S1oUhZrc63evQA== + dependencies: + buffer-equal-constant-time "1.0.1" + ecdsa-sig-formatter "1.0.11" + safe-buffer "^5.0.1" + +jws@^3.2.2: + version "3.2.2" + resolved "https://registry.yarnpkg.com/jws/-/jws-3.2.2.tgz#001099f3639468c9414000e99995fa52fb478304" + integrity sha512-YHlZCB6lMTllWDtSPHz/ZXTsi8S00usEV6v1tjq8tOUZzw7DpSDWVXjXDre6ed1w/pd495ODpHZYSdkRTsa0HA== + dependencies: + jwa "^1.4.1" + safe-buffer "^5.0.1" + keccak@^3.0.0: version "3.0.4" resolved "https://registry.yarnpkg.com/keccak/-/keccak-3.0.4.tgz#edc09b89e633c0549da444432ecf062ffadee86d" @@ -3487,6 +4706,11 @@ keyv@^4.0.0: dependencies: json-buffer "3.0.1" +kind-of@^6.0.2: + version "6.0.3" + resolved "https://registry.yarnpkg.com/kind-of/-/kind-of-6.0.3.tgz#07c05034a6c349fa06e24fa35aa76db4580ce4dd" + integrity sha512-dcS1ul+9tmeD95T+x28/ehLgd9mENa3LsvDTtzm3vyBEO7RPptvAD+t44WVXaUjTBRcrpFeFlC8WCruUR456hw== + lazy-val@^1.0.4, lazy-val@^1.0.5: version "1.0.5" resolved "https://registry.npmjs.org/lazy-val/-/lazy-val-1.0.5.tgz" @@ -3499,19 +4723,202 @@ lie@~3.3.0: dependencies: immediate "~3.0.5" +loader-runner@^4.2.0: + version "4.3.0" + resolved "https://registry.yarnpkg.com/loader-runner/-/loader-runner-4.3.0.tgz#c1b4a163b99f614830353b16755e7149ac2314e1" + integrity sha512-3R/1M+yS3j5ou80Me59j7F9IMs4PXs3VqRrm0TU3AbKPxlmpoY1TNscJV/oGJXo8qCatFGTfDbY6W6ipGOYXfg== + +loader-utils@^2.0.0: + version "2.0.4" + resolved "https://registry.yarnpkg.com/loader-utils/-/loader-utils-2.0.4.tgz#8b5cb38b5c34a9a018ee1fc0e6a066d1dfcc528c" + integrity sha512-xXqpXoINfFhgua9xiqD8fPFHgkoq1mmmpE92WlDbm9rNRd/EbRb+Gqf908T2DMfuHjjJlksiK2RbHVOdD/MqSw== + dependencies: + big.js "^5.2.2" + emojis-list "^3.0.0" + json5 "^2.1.2" + +locate-path@^5.0.0: + version "5.0.0" + resolved "https://registry.yarnpkg.com/locate-path/-/locate-path-5.0.0.tgz#1afba396afd676a6d42504d0a67a3a7eb9f62aa0" + integrity sha512-t7hw9pI+WvuwNJXwk5zVHpyhIqzg2qTlklJOf0mVxGSbe3Fp2VieZcduNYjaLDoy6p9uGpQEGWG87WpMKlNq8g== + dependencies: + p-locate "^4.1.0" + +locate-path@^6.0.0: + version "6.0.0" + resolved "https://registry.yarnpkg.com/locate-path/-/locate-path-6.0.0.tgz#55321eb309febbc59c4801d931a72452a681d286" + integrity sha512-iPZK6eYjbxRu3uB4/WZ3EsEIMJFMqAoopl3R+zuq0UjcAm/MO6KCweDgPfP3elTztoKP3KtnVHxTn2NHBSDVUw== + dependencies: + p-locate "^5.0.0" + +lodash._arraycopy@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/lodash._arraycopy/-/lodash._arraycopy-3.0.0.tgz#76e7b7c1f1fb92547374878a562ed06a3e50f6e1" + integrity sha512-RHShTDnPKP7aWxlvXKiDT6IX2jCs6YZLCtNhOru/OX2Q/tzX295vVBK5oX1ECtN+2r86S0Ogy8ykP1sgCZAN0A== + +lodash._arrayeach@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/lodash._arrayeach/-/lodash._arrayeach-3.0.0.tgz#bab156b2a90d3f1bbd5c653403349e5e5933ef9e" + integrity sha512-Mn7HidOVcl3mkQtbPsuKR0Fj0N6Q6DQB77CtYncZcJc0bx5qv2q4Gl6a0LC1AN+GSxpnBDNnK3CKEm9XNA4zqQ== + +lodash._baseassign@^3.0.0: + version "3.2.0" + resolved "https://registry.yarnpkg.com/lodash._baseassign/-/lodash._baseassign-3.2.0.tgz#8c38a099500f215ad09e59f1722fd0c52bfe0a4e" + integrity sha512-t3N26QR2IdSN+gqSy9Ds9pBu/J1EAFEshKlUHpJG3rvyJOYgcELIxcIeKKfZk7sjOz11cFfzJRsyFry/JyabJQ== + dependencies: + lodash._basecopy "^3.0.0" + lodash.keys "^3.0.0" + +lodash._baseclone@^3.0.0: + version "3.3.0" + resolved "https://registry.yarnpkg.com/lodash._baseclone/-/lodash._baseclone-3.3.0.tgz#303519bf6393fe7e42f34d8b630ef7794e3542b7" + integrity sha512-1K0dntf2dFQ5my0WoGKkduewR6+pTNaqX03kvs45y7G5bzl4B3kTR4hDfJIc2aCQDeLyQHhS280tc814m1QC1Q== + dependencies: + lodash._arraycopy "^3.0.0" + lodash._arrayeach "^3.0.0" + lodash._baseassign "^3.0.0" + lodash._basefor "^3.0.0" + lodash.isarray "^3.0.0" + lodash.keys "^3.0.0" + +lodash._basecopy@^3.0.0: + version "3.0.1" + resolved "https://registry.yarnpkg.com/lodash._basecopy/-/lodash._basecopy-3.0.1.tgz#8da0e6a876cf344c0ad8a54882111dd3c5c7ca36" + integrity sha512-rFR6Vpm4HeCK1WPGvjZSJ+7yik8d8PVUdCJx5rT2pogG4Ve/2ZS7kfmO5l5T2o5V2mqlNIfSF5MZlr1+xOoYQQ== + +lodash._basefor@^3.0.0: + version "3.0.3" + resolved "https://registry.yarnpkg.com/lodash._basefor/-/lodash._basefor-3.0.3.tgz#7550b4e9218ef09fad24343b612021c79b4c20c2" + integrity sha512-6bc3b8grkpMgDcVJv9JYZAk/mHgcqMljzm7OsbmcE2FGUMmmLQTPHlh/dFqR8LA0GQ7z4K67JSotVKu5058v1A== + +lodash._bindcallback@^3.0.0: + version "3.0.1" + resolved "https://registry.yarnpkg.com/lodash._bindcallback/-/lodash._bindcallback-3.0.1.tgz#e531c27644cf8b57a99e17ed95b35c748789392e" + integrity sha512-2wlI0JRAGX8WEf4Gm1p/mv/SZ+jLijpj0jyaE/AXeuQphzCgD8ZQW4oSpoN8JAopujOFGU3KMuq7qfHBWlGpjQ== + +lodash._getnative@^3.0.0: + version "3.9.1" + resolved "https://registry.yarnpkg.com/lodash._getnative/-/lodash._getnative-3.9.1.tgz#570bc7dede46d61cdcde687d65d3eecbaa3aaff5" + integrity sha512-RrL9VxMEPyDMHOd9uFbvMe8X55X16/cGM5IgOKgRElQZutpX89iS6vwl64duTV1/16w5JY7tuFNXqoekmh1EmA== + +lodash._isiterateecall@^3.0.0: + version "3.0.9" + resolved "https://registry.yarnpkg.com/lodash._isiterateecall/-/lodash._isiterateecall-3.0.9.tgz#5203ad7ba425fae842460e696db9cf3e6aac057c" + integrity sha512-De+ZbrMu6eThFti/CSzhRvTKMgQToLxbij58LMfM8JnYDNSOjkjTCIaa8ixglOeGh2nyPlakbt5bJWJ7gvpYlQ== + +lodash.clone@3.0.3: + version "3.0.3" + resolved "https://registry.yarnpkg.com/lodash.clone/-/lodash.clone-3.0.3.tgz#84688c73d32b5a90ca25616963f189252a997043" + integrity sha512-yVYPpFTdZDCLG2p07gVRTvcwN5X04oj2hu4gG6r0fer58JA08wAVxXzWM+CmmxO2bzOH8u8BkZTZqgX6juVF7A== + dependencies: + lodash._baseclone "^3.0.0" + lodash._bindcallback "^3.0.0" + lodash._isiterateecall "^3.0.0" + +lodash.defaultsdeep@4.6.1: + version "4.6.1" + resolved "https://registry.yarnpkg.com/lodash.defaultsdeep/-/lodash.defaultsdeep-4.6.1.tgz#512e9bd721d272d94e3d3a63653fa17516741ca6" + integrity sha512-3j8wdDzYuWO3lM3Reg03MuQR957t287Rpcxp1njpEa8oDrikb+FwGdW3n+FELh/A6qib6yPit0j/pv9G/yeAqA== + +lodash.escape@4.0.1: + version "4.0.1" + resolved "https://registry.yarnpkg.com/lodash.escape/-/lodash.escape-4.0.1.tgz#c9044690c21e04294beaa517712fded1fa88de98" + integrity sha512-nXEOnb/jK9g0DYMr1/Xvq6l5xMD7GDG55+GSYIYmS0G4tBk/hURD4JR9WCavs04t33WmJx9kCyp9vJ+mr4BOUw== + +lodash.escaperegexp@^4.1.2: + version "4.1.2" + resolved "https://registry.yarnpkg.com/lodash.escaperegexp/-/lodash.escaperegexp-4.1.2.tgz#64762c48618082518ac3df4ccf5d5886dae20347" + integrity sha512-TM9YBvyC84ZxE3rgfefxUWiQKLilstD6k7PTGt6wfbtXF8ixIJLOL3VYyV/z+ZiPLsVxAsKAFVwWlWeb2Y8Yyw== + +lodash.includes@^4.3.0: + version "4.3.0" + resolved "https://registry.yarnpkg.com/lodash.includes/-/lodash.includes-4.3.0.tgz#60bb98a87cb923c68ca1e51325483314849f553f" + integrity sha512-W3Bx6mdkRTGtlJISOvVD/lbqjTlPPUDTMnlXZFnVwi9NKJ6tiAk6LVdlhZMm17VZisqhKcgzpO5Wz91PCt5b0w== + +lodash.isarguments@^3.0.0: + version "3.1.0" + resolved "https://registry.yarnpkg.com/lodash.isarguments/-/lodash.isarguments-3.1.0.tgz#2f573d85c6a24289ff00663b491c1d338ff3458a" + integrity sha512-chi4NHZlZqZD18a0imDHnZPrDeBbTtVN7GXMwuGdRH9qotxAjYs3aVLKc7zNOG9eddR5Ksd8rvFEBc9SsggPpg== + +lodash.isarray@^3.0.0: + version "3.0.4" + resolved "https://registry.yarnpkg.com/lodash.isarray/-/lodash.isarray-3.0.4.tgz#79e4eb88c36a8122af86f844aa9bcd851b5fbb55" + integrity sha512-JwObCrNJuT0Nnbuecmqr5DgtuBppuCvGD9lxjFpAzwnVtdGoDQ1zig+5W8k5/6Gcn0gZ3936HDAlGd28i7sOGQ== + +lodash.isboolean@^3.0.3: + version "3.0.3" + resolved "https://registry.yarnpkg.com/lodash.isboolean/-/lodash.isboolean-3.0.3.tgz#6c2e171db2a257cd96802fd43b01b20d5f5870f6" + integrity sha512-Bz5mupy2SVbPHURB98VAcw+aHh4vRV5IPNhILUCsOzRmsTmSQ17jIuqopAentWoehktxGd9e/hbIXq980/1QJg== + +lodash.isequal@^4.5.0: + version "4.5.0" + resolved "https://registry.yarnpkg.com/lodash.isequal/-/lodash.isequal-4.5.0.tgz#415c4478f2bcc30120c22ce10ed3226f7d3e18e0" + integrity sha512-pDo3lu8Jhfjqls6GkMgpahsF9kCyayhgykjyLMNFTKWrpVdAQtYyB4muAMWozBB4ig/dtWAmsMxLEI8wuz+DYQ== + +lodash.isinteger@^4.0.4: + version "4.0.4" + resolved "https://registry.yarnpkg.com/lodash.isinteger/-/lodash.isinteger-4.0.4.tgz#619c0af3d03f8b04c31f5882840b77b11cd68343" + integrity sha512-DBwtEWN2caHQ9/imiNeEA5ys1JoRtRfY3d7V9wkqtbycnAmTvRRmbHKDV4a0EYc678/dia0jrte4tjYwVBaZUA== + +lodash.isnumber@^3.0.3: + version "3.0.3" + resolved "https://registry.yarnpkg.com/lodash.isnumber/-/lodash.isnumber-3.0.3.tgz#3ce76810c5928d03352301ac287317f11c0b1ffc" + integrity sha512-QYqzpfwO3/CWf3XP+Z+tkQsfaLL/EnUlXWVkIk5FUPc4sBdTehEqZONuyRt2P67PXAk+NXmTBcc97zw9t1FQrw== + +lodash.isplainobject@^4.0.6: + version "4.0.6" + resolved "https://registry.yarnpkg.com/lodash.isplainobject/-/lodash.isplainobject-4.0.6.tgz#7c526a52d89b45c45cc690b88163be0497f550cb" + integrity sha512-oSXzaWypCMHkPC3NvBEaPHf0KsA5mvPrOPgQWDsbg8n7orZ290M0BmC/jgRZ4vcJ6DTAhjrsSYgdsW/F+MFOBA== + +lodash.isstring@^4.0.1: + version "4.0.1" + resolved "https://registry.yarnpkg.com/lodash.isstring/-/lodash.isstring-4.0.1.tgz#d527dfb5456eca7cc9bb95d5daeaf88ba54a5451" + integrity sha512-0wJxfxH1wgO3GrbuP+dTTk7op+6L41QCXbGINEmD+ny/G/eCqGzxyCsh7159S+mgDDcoarnBw6PC1PS5+wUGgw== + +lodash.keys@^3.0.0: + version "3.1.2" + resolved "https://registry.yarnpkg.com/lodash.keys/-/lodash.keys-3.1.2.tgz#4dbc0472b156be50a0b286855d1bd0b0c656098a" + integrity sha512-CuBsapFjcubOGMn3VD+24HOAPxM79tH+V6ivJL3CHYjtrawauDJHUk//Yew9Hvc6e9rbCrURGk8z6PC+8WJBfQ== + dependencies: + lodash._getnative "^3.0.0" + lodash.isarguments "^3.0.0" + lodash.isarray "^3.0.0" + +lodash.mapvalues@^4.6.0: + version "4.6.0" + resolved "https://registry.yarnpkg.com/lodash.mapvalues/-/lodash.mapvalues-4.6.0.tgz#1bafa5005de9dd6f4f26668c30ca37230cc9689c" + integrity sha512-JPFqXFeZQ7BfS00H58kClY7SPVeHertPE0lNuCyZ26/XlN8TvakYD7b9bGyNmXbT/D3BbtPAAmq90gPWqLkxlQ== + +lodash.merge@4.6.2, lodash.merge@^4.6.2: + version "4.6.2" + resolved "https://registry.yarnpkg.com/lodash.merge/-/lodash.merge-4.6.2.tgz#558aa53b43b661e1925a0afdfa36a9a1085fe57a" + integrity sha512-0KpjqXRVvrYyCsX1swR/XTK0va6VQkQM6MNo7PqW77ByjAhoARA8EfrP1N4+KlKj8YS0ZUCtRT/YUuhyYDujIQ== + +lodash.once@^4.0.0: + version "4.1.1" + resolved "https://registry.yarnpkg.com/lodash.once/-/lodash.once-4.1.1.tgz#0dd3971213c7c56df880977d504c88fb471a97ac" + integrity sha512-Sb487aTOCr9drQVL8pIxOzVhafOjZN9UU54hiN8PU3uAiSV7lx1yYNpbNmex2PK6dSJoNTSJUUswT651yww3Mg== + lodash@^4.17.15: version "4.17.21" resolved "https://registry.npmjs.org/lodash/-/lodash-4.17.21.tgz" integrity sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg== -log-symbols@^4.1.0: +log-symbols@4.1.0, log-symbols@^4.1.0: version "4.1.0" - resolved "https://registry.npmjs.org/log-symbols/-/log-symbols-4.1.0.tgz" + resolved "https://registry.yarnpkg.com/log-symbols/-/log-symbols-4.1.0.tgz#3fbdbb95b4683ac9fc785111e792e558d4abd503" integrity sha512-8XPvpAA8uyhfteu8pIvQxpJZ7SYYdpUivZpGy6sFsBuKRY/7rQGavedeB8aK+Zkyq6upMFVL/9AW6vOYzfRyLg== dependencies: chalk "^4.1.0" is-unicode-supported "^0.1.0" +loupe@2.3.4: + version "2.3.4" + resolved "https://registry.yarnpkg.com/loupe/-/loupe-2.3.4.tgz#7e0b9bffc76f148f9be769cb1321d3dcf3cb25f3" + integrity sha512-OvKfgCC2Ndby6aSTREl5aCCPTNIzlDfQZvZxNUrBrihDhL3xcrYegTblhmEiCrg2kKQz4XsFIaemE5BF4ybSaQ== + dependencies: + get-func-name "^2.0.0" + lowercase-keys@^2.0.0: version "2.0.0" resolved "https://registry.npmjs.org/lowercase-keys/-/lowercase-keys-2.0.0.tgz" @@ -3522,6 +4929,11 @@ lowercase-keys@^3.0.0: resolved "https://registry.yarnpkg.com/lowercase-keys/-/lowercase-keys-3.0.0.tgz#c5e7d442e37ead247ae9db117a9d0a467c89d4f2" integrity sha512-ozCC6gdQ+glXOQsveKD0YsDy8DSQFjDTz4zyzEHNV5+JP5D62LmfDZ6o1cycFx9ouG940M5dE8C8CTewdj2YWQ== +lru-cache@^10.0.0, lru-cache@^10.2.0: + version "10.4.3" + resolved "https://registry.yarnpkg.com/lru-cache/-/lru-cache-10.4.3.tgz#410fc8a17b70e598013df257c2446b7f3383f119" + integrity sha512-JNAzZcXrCt42VGLuYz0zfAzDfAvJWW6AfYlDBQyDV5DClI2m5sAmK+OIO7s59XfsRsWHp02jAJrRadPRGTt6SQ== + lru-cache@^6.0.0: version "6.0.0" resolved "https://registry.npmjs.org/lru-cache/-/lru-cache-6.0.0.tgz" @@ -3529,37 +4941,6 @@ lru-cache@^6.0.0: dependencies: yallist "^4.0.0" -lru-cache@^7.7.1: - version "7.18.3" - resolved "https://registry.npmjs.org/lru-cache/-/lru-cache-7.18.3.tgz" - integrity sha512-jumlc0BIUrS3qJGgIkWZsyfAM7NCWiBcCDhnd+3NNM5KbBmLTgHVfWBcg6W+rLUsIpzpERPsvwUP7CckAQSOoA== - -lru-cache@^9.1.1: - version "9.1.2" - resolved "https://registry.npmjs.org/lru-cache/-/lru-cache-9.1.2.tgz" - integrity sha512-ERJq3FOzJTxBbFjZ7iDs+NiK4VI9Wz+RdrrAB8dio1oV+YvdPzUEE4QNiT2VD51DkIbCYRUUzCRkssXCHqSnKQ== - -make-fetch-happen@^11.0.3: - version "11.1.1" - resolved "https://registry.npmjs.org/make-fetch-happen/-/make-fetch-happen-11.1.1.tgz" - integrity sha512-rLWS7GCSTcEujjVBs2YqG7Y4643u8ucvCJeSRqiLYhesrDuzeuFIk37xREzAsfQaqzl8b9rNCE4m6J8tvX4Q8w== - dependencies: - agentkeepalive "^4.2.1" - cacache "^17.0.0" - http-cache-semantics "^4.1.1" - http-proxy-agent "^5.0.0" - https-proxy-agent "^5.0.0" - is-lambda "^1.0.1" - lru-cache "^7.7.1" - minipass "^5.0.0" - minipass-fetch "^3.0.0" - minipass-flush "^1.0.5" - minipass-pipeline "^1.2.4" - negotiator "^0.6.3" - promise-retry "^2.0.1" - socks-proxy-agent "^7.0.0" - ssri "^10.0.0" - matcher@^3.0.0: version "3.0.0" resolved "https://registry.npmjs.org/matcher/-/matcher-3.0.0.tgz" @@ -3567,6 +4948,11 @@ matcher@^3.0.0: dependencies: escape-string-regexp "^4.0.0" +matomo-tracker@^2.2.4: + version "2.2.4" + resolved "https://registry.yarnpkg.com/matomo-tracker/-/matomo-tracker-2.2.4.tgz#ee397d915d7b2e7964996ca28a0a03f4f0692453" + integrity sha512-7fDy4wRhDQ1dnSxVqmnVqmmos9ACKag0fCBtBD3/Qeoqks7MFqXcO35nfS6S8xU/IXNf7534q/4Gx8fuWKYW6A== + md5.js@^1.3.4: version "1.3.5" resolved "https://registry.yarnpkg.com/md5.js/-/md5.js-1.3.5.tgz#b5d07b8e3216e3e27cd728d72f70d1e6a342005f" @@ -3576,6 +4962,15 @@ md5.js@^1.3.4: inherits "^2.0.1" safe-buffer "^5.1.2" +md5@^2.3.0: + version "2.3.0" + resolved "https://registry.yarnpkg.com/md5/-/md5-2.3.0.tgz#c3da9a6aae3a30b46b7b0c349b87b110dc3bda4f" + integrity sha512-T1GITYmFaKuO91vxyoQMFETst+O71VUPEU3ze5GNzDm0OWdP8v1ziTaAEPUr/3kLsY3Sftgz242A1SetQiDL7g== + dependencies: + charenc "0.0.2" + crypt "0.0.2" + is-buffer "~1.1.6" + media-typer@0.3.0: version "0.3.0" resolved "https://registry.yarnpkg.com/media-typer/-/media-typer-0.3.0.tgz#8710d7af0aa626f8fffa1ce00168545263255748" @@ -3586,6 +4981,11 @@ merge-descriptors@1.0.3: resolved "https://registry.yarnpkg.com/merge-descriptors/-/merge-descriptors-1.0.3.tgz#d80319a65f3c7935351e5cfdac8f9318504dbed5" integrity sha512-gaNvAS7TZ897/rVaZ0nMtAyxNyi/pdbjbAwUpFQpN70GqnVfOiXpeUUMKRBmzXaSQ8DdTX4/0ms62r2K+hE6mQ== +merge-stream@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/merge-stream/-/merge-stream-2.0.0.tgz#52823629a14dd00c9770fb6ad47dc6310f2c1f60" + integrity sha512-abv/qOcuPfk3URPfDzmZU1LKmuw8kT+0nIHvKrKgFrwifol/doWcdA4ZqsWQ8ENrFKkd67Mfpo/LovbIUsbt3w== + methods@~1.1.2: version "1.1.2" resolved "https://registry.yarnpkg.com/methods/-/methods-1.1.2.tgz#5529a4d67654134edcc5266656835b0f851afcee" @@ -3596,12 +4996,20 @@ micro-ftch@^0.3.1: resolved "https://registry.yarnpkg.com/micro-ftch/-/micro-ftch-0.3.1.tgz#6cb83388de4c1f279a034fb0cf96dfc050853c5f" integrity sha512-/0LLxhzP0tfiR5hcQebtudP56gUurs2CLkGarnCiB/OqEyUFQ6U3paQi/tgLv0hBJYt2rnr9MNpxz4fiiugstg== +micromatch@^4.0.0: + version "4.0.7" + resolved "https://registry.yarnpkg.com/micromatch/-/micromatch-4.0.7.tgz#33e8190d9fe474a9895525f5618eee136d46c2e5" + integrity sha512-LPP/3KorzCwBxfeUuZmaR6bG2kdeHSbe0P2tY3FLRU4vYrjYz5hI4QZwV0njUx3jeuKe67YukQ1LSPZBKDqO/Q== + dependencies: + braces "^3.0.3" + picomatch "^2.3.1" + mime-db@1.52.0: version "1.52.0" resolved "https://registry.npmjs.org/mime-db/-/mime-db-1.52.0.tgz" integrity sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg== -mime-types@^2.1.12, mime-types@^2.1.16, mime-types@~2.1.19, mime-types@~2.1.24, mime-types@~2.1.34: +mime-types@^2.1.12, mime-types@^2.1.16, mime-types@^2.1.27, mime-types@~2.1.19, mime-types@~2.1.24, mime-types@~2.1.34: version "2.1.35" resolved "https://registry.npmjs.org/mime-types/-/mime-types-2.1.35.tgz" integrity sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw== @@ -3620,7 +5028,7 @@ mime@^2.5.2: mimic-fn@^2.1.0: version "2.1.0" - resolved "https://registry.npmjs.org/mimic-fn/-/mimic-fn-2.1.0.tgz" + resolved "https://registry.yarnpkg.com/mimic-fn/-/mimic-fn-2.1.0.tgz#7ed2c2ccccaf84d3ffcb7a69b57711fc2083401b" integrity sha512-OqbOk5oEQeAZ8WXWydlu9HJjz9WVdEIvamMCcXmuqUYjTknH/sqsWvhQ3vgwKFRR1HpjvNBKQ37nbJgYzGqGcg== mimic-response@^1.0.0: @@ -3650,35 +5058,40 @@ minimalistic-crypto-utils@^1.0.1: resolved "https://registry.yarnpkg.com/minimalistic-crypto-utils/-/minimalistic-crypto-utils-1.0.1.tgz#f6c00c1c0b082246e5c4d99dfb8c7c083b2b582a" integrity sha512-JIYlbt6g8i5jKfJ3xz7rF0LXmv2TkDxBLUkiBeZ7bAx4GnnNMr8xFpGnOxn6GhTEHx3SjRrZEoU+j04prX1ktg== -minimatch@3.0.4: - version "3.0.4" - resolved "https://registry.yarnpkg.com/minimatch/-/minimatch-3.0.4.tgz#5166e286457f03306064be5497e8dbb0c3d32083" - integrity sha512-yJHVQEhyqPLUTgt9B83PXu6W3rx4MvvHvSUvToogpwoGDOUQ+yDrR0HRot+yOCdCO7u4hX3pWft6kWBBcqh0UA== - dependencies: - brace-expansion "^1.1.7" - -minimatch@^3.0.4, minimatch@^3.1.1, minimatch@^3.1.2: +minimatch@3.1.2, minimatch@^3.0.4, minimatch@^3.1.1, minimatch@^3.1.2: version "3.1.2" resolved "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz" integrity sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw== dependencies: brace-expansion "^1.1.7" -minimatch@^5.0.1: +minimatch@4.2.1: + version "4.2.1" + resolved "https://registry.yarnpkg.com/minimatch/-/minimatch-4.2.1.tgz#40d9d511a46bdc4e563c22c3080cde9c0d8299b4" + integrity sha512-9Uq1ChtSZO+Mxa/CL1eGizn2vRn3MlLgzhT0Iz8zaY8NdvxvB0d5QdPFmCKf7JKA9Lerx5vRrnwO03jsSfGG9g== + dependencies: + brace-expansion "^1.1.7" + +minimatch@^5.0.1, minimatch@^5.1.1: version "5.1.6" resolved "https://registry.npmjs.org/minimatch/-/minimatch-5.1.6.tgz" integrity sha512-lKwV/1brpG6mBUFHtb7NUmtABCb2WZZmm2wNiOA5hAb8VdCS4B3dtMWyvcoViccwAW/COERjXLt0zP1zXUN26g== dependencies: brace-expansion "^2.0.1" -minimatch@^9.0.1: - version "9.0.2" - resolved "https://registry.npmjs.org/minimatch/-/minimatch-9.0.2.tgz" - integrity sha512-PZOT9g5v2ojiTL7r1xF6plNHLtOeTpSlDI007As2NlA2aYBMfVom17yqa6QzhmDP8QOhn7LjHTg7DFCVSSa6yg== +minimatch@^9.0.4: + version "9.0.5" + resolved "https://registry.yarnpkg.com/minimatch/-/minimatch-9.0.5.tgz#d74f9dd6b57d83d8e98cfb82133b03978bc929e5" + integrity sha512-G6T0ZX48xgozx7587koeX9Ys2NYy6Gmv//P89sEte9V9whIapMNF4idKxnW2QtCcLiTWlb/wfCabAtAFWhhBow== dependencies: brace-expansion "^2.0.1" -minimist@^1.2.0, minimist@^1.2.5, minimist@^1.2.6: +minimist@1.2.6: + version "1.2.6" + resolved "https://registry.yarnpkg.com/minimist/-/minimist-1.2.6.tgz#8637a5b759ea0d6e98702cfb3a9283323c93af44" + integrity sha512-Jsjnk4bw3YJqYzbdyBiNsPWHPfO++UGG749Cxs6peCu5Xg4nrena6OVxOYxrQTqww0Jmwt+Ref8rggumkTLz9Q== + +minimist@^1.2.5, minimist@^1.2.6: version "1.2.8" resolved "https://registry.npmjs.org/minimist/-/minimist-1.2.8.tgz" integrity sha512-2yyAR8qBkN3YuheJanUpWC5U3bb5osDywNB8RzDVlDwDHbocAJveqqj1u8+SVD7jkWT4yvsHCpWqqWqAxb0zCA== @@ -3686,48 +5099,9 @@ minimist@^1.2.0, minimist@^1.2.5, minimist@^1.2.6: minimisted@^2.0.0: version "2.0.1" resolved "https://registry.npmjs.org/minimisted/-/minimisted-2.0.1.tgz" - integrity sha512-1oPjfuLQa2caorJUM8HV8lGgWCc0qqAO1MNv/k05G4qslmsndV/5WdNZrqCiyqiz3wohia2Ij2B7w2Dr7/IyrA== - dependencies: - minimist "^1.2.5" - -minipass-collect@^1.0.2: - version "1.0.2" - resolved "https://registry.npmjs.org/minipass-collect/-/minipass-collect-1.0.2.tgz" - integrity sha512-6T6lH0H8OG9kITm/Jm6tdooIbogG9e0tLgpY6mphXSm/A9u8Nq1ryBG+Qspiub9LjWlBPsPS3tWQ/Botq4FdxA== - dependencies: - minipass "^3.0.0" - -minipass-fetch@^3.0.0: - version "3.0.3" - resolved "https://registry.npmjs.org/minipass-fetch/-/minipass-fetch-3.0.3.tgz" - integrity sha512-n5ITsTkDqYkYJZjcRWzZt9qnZKCT7nKCosJhHoj7S7zD+BP4jVbWs+odsniw5TA3E0sLomhTKOKjF86wf11PuQ== - dependencies: - minipass "^5.0.0" - minipass-sized "^1.0.3" - minizlib "^2.1.2" - optionalDependencies: - encoding "^0.1.13" - -minipass-flush@^1.0.5: - version "1.0.5" - resolved "https://registry.npmjs.org/minipass-flush/-/minipass-flush-1.0.5.tgz" - integrity sha512-JmQSYYpPUqX5Jyn1mXaRwOda1uQ8HP5KAT/oDSLCzt1BYRhQU0/hDtsB1ufZfEEzMZ9aAVmsBw8+FWsIXlClWw== - dependencies: - minipass "^3.0.0" - -minipass-pipeline@^1.2.4: - version "1.2.4" - resolved "https://registry.npmjs.org/minipass-pipeline/-/minipass-pipeline-1.2.4.tgz" - integrity sha512-xuIq7cIOt09RPRJ19gdi4b+RiNvDFYe5JH+ggNvBqGqpQXcru3PcRmOZuHBKWK1Txf9+cQ+HMVN4d6z46LZP7A== - dependencies: - minipass "^3.0.0" - -minipass-sized@^1.0.3: - version "1.0.3" - resolved "https://registry.npmjs.org/minipass-sized/-/minipass-sized-1.0.3.tgz" - integrity sha512-MbkQQ2CTiBMlA2Dm/5cY+9SWFEN8pzzOXi6rlM5Xxq0Yqbda5ZQy9sU75a673FE9ZK0Zsbr6Y5iP6u9nktfg2g== + integrity sha512-1oPjfuLQa2caorJUM8HV8lGgWCc0qqAO1MNv/k05G4qslmsndV/5WdNZrqCiyqiz3wohia2Ij2B7w2Dr7/IyrA== dependencies: - minipass "^3.0.0" + minimist "^1.2.5" minipass@^2.6.0, minipass@^2.9.0: version "2.9.0" @@ -3749,10 +5123,15 @@ minipass@^5.0.0: resolved "https://registry.npmjs.org/minipass/-/minipass-5.0.0.tgz" integrity sha512-3FnjYuehv9k6ovOEbyOswadCDPX1piCfhV8ncmYtHOjuPwylVWsghTLo7rabjC3Rx5xD4HDx8Wm1xnMF7S5qFQ== -"minipass@^5.0.0 || ^6.0.2": - version "6.0.2" - resolved "https://registry.npmjs.org/minipass/-/minipass-6.0.2.tgz" - integrity sha512-MzWSV5nYVT7mVyWCwn2o7JH13w2TBRmmSqSRCKzTw+lmft9X4z+3wjvs06Tzijo5z4W/kahUCDpRXTF+ZrmF/w== +"minipass@^5.0.0 || ^6.0.2 || ^7.0.0": + version "7.0.4" + resolved "https://registry.yarnpkg.com/minipass/-/minipass-7.0.4.tgz#dbce03740f50a4786ba994c1fb908844d27b038c" + integrity sha512-jYofLM5Dam9279rdkWzqHozUo4ybjdZmCsDHePy5V/PbBcVMiSZR97gmAy45aqi8CK1lG2ECd356FU86avfwUQ== + +minipass@^7.1.2: + version "7.1.2" + resolved "https://registry.yarnpkg.com/minipass/-/minipass-7.1.2.tgz#93a9626ce5e5e66bd4db86849e7515e92340a707" + integrity sha512-qOOzS1cBTWYF4BH8fVePDBOO9iptMnGUEZwNc/cMWnTV2nVLZ7VoNWEPHkYczZA0pdoA7dl6e7FL659nX9S2aw== minizlib@^1.3.3: version "1.3.3" @@ -3761,7 +5140,7 @@ minizlib@^1.3.3: dependencies: minipass "^2.9.0" -minizlib@^2.1.1, minizlib@^2.1.2: +minizlib@^2.1.1: version "2.1.2" resolved "https://registry.npmjs.org/minizlib/-/minizlib-2.1.2.tgz" integrity sha512-bAxsR8BVfj60DWXHE3u30oHzfl4G7khkSuPW+qvpd7jFRHm7dLxOjUk1EHACJ/hxLY8phGJ0YhYHZo7jil7Qdg== @@ -3793,6 +5172,46 @@ mkdirp@^1.0.3: resolved "https://registry.npmjs.org/mkdirp/-/mkdirp-1.0.4.tgz" integrity sha512-vVqVZQyf3WLx2Shd0qJ9xuvqgAyKPLAiqITEtqW0oIUjzo3PePDd6fW9iFz30ef7Ysp/oiWqbhszeGWW2T6Gzw== +mkdirp@^2.1.3: + version "2.1.6" + resolved "https://registry.yarnpkg.com/mkdirp/-/mkdirp-2.1.6.tgz#964fbcb12b2d8c5d6fbc62a963ac95a273e2cc19" + integrity sha512-+hEnITedc8LAtIP9u3HJDFIdcLV2vXP33sqLLIzkv1Db1zO/1OxbvYf0Y1OC/S/Qo5dxHXepofhmxL02PsKe+A== + +mkpath@1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/mkpath/-/mkpath-1.0.0.tgz#ebb3a977e7af1c683ae6fda12b545a6ba6c5853d" + integrity sha512-PbNHr7Y/9Y/2P5pKFv5XOGBfNQqZ+fdiHWcuf7swLACN5ZW5LU7J5tMU8LSBjpluAxAxKYGD9nnaIbdRy9+m1w== + +mocha@9.2.2: + version "9.2.2" + resolved "https://registry.yarnpkg.com/mocha/-/mocha-9.2.2.tgz#d70db46bdb93ca57402c809333e5a84977a88fb9" + integrity sha512-L6XC3EdwT6YrIk0yXpavvLkn8h+EU+Y5UcCHKECyMbdUIxyMuZj4bX4U9e1nvnvUUvQVsV2VHQr5zLdcUkhW/g== + dependencies: + "@ungap/promise-all-settled" "1.1.2" + ansi-colors "4.1.1" + browser-stdout "1.3.1" + chokidar "3.5.3" + debug "4.3.3" + diff "5.0.0" + escape-string-regexp "4.0.0" + find-up "5.0.0" + glob "7.2.0" + growl "1.10.5" + he "1.2.0" + js-yaml "4.1.0" + log-symbols "4.1.0" + minimatch "4.2.1" + ms "2.1.3" + nanoid "3.3.1" + serialize-javascript "6.0.0" + strip-json-comments "3.1.1" + supports-color "8.1.1" + which "2.0.2" + workerpool "6.2.0" + yargs "16.2.0" + yargs-parser "20.2.4" + yargs-unparser "2.0.0" + mock-fs@^4.1.0: version "4.14.0" resolved "https://registry.yarnpkg.com/mock-fs/-/mock-fs-4.14.0.tgz#ce5124d2c601421255985e6e94da80a7357b1b18" @@ -3808,7 +5227,7 @@ ms@2.1.2: resolved "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz" integrity sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w== -ms@2.1.3, ms@^2.0.0: +ms@2.1.3, ms@^2.1.1: version "2.1.3" resolved "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz" integrity sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA== @@ -3853,32 +5272,76 @@ multihashes@^0.4.15, multihashes@~0.4.15: multibase "^0.7.0" varint "^5.0.0" -nan@^2.14.0: - version "2.17.0" - resolved "https://registry.npmjs.org/nan/-/nan-2.17.0.tgz" - integrity sha512-2ZTgtl0nJsO0KQCjEpxcIr5D+Yv90plTitZt9JBfQvVJDS5seMl3FOvsh3+9CoYWXf/1l5OaZzzF6nDm4cagaQ== +nan@^2.17.0: + version "2.20.0" + resolved "https://registry.yarnpkg.com/nan/-/nan-2.20.0.tgz#08c5ea813dd54ed16e5bd6505bf42af4f7838ca3" + integrity sha512-bk3gXBZDGILuuo/6sKtr0DQmSThYHLtNCdSdXk9YkxD/jK6X2vmCyyXBBxyqZ4XcnzTyYEAThfX3DCEnLf6igw== nano-json-stream-parser@^0.1.2: version "0.1.2" resolved "https://registry.yarnpkg.com/nano-json-stream-parser/-/nano-json-stream-parser-0.1.2.tgz#0cc8f6d0e2b622b479c40d499c46d64b755c6f5f" integrity sha512-9MqxMH/BSJC7dnLsEMPyfN5Dvoo49IsPFYMcHw3Bcfc2kN0lpHRBSzlMSVx4HGyJ7s9B31CyBTVehWJoQ8Ctew== -negotiator@0.6.3, negotiator@^0.6.3: +nanoid@3.3.1: + version "3.3.1" + resolved "https://registry.yarnpkg.com/nanoid/-/nanoid-3.3.1.tgz#6347a18cac88af88f58af0b3594b723d5e99bb35" + integrity sha512-n6Vs/3KGyxPQd6uO0eH4Bv0ojGSUvuLlIHtC3Y0kEO23YRge8H9x1GCzLn28YX0H66pMkxuaeESFq4tKISKwdw== + +negotiator@0.6.3: version "0.6.3" resolved "https://registry.npmjs.org/negotiator/-/negotiator-0.6.3.tgz" integrity sha512-+EUsqGPLsM+j/zdChZjsnX51g4XrHFOIXwfnCVPGlQk/k5giakcKsuxCObBRu6DSm9opw/O6slWbJdghQM4bBg== +neo-async@^2.6.2: + version "2.6.2" + resolved "https://registry.yarnpkg.com/neo-async/-/neo-async-2.6.2.tgz#b4aafb93e3aeb2d8174ca53cf163ab7d7308305f" + integrity sha512-Yd3UES5mWCSqR+qNT93S3UoYUkqAZ9lLg8a7g9rimsWmYGK8cVToA4/sF3RrshdyV3sAGMXVUmpMYOw+dLpOuw== + next-tick@^1.1.0: version "1.1.0" resolved "https://registry.yarnpkg.com/next-tick/-/next-tick-1.1.0.tgz#1836ee30ad56d67ef281b22bd199f709449b35eb" integrity sha512-CXdUiJembsNjuToQvxayPZF9Vqht7hewsvy2sOWafLvi2awflj9mOC6bHIg50orX8IJvWKY9wYQ/zB2kogPslQ== -node-abi@^3.0.0: - version "3.45.0" - resolved "https://registry.npmjs.org/node-abi/-/node-abi-3.45.0.tgz" - integrity sha512-iwXuFrMAcFVi/ZoZiqq8BzAdsLw9kxDfTC0HMyjXfSL/6CSDAGD5UmR7azrAgWV1zKYq7dUUMj4owusBWKLsiQ== - dependencies: - semver "^7.3.5" +nightwatch-axe-verbose@2.0.3: + version "2.0.3" + resolved "https://registry.yarnpkg.com/nightwatch-axe-verbose/-/nightwatch-axe-verbose-2.0.3.tgz#719f0a1b53d611fa2b4872ee5730f5c0ad2c0cec" + integrity sha512-VxwYTXmdbWZ4GRxgAc0/6uZ1nDQ5/xnXUipLrxoUsLxrh9OjNmAwqlMsIlQN8o33XwbjGm+o9ikan5erYGEOFQ== + dependencies: + axe-core "^4.4.3" + +nightwatch@2.3: + version "2.3.9" + resolved "https://registry.yarnpkg.com/nightwatch/-/nightwatch-2.3.9.tgz#3d3153d57a005e49689e5904d73a23b6bfb2c863" + integrity sha512-yjcri3URaV7bKCbTXJK0k7heBZ9OOGpuPdur4hQAxoODx/XuKVV53rtc7a/W4MZ39GhzepHKJCtelvrEu6nJeQ== + dependencies: + "@nightwatch/chai" "5.0.2" + ansi-to-html "0.7.2" + assertion-error "1.1.0" + boxen "5.1.2" + chai-nightwatch "0.5.3" + ci-info "3.3.0" + didyoumean "1.2.2" + dotenv "10.0.0" + ejs "3.1.8" + envinfo "7.8.1" + fs-extra "^10.1.0" + glob "^7.2.3" + lodash.clone "3.0.3" + lodash.defaultsdeep "4.6.1" + lodash.escape "4.0.1" + lodash.merge "4.6.2" + minimatch "3.1.2" + minimist "1.2.6" + mkpath "1.0.0" + mocha "9.2.2" + nightwatch-axe-verbose "2.0.3" + open "8.4.0" + ora "5.4.1" + selenium-webdriver "4.3.1" + semver "7.3.5" + stacktrace-parser "0.1.10" + strip-ansi "6.0.1" + uuid "8.3.2" node-addon-api@^1.6.3: version "1.7.2" @@ -3890,13 +5353,6 @@ node-addon-api@^2.0.0: resolved "https://registry.yarnpkg.com/node-addon-api/-/node-addon-api-2.0.2.tgz#432cfa82962ce494b132e9d72a15b29f71ff5d32" integrity sha512-Ntyt4AIXyaLIuMHF6IOoTakB3K+RWxwtsHNRxllEoA6vPwP9o4866g6YWDLUdnucilZhmkxiHwHr11gAENw+QA== -node-api-version@^0.1.4: - version "0.1.4" - resolved "https://registry.npmjs.org/node-api-version/-/node-api-version-0.1.4.tgz" - integrity sha512-KGXihXdUChwJAOHO53bv9/vXcLmdUsZ6jIptbvYvkpKfth+r7jw44JkVxQFA3kX5nQjzjmGu1uAu/xNNLNlI5g== - dependencies: - semver "^7.3.5" - node-fetch@^2.6.0, node-fetch@^2.6.12: version "2.7.0" resolved "https://registry.yarnpkg.com/node-fetch/-/node-fetch-2.7.0.tgz#d0f0fa6e3e2dc1d27efcd8ad99d550bda94d187d" @@ -3909,36 +5365,24 @@ node-gyp-build@^4.2.0, node-gyp-build@^4.3.0: resolved "https://registry.yarnpkg.com/node-gyp-build/-/node-gyp-build-4.6.1.tgz#24b6d075e5e391b8d5539d98c7fc5c210cac8a3e" integrity sha512-24vnklJmyRS8ViBNI8KbtK/r/DmXQMRiOMXTNz2nrTnAYUwjmEEbnnpB/+kt+yWRv73bPsSPRFddrcIbAxSiMQ== -node-gyp@^9.0.0: - version "9.4.0" - resolved "https://registry.npmjs.org/node-gyp/-/node-gyp-9.4.0.tgz" - integrity sha512-dMXsYP6gc9rRbejLXmTbVRYjAHw7ppswsKyMxuxJxxOHzluIO1rGp9TOQgjFJ+2MCqcOcQTOPB/8Xwhr+7s4Eg== +node-loader@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/node-loader/-/node-loader-2.0.0.tgz#9109a6d828703fd3e0aa03c1baec12a798071562" + integrity sha512-I5VN34NO4/5UYJaUBtkrODPWxbobrE4hgDqPrjB25yPkonFhCmZ146vTH+Zg417E9Iwoh1l/MbRs1apc5J295Q== dependencies: - env-paths "^2.2.0" - exponential-backoff "^3.1.1" - glob "^7.1.4" - graceful-fs "^4.2.6" - make-fetch-happen "^11.0.3" - nopt "^6.0.0" - npmlog "^6.0.0" - rimraf "^3.0.2" - semver "^7.3.5" - tar "^6.1.2" - which "^2.0.2" + loader-utils "^2.0.0" -node-pty@^0.10.1: - version "0.10.1" - resolved "https://registry.npmjs.org/node-pty/-/node-pty-0.10.1.tgz" - integrity sha512-JTdtUS0Im/yRsWJSx7yiW9rtpfmxqxolrtnyKwPLI+6XqTAPW/O2MjS8FYL4I5TsMbH2lVgDb2VMjp+9LoQGNg== +node-pty@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/node-pty/-/node-pty-1.0.0.tgz#7daafc0aca1c4ca3de15c61330373af4af5861fd" + integrity sha512-wtBMWWS7dFZm/VgqElrTvtfMq4GzJ6+edFI0Y0zyzygUSZMgZdraDUMUhCIvkjhJjme15qWmbyJbtAx4ot4uZA== dependencies: - nan "^2.14.0" + nan "^2.17.0" -nopt@^6.0.0: - version "6.0.0" - resolved "https://registry.npmjs.org/nopt/-/nopt-6.0.0.tgz" - integrity sha512-ZwLpbTgdhuZUnZzjd7nb1ZV+4DoiC6/sfiVKok72ym/4Tlf+DFdlHYmT2JPmcNNWV6Pi3SDf1kT+A4r9RTuT9g== - dependencies: - abbrev "^1.0.0" +node-releases@^2.0.14: + version "2.0.14" + resolved "https://registry.yarnpkg.com/node-releases/-/node-releases-2.0.14.tgz#2ffb053bceb8b2be8495ece1ab6ce600c4461b0b" + integrity sha512-y10wOWt8yZpqXmOgRo77WaHEmhYQYGNA6y421PKsKYWEK8aW+cqAphborZDhqfyKrbZEN92CN1X2KbafY2s7Yw== normalize-path@^3.0.0, normalize-path@~3.0.0: version "3.0.0" @@ -3950,15 +5394,12 @@ normalize-url@^6.0.1: resolved "https://registry.npmjs.org/normalize-url/-/normalize-url-6.1.0.tgz" integrity sha512-DlL+XwOy3NxAQ8xuC0okPgK46iuVNAK01YN7RueYBqqFeGsBjV9XmCAzAdgt+667bCl5kPh9EqKKDwnaPG1I7A== -npmlog@^6.0.0: - version "6.0.2" - resolved "https://registry.npmjs.org/npmlog/-/npmlog-6.0.2.tgz" - integrity sha512-/vBvz5Jfr9dT/aFWd0FIRf+T/Q2WBsLENygUaFUqstqsycmZAP/t5BvFJTK0viFmSUxiUKTUplWy5vt+rvKIxg== +npm-run-path@^4.0.0, npm-run-path@^4.0.1: + version "4.0.1" + resolved "https://registry.yarnpkg.com/npm-run-path/-/npm-run-path-4.0.1.tgz#b7ecd1e5ed53da8e37a55e1c2269e0b97ed748ea" + integrity sha512-S48WzZW777zhNIrn7gxOlISNAqi9ZC/uQFnRdbeIHhZhCA6UqpkOT8T1G7BvfdgP4Er8gF4sUbaS0i7QvIfCWw== dependencies: - are-we-there-yet "^3.0.0" - console-control-strings "^1.1.0" - gauge "^4.0.3" - set-blocking "^2.0.0" + path-key "^3.0.0" number-to-bn@1.7.0: version "1.7.0" @@ -3983,6 +5424,14 @@ object-inspect@^1.13.1, object-inspect@^1.9.0: resolved "https://registry.yarnpkg.com/object-inspect/-/object-inspect-1.13.1.tgz#b96c6109324ccfef6b12216a956ca4dc2ff94bc2" integrity sha512-5qoj1RUiKOMsCCNLV1CBiPYE10sziTsnmNxkAI/rZhiD63CF7IqdFGC/XzjWjpSgLf0LxXX3bDFIh0E18f6UhQ== +object-is@^1.1.5: + version "1.1.6" + resolved "https://registry.yarnpkg.com/object-is/-/object-is-1.1.6.tgz#1a6a53aed2dd8f7e6775ff870bea58545956ab07" + integrity sha512-F8cZ+KfGlSGi09lJT7/Nd6KJZ9ygtvYC0/UYYLI9nmQKLMnydpB9yvbv9K1uSkEu7FU9vYPmVwLg328tX+ot3Q== + dependencies: + call-bind "^1.0.7" + define-properties "^1.2.1" + object-keys@^1.1.1: version "1.1.1" resolved "https://registry.npmjs.org/object-keys/-/object-keys-1.1.1.tgz" @@ -4005,6 +5454,22 @@ oboe@2.1.5: dependencies: http-https "^1.0.0" +octokit@^3.1.2: + version "3.2.1" + resolved "https://registry.yarnpkg.com/octokit/-/octokit-3.2.1.tgz#d376ca3b12a61c58da02a93c491d2e627069b194" + integrity sha512-u+XuSejhe3NdIvty3Jod00JvTdAE/0/+XbhIDhefHbu+2OcTRHd80aCiH6TX19ZybJmwPQBKFQmHGxp0i9mJrg== + dependencies: + "@octokit/app" "^14.0.2" + "@octokit/core" "^5.0.0" + "@octokit/oauth-app" "^6.0.0" + "@octokit/plugin-paginate-graphql" "^4.0.0" + "@octokit/plugin-paginate-rest" "11.3.1" + "@octokit/plugin-rest-endpoint-methods" "13.2.2" + "@octokit/plugin-retry" "^6.0.0" + "@octokit/plugin-throttling" "^8.0.0" + "@octokit/request-error" "^5.0.0" + "@octokit/types" "^13.0.0" + on-finished@2.4.1: version "2.4.1" resolved "https://registry.yarnpkg.com/on-finished/-/on-finished-2.4.1.tgz#58c8c44116e54845ad57f14ab10b03533184ac3f" @@ -4019,16 +5484,25 @@ once@^1.3.0, once@^1.3.1, once@^1.4.0: dependencies: wrappy "1" -onetime@^5.1.0: +onetime@^5.1.0, onetime@^5.1.2: version "5.1.2" - resolved "https://registry.npmjs.org/onetime/-/onetime-5.1.2.tgz" + resolved "https://registry.yarnpkg.com/onetime/-/onetime-5.1.2.tgz#d0e96ebb56b07476df1dd9c4806e5237985ca45e" integrity sha512-kbpaSSGJTWdAY5KPVeMOKXSrPtr8C8C7wodJbcsd51jRnmD+GZu8Y0VoU6Dm5Z4vWr0Ig/1NKuWRKf7j5aaYSg== dependencies: mimic-fn "^2.1.0" -ora@^5.1.0: +open@8.4.0: + version "8.4.0" + resolved "https://registry.yarnpkg.com/open/-/open-8.4.0.tgz#345321ae18f8138f82565a910fdc6b39e8c244f8" + integrity sha512-XgFPPM+B28FtCCgSb9I+s9szOC1vZRSwgWsRUA5ylIxRTgKozqjOCrVOqGsYABPYK5qnfqClxZTFBa8PKt2v6Q== + dependencies: + define-lazy-prop "^2.0.0" + is-docker "^2.1.1" + is-wsl "^2.2.0" + +ora@5.4.1: version "5.4.1" - resolved "https://registry.npmjs.org/ora/-/ora-5.4.1.tgz" + resolved "https://registry.yarnpkg.com/ora/-/ora-5.4.1.tgz#1b2678426af4ac4a509008e5e4ac9e9959db9e18" integrity sha512-5b6Y85tPxZZ7QytO+BQzysW31HJku27cRIlkbAXaNx+BdcVi+LlRFmVXzeF6a7JCwJpyw5c4b+YSVImQIrBpuQ== dependencies: bl "^4.1.0" @@ -4051,12 +5525,48 @@ p-cancelable@^3.0.0: resolved "https://registry.yarnpkg.com/p-cancelable/-/p-cancelable-3.0.0.tgz#63826694b54d61ca1c20ebcb6d3ecf5e14cd8050" integrity sha512-mlVgR3PGuzlo0MmTdk4cXqXWlwQDLnONTAg6sm62XkMJEiRxN3GL3SffkYvqwonbkJBcrI7Uvv5Zh9yjvn2iUw== -p-map@^4.0.0: - version "4.0.0" - resolved "https://registry.npmjs.org/p-map/-/p-map-4.0.0.tgz" - integrity sha512-/bjOqmgETBYB5BoEeGVea8dmvHb2m9GLy1E9W43yeyfP6QQCZGFNa+XRceJEuDB6zqr+gKpIAmlLebMpykw/MQ== +p-finally@^2.0.0: + version "2.0.1" + resolved "https://registry.yarnpkg.com/p-finally/-/p-finally-2.0.1.tgz#bd6fcaa9c559a096b680806f4d657b3f0f240561" + integrity sha512-vpm09aKwq6H9phqRQzecoDpD8TmVyGw70qmWlyq5onxY7tqyTTFVvxMykxQSQKILBSFlbXpypIw2T1Ml7+DDtw== + +p-limit@^2.2.0: + version "2.3.0" + resolved "https://registry.yarnpkg.com/p-limit/-/p-limit-2.3.0.tgz#3dd33c647a214fdfffd835933eb086da0dc21db1" + integrity sha512-//88mFWSJx8lxCzwdAABTJL2MyWB12+eIY7MDL2SqLmAkeKU9qxRvWuSyTjm3FUmpBEMuFfckAIqEaVGUDxb6w== + dependencies: + p-try "^2.0.0" + +p-limit@^3.0.2: + version "3.1.0" + resolved "https://registry.yarnpkg.com/p-limit/-/p-limit-3.1.0.tgz#e1daccbe78d0d1388ca18c64fea38e3e57e3706b" + integrity sha512-TYOanM3wGwNGsZN2cVTYPArw454xnXj5qmWF1bEoAc4+cU/ol7GVh7odevjp1FNHduHc3KZMcFduxU5Xc6uJRQ== + dependencies: + yocto-queue "^0.1.0" + +p-locate@^4.1.0: + version "4.1.0" + resolved "https://registry.yarnpkg.com/p-locate/-/p-locate-4.1.0.tgz#a3428bb7088b3a60292f66919278b7c297ad4f07" + integrity sha512-R79ZZ/0wAxKGu3oYMlz8jy/kbhsNrS7SKZ7PxEHBgJ5+F2mtFW2fK2cOtBh1cHYkQsbzFV7I+EoRKe6Yt0oK7A== + dependencies: + p-limit "^2.2.0" + +p-locate@^5.0.0: + version "5.0.0" + resolved "https://registry.yarnpkg.com/p-locate/-/p-locate-5.0.0.tgz#83c8315c6785005e3bd021839411c9e110e6d834" + integrity sha512-LaNjtRWUBY++zB5nE/NwcaoMylSPk+S+ZHNB1TzdbMJMny6dynpAGt7X/tl/QYq3TIeE6nxHppbo2LGymrG5Pw== dependencies: - aggregate-error "^3.0.0" + p-limit "^3.0.2" + +p-try@^2.0.0: + version "2.2.0" + resolved "https://registry.yarnpkg.com/p-try/-/p-try-2.2.0.tgz#cb2868540e313d61de58fafbe35ce9004d5540e6" + integrity sha512-R4nPAVTAU0B9D35/Gk3uJf/7XYbQcyohSKdvAxIRSNghFl4e71hVoGnBNQz9cWaXxO2I10KTC+3jMdvvoKw6dQ== + +package-json-from-dist@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/package-json-from-dist/-/package-json-from-dist-1.0.0.tgz#e501cd3094b278495eb4258d4c9f6d5ac3019f00" + integrity sha512-dATvCeZN/8wQsGywez1mzHtTlP22H8OEfPrVMLNr4/eGa+ijtLn/6M5f0dY8UKNrC2O9UCU6SSoG3qRKnt7STw== pako@^1.0.10, pako@~1.0.2: version "1.0.11" @@ -4073,29 +5583,44 @@ parseurl@~1.3.3: resolved "https://registry.yarnpkg.com/parseurl/-/parseurl-1.3.3.tgz#9da19e7bee8d12dff0513ed5b76957793bc2e8d4" integrity sha512-CiyeOxFT/JZyN5m0z9PfXw4SCBJ6Sygz1Dpl0wqjlhDEGGBP1GnsUVEL0p63hoG1fcj3fHynXi9NYO4nWOL+qQ== +path-exists@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/path-exists/-/path-exists-4.0.0.tgz#513bdbe2d3b95d7762e8c1137efa195c6c61b5b3" + integrity sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w== + path-is-absolute@^1.0.0: version "1.0.1" resolved "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz" integrity sha512-AVbw3UJ2e9bq64vSaS9Am0fje1Pa8pbGqTTsmXfaIiMpnr5DlDhfJOuLj9Sf95ZPVDAUerDfEk88MPmPe7UCQg== -path-key@^3.1.0: +path-key@^3.0.0, path-key@^3.1.0: version "3.1.1" resolved "https://registry.npmjs.org/path-key/-/path-key-3.1.1.tgz" integrity sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q== -path-scurry@^1.7.0: - version "1.9.2" - resolved "https://registry.npmjs.org/path-scurry/-/path-scurry-1.9.2.tgz" - integrity sha512-qSDLy2aGFPm8i4rsbHd4MNyTcrzHFsLQykrtbuGRknZZCBBVXSv2tSCDN2Cg6Rt/GFRw8GoW9y9Ecw5rIPG1sg== +path-parse@^1.0.7: + version "1.0.7" + resolved "https://registry.yarnpkg.com/path-parse/-/path-parse-1.0.7.tgz#fbc114b60ca42b30d9daf5858e4bd68bbedb6735" + integrity sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw== + +path-scurry@^1.11.1: + version "1.11.1" + resolved "https://registry.yarnpkg.com/path-scurry/-/path-scurry-1.11.1.tgz#7960a668888594a0720b12a911d1a742ab9f11d2" + integrity sha512-Xa4Nw17FS9ApQFJ9umLiJS4orGjm7ZzwUrwamcGQuHSzDyth9boKDaycYdDcZDuqYATXw4HFXgaqWTctW/v1HA== dependencies: - lru-cache "^9.1.1" - minipass "^5.0.0 || ^6.0.2" + lru-cache "^10.2.0" + minipass "^5.0.0 || ^6.0.2 || ^7.0.0" path-to-regexp@0.1.10: version "0.1.10" resolved "https://registry.yarnpkg.com/path-to-regexp/-/path-to-regexp-0.1.10.tgz#67e9108c5c0551b9e5326064387de4763c4d5f8b" integrity sha512-7lf7qcQidTku0Gu3YDPc8DJ1q7OOucfa/BSsIwjuh56VU7katFvuM8hULfkwB3Fns/rsVF7PwPKVw1sl5KQS9w== +pathval@1.1.1: + version "1.1.1" + resolved "https://registry.yarnpkg.com/pathval/-/pathval-1.1.1.tgz#8534e77a77ce7ac5a2512ea21e0fdb8fcf6c3d8d" + integrity sha512-Dp6zGqpTdETdR63lehJYPeIOqpiNBNtc7BpWSLrOje7UaIsE5aY92r/AunQA7rsXvet3lrJ3JnZX29UPTKXyKQ== + pbkdf2@^3.0.17: version "3.1.2" resolved "https://registry.yarnpkg.com/pbkdf2/-/pbkdf2-3.1.2.tgz#dd822aa0887580e52f1a039dc3eda108efae3075" @@ -4117,24 +5642,34 @@ performance-now@^2.1.0: resolved "https://registry.yarnpkg.com/performance-now/-/performance-now-2.1.0.tgz#6309f4e0e5fa913ec1c69307ae364b4b377c9e7b" integrity sha512-7EAHlyLHI56VEIdK57uwHdHKIaAGbnXPiw0yWbarQZOKaKpvUIgW0jWRVLiatnM+XXlSwsanIBH/hzGMJulMow== -picomatch@^2.0.4, picomatch@^2.2.1: +picocolors@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/picocolors/-/picocolors-1.0.1.tgz#a8ad579b571952f0e5d25892de5445bcfe25aaa1" + integrity sha512-anP1Z8qwhkbmu7MFP5iTt+wQKXgwzf7zTyGlcdzabySa9vd0Xt392U0rVmz9poOaBj0uHJKyyo9/upk0HrEQew== + +picomatch@^2.0.4, picomatch@^2.2.1, picomatch@^2.3.1: version "2.3.1" resolved "https://registry.npmjs.org/picomatch/-/picomatch-2.3.1.tgz" integrity sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA== +pid-port@^0.1.0: + version "0.1.1" + resolved "https://registry.yarnpkg.com/pid-port/-/pid-port-0.1.1.tgz#2ac86fa8a0e97ef2e7eb9e7e9567cdc1eda78098" + integrity sha512-boqPJtSgZC6KOgXKNPC+/XR3xwVtpOtaLa7JLcdf8jfVe0ZM2TwllBXxxLUO8GQbOLJ4/hEtf2+L1QCKbaoHUg== + dependencies: + execa "^5.0.0" + pify@^4.0.1: version "4.0.1" resolved "https://registry.npmjs.org/pify/-/pify-4.0.1.tgz" integrity sha512-uB80kBFb/tfd68bVleG9T5GGsGPjJrLAUpR5PZIrhBnIaRTQRjqdJSsIKkOP6OAIFbj7GOrcudc5pNjZ+geV2g== -plist@^3.0.1: - version "3.1.0" - resolved "https://registry.yarnpkg.com/plist/-/plist-3.1.0.tgz#797a516a93e62f5bde55e0b9cc9c967f860893c9" - integrity sha512-uysumyrvkUX0rX/dEVqt8gC3sTBzd4zoWfLeS29nb53imdaXVvLINYXTI2GNqzaMuvacNx4uJQ8+b3zXR0pkgQ== +pkg-dir@^4.2.0: + version "4.2.0" + resolved "https://registry.yarnpkg.com/pkg-dir/-/pkg-dir-4.2.0.tgz#f099133df7ede422e81d1d8448270eeb3e4261f3" + integrity sha512-HRDzbaKjC+AOWVXxAU/x54COGeIv9eb+6CkDSQoNTt4XyWoIJvuPsXizxu/Fr23EiekbtZwmh1IcIG/l/a10GQ== dependencies: - "@xmldom/xmldom" "^0.8.8" - base64-js "^1.5.1" - xmlbuilder "^15.1.1" + find-up "^4.0.0" plist@^3.0.4: version "3.0.6" @@ -4144,6 +5679,22 @@ plist@^3.0.4: base64-js "^1.5.1" xmlbuilder "^15.1.1" +plist@^3.0.5: + version "3.1.0" + resolved "https://registry.yarnpkg.com/plist/-/plist-3.1.0.tgz#797a516a93e62f5bde55e0b9cc9c967f860893c9" + integrity sha512-uysumyrvkUX0rX/dEVqt8gC3sTBzd4zoWfLeS29nb53imdaXVvLINYXTI2GNqzaMuvacNx4uJQ8+b3zXR0pkgQ== + dependencies: + "@xmldom/xmldom" "^0.8.8" + base64-js "^1.5.1" + xmlbuilder "^15.1.1" + +process-exists@^4.0.0: + version "4.1.0" + resolved "https://registry.yarnpkg.com/process-exists/-/process-exists-4.1.0.tgz#4132c516324c1da72d65896851cdbd8bbdf5b9d8" + integrity sha512-BBJoiorUKoP2AuM5q/yKwIfT1YWRHsaxjW+Ayu9erLhqKOfnXzzVVML0XTYoQZuI1YvcWKmc1dh06DEy4+KzfA== + dependencies: + ps-list "^6.3.0" + process-nextick-args@~2.0.0: version "2.0.1" resolved "https://registry.yarnpkg.com/process-nextick-args/-/process-nextick-args-2.0.1.tgz#7820d9b16120cc55ca9ae7792680ae7dba6d7fe2" @@ -4154,14 +5705,14 @@ process@^0.11.10: resolved "https://registry.yarnpkg.com/process/-/process-0.11.10.tgz#7332300e840161bda3e69a1d1d91a7d4bc16f182" integrity sha512-cdGef/drWFoydD1JsMzuFf8100nZl+GT+yacc2bEced5f9Rjk4z+WtFUTBu9PhOi9j/jfmBPu0mMEY4wIdAF8A== -progress@^2.0.3: +progress@2.0.3, progress@^2.0.3: version "2.0.3" resolved "https://registry.npmjs.org/progress/-/progress-2.0.3.tgz" integrity sha512-7PiHtLll5LdnKIMw100I+8xJXR5gW2QwWYkT6iJva0bXitZKa/XMrSbdmg3r2Xnaidz9Qumd0VPaMrZlF9V9sA== promise-retry@^2.0.1: version "2.0.1" - resolved "https://registry.npmjs.org/promise-retry/-/promise-retry-2.0.1.tgz" + resolved "https://registry.yarnpkg.com/promise-retry/-/promise-retry-2.0.1.tgz#ff747a13620ab57ba688f5fc67855410c370da22" integrity sha512-y+WKFlBR8BGXnsNlIHFGPZmyDf3DFMoLhaflAnyZgV6rG6xu+JwesTo2Q9R6XwYmtmwAFCkAk3e35jEdoeh/3g== dependencies: err-code "^2.0.2" @@ -4180,6 +5731,16 @@ proxy-from-env@^1.1.0: resolved "https://registry.npmjs.org/proxy-from-env/-/proxy-from-env-1.1.0.tgz" integrity sha512-D+zkORCbA9f1tdWRK0RaCR3GPv50cMxcrz4X8k5LTSUD1Dkw47mKJEZQNunItRTkWwgtaUSo1RVFRIG9ZXiFYg== +ps-list@^6.3.0: + version "6.3.0" + resolved "https://registry.yarnpkg.com/ps-list/-/ps-list-6.3.0.tgz#a2b775c2db7d547a28fbaa3a05e4c281771259be" + integrity sha512-qau0czUSB0fzSlBOQt0bo+I2v6R+xiQdj78e1BR/Qjfl5OHWJ/urXi8+ilw1eHe+5hSeDI1wrwVTgDp2wst4oA== + +ps-list@^7.2.0: + version "7.2.0" + resolved "https://registry.yarnpkg.com/ps-list/-/ps-list-7.2.0.tgz#3d110e1de8249a4b178c9b1cf2a215d1e4e42fc0" + integrity sha512-v4Bl6I3f2kJfr5o80ShABNHAokIgY+wFDTQfE+X3zWYgSGQOCBeYptLZUpoOALBqO5EawmDN/tjTldJesd0ujQ== + psl@^1.1.28: version "1.9.0" resolved "https://registry.yarnpkg.com/psl/-/psl-1.9.0.tgz#d0df2a137f00794565fcaf3b2c00cd09f8d5a5a7" @@ -4236,6 +5797,11 @@ query-string@^5.0.1: object-assign "^4.1.0" strict-uri-encode "^1.0.0" +queue-tick@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/queue-tick/-/queue-tick-1.0.1.tgz#f6f07ac82c1fd60f82e098b417a80e52f1f4c142" + integrity sha512-kJt5qhMxoszgU/62PLP1CJytzd2NKetjSRnyuj31fDd3Rlcz3fzlFdFLD1SItunPwyqEOkca6GbV612BWfaBag== + quick-lru@^5.1.1: version "5.1.1" resolved "https://registry.npmjs.org/quick-lru/-/quick-lru-5.1.1.tgz" @@ -4263,11 +5829,12 @@ raw-body@2.5.2: iconv-lite "0.4.24" unpipe "1.0.0" -read-config-file@6.2.0: - version "6.2.0" - resolved "https://registry.yarnpkg.com/read-config-file/-/read-config-file-6.2.0.tgz#71536072330bcd62ba814f91458b12add9fc7ade" - integrity sha512-gx7Pgr5I56JtYz+WuqEbQHj/xWo+5Vwua2jhb1VwM4Wid5PqYmZ4i00ZB0YEGIfkVBsCv9UrjgyqCiQfS/Oosg== +read-config-file@6.3.2: + version "6.3.2" + resolved "https://registry.yarnpkg.com/read-config-file/-/read-config-file-6.3.2.tgz#556891aa6ffabced916ed57457cb192e61880411" + integrity sha512-M80lpCjnE6Wt6zb98DoW8WHR09nzMSpu8XHtPkiTHrJ5Az9CybfeQhTJ8D7saeBHpGhLPIVyA8lcL6ZmdKwY6Q== dependencies: + config-file-ts "^0.2.4" dotenv "^9.0.2" dotenv-expand "^5.1.0" js-yaml "^4.1.0" @@ -4303,6 +5870,13 @@ readdirp@~3.6.0: dependencies: picomatch "^2.2.1" +rechoir@^0.8.0: + version "0.8.0" + resolved "https://registry.yarnpkg.com/rechoir/-/rechoir-0.8.0.tgz#49f866e0d32146142da3ad8f0eff352b3215ff22" + integrity sha512-/vxpCXddiX8NGfGO/mTafwjq4aFa/71pvamip0++IQk3zG8cbCj0fifNPrjjF1XMXUne91jL9OoxmdykoEtifQ== + dependencies: + resolve "^1.20.0" + regenerator-runtime@^0.14.0: version "0.14.0" resolved "https://registry.yarnpkg.com/regenerator-runtime/-/regenerator-runtime-0.14.0.tgz#5e19d68eb12d486f797e15a3c6a918f7cec5eb45" @@ -4353,6 +5927,27 @@ resolve-alpn@^1.0.0, resolve-alpn@^1.2.0: resolved "https://registry.npmjs.org/resolve-alpn/-/resolve-alpn-1.2.1.tgz" integrity sha512-0a1F4l73/ZFZOakJnQ3FvkJ2+gSTQWz/r2KE5OdDY0TxPm5h4GkqkWWfM47T7HsbnOtcJVEF4epCVy6u7Q3K+g== +resolve-cwd@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/resolve-cwd/-/resolve-cwd-3.0.0.tgz#0f0075f1bb2544766cf73ba6a6e2adfebcb13f2d" + integrity sha512-OrZaX2Mb+rJCpH/6CpSqt9xFVpN++x01XnN2ie9g6P5/3xelLAkXWVADpdz1IHD/KFfEXyE6V0U01OQ3UO2rEg== + dependencies: + resolve-from "^5.0.0" + +resolve-from@^5.0.0: + version "5.0.0" + resolved "https://registry.yarnpkg.com/resolve-from/-/resolve-from-5.0.0.tgz#c35225843df8f776df21c57557bc087e9dfdfc69" + integrity sha512-qYg9KP24dD5qka9J47d0aVky0N+b4fTU89LN9iDnjB5waksiC49rvMB0PrUJQGoTmH50XPiqOvAjDfaijGxYZw== + +resolve@^1.20.0: + version "1.22.8" + resolved "https://registry.yarnpkg.com/resolve/-/resolve-1.22.8.tgz#b6c87a9f2aa06dfab52e3d70ac8cde321fa5a48d" + integrity sha512-oKWePCxqpd6FlLvGV1VU0x7bkPmmCNolxzjMf4NczoDnQcIWrAF+cPtZn5i6n+RfD2d9i0tzpKnG6Yk168yIyw== + dependencies: + is-core-module "^2.13.0" + path-parse "^1.0.7" + supports-preserve-symlinks-flag "^1.0.0" + responselike@^2.0.0: version "2.0.1" resolved "https://registry.npmjs.org/responselike/-/responselike-2.0.1.tgz" @@ -4362,7 +5957,7 @@ responselike@^2.0.0: restore-cursor@^3.1.0: version "3.1.0" - resolved "https://registry.npmjs.org/restore-cursor/-/restore-cursor-3.1.0.tgz" + resolved "https://registry.yarnpkg.com/restore-cursor/-/restore-cursor-3.1.0.tgz#39f67c54b3a7a58cea5236d95cf0034239631f7e" integrity sha512-l+sSefzHpj5qimhFSE5a8nufZYAM3sBSVMAPtYkmC+4EH2anSGaEMXSD0izRQbu9nfyQ9y5JrVmp7E8oZrUjvA== dependencies: onetime "^5.1.0" @@ -4370,7 +5965,7 @@ restore-cursor@^3.1.0: retry@^0.12.0: version "0.12.0" - resolved "https://registry.npmjs.org/retry/-/retry-0.12.0.tgz" + resolved "https://registry.yarnpkg.com/retry/-/retry-0.12.0.tgz#1b42a6266a21f07421d1b0b54b7dc167b01c013b" integrity sha512-9LkiTwjUh6rT555DtE9rTX+BKByPfrMzEAtnlEtdEwr3Nkffwiihqe2bWADg+OQRjt9gl6ICdmB/ZFDCGAtSow== rimraf@^3.0.0, rimraf@^3.0.2: @@ -4453,6 +6048,15 @@ sax@^1.2.4: resolved "https://registry.npmjs.org/sax/-/sax-1.2.4.tgz" integrity sha512-NqVDv9TpANUjFm0N8uM5GxL36UgKi9/atZw+x7YFnQ8ckwFGKrl4xX4yWtrey3UJm5nP1kUbnYgLopqWNSRhWw== +schema-utils@^3.1.1, schema-utils@^3.2.0: + version "3.3.0" + resolved "https://registry.yarnpkg.com/schema-utils/-/schema-utils-3.3.0.tgz#f50a88877c3c01652a15b622ae9e9795df7a60fe" + integrity sha512-pN/yOAvcC+5rQ5nERGuwrjLlYvLTbCibnZ1I7B1LaiAz9BRBlE9GMgE/eqV30P7aJQUf7Ddimy/RsbYO/GrVGg== + dependencies: + "@types/json-schema" "^7.0.8" + ajv "^6.12.5" + ajv-keywords "^3.5.2" + scrypt-js@3.0.1, scrypt-js@^3.0.0, scrypt-js@^3.0.1: version "3.0.1" resolved "https://registry.yarnpkg.com/scrypt-js/-/scrypt-js-3.0.1.tgz#d314a57c2aef69d1ad98a138a21fe9eafa9ee312" @@ -4467,34 +6071,79 @@ secp256k1@^4.0.1: node-addon-api "^2.0.0" node-gyp-build "^4.2.0" +selenium-standalone@^9.3.1: + version "9.3.1" + resolved "https://registry.yarnpkg.com/selenium-standalone/-/selenium-standalone-9.3.1.tgz#a302ad9ab2f5d58f019895c87b4001de1c51969d" + integrity sha512-M/nHs/fbzCEr3370/ZlUXx8+Ia2aGbx5gSgONUn0ooCcFx8ScmouIWCp/Wms8dUTDiivC8F4WzXYRSCMIdiglw== + dependencies: + axios "^0.27.2" + commander "^8.3.0" + cross-spawn "^7.0.3" + debug "^4.3.1" + execa "^5.1.1" + find-process "^1.4.7" + fkill "^7.2.1" + got "^11.8.6" + is-port-reachable "^3.0.0" + lodash.mapvalues "^4.6.0" + lodash.merge "^4.6.2" + md5 "^2.3.0" + minimist "^1.2.5" + mkdirp "^2.1.3" + progress "2.0.3" + tar-stream "3.1.6" + which "^2.0.2" + yauzl "^2.10.0" + +selenium-webdriver@4.3.1: + version "4.3.1" + resolved "https://registry.yarnpkg.com/selenium-webdriver/-/selenium-webdriver-4.3.1.tgz#5e9c6c4adee65e57776b5bd4c07c59b65b8f056d" + integrity sha512-TjH/ls1WKRQoFEHcqtn6UtwcLnA3yvx08v9cSSFYvyhp8hJWRtbe9ae2I8uXPisEZ2EaGKKoxBZ4EHv0BJM15g== + dependencies: + jszip "^3.10.0" + tmp "^0.2.1" + ws ">=8.7.0" + semver-compare@^1.0.0: version "1.0.0" resolved "https://registry.npmjs.org/semver-compare/-/semver-compare-1.0.0.tgz" integrity sha512-YM3/ITh2MJ5MtzaM429anh+x2jiLVjqILF4m4oyQB18W7Ggea7BfqdH/wGMK7dDiMghv/6WG7znWMwUDzJiXow== +semver@7.3.5: + version "7.3.5" + resolved "https://registry.yarnpkg.com/semver/-/semver-7.3.5.tgz#0b621c879348d8998e4b0e4be94b3f12e6018ef7" + integrity sha512-PoeGJYh8HK4BTO/a9Tf6ZG3veo/A7ZVsYrSA6J8ny9nb3B1VrpkuN+z9OE5wfE5p6H4LchYZsegiQgbJD94ZFQ== + dependencies: + lru-cache "^6.0.0" + semver@^6.2.0: version "6.3.0" resolved "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz" integrity sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw== -semver@^7.2.1, semver@^7.3.7, semver@^7.5.4: +semver@^7.2.1, semver@^7.3.8, semver@^7.5.3, semver@^7.5.4: version "7.5.4" resolved "https://registry.yarnpkg.com/semver/-/semver-7.5.4.tgz#483986ec4ed38e1c6c48c34894a9182dbff68a6e" integrity sha512-1bCSESV6Pv+i21Hvpxp3Dx+pSD8lIPt8uVjRrxAUt/nbswYc+tK6Y2btiULjd4+fnq15PX+nqQDC7Oft7WkwcA== dependencies: lru-cache "^6.0.0" -semver@^7.3.2, semver@^7.3.5: +semver@^7.3.2: version "7.5.3" resolved "https://registry.npmjs.org/semver/-/semver-7.5.3.tgz" integrity sha512-QBlUtyVk/5EeHbi7X0fw6liDZc7BBmEaSYn01fMU1OUYbf6GPsbTtd8WmnqbI20SeycoHSeiybkE/q1Q+qlThQ== dependencies: lru-cache "^6.0.0" -semver@~7.0.0: - version "7.0.0" - resolved "https://registry.yarnpkg.com/semver/-/semver-7.0.0.tgz#5f3ca35761e47e05b206c6daff2cf814f0316b8e" - integrity sha512-+GB6zVA9LWh6zovYQLALHwv5rb2PHGlJi3lfiqIHxR0uuwCgefcOJc59v9fv1w8GbStwxuuqqAjI9NMAOOgq1A== +semver@^7.3.4: + version "7.6.2" + resolved "https://registry.yarnpkg.com/semver/-/semver-7.6.2.tgz#1e3b34759f896e8f14d6134732ce798aeb0c6e13" + integrity sha512-FNAIBWCx9qcRhoHcgcJ0gvU7SN1lYU2ZXuSfl04bSC5OpvDHFyJCjdNHomPXxjQlCBU67YW64PzY7/VIEH7F2w== + +semver@^7.6.3: + version "7.6.3" + resolved "https://registry.yarnpkg.com/semver/-/semver-7.6.3.tgz#980f7b5550bc175fb4dc09403085627f9eb33143" + integrity sha512-oVekP1cKtI+CTDvHWYFUcMtsK/00wmAEfyqKfNdARm8u1wNVhSgaX7A8d4UuIlUI5e84iEwOhs7ZPYRmzU9U6A== send@0.18.0: version "0.18.0" @@ -4541,6 +6190,20 @@ serialize-error@^7.0.1: dependencies: type-fest "^0.13.1" +serialize-javascript@6.0.0: + version "6.0.0" + resolved "https://registry.yarnpkg.com/serialize-javascript/-/serialize-javascript-6.0.0.tgz#efae5d88f45d7924141da8b5c3a7a7e663fefeb8" + integrity sha512-Qr3TosvguFt8ePWqsvRfrKyQXIiW+nGbYpy8XK24NQHE83caxWt+mIymTT19DGFbNWNLfEwsrkSmN64lVWB9ag== + dependencies: + randombytes "^2.1.0" + +serialize-javascript@^6.0.1: + version "6.0.2" + resolved "https://registry.yarnpkg.com/serialize-javascript/-/serialize-javascript-6.0.2.tgz#defa1e055c83bf6d59ea805d8da862254eb6a6c2" + integrity sha512-Saa1xPByTTq2gdeFZYLLo+RFE35NHZkAbqZeWNd3BpzppeVisAqpDjcp8dyf6uIvEqJRd46jemmyA4iFIeVk8g== + dependencies: + randombytes "^2.1.0" + serve-static@1.16.0: version "1.16.0" resolved "https://registry.yarnpkg.com/serve-static/-/serve-static-1.16.0.tgz#2bf4ed49f8af311b519c46f272bf6ac3baf38a92" @@ -4562,11 +6225,6 @@ servify@^0.1.12: request "^2.79.0" xhr "^2.3.3" -set-blocking@^2.0.0: - version "2.0.0" - resolved "https://registry.npmjs.org/set-blocking/-/set-blocking-2.0.0.tgz" - integrity sha512-KiKBS8AnWGEyLzofFfmvKwpdPzqiy16LvQfK3yv/fVH7Bj13/wl3JSR1J+rfgRE9q7xUJK4qvgS8raSOeLUehw== - set-function-length@^1.1.1: version "1.1.1" resolved "https://registry.yarnpkg.com/set-function-length/-/set-function-length-1.1.1.tgz#4bc39fafb0307224a33e106a7d35ca1218d659ed" @@ -4616,6 +6274,13 @@ sha.js@^2.4.0, sha.js@^2.4.8, sha.js@^2.4.9: inherits "^2.0.1" safe-buffer "^5.0.1" +shallow-clone@^3.0.0: + version "3.0.1" + resolved "https://registry.yarnpkg.com/shallow-clone/-/shallow-clone-3.0.1.tgz#8f2981ad92531f55035b01fb230769a40e02efa3" + integrity sha512-/6KqX+GVUdqPuPPd2LxDDxzX6CAbjJehAAOKlNpqqUpAqPM6HeL8f+o3a+JsyGjn2lv0WY8UsTgUJjU9Ok55NA== + dependencies: + kind-of "^6.0.2" + shebang-command@^2.0.0: version "2.0.0" resolved "https://registry.npmjs.org/shebang-command/-/shebang-command-2.0.0.tgz" @@ -4647,15 +6312,15 @@ side-channel@^1.0.6: get-intrinsic "^1.2.4" object-inspect "^1.13.1" -signal-exit@^3.0.2, signal-exit@^3.0.7: +signal-exit@^3.0.2, signal-exit@^3.0.3: version "3.0.7" - resolved "https://registry.npmjs.org/signal-exit/-/signal-exit-3.0.7.tgz" + resolved "https://registry.yarnpkg.com/signal-exit/-/signal-exit-3.0.7.tgz#a9a1767f8af84155114eaabd73f99273c8f59ad9" integrity sha512-wnD2ZE+l+SPC/uoS0vXeE9L1+0wuaMqKlfz9AMUo38JsyLSBWSFcHR1Rri62LZc12vLr1gb3jl7iwQhgwpAbGQ== signal-exit@^4.0.1: - version "4.0.2" - resolved "https://registry.npmjs.org/signal-exit/-/signal-exit-4.0.2.tgz" - integrity sha512-MY2/qGx4enyjprQnFaZsHib3Yadh3IXyV2C321GY0pjGfVBu4un0uDJkwgdxqO+Rdx8JMT8IfJIRwbYVz3Ob3Q== + version "4.1.0" + resolved "https://registry.yarnpkg.com/signal-exit/-/signal-exit-4.1.0.tgz#952188c1cbd546070e2dd20d0f41c0ae0530cb04" + integrity sha512-bzyZ1e88w9O1iNJbKnOlvYTrWPDl46O1bG0D3XInv+9tkPrxrN8jUUTiFlDkkmKWgn1M6CfIA13SuGqOa9Korw== simple-concat@^1.0.0: version "1.0.1" @@ -4680,12 +6345,12 @@ simple-get@^4.0.1: once "^1.3.1" simple-concat "^1.0.0" -simple-update-notifier@^1.0.7: - version "1.1.0" - resolved "https://registry.yarnpkg.com/simple-update-notifier/-/simple-update-notifier-1.1.0.tgz#67694c121de354af592b347cdba798463ed49c82" - integrity sha512-VpsrsJSUcJEseSbMHkrsrAVSdvVS5I96Qo1QAQ4FxQ9wXFcB+pjj7FB7/us9+GcgfW4ziHtYMc1J0PLczb55mg== +simple-update-notifier@2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/simple-update-notifier/-/simple-update-notifier-2.0.0.tgz#d70b92bdab7d6d90dfd73931195a30b6e3d7cebb" + integrity sha512-a2B9Y0KlNXl9u/vsW6sTIu9vGEpfKu2wRV6l1H3XEas/0gUIzGzBoP/IouTcUQbm9JWZLH3COxyn03TYlFax6w== dependencies: - semver "~7.0.0" + semver "^7.5.3" slice-ansi@^3.0.0: version "3.0.0" @@ -4696,29 +6361,12 @@ slice-ansi@^3.0.0: astral-regex "^2.0.0" is-fullwidth-code-point "^3.0.0" -smart-buffer@^4.0.2, smart-buffer@^4.2.0: +smart-buffer@^4.0.2: version "4.2.0" - resolved "https://registry.npmjs.org/smart-buffer/-/smart-buffer-4.2.0.tgz" + resolved "https://registry.yarnpkg.com/smart-buffer/-/smart-buffer-4.2.0.tgz#6e1d71fa4f18c05f7d0ff216dd16a481d0e8d9ae" integrity sha512-94hK0Hh8rPqQl2xXc3HsaBoOXKV20MToPkcXvwbISWLEs+64sBq5kFgn2kJDHb1Pry9yrP0dxrCI9RRci7RXKg== -socks-proxy-agent@^7.0.0: - version "7.0.0" - resolved "https://registry.npmjs.org/socks-proxy-agent/-/socks-proxy-agent-7.0.0.tgz" - integrity sha512-Fgl0YPZ902wEsAyiQ+idGd1A7rSFx/ayC1CQVMw5P+EQx2V0SgpGtf6OKFhVjPflPUl9YMmEOnmfjCdMUsygww== - dependencies: - agent-base "^6.0.2" - debug "^4.3.3" - socks "^2.6.2" - -socks@^2.6.2: - version "2.7.1" - resolved "https://registry.npmjs.org/socks/-/socks-2.7.1.tgz" - integrity sha512-7maUZy1N7uo6+WVEX6psASxtNlKaNVMlGQKkG/63nEDdLOWNbiUMoLK7X4uYoLhQstau72mLgfEWcXcwsaHbYQ== - dependencies: - ip "^2.0.0" - smart-buffer "^4.2.0" - -source-map-support@^0.5.19: +source-map-support@^0.5.19, source-map-support@~0.5.20: 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== @@ -4731,6 +6379,11 @@ source-map@^0.6.0: resolved "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz" integrity sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g== +source-map@^0.7.4: + version "0.7.4" + resolved "https://registry.yarnpkg.com/source-map/-/source-map-0.7.4.tgz#a9bbe705c9d8846f4e08ff6765acf0f1b0898656" + integrity sha512-l3BikUxvPOcn5E74dZiq5BGsTb5yEwhaTSzccU6t4sDOH8NWJCstKO5QT2CvtFoK6F0saL7p9xHAqHOlCPJygA== + sprintf-js@^1.1.2: version "1.1.2" resolved "https://registry.npmjs.org/sprintf-js/-/sprintf-js-1.1.2.tgz" @@ -4751,12 +6404,12 @@ sshpk@^1.7.0: safer-buffer "^2.0.2" tweetnacl "~0.14.0" -ssri@^10.0.0: - version "10.0.4" - resolved "https://registry.npmjs.org/ssri/-/ssri-10.0.4.tgz" - integrity sha512-12+IR2CB2C28MMAw0Ncqwj5QbTcs0nGIhgJzYWzDkb21vWmfNI83KS4f3Ci6GI98WreIfG7o9UXp3C0qbpA8nQ== +stacktrace-parser@0.1.10: + version "0.1.10" + resolved "https://registry.yarnpkg.com/stacktrace-parser/-/stacktrace-parser-0.1.10.tgz#29fb0cae4e0d0b85155879402857a1639eb6051a" + integrity sha512-KJP1OCML99+8fhOHxwwzyWrlUuVX5GQ0ZpJTd1DFXhdkrvg1szxfHhawXUZ3g9TkXORQd4/WG68jMlQZ2p8wlg== dependencies: - minipass "^5.0.0" + type-fest "^0.7.1" stat-mode@^1.0.0: version "1.0.0" @@ -4768,21 +6421,27 @@ statuses@2.0.1: resolved "https://registry.yarnpkg.com/statuses/-/statuses-2.0.1.tgz#55cb000ccf1d48728bd23c685a063998cf1a1b63" integrity sha512-RwNA9Z/7PrK06rYLIzFMlaF+l73iwpzsqRIFgbMLbTcLD6cOao82TaWefPXQvB2fOC4AjuYSEndS7N/mTCbkdQ== +stop-iteration-iterator@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/stop-iteration-iterator/-/stop-iteration-iterator-1.0.0.tgz#6a60be0b4ee757d1ed5254858ec66b10c49285e4" + integrity sha512-iCGQj+0l0HOdZ2AEeBADlsRC+vsnDsZsbdSiH1yNSjcfKM7fdpCMfqAL/dwF5BLiw/XhRft/Wax6zQbhq2BcjQ== + dependencies: + internal-slot "^1.0.4" + +streamx@^2.15.0: + version "2.15.6" + resolved "https://registry.yarnpkg.com/streamx/-/streamx-2.15.6.tgz#28bf36997ebc7bf6c08f9eba958735231b833887" + integrity sha512-q+vQL4AAz+FdfT137VF69Cc/APqUbxy+MDOImRrMvchJpigHj9GksgDU2LYbO9rx7RX6osWgxJB2WxhYv4SZAw== + dependencies: + fast-fifo "^1.1.0" + queue-tick "^1.0.1" + strict-uri-encode@^1.0.0: version "1.1.0" resolved "https://registry.yarnpkg.com/strict-uri-encode/-/strict-uri-encode-1.1.0.tgz#279b225df1d582b1f54e65addd4352e18faa0713" integrity sha512-R3f198pcvnB+5IpnBlRkphuE9n46WyVl8I39W/ZUTZLz4nqSP/oLYUrcnJrw462Ds8he4YKMov2efsTIw1BDGQ== -"string-width-cjs@npm:string-width@^4.2.0": - version "4.2.3" - resolved "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz" - integrity sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g== - dependencies: - emoji-regex "^8.0.0" - is-fullwidth-code-point "^3.0.0" - strip-ansi "^6.0.1" - -"string-width@^1.0.2 || 2 || 3 || 4", string-width@^4.1.0, string-width@^4.2.0, string-width@^4.2.3: +"string-width-cjs@npm:string-width@^4.2.0", string-width@^4.0.0, string-width@^4.1.0, string-width@^4.2.0, string-width@^4.2.2, string-width@^4.2.3: version "4.2.3" resolved "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz" integrity sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g== @@ -4793,7 +6452,7 @@ strict-uri-encode@^1.0.0: string-width@^5.0.1, string-width@^5.1.2: version "5.1.2" - resolved "https://registry.npmjs.org/string-width/-/string-width-5.1.2.tgz" + resolved "https://registry.yarnpkg.com/string-width/-/string-width-5.1.2.tgz#14f8daec6d81e7221d2a357e668cab73bdbca794" integrity sha512-HnLOCR3vjcY8beoNLtcjZ5/nxn2afmME6lhrDrebokqMap+XbeW8n9TXpPDOqdGK5qcI3oT0GKTW6wC7EMiVqA== dependencies: eastasianwidth "^0.2.0" @@ -4841,14 +6500,7 @@ string_decoder@~1.1.1: dependencies: safe-buffer "~5.1.0" -"strip-ansi-cjs@npm:strip-ansi@^6.0.1": - version "6.0.1" - resolved "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz" - integrity sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A== - dependencies: - ansi-regex "^5.0.1" - -strip-ansi@^6.0.0, strip-ansi@^6.0.1: +"strip-ansi-cjs@npm:strip-ansi@^6.0.1", strip-ansi@6.0.1, strip-ansi@^6.0.0, strip-ansi@^6.0.1: version "6.0.1" resolved "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz" integrity sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A== @@ -4862,6 +6514,16 @@ strip-ansi@^7.0.1: dependencies: ansi-regex "^6.0.1" +strip-bom@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/strip-bom/-/strip-bom-3.0.0.tgz#2334c18e9c759f7bdd56fdef7e9ae3d588e68ed3" + integrity sha512-vavAMRXOgBVNF6nyEEmL3DBK19iRpDcoIwW+swQ+CbGiu7lju6t+JklA1MHweoWtadgt4ISVUsXLyDq34ddcwA== + +strip-final-newline@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/strip-final-newline/-/strip-final-newline-2.0.0.tgz#89b852fb2fcbe936f6f4b3187afb0a12c1ab58ad" + integrity sha512-BrpvfNAE3dcvq7ll3xVumzjKjZQ5tI1sEUIKr3Uoks0XUl45St3FlatVqef9prk4jRDzhW6WZg+3bk93y6pLjA== + strip-hex-prefix@1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/strip-hex-prefix/-/strip-hex-prefix-1.0.0.tgz#0c5f155fef1151373377de9dbb588da05500e36f" @@ -4869,6 +6531,11 @@ strip-hex-prefix@1.0.0: dependencies: is-hex-prefixed "1.0.0" +strip-json-comments@3.1.1: + version "3.1.1" + resolved "https://registry.yarnpkg.com/strip-json-comments/-/strip-json-comments-3.1.1.tgz#31f1281b3832630434831c310c01cccda8cbe006" + integrity sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig== + sumchecker@^3.0.1: version "3.0.1" resolved "https://registry.npmjs.org/sumchecker/-/sumchecker-3.0.1.tgz" @@ -4876,6 +6543,13 @@ sumchecker@^3.0.1: dependencies: debug "^4.1.0" +supports-color@8.1.1, supports-color@^8.0.0: + version "8.1.1" + resolved "https://registry.yarnpkg.com/supports-color/-/supports-color-8.1.1.tgz#cd6fc17e28500cff56c1b86c0a7fd4a54a73005c" + integrity sha512-MpUEN2OodtUzxvKQl72cUF7RQ5EiHsGvSsVG0ia9c5RbWGL2CI4C7EpPS8UTBIplnlzZiNuV56w+FuNxy3ty2Q== + dependencies: + has-flag "^4.0.0" + supports-color@^7.1.0: version "7.2.0" resolved "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz" @@ -4883,6 +6557,11 @@ supports-color@^7.1.0: dependencies: has-flag "^4.0.0" +supports-preserve-symlinks-flag@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/supports-preserve-symlinks-flag/-/supports-preserve-symlinks-flag-1.0.0.tgz#6eda4bd344a3c94aea376d4cc31bc77311039e09" + integrity sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w== + swarm-js@^0.1.40: version "0.1.42" resolved "https://registry.yarnpkg.com/swarm-js/-/swarm-js-0.1.42.tgz#497995c62df6696f6e22372f457120e43e727979" @@ -4900,6 +6579,20 @@ swarm-js@^0.1.40: tar "^4.0.2" xhr-request "^1.0.1" +tapable@^2.1.1, tapable@^2.2.0: + version "2.2.1" + resolved "https://registry.yarnpkg.com/tapable/-/tapable-2.2.1.tgz#1967a73ef4060a82f12ab96af86d52fdb76eeca0" + integrity sha512-GNzQvQTOIP6RyTfE2Qxb8ZVlNmw0n88vp1szwWRimP02mnTsx3Wtn5qRdqY9w2XduFNUgvOwhNnQsjwCp+kqaQ== + +tar-stream@3.1.6: + version "3.1.6" + resolved "https://registry.yarnpkg.com/tar-stream/-/tar-stream-3.1.6.tgz#6520607b55a06f4a2e2e04db360ba7d338cc5bab" + integrity sha512-B/UyjYwPpMBv+PaFSWAmtYjwdrlEaZQEhMIBFNC5oEG8lpiW8XjcSdmEaClj28ArfKScKHs2nshz3k2le6crsg== + dependencies: + b4a "^1.6.4" + fast-fifo "^1.2.0" + streamx "^2.15.0" + tar-stream@^2.1.0: version "2.2.0" resolved "https://registry.yarnpkg.com/tar-stream/-/tar-stream-2.2.0.tgz#acad84c284136b060dc3faa64474aa9aebd77287" @@ -4924,10 +6617,10 @@ tar@^4.0.2: safe-buffer "^5.2.1" yallist "^3.1.1" -tar@^6.0.5, tar@^6.1.11, tar@^6.1.2: - version "6.1.15" - resolved "https://registry.npmjs.org/tar/-/tar-6.1.15.tgz" - integrity sha512-/zKt9UyngnxIT/EAGYuxaMYgOIJiP81ab9ZfkILq4oNLPFX50qyYmu7jRj9qeXoxmJHjGlbH0+cm2uy1WCs10A== +tar@^6.1.12: + version "6.2.0" + resolved "https://registry.yarnpkg.com/tar/-/tar-6.2.0.tgz#b14ce49a79cb1cd23bc9b016302dea5474493f73" + integrity sha512-/Wo7DcT0u5HUV486xg675HtjNd3BXZ6xDbzsCUZPt5iw8bTQ63bP0Raut3mvro9u+CUyq7YQd8Cx55fsZXxqLQ== dependencies: chownr "^2.0.0" fs-minipass "^2.0.0" @@ -4936,6 +6629,22 @@ tar@^6.0.5, tar@^6.1.11, tar@^6.1.2: mkdirp "^1.0.3" yallist "^4.0.0" +taskkill@^3.1.0: + version "3.1.0" + resolved "https://registry.yarnpkg.com/taskkill/-/taskkill-3.1.0.tgz#28001339feb23bfae3f447902c4b4abcdd057680" + integrity sha512-5KcOFzPvd1nGFVrmB7H4+QAWVjYOf//+QTbOj0GpXbqtqbKGWVczG+rq6VhXAtdtlKLTs16NAmHRyF5vbggQ2w== + dependencies: + arrify "^2.0.1" + execa "^3.3.0" + +tcp-port-used@^1.0.1: + version "1.0.2" + resolved "https://registry.yarnpkg.com/tcp-port-used/-/tcp-port-used-1.0.2.tgz#9652b7436eb1f4cfae111c79b558a25769f6faea" + integrity sha512-l7ar8lLUD3XS1V2lfoJlCBaeoaWo/2xfYt81hM7VlvR4RrMVFqfmzfhLVk40hAb368uitje5gPtBRL1m/DGvLA== + dependencies: + debug "4.3.1" + is2 "^2.0.6" + temp-file@^3.4.0: version "3.4.0" resolved "https://registry.npmjs.org/temp-file/-/temp-file-3.4.0.tgz" @@ -4944,11 +6653,37 @@ temp-file@^3.4.0: async-exit-hook "^2.0.1" fs-extra "^10.0.0" +terser-webpack-plugin@^5.3.10: + version "5.3.10" + resolved "https://registry.yarnpkg.com/terser-webpack-plugin/-/terser-webpack-plugin-5.3.10.tgz#904f4c9193c6fd2a03f693a2150c62a92f40d199" + integrity sha512-BKFPWlPDndPs+NGGCr1U59t0XScL5317Y0UReNrHaw9/FwhPENlq6bfgs+4yPfyP51vqC1bQ4rp1EfXW5ZSH9w== + dependencies: + "@jridgewell/trace-mapping" "^0.3.20" + jest-worker "^27.4.5" + schema-utils "^3.1.1" + serialize-javascript "^6.0.1" + terser "^5.26.0" + +terser@^5.26.0: + version "5.31.1" + resolved "https://registry.yarnpkg.com/terser/-/terser-5.31.1.tgz#735de3c987dd671e95190e6b98cfe2f07f3cf0d4" + integrity sha512-37upzU1+viGvuFtBo9NPufCb9dwM0+l9hMxYyWfBA+fbwrPqNJAhbZ6W47bBFnZHKHTUBnMvi87434qq+qnxOg== + dependencies: + "@jridgewell/source-map" "^0.3.3" + acorn "^8.8.2" + commander "^2.20.0" + source-map-support "~0.5.20" + timed-out@^4.0.1: version "4.0.1" resolved "https://registry.yarnpkg.com/timed-out/-/timed-out-4.0.1.tgz#f32eacac5a175bea25d7fab565ab3ed8741ef56f" integrity sha512-G7r3AhovYtr5YKOWQkta8RKAPb+J9IsO4uVmzjl8AZwfhs8UcUwTiD6gcJYSgOtzyjvQKrKYn41syHbUWMkafA== +tiny-typed-emitter@^2.1.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/tiny-typed-emitter/-/tiny-typed-emitter-2.1.0.tgz#b3b027fdd389ff81a152c8e847ee2f5be9fad7b5" + integrity sha512-qVtvMxeXbVej0cQWKqVSSAHmKZEHAvxdF8HEUBFWts8h+xEo5m/lEiPakuyZ3BnCBjOD8i24kzNOiOLLgsSxhA== + tmp-promise@^3.0.2: version "3.0.3" resolved "https://registry.npmjs.org/tmp-promise/-/tmp-promise-3.0.3.tgz" @@ -4956,7 +6691,7 @@ tmp-promise@^3.0.2: dependencies: tmp "^0.2.0" -tmp@^0.2.0: +tmp@^0.2.0, tmp@^0.2.1: version "0.2.1" resolved "https://registry.npmjs.org/tmp/-/tmp-0.2.1.tgz" integrity sha512-76SUhtfqR2Ijn+xllcI5P1oyannHNHByD80W1q447gU3mp9G9PSpGdWmjUOHRDPiHYacIk66W7ubDTuPF3BEtQ== @@ -4988,6 +6723,11 @@ tr46@~0.0.3: resolved "https://registry.yarnpkg.com/tr46/-/tr46-0.0.3.tgz#8184fd347dac9cdc185992f3a6622e14b9d9ab6a" integrity sha512-N3WMsuqV66lT30CrXNbEjx4GEwlow3v6rr4mCcv6prnfwhS01rkgyFdjPNBYd9br7LpXV1+Emh01fHnq2Gdgrw== +tree-kill@^1.2.2: + version "1.2.2" + resolved "https://registry.yarnpkg.com/tree-kill/-/tree-kill-1.2.2.tgz#4ca09a9092c88b73a7cdc5e8a01b507b0790a0cc" + integrity sha512-L0Orpi8qGpRG//Nd+H90vFB+3iHnue1zSSGmNOOCh1GLJ7rUKVwV2HvijphGQS2UmhUZewS9VgvxYIdgr+fG1A== + truncate-utf8-bytes@^1.0.0: version "1.0.2" resolved "https://registry.npmjs.org/truncate-utf8-bytes/-/truncate-utf8-bytes-1.0.2.tgz" @@ -4995,6 +6735,35 @@ truncate-utf8-bytes@^1.0.0: dependencies: utf8-byte-length "^1.0.1" +ts-loader@^9.5.1: + version "9.5.1" + resolved "https://registry.yarnpkg.com/ts-loader/-/ts-loader-9.5.1.tgz#63d5912a86312f1fbe32cef0859fb8b2193d9b89" + integrity sha512-rNH3sK9kGZcH9dYzC7CewQm4NtxJTjSEVRJ2DyBZR7f8/wcta+iV44UPCXc5+nzDzivKtlzV6c9P4e+oFhDLYg== + dependencies: + chalk "^4.1.0" + enhanced-resolve "^5.0.0" + micromatch "^4.0.0" + semver "^7.3.4" + source-map "^0.7.4" + +tsconfig-paths-webpack-plugin@^4.1.0: + version "4.1.0" + resolved "https://registry.yarnpkg.com/tsconfig-paths-webpack-plugin/-/tsconfig-paths-webpack-plugin-4.1.0.tgz#3c6892c5e7319c146eee1e7302ed9e6f2be4f763" + integrity sha512-xWFISjviPydmtmgeUAuXp4N1fky+VCtfhOkDUFIv5ea7p4wuTomI4QTrXvFBX2S4jZsmyTSrStQl+E+4w+RzxA== + dependencies: + chalk "^4.1.0" + enhanced-resolve "^5.7.0" + tsconfig-paths "^4.1.2" + +tsconfig-paths@^4.1.2: + version "4.2.0" + resolved "https://registry.yarnpkg.com/tsconfig-paths/-/tsconfig-paths-4.2.0.tgz#ef78e19039133446d244beac0fd6a1632e2d107c" + integrity sha512-NoZ4roiN7LnbKn9QqE1amc9DJfzvZXxF4xDavcOWt1BPkdx+m+0gJuPM+S0vCe7zTJMYUP0R8pO2XMr+Y8oLIg== + dependencies: + json5 "^2.2.2" + minimist "^1.2.6" + strip-bom "^3.0.0" + tslib@2.0.1: version "2.0.1" resolved "https://registry.npmjs.org/tslib/-/tslib-2.0.1.tgz" @@ -5017,11 +6786,26 @@ tweetnacl@^0.14.3, tweetnacl@~0.14.0: resolved "https://registry.yarnpkg.com/tweetnacl/-/tweetnacl-0.14.5.tgz#5ae68177f192d4456269d108afa93ff8743f4f64" integrity sha512-KXXFFdAbFXY4geFIwoyNK+f5Z1b7swfXABfL7HXCmoIWMKU3dmS26672A4EeQtDzLKy7SXmfBu51JolvEKwtGA== +type-detect@4.0.8, type-detect@^4.0.0: + version "4.0.8" + resolved "https://registry.yarnpkg.com/type-detect/-/type-detect-4.0.8.tgz#7646fb5f18871cfbb7749e69bd39a6388eb7450c" + integrity sha512-0fr/mIH1dlO+x7TlcMy+bIDqKPsw/70tVyeHW787goQjhmqaZe10uwLujubK9q9Lg6Fiho1KUKDYz0Z7k7g5/g== + type-fest@^0.13.1: version "0.13.1" resolved "https://registry.npmjs.org/type-fest/-/type-fest-0.13.1.tgz" integrity sha512-34R7HTnG0XIJcBSn5XhDd7nNFPRcXYRZrBB2O2jdKqYODldSzBAqzsWoZYYvduky73toYS/ESqxPvkDf/F0XMg== +type-fest@^0.20.2: + version "0.20.2" + resolved "https://registry.yarnpkg.com/type-fest/-/type-fest-0.20.2.tgz#1bf207f4b28f91583666cb5fbd327887301cd5f4" + integrity sha512-Ne+eE4r0/iWnpAxD852z3A+N0Bt5RN//NjJwRd2VFHEmrywxf5vsZlh4R6lixl6B+wz/8d+maTSAkN1FIkI3LQ== + +type-fest@^0.7.1: + version "0.7.1" + resolved "https://registry.yarnpkg.com/type-fest/-/type-fest-0.7.1.tgz#8dda65feaf03ed78f0a3f9678f1869147f7c5c48" + integrity sha512-Ne2YiiGN8bmrmJJEuTWTLJR32nh/JdL1+PSicowtNb0WFpn59GK8/lfD61bVtzguz7b3PBt74nxpv/Pw5po5Rg== + type-is@~1.6.18: version "1.6.18" resolved "https://registry.yarnpkg.com/type-is/-/type-is-1.6.18.tgz#4e552cd05df09467dcbc4ef739de89f2cf37c131" @@ -5086,10 +6870,10 @@ typedarray-to-buffer@^3.1.5: dependencies: is-typedarray "^1.0.0" -typescript@^5.1.3: - version "5.1.3" - resolved "https://registry.npmjs.org/typescript/-/typescript-5.1.3.tgz" - integrity sha512-XH627E9vkeqhlZFQuL+UsyAXEnibT0kWR2FWONlr4sTjvxyJYnyefgrkyECLzM5NenmKzRAy2rR/OlYLA1HkZw== +typescript@^5.1.3, typescript@^5.3.3: + version "5.6.2" + resolved "https://registry.yarnpkg.com/typescript/-/typescript-5.6.2.tgz#d1de67b6bef77c41823f822df8f0b3bcff60a5a0" + integrity sha512-NW8ByodCSNCwZeghjN3o+JX5OFH0Ojg6sadjEKY4huZ52TqbJTJnDo5+Tw98lSy63NZvi4n+ez5m2u5d4PkZyw== ultron@~1.1.0: version "1.1.1" @@ -5106,19 +6890,23 @@ unbox-primitive@^1.0.2: has-symbols "^1.0.3" which-boxed-primitive "^1.0.2" -unique-filename@^3.0.0: - version "3.0.0" - resolved "https://registry.npmjs.org/unique-filename/-/unique-filename-3.0.0.tgz" - integrity sha512-afXhuC55wkAmZ0P18QsVE6kp8JaxrEokN2HGIoIVv2ijHQd419H0+6EigAFcIzXeMIkcIkNBpB3L/DXB3cTS/g== - dependencies: - unique-slug "^4.0.0" +undici-types@~5.26.4: + version "5.26.5" + resolved "https://registry.yarnpkg.com/undici-types/-/undici-types-5.26.5.tgz#bcd539893d00b56e964fd2657a4866b221a65617" + integrity sha512-JlCMO+ehdEIKqlFxk6IfVoAUVmgz7cU7zD/h9XZ0qzeosSHmUJVOzSQvvYSYWXkFXC+IfLKSIffhv0sVZup6pA== -unique-slug@^4.0.0: - version "4.0.0" - resolved "https://registry.npmjs.org/unique-slug/-/unique-slug-4.0.0.tgz" - integrity sha512-WrcA6AyEfqDX5bWige/4NQfPZMtASNVxdmWR76WESYQVAACSgWcR6e9i0mofqqBxYFtL4oAxPIptY73/0YE1DQ== +universal-github-app-jwt@^1.1.2: + version "1.1.2" + resolved "https://registry.yarnpkg.com/universal-github-app-jwt/-/universal-github-app-jwt-1.1.2.tgz#8c1867a394d7d9d42cda34f11d1bcb023797d8df" + integrity sha512-t1iB2FmLFE+yyJY9+3wMx0ejB+MQpEVkH0gQv7dR6FZyltyq+ZZO0uDpbopxhrZ3SLEO4dCEkIujOMldEQ2iOA== dependencies: - imurmurhash "^0.1.4" + "@types/jsonwebtoken" "^9.0.0" + jsonwebtoken "^9.0.2" + +universal-user-agent@^6.0.0: + version "6.0.1" + resolved "https://registry.yarnpkg.com/universal-user-agent/-/universal-user-agent-6.0.1.tgz#15f20f55da3c930c57bddbf1734c6654d5fd35aa" + integrity sha512-yCzhz6FN2wU1NiiQRogkTQszlQSlpWaw8SvVegAc+bDxbzHgh1vX8uIe8OYyMH6DwH+sdTJsgMl36+mSMdRJIQ== universalify@^0.1.0: version "0.1.2" @@ -5144,6 +6932,14 @@ unzip-crx-3@^0.2.0: mkdirp "^0.5.1" yaku "^0.16.6" +update-browserslist-db@^1.0.16: + version "1.1.0" + resolved "https://registry.yarnpkg.com/update-browserslist-db/-/update-browserslist-db-1.1.0.tgz#7ca61c0d8650766090728046e416a8cde682859e" + integrity sha512-EdRAaAyk2cUE1wOf2DkEhzxqOQvFOoRJFNS6NeyJ01Gp2beMRpBAINjM2iDXE3KCuKhwnvHIQCJm6ThL2Z+HzQ== + dependencies: + escalade "^3.1.2" + picocolors "^1.0.1" + uri-js@^4.2.2: version "4.4.1" resolved "https://registry.npmjs.org/uri-js/-/uri-js-4.4.1.tgz" @@ -5202,6 +6998,11 @@ utils-merge@1.0.1: resolved "https://registry.yarnpkg.com/utils-merge/-/utils-merge-1.0.1.tgz#9f95710f50a267947b2ccc124741c1028427e713" integrity sha512-pMZTvIkT1d+TFGvDOqodOclx0QWkkgi6Tdoa8gC8ffGAAqz9pzPTZWAybbsHHoED/ztMtkv/VoYTYyShUn81hA== +uuid@8.3.2: + version "8.3.2" + resolved "https://registry.yarnpkg.com/uuid/-/uuid-8.3.2.tgz#80d5b5ced271bb9af6c445f21a1a04c606cefbe2" + integrity sha512-+NYs2QeMWy+GWFOEm9xnn6HCDp0l7QBD7ml8zLUmJ+93Q5NF0NocErnwkTkXVFNiX3/fpC6afS8Dhb/gz7R7eg== + uuid@^3.3.2: version "3.4.0" resolved "https://registry.yarnpkg.com/uuid/-/uuid-3.4.0.tgz#b23e4358afa8a202fe7a100af1f5f883f02007ee" @@ -5245,9 +7046,17 @@ verror@^1.10.0: core-util-is "1.0.2" extsprintf "^1.2.0" +watchpack@^2.4.1: + version "2.4.1" + resolved "https://registry.yarnpkg.com/watchpack/-/watchpack-2.4.1.tgz#29308f2cac150fa8e4c92f90e0ec954a9fed7fff" + integrity sha512-8wrBCMtVhqcXP2Sup1ctSkga6uc2Bx0IIvKyT7yTFier5AXHooSI+QyQQAtTb7+E0IUCCKyTFmXqdqgum2XWGg== + dependencies: + glob-to-regexp "^0.4.1" + graceful-fs "^4.1.2" + wcwidth@^1.0.1: version "1.0.1" - resolved "https://registry.npmjs.org/wcwidth/-/wcwidth-1.0.1.tgz" + resolved "https://registry.yarnpkg.com/wcwidth/-/wcwidth-1.0.1.tgz#f0b0dcf915bc5ff1528afadb2c0e17b532da2fe8" integrity sha512-XHPEwS0q6TaxcvG85+8EYkbiCux2XtWG2mkc47Ng2A77BQu9+DqIOJldST4HgPkuea7dvKSj5VgX3P1d4rW8Tg== dependencies: defaults "^1.0.3" @@ -5487,6 +7296,82 @@ webidl-conversions@^3.0.0: resolved "https://registry.yarnpkg.com/webidl-conversions/-/webidl-conversions-3.0.1.tgz#24534275e2a7bc6be7bc86611cc16ae0a5654871" integrity sha512-2JAn3z8AR6rjK8Sm8orRC0h/bcl/DqL7tRPdGZ4I1CjdF+EaMLmYxBHyXuKL849eucPFhvBoxMsflfOb8kxaeQ== +webpack-cli@^5.1.4: + version "5.1.4" + resolved "https://registry.yarnpkg.com/webpack-cli/-/webpack-cli-5.1.4.tgz#c8e046ba7eaae4911d7e71e2b25b776fcc35759b" + integrity sha512-pIDJHIEI9LR0yxHXQ+Qh95k2EvXpWzZ5l+d+jIo+RdSm9MiHfzazIxwwni/p7+x4eJZuvG1AJwgC4TNQ7NRgsg== + dependencies: + "@discoveryjs/json-ext" "^0.5.0" + "@webpack-cli/configtest" "^2.1.1" + "@webpack-cli/info" "^2.0.2" + "@webpack-cli/serve" "^2.0.5" + colorette "^2.0.14" + commander "^10.0.1" + cross-spawn "^7.0.3" + envinfo "^7.7.3" + fastest-levenshtein "^1.0.12" + import-local "^3.0.2" + interpret "^3.1.1" + rechoir "^0.8.0" + webpack-merge "^5.7.3" + +webpack-merge@^5.7.3: + version "5.10.0" + resolved "https://registry.yarnpkg.com/webpack-merge/-/webpack-merge-5.10.0.tgz#a3ad5d773241e9c682803abf628d4cd62b8a4177" + integrity sha512-+4zXKdx7UnO+1jaN4l2lHVD+mFvnlZQP/6ljaJVb4SZiwIKeUnrT5l0gkT8z+n4hKpC+jpOv6O9R+gLtag7pSA== + dependencies: + clone-deep "^4.0.1" + flat "^5.0.2" + wildcard "^2.0.0" + +webpack-merge@^6.0.1: + version "6.0.1" + resolved "https://registry.yarnpkg.com/webpack-merge/-/webpack-merge-6.0.1.tgz#50c776868e080574725abc5869bd6e4ef0a16c6a" + integrity sha512-hXXvrjtx2PLYx4qruKl+kyRSLc52V+cCvMxRjmKwoA+CBbbF5GfIBtR6kCvl0fYGqTUPKB+1ktVmTHqMOzgCBg== + dependencies: + clone-deep "^4.0.1" + flat "^5.0.2" + wildcard "^2.0.1" + +webpack-node-externals@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/webpack-node-externals/-/webpack-node-externals-3.0.0.tgz#1a3407c158d547a9feb4229a9e3385b7b60c9917" + integrity sha512-LnL6Z3GGDPht/AigwRh2dvL9PQPFQ8skEpVrWZXLWBYmqcaojHNN0onvHzie6rq7EWKrrBfPYqNEzTJgiwEQDQ== + +webpack-sources@^3.2.3: + version "3.2.3" + resolved "https://registry.yarnpkg.com/webpack-sources/-/webpack-sources-3.2.3.tgz#2d4daab8451fd4b240cc27055ff6a0c2ccea0cde" + integrity sha512-/DyMEOrDgLKKIG0fmvtz+4dUX/3Ghozwgm6iPp8KRhvn+eQf9+Q7GWxVNMk3+uCPWfdXYC4ExGBckIXdFEfH1w== + +webpack@^5.92.1: + version "5.94.0" + resolved "https://registry.yarnpkg.com/webpack/-/webpack-5.94.0.tgz#77a6089c716e7ab90c1c67574a28da518a20970f" + integrity sha512-KcsGn50VT+06JH/iunZJedYGUJS5FGjow8wb9c0v5n1Om8O1g4L6LjtfxwlXIATopoQu+vOXXa7gYisWxCoPyg== + dependencies: + "@types/estree" "^1.0.5" + "@webassemblyjs/ast" "^1.12.1" + "@webassemblyjs/wasm-edit" "^1.12.1" + "@webassemblyjs/wasm-parser" "^1.12.1" + acorn "^8.7.1" + acorn-import-attributes "^1.9.5" + browserslist "^4.21.10" + chrome-trace-event "^1.0.2" + enhanced-resolve "^5.17.1" + es-module-lexer "^1.2.1" + eslint-scope "5.1.1" + events "^3.2.0" + glob-to-regexp "^0.4.1" + graceful-fs "^4.2.11" + json-parse-even-better-errors "^2.3.1" + loader-runner "^4.2.0" + mime-types "^2.1.27" + neo-async "^2.6.2" + schema-utils "^3.2.0" + tapable "^2.1.1" + terser-webpack-plugin "^5.3.10" + watchpack "^2.4.1" + webpack-sources "^3.2.3" + websocket@^1.0.32: version "1.0.34" resolved "https://registry.yarnpkg.com/websocket/-/websocket-1.0.34.tgz#2bdc2602c08bf2c82253b730655c0ef7dcab3111" @@ -5518,6 +7403,16 @@ which-boxed-primitive@^1.0.2: is-string "^1.0.5" is-symbol "^1.0.3" +which-collection@^1.0.1: + version "1.0.2" + resolved "https://registry.yarnpkg.com/which-collection/-/which-collection-1.0.2.tgz#627ef76243920a107e7ce8e96191debe4b16c2a0" + integrity sha512-K4jVyjnBdgvc86Y6BkaLZEN933SwYOuBFkdmBu9ZfkcAbdVbpITnDmjvZ/aQjRXQrv5EPkTnD1s39GiiqbngCw== + dependencies: + is-map "^2.0.3" + is-set "^2.0.3" + is-weakmap "^2.0.2" + is-weakset "^2.0.3" + which-typed-array@^1.1.11, which-typed-array@^1.1.13, which-typed-array@^1.1.2: version "1.1.13" resolved "https://registry.yarnpkg.com/which-typed-array/-/which-typed-array-1.1.13.tgz#870cd5be06ddb616f504e7b039c4c24898184d36" @@ -5529,30 +7424,31 @@ which-typed-array@^1.1.11, which-typed-array@^1.1.13, which-typed-array@^1.1.2: gopd "^1.0.1" has-tostringtag "^1.0.0" -which@^2.0.1, which@^2.0.2: +which@2.0.2, which@^2.0.1, which@^2.0.2: version "2.0.2" - resolved "https://registry.npmjs.org/which/-/which-2.0.2.tgz" + resolved "https://registry.yarnpkg.com/which/-/which-2.0.2.tgz#7c6a8dd0a636a0327e10b59c9286eee93f3f51b1" integrity sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA== dependencies: isexe "^2.0.0" -wide-align@^1.1.5: - version "1.1.5" - resolved "https://registry.npmjs.org/wide-align/-/wide-align-1.1.5.tgz" - integrity sha512-eDMORYaPNZ4sQIuuYPDHdQvf4gyCF9rEEV/yPxGfwPkRodwEgiMUUXTx/dex+Me0wxx53S+NgUHaP7y3MGlDmg== +widest-line@^3.1.0: + version "3.1.0" + resolved "https://registry.yarnpkg.com/widest-line/-/widest-line-3.1.0.tgz#8292333bbf66cb45ff0de1603b136b7ae1496eca" + integrity sha512-NsmoXalsWVDMGupxZ5R08ka9flZjjiLvHVAWYOKtiKM8ujtZWr9cRffak+uSE48+Ob8ObalXpwyeUiyDD6QFgg== dependencies: - string-width "^1.0.2 || 2 || 3 || 4" + string-width "^4.0.0" -"wrap-ansi-cjs@npm:wrap-ansi@^7.0.0": - version "7.0.0" - resolved "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-7.0.0.tgz" - integrity sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q== - dependencies: - ansi-styles "^4.0.0" - string-width "^4.1.0" - strip-ansi "^6.0.0" +wildcard@^2.0.0, wildcard@^2.0.1: + version "2.0.1" + resolved "https://registry.yarnpkg.com/wildcard/-/wildcard-2.0.1.tgz#5ab10d02487198954836b6349f74fff961e10f67" + integrity sha512-CC1bOL87PIWSBhDcTrdeLo6eGT7mCFtrg0uIJtqJUFyK+eJnzl8A1niH56uu7KMa5XFrtiV+AQuHO3n7DsHnLQ== + +workerpool@6.2.0: + version "6.2.0" + resolved "https://registry.yarnpkg.com/workerpool/-/workerpool-6.2.0.tgz#827d93c9ba23ee2019c3ffaff5c27fccea289e8b" + integrity sha512-Rsk5qQHJ9eowMH28Jwhe8HEbmdYDX4lwoMWshiCXugjtHqMD9ZbiqSDLxcsfdqsETPzVUtX5s1Z5kStiIM6l4A== -wrap-ansi@^7.0.0: +"wrap-ansi-cjs@npm:wrap-ansi@^7.0.0", wrap-ansi@^7.0.0: version "7.0.0" resolved "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-7.0.0.tgz" integrity sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q== @@ -5563,7 +7459,7 @@ wrap-ansi@^7.0.0: wrap-ansi@^8.1.0: version "8.1.0" - resolved "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-8.1.0.tgz" + resolved "https://registry.yarnpkg.com/wrap-ansi/-/wrap-ansi-8.1.0.tgz#56dc22368ee570face1b49819975d9b9a5ead214" integrity sha512-si7QWI6zUMq56bESFvagtmzMdGOtoxfR+Sez11Mobfc7tm+VkUckk9bW2UeffTGVUbOksxmSw0AA2gs8g71NCQ== dependencies: ansi-styles "^6.1.0" @@ -5580,6 +7476,11 @@ ws@7.4.6: resolved "https://registry.yarnpkg.com/ws/-/ws-7.4.6.tgz#5654ca8ecdeee47c33a9a4bf6d28e2be2980377c" integrity sha512-YmhHDO4MzaDLB+M9ym/mDA5z0naX8j7SIlT8f8z+I0VtzsRbekxEutHSme7NPS2qE8StCYQNUnfWdXta/Yu85A== +ws@>=8.7.0: + version "8.16.0" + resolved "https://registry.yarnpkg.com/ws/-/ws-8.16.0.tgz#d1cd774f36fbc07165066a60e40323eab6446fd4" + integrity sha512-HS0c//TP7Ina87TfiPUz1rQzMhHrl/SG2guqRcTOIUYD2q8uhUdNHZYJUaQ8aTGPzCh+c6oawMKW35nFl1dxyQ== + ws@^3.0.0: version "3.3.3" resolved "https://registry.yarnpkg.com/ws/-/ws-3.3.3.tgz#f1cf84fe2d5e901ebce94efaece785f187a228f2" @@ -5654,14 +7555,47 @@ yallist@^4.0.0: resolved "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz" integrity sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A== +yargs-parser@20.2.4: + version "20.2.4" + resolved "https://registry.yarnpkg.com/yargs-parser/-/yargs-parser-20.2.4.tgz#b42890f14566796f85ae8e3a25290d205f154a54" + integrity sha512-WOkpgNhPTlE73h4VFAFsOnomJVaovO8VqLDzy5saChRBFQFBoMYirowyW+Q9HB4HFF4Z7VZTiG3iSzJJA29yRA== + +yargs-parser@^20.2.2: + version "20.2.9" + resolved "https://registry.yarnpkg.com/yargs-parser/-/yargs-parser-20.2.9.tgz#2eb7dc3b0289718fc295f362753845c41a0c94ee" + integrity sha512-y11nGElTIV+CT3Zv9t7VKl+Q3hTQoT9a1Qzezhhl6Rp21gJ/IVTW7Z3y9EWXhuUBC2Shnf+DX0antecpAwSP8w== + yargs-parser@^21.1.1: version "21.1.1" resolved "https://registry.npmjs.org/yargs-parser/-/yargs-parser-21.1.1.tgz" integrity sha512-tVpsJW7DdjecAiFpbIB1e3qxIQsE6NoPc5/eTdrbbIC4h0LVsWhnoa3g+m2HclBIujHzsxZ4VJVA+GUuc2/LBw== -yargs@^17.0.1, yargs@^17.5.1: +yargs-unparser@2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/yargs-unparser/-/yargs-unparser-2.0.0.tgz#f131f9226911ae5d9ad38c432fe809366c2325eb" + integrity sha512-7pRTIA9Qc1caZ0bZ6RYRGbHJthJWuakf+WmHK0rVeLkNrrGhfoabBNdue6kdINI6r4if7ocq9aD/n7xwKOdzOA== + dependencies: + camelcase "^6.0.0" + decamelize "^4.0.0" + flat "^5.0.2" + is-plain-obj "^2.1.0" + +yargs@16.2.0: + version "16.2.0" + resolved "https://registry.yarnpkg.com/yargs/-/yargs-16.2.0.tgz#1c82bf0f6b6a66eafce7ef30e376f49a12477f66" + integrity sha512-D1mvvtDG0L5ft/jGWkLpG1+m0eQxOfaBvTNELraWj22wSVUMWxZUvYgJYcKh6jGGIkJFhH4IZPQhR4TKpc8mBw== + dependencies: + cliui "^7.0.2" + escalade "^3.1.1" + get-caller-file "^2.0.5" + require-directory "^2.1.1" + string-width "^4.2.0" + y18n "^5.0.5" + yargs-parser "^20.2.2" + +yargs@^17.6.2: version "17.7.2" - resolved "https://registry.npmjs.org/yargs/-/yargs-17.7.2.tgz" + resolved "https://registry.yarnpkg.com/yargs/-/yargs-17.7.2.tgz#991df39aca675a192b816e1e0363f9d75d2aa269" integrity sha512-7dSzzRQ++CKnNI/krKnYRV7JKKPUXMEh61soaHKg9mrWEhzFWhFnxPxGl+69cD1Ou63C13NUPCnmIcrvqCuM6w== dependencies: cliui "^8.0.1" @@ -5677,10 +7611,15 @@ yarn@^1.22.21: resolved "https://registry.yarnpkg.com/yarn/-/yarn-1.22.21.tgz#1959a18351b811cdeedbd484a8f86c3cc3bbaf72" integrity sha512-ynXaJsADJ9JiZ84zU25XkPGOvVMmZ5b7tmTSpKURYwgELdjucAOydqIOrOfTxVYcNXe91xvLZwcRh68SR3liCg== -yauzl@^2.10.0: +yauzl@^2.10.0, yauzl@^2.9.2: version "2.10.0" - resolved "https://registry.npmjs.org/yauzl/-/yauzl-2.10.0.tgz" + resolved "https://registry.yarnpkg.com/yauzl/-/yauzl-2.10.0.tgz#c7eb17c93e112cb1086fa6d8e51fb0667b79a5f9" integrity sha512-p4a9I6X6nu6IhoGmBqAcbJy1mlC4j27vEPZX9F4L4/vZT3Lyq1VkFHw/V/PUcB9Buo+DG3iHkT0x3Qya58zc3g== dependencies: buffer-crc32 "~0.2.3" fd-slicer "~1.1.0" + +yocto-queue@^0.1.0: + version "0.1.0" + resolved "https://registry.yarnpkg.com/yocto-queue/-/yocto-queue-0.1.0.tgz#0294eb3dee05028d31ee1a5fa2c556a6aaf10a1b" + integrity sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q== diff --git a/apps/solidity-compiler/src/app/compiler.ts b/apps/solidity-compiler/src/app/compiler.ts index d86d5322cb..d20f8db8d8 100644 --- a/apps/solidity-compiler/src/app/compiler.ts +++ b/apps/solidity-compiler/src/app/compiler.ts @@ -55,4 +55,8 @@ export class CompilerClientApi extends CompilerApiMixin(PluginClient) implements getFileManagerMode () { return 'browser' } + + isDesktop() { + return false + } } diff --git a/libs/remix-api/src/index.ts b/libs/remix-api/src/index.ts index 71e343fc8a..96515e169f 100644 --- a/libs/remix-api/src/index.ts +++ b/libs/remix-api/src/index.ts @@ -1 +1,2 @@ -export * from './lib/remix-api' \ No newline at end of file +export * from './lib/remix-api' +export * from './lib/types/git' \ No newline at end of file diff --git a/libs/remix-api/src/lib/plugins/filePanel-api.ts b/libs/remix-api/src/lib/plugins/filePanel-api.ts index 02255c26ba..53b0a7170d 100644 --- a/libs/remix-api/src/lib/plugins/filePanel-api.ts +++ b/libs/remix-api/src/lib/plugins/filePanel-api.ts @@ -7,6 +7,6 @@ export interface IFilePanelApi { switchToWorkspace: (workspace: string) => Promise; } & StatusEvents methods: IFilePanel['methods'] & { - + clone: () => Promise; } } diff --git a/libs/remix-api/src/lib/plugins/fileSystem-api.ts b/libs/remix-api/src/lib/plugins/fileSystem-api.ts index cba69f007e..84210f2f7d 100644 --- a/libs/remix-api/src/lib/plugins/fileSystem-api.ts +++ b/libs/remix-api/src/lib/plugins/fileSystem-api.ts @@ -1,10 +1,13 @@ -import { commitChange } from "@remix-ui/git"; +import { commitChange } from "@remix-api"; import { IFileSystem } from "@remixproject/plugin-api" // Extended interface with 'diff' method export interface IExtendedFileSystem extends IFileSystem { methods: IFileSystem['methods'] & { + /** Compare the differences between two files */ diff(change: commitChange): Promise + refresh(): Promise + hasGitSubmodules(): Promise isGitRepo(): Promise }; } \ No newline at end of file diff --git a/libs/remix-api/src/lib/plugins/fs-api.ts b/libs/remix-api/src/lib/plugins/fs-api.ts new file mode 100644 index 0000000000..2488db988d --- /dev/null +++ b/libs/remix-api/src/lib/plugins/fs-api.ts @@ -0,0 +1,13 @@ +import { StatusEvents } from "@remixproject/plugin-utils"; + +export interface IFs { + events: { + workingDirChanged(path: string): Promise, + } & StatusEvents, + methods: { + selectFolder(path?: string, title?: string, button?: string): Promise + openWindow(path?: string): Promise, + getWorkingDir(): Promise, + openFolderInSameWindow(path: string): Promise, + } +} \ No newline at end of file diff --git a/libs/remix-api/src/lib/plugins/git-api.ts b/libs/remix-api/src/lib/plugins/git-api.ts new file mode 100644 index 0000000000..228b0ccc07 --- /dev/null +++ b/libs/remix-api/src/lib/plugins/git-api.ts @@ -0,0 +1,43 @@ +import { StatusEvents } from "@remixproject/plugin-utils" +import { ReadBlobResult, ReadCommitResult, StatusRow } from "isomorphic-git" +import { commitChange, repositoriesInput, repository, cloneInputType, branchesInputType, branch, remote, logInputType, remoteCommitsInputType, pagedCommits, fetchInputType, pullInputType, pushInputType, currentBranchInput, branchInputType, checkoutInputType, addInputType, rmInputType, resolveRefInput, readBlobInput, commitInputType, statusInput, compareBranchesInput, branchDifference, initInputType, updateSubmodulesInput } from "../types/git" + +export interface IGitApi { + events: { + "checkout": () => void + "clone": () => void + "add": () => void + "rm": () => void + "commit": () => void + "branch": () => void + "init": () => void + } & StatusEvents, + methods: { + getCommitChanges(oid1: string, oid2: string): Promise + repositories(input: repositoriesInput): Promise + clone(input: cloneInputType): Promise + branches(input?: branchesInputType): Promise, + remotes(): Promise, + log(input: logInputType): Promise, + remotecommits(input: remoteCommitsInputType): Promise + fetch(input: fetchInputType): Promise + pull(input: pullInputType): Promise + push(input: pushInputType): Promise + currentbranch(input?: currentBranchInput): Promise + branch(input: branchInputType): Promise + checkout(input: checkoutInputType): Promise + add(input: addInputType): Promise + rm(input: rmInputType): Promise + resolveref(input: resolveRefInput): Promise + readblob(input: readBlobInput): Promise + commit(input: commitInputType): Promise + addremote(input: remote): Promise + delremote(input: remote): Promise + status(input?: statusInput): Promise> + compareBranches(input: compareBranchesInput): Promise + init(input?: initInputType): Promise + updateSubmodules: (input: updateSubmodulesInput) => Promise + version: () => Promise + } +} + diff --git a/libs/remix-api/src/lib/plugins/terminal-api.ts b/libs/remix-api/src/lib/plugins/terminal-api.ts new file mode 100644 index 0000000000..e7fc77bab5 --- /dev/null +++ b/libs/remix-api/src/lib/plugins/terminal-api.ts @@ -0,0 +1,10 @@ +import { ITerminal } from "@remixproject/plugin-api/src/lib/terminal" +import { StatusEvents } from "@remixproject/plugin-utils" + +export interface IExtendedTerminalApi extends ITerminal { + events: { + } & StatusEvents + methods: ITerminal['methods'] & { + logHtml(html: string): void + } +} \ No newline at end of file diff --git a/libs/remix-api/src/lib/remix-api.ts b/libs/remix-api/src/lib/remix-api.ts index 56628dc5b0..71b3536910 100644 --- a/libs/remix-api/src/lib/remix-api.ts +++ b/libs/remix-api/src/lib/remix-api.ts @@ -1,13 +1,14 @@ -import { IGitApi } from "@remix-ui/git" import { IRemixApi } from "@remixproject/plugin-api" import { StatusEvents } from "@remixproject/plugin-utils" import { IConfigApi } from "./plugins/config-api" import { IFileDecoratorApi } from "./plugins/filedecorator-api" import { IExtendedFileSystem } from "./plugins/fileSystem-api" +import { IFs } from "./plugins/fs-api" +import { IGitApi } from "./plugins/git-api" import { INotificationApi } from "./plugins/notification-api" import { ISettings } from "./plugins/settings-api" +import { IExtendedTerminalApi } from "./plugins/terminal-api" import { IFilePanelApi } from "./plugins/filePanel-api" -import { Plugin } from "@remixproject/engine" import { ISidePanelApi } from "./plugins/sidePanel-api" import { IPinnedPanelApi } from "./plugins/pinned-panel-api" import { ILayoutApi } from "./plugins/layout-api" @@ -20,6 +21,9 @@ export interface ICustomRemixApi extends IRemixApi { settings: ISettings fileDecorator: IFileDecoratorApi fileManager: IExtendedFileSystem + isogit: IGitApi, + terminal: IExtendedTerminalApi + fs: IFs filePanel: IFilePanelApi sidePanel: ISidePanelApi pinnedPanel: IPinnedPanelApi diff --git a/libs/remix-api/src/lib/types/git.ts b/libs/remix-api/src/lib/types/git.ts new file mode 100644 index 0000000000..463e515715 --- /dev/null +++ b/libs/remix-api/src/lib/types/git.ts @@ -0,0 +1,206 @@ +import { Endpoints } from "@octokit/types" +import { AuthCallback, HttpClient, ReadCommitResult } from "isomorphic-git" + +export type branchDifference = { + uniqueHeadCommits: ReadCommitResult[], + uniqueRemoteCommits: ReadCommitResult[], +} + + +export type commitChange = { + type: commitChangeType + path: string, + hashModified: string, + hashOriginal: string, + original?: string, + modified?: string, + readonly?: boolean +} + +export type commitChangeTypes = { + "deleted": "D" + "modified": "M" + "added": "A", + "unknown": "?" +} + +export type pagedCommits = { + page: number, + perPage: number, + total: number, + hasNextPage: boolean, + commits: ReadCommitResult[] +} + +export enum syncStatus { + "sync" = "sync", + "publishBranch" = "publishBranch", + "none" = "none", +} + +export type repository = { + name: string + html_url: string + owner: { + login: string + }, + full_name: string + default_branch: string + id: number + url: string +} + +export type branch = { + name: string + remote: remote +} + +export type remote = { + name: string + url: string +} + +export type remoteBranch = { + name: string +} + +export type commitChangeType = keyof commitChangeTypes + +export type initInputType = { + defaultBranch: string +} + +export type author = { + name: string, + email: string, +} + +export type updateSubmodulesInput = { + dir?: string + token?: string +} + +export type remoteCommitsInputType = { + owner: string, repo: string, token: string, branch: string, length: number, page: number +} + +export type compareBranchesInput = { + branch: branch, remote: remote +} + +export type fetchInputType = { + remote: remote, + ref?: branch, + remoteRef?: branch, + depth?: number, + singleBranch?: boolean, + relative?: boolean, + quiet?: boolean + author?: author + token?: string +} + +export type logInputType = { + ref: string, + depth?: number, +} + +export type pullInputType = { + remote: remote, + ref: branch, + remoteRef?: branch + author?: author + token?: string +} + +export type pushInputType = { + remote: remote, + ref: branch, + remoteRef?: branch, + force?: boolean, + author?: author, + token?: string +} + +export type branchInputType = { + ref: string, + checkout?: boolean + refresh?: boolean + force?: boolean +} + +export type currentBranchInput = { + fs: any, + dir: string +} + +export type checkoutInputType = { + ref: string, + force?: boolean, + remote?: string + refresh?: boolean + fetch?: boolean +} + +export type addInputType = { + filepath: string | string[] +} + +export type rmInputType = { + filepath: string +} + +export type resolveRefInput = { + ref: string +} + +export type readBlobInput = { + oid: string, + filepath: string +} + +export type commitInputType = { + author: { + name: string, + email: string, + }, + message: string, +} + +export type branchesInputType = { + fs?: any + dir?: string +} + +export interface cloneInputType { + url: string, + branch?: string, + depth?: number, + singleBranch?: boolean + workspaceName?: string + workspaceExists?: boolean + token?: string + dir?: string // where the clone should happen on desktop +} + +export interface repositoriesInput { token: string, page?: number, per_page?: number } + +export interface statusInput { ref: string, filepaths?: string[] } + +export type isoGitFSConfig = { + fs: any, + dir: string, +} + +export type isoGitProxyConfig = { + corsProxy: string + http: HttpClient + onAuth: AuthCallback +} + +export type GitHubUser = Partial & { + isConnected: boolean +} + +export type userEmails = Endpoints["GET /user/emails"]["response"]["data"] + diff --git a/libs/remix-core-plugin/src/lib/gist-handler.ts b/libs/remix-core-plugin/src/lib/gist-handler.ts index 7d71742552..2b1f586bbf 100644 --- a/libs/remix-core-plugin/src/lib/gist-handler.ts +++ b/libs/remix-core-plugin/src/lib/gist-handler.ts @@ -2,6 +2,7 @@ 'use strict' import { Plugin } from '@remixproject/engine' import isElectron from 'is-electron' +import { Registry } from '@remix-project/remix-lib' interface StringByString { [key: string]: string; @@ -17,12 +18,16 @@ const profile = { type GistCallBackFn = (gistId: string) => void export class GistHandler extends Plugin { - constructor () { + isDesktop: boolean = false + constructor() { super(profile) + if (Registry.getInstance().get('platform').api.isDesktop()) { + this.isDesktop = true + } } - async handleLoad (gistId: string | null, cb: GistCallBackFn) { - if (!cb) cb = () => {} + async handleLoad(gistId: string | null, cb: GistCallBackFn) { + if (!cb) cb = () => { } let loadingFromGist = false if (!gistId) { @@ -36,7 +41,7 @@ export class GistHandler extends Plugin { title: 'Load a Gist', message: 'Enter the ID of the Gist or URL you would like to load.', modalType: 'prompt', - okLabel: 'OK', + okLabel: (this.isDesktop ? 'Load and select destination' : 'OK'), cancelLabel: 'Cancel', okFn: (value) => { setTimeout(() => resolve(value), 0) @@ -86,7 +91,7 @@ export class GistHandler extends Plugin { return loadingFromGist } - load (gistId: string | null) { + load(gistId: string | null) { const self = this return self.handleLoad(gistId, async (gistId: string | null) => { let data: any @@ -115,34 +120,38 @@ export class GistHandler extends Plugin { } const gistIdWorkspace = 'gist ' + gistId - const workspaces = await this.call('filePanel', 'getWorkspaces') - const found = workspaces.find((workspace) => workspace.name === gistIdWorkspace) - if (found) { - await this.call('notification', 'alert', { - id: 'gistAlert', - message: `workspace "${gistIdWorkspace}" already exists`, - }) - return - } - await this.call('filePanel', 'createWorkspace', 'gist ' + gistId, '', true) - await this.call('filePanel', 'switchToWorkspace', { name: 'gist ' + gistId, isLocalHost: false }) - const obj: StringByString = {} Object.keys(data.files).forEach((element) => { const path = element.replace(/\.\.\./g, '/') obj['/' + path] = data.files[element] }) - this.call('fileManager', 'setBatchFiles', obj, isElectron()? 'electron':'workspace', true, async (errorSavingFiles: any) => { - if (errorSavingFiles) { - const modalContent = { - id: 'gisthandler', - title: 'Gist load error', - message: errorSavingFiles.message || errorSavingFiles - } - this.call('notification', 'alert', modalContent) + if (this.isDesktop) { + await this.call('remix-templates', 'loadFilesInNewWindow', obj) + } else { + const workspaces = await this.call('filePanel', 'getWorkspaces') + const found = workspaces.find((workspace) => workspace.name === gistIdWorkspace) + if (found) { + await this.call('notification', 'alert', { + id: 'gistAlert', + message: `workspace "${gistIdWorkspace}" already exists`, + }) + return } - }) + await this.call('filePanel', 'createWorkspace', 'gist ' + gistId, '', true) + await this.call('filePanel', 'switchToWorkspace', { name: 'gist ' + gistId, isLocalHost: false }) + this.call('fileManager', 'setBatchFiles', obj, isElectron() ? 'electron' : 'workspace', true, async (errorSavingFiles: any) => { + if (errorSavingFiles) { + const modalContent = { + id: 'gisthandler', + title: 'Gist load error', + message: errorSavingFiles.message || errorSavingFiles + + } + this.call('notification', 'alert', modalContent) + } + }) + } }) } } diff --git a/libs/remix-git/index.ts b/libs/remix-git/index.ts new file mode 100644 index 0000000000..7285bb292a --- /dev/null +++ b/libs/remix-git/index.ts @@ -0,0 +1 @@ +export { isoGit } from './src/isogit' \ No newline at end of file diff --git a/libs/remix-git/src/isogit.ts b/libs/remix-git/src/isogit.ts new file mode 100644 index 0000000000..2c608d9ce2 --- /dev/null +++ b/libs/remix-git/src/isogit.ts @@ -0,0 +1,345 @@ +import { GitHubUser, author, branch, cloneInputType, commitChange, compareBranchesInput, currentBranchInput, fetchInputType, isoGitFSConfig, isoGitProxyConfig, pullInputType, pushInputType, remote, userEmails } from "@remix-api" +import git from 'isomorphic-git' +import { + Plugin +} from '@remixproject/engine' +import http from 'isomorphic-git/http/web' + +import { Octokit } from "octokit" +import { ElectronBasePluginClient } from "@remixproject/plugin-electron" +const currentbranch = async (input: currentBranchInput, fsConfig: isoGitFSConfig) => { + + try { + const cmd = input ? fsConfig ? { ...fsConfig, ...input } : input : fsConfig + + const name = await git.currentBranch(cmd) + let remote: remote = undefined + try { + const remoteName = await git.getConfig({ + ...fsConfig, + path: `branch.${name}.remote` + }) + if (remoteName) { + const remoteUrl = await git.getConfig({ + ...fsConfig, + path: `remote.${remoteName}.url` + }) + remote = { name: remoteName, url: remoteUrl } + } + + } catch (e) { + // do nothing + } + + return { + remote: remote, + name: name || '' + } + } catch (e) { + return undefined + } +} + +const branches = async (fsConfig: isoGitFSConfig) => { + try { + + const remotes = await isoGit.remotes(fsConfig) + let branches: branch[] = [] + branches = (await git.listBranches(fsConfig)).map((branch) => { return { remote: undefined, name: branch } }) + for (const remote of remotes) { + const cmd = { + ...fsConfig, + remote: remote.name + } + const remotebranches = (await git.listBranches(cmd)).map((branch) => { return { remote: remote, name: branch } }) + branches = [...branches, ...remotebranches] + } + return branches + } catch (e) { + console.log(e) + return [] + } +} + +const remotes = async (fsConfig: isoGitFSConfig) => { + + let remotes: remote[] = [] + try { + remotes = (await git.listRemotes({ ...fsConfig })).map((remote) => { return { name: remote.remote, url: remote.url } } + ) + } catch (e) { + // do nothing + } + return remotes +} + +const push = async (input: pushInputType, fsConfig: isoGitFSConfig, plugin: Plugin | ElectronBasePluginClient) => { + const cmd = { + force: input.force, + ref: input.ref.name, + remoteRef: input.remoteRef && input.remoteRef.name, + remote: input.remote.name, + author: await getAuthor(input, plugin), + input, + } + + const proxy = await isoGit.addIsomorphicGitProxyConfig(input, plugin) + console.log({ ...fsConfig, ...cmd, ...proxy }) + return await git.push({ ...fsConfig, ...cmd, ...proxy }) +} + +const pull = async (input: pullInputType, fsConfig: isoGitFSConfig, plugin: Plugin | ElectronBasePluginClient) => { + const cmd = { + ref: input.ref.name, + remoteRef: input.remoteRef && input.remoteRef.name, + author: await getAuthor(input, plugin), + remote: input.remote.name, + input, + } + const proxy = await isoGit.addIsomorphicGitProxyConfig(input, plugin) + console.log({ ...fsConfig, ...cmd, ...proxy }) + return await git.pull({ ...fsConfig, ...cmd, ...proxy }) +} + +const fetch = async (input: fetchInputType, fsConfig: isoGitFSConfig, plugin: Plugin | ElectronBasePluginClient) => { + const cmd = { + ref: input.ref && input.ref.name, + remoteRef: input.remoteRef && input.remoteRef.name, + author: await getAuthor(input, plugin), + remote: input.remote && input.remote.name, + depth: input.depth || 5, + singleBranch: input.singleBranch, + relative: input.relative, + input + } + const proxy = await isoGit.addIsomorphicGitProxyConfig(input, plugin) + console.log({ ...fsConfig, ...cmd, ...proxy }) + return await git.fetch({ ...fsConfig, ...cmd, ...proxy }) +} + +const clone = async (input: cloneInputType, fsConfig: isoGitFSConfig, plugin: Plugin | ElectronBasePluginClient) => { + const proxy = await isoGit.addIsomorphicGitProxyConfig(input, plugin) + const cmd = { + url: input.url, + singleBranch: input.singleBranch, + ref: input.branch, + depth: input.depth || 10, + dir: input.dir, + input + } + await git.clone({ ...fsConfig, ...cmd, ...proxy }) +} + +const getAuthor = async (input, plugin: any) => { + const author: author = { + name: '', + email: '' + } + if (input && input.name && input.email) { + author.name = input.name + author.email = input.email + } else { + const username = await plugin.call('config' as any, 'getAppParameter', 'settings/github-user-name') + const email = await plugin.call('config' as any, 'getAppParameter', 'settings/github-email') + const token = await plugin.call('config' as any, 'getAppParameter', 'settings/gist-access-token') + if (username && email) { + author.name = username + author.email = email + } else if (token) { + + const gitHubUser = await isoGit.getGitHubUser({ token }) + + if (gitHubUser) { + author.name = gitHubUser.user.login + } + } + } + return author +} + + +const getGitHubUser = async(input: { token: string }): Promise<{ + user: GitHubUser, + emails: userEmails, + scopes: string[] +}> => { + try { + const octokit = new Octokit({ + auth: input.token + }) + + const user = await octokit.request('GET /user', { + headers: { + 'X-GitHub-Api-Version': '2022-11-28' + } + }) + const emails = await octokit.request('GET /user/emails') + + const scopes = user.headers['x-oauth-scopes'] || '' + + return { + user: { + ...user.data, isConnected: + user.data.login !== undefined && user.data.login !== null && user.data.login !== '' + }, + emails: emails.data, + scopes: scopes && scopes.split(',').map(scope => scope.trim()) + } + } catch (e) { + return null + } +} + +const addIsomorphicGitProxyConfig = async (input: { + url?: string, + remote?: remote, + provider?: 'github' | 'localhost', + token?: string, +}, plugin: any) => { + + const token = await plugin.call('config' as any, 'getAppParameter', 'settings/gist-access-token') + + let config: isoGitProxyConfig = { + corsProxy: 'https://corsproxy.remixproject.org/', + http, + onAuth: url => { + url + const auth = { + username: input.token || token, + password: '' + } + return auth + } + } + if (input.url) { + + const url = new URL(input.url) + if (url.hostname.includes('localhost')) { + config = { + ...config, + corsProxy: null + } + } + } + if ((input.remote && input.remote.url)) { + + const url = new URL(input.remote.url) + if (url.hostname.includes('localhost')) { + config = { + ...config, + corsProxy: null, + } + } + } + + if (input.provider && input.provider === 'github') { + config = { + ...config, + corsProxy: 'https://corsproxy.remixproject.org/', + } + } + + if (input.provider && input.provider === 'localhost') { + config = { + ...config, + corsProxy: null + } + } + + return config +} + +const getCommitChanges = async (commitHash1: string, commitHash2: string, fsConfig: isoGitFSConfig) => { + const result: commitChange[] = await git.walk({ + ...fsConfig, + trees: [git.TREE({ ref: commitHash1 }), git.TREE({ ref: commitHash2 })], + map: async function (filepath, [A, B]) { + + if (filepath === '.') { + return + } + try { + if ((A && await A.type()) === 'tree' || B && (await B.type()) === 'tree') { + return + } + } catch (e) { + // ignore + } + + // generate ids + const Aoid = A && await A.oid() || undefined + const Boid = B && await B.oid() || undefined + + const commitChange: Partial = { + hashModified: commitHash1, + hashOriginal: commitHash2, + path: filepath, + } + + // determine modification type + if (Aoid !== Boid) { + commitChange.type = "modified" + } + if (Aoid === undefined) { + commitChange.type = "deleted" + } + if (Boid === undefined || !commitHash2) { + commitChange.type = "added" + } + if (Aoid === undefined && Boid === undefined) { + commitChange.type = "unknown" + } + if (commitChange.type) + return commitChange + else + return undefined + }, + }) + + return result +} + +const compareBranches = async ({ branch, remote }: compareBranchesInput, fsConfig: isoGitFSConfig) => { + // Get current branch commits + const headCommits = await git.log({ + ...fsConfig, + ref: branch.name, + depth: 10, + }); + + // Get remote branch commits + const remoteCommits = await git.log({ + ...fsConfig, + ref: `${remote.name}/${branch.name}`, + depth: 10, + }); + + // Convert arrays of commit objects to sets of commit SHAs + const headCommitSHAs = new Set(headCommits.map(commit => commit.oid)); + const remoteCommitSHAs = new Set(remoteCommits.map(commit => commit.oid)); + + // Filter out commits that are only in the remote branch + const uniqueRemoteCommits = remoteCommits.filter(commit => !headCommitSHAs.has(commit.oid)); + + // filter out commits that are only in the local branch + const uniqueHeadCommits = headCommits.filter(commit => !remoteCommitSHAs.has(commit.oid)); + + return { + uniqueHeadCommits, + uniqueRemoteCommits, + }; +} + +export const isoGit = { + currentbranch, + remotes, + branches, + getCommitChanges, + compareBranches, + addIsomorphicGitProxyConfig, + push, + pull, + fetch, + getGitHubUser, + clone +} \ No newline at end of file diff --git a/libs/remix-lib/src/types/ICompilerApi.ts b/libs/remix-lib/src/types/ICompilerApi.ts index da8dc3b694..cfb4ce832f 100644 --- a/libs/remix-lib/src/types/ICompilerApi.ts +++ b/libs/remix-lib/src/types/ICompilerApi.ts @@ -18,6 +18,7 @@ export interface ICompilerApi { setAppParameter: (name: string, value: string | boolean) => void getFileManagerMode: () => string + isDesktop: () => boolean setCompilerConfig: (settings: any) => void getCompilationResult: () => any diff --git a/libs/remix-ui/app/src/lib/remix-app/actions/app.ts b/libs/remix-ui/app/src/lib/remix-app/actions/app.ts index 20932eef6c..9822635e1e 100644 --- a/libs/remix-ui/app/src/lib/remix-app/actions/app.ts +++ b/libs/remix-ui/app/src/lib/remix-app/actions/app.ts @@ -1,4 +1,4 @@ -import { GitHubUser } from '@remix-ui/git'; +import { GitHubUser } from '@remix-api'; import { AppModal } from '../interface' type ActionMap = { diff --git a/libs/remix-ui/app/src/lib/remix-app/interface/index.ts b/libs/remix-ui/app/src/lib/remix-app/interface/index.ts index dc6e453edc..b1cee75257 100644 --- a/libs/remix-ui/app/src/lib/remix-app/interface/index.ts +++ b/libs/remix-ui/app/src/lib/remix-app/interface/index.ts @@ -1,4 +1,4 @@ -import { GitHubUser } from '@remix-ui/git' +import { GitHubUser } from '@remix-api' import { ModalTypes } from '../types' export type ValidationResult = { diff --git a/libs/remix-ui/app/src/lib/remix-app/state/app.ts b/libs/remix-ui/app/src/lib/remix-app/state/app.ts index 417911ae0c..1e76098bdc 100644 --- a/libs/remix-ui/app/src/lib/remix-app/state/app.ts +++ b/libs/remix-ui/app/src/lib/remix-app/state/app.ts @@ -1,4 +1,4 @@ -import { GitHubUser } from "@remix-ui/git"; +import { GitHubUser } from "@remix-api"; import { AppState } from "../interface"; export const appInitialState: AppState = { diff --git a/libs/remix-ui/editor/src/lib/remix-plugin-types.ts b/libs/remix-ui/editor/src/lib/remix-plugin-types.ts index 9e55e5b55d..6f605f829a 100644 --- a/libs/remix-ui/editor/src/lib/remix-plugin-types.ts +++ b/libs/remix-ui/editor/src/lib/remix-plugin-types.ts @@ -380,7 +380,6 @@ declare interface IDgitSystem { status(cmd: any): any[]; rm(cmd: any): string; log(cmd: any): any[]; - lsfiles(cmd: any): any[]; readblob(cmd: any): { oid: string, blob: Uint8Array } resolveref(cmd: any): string branch(cmd: any): void diff --git a/libs/remix-ui/git/src/components/buttons/sourceControlBase.tsx b/libs/remix-ui/git/src/components/buttons/sourceControlBase.tsx index 36f2da120f..628e57f0fb 100644 --- a/libs/remix-ui/git/src/components/buttons/sourceControlBase.tsx +++ b/libs/remix-ui/git/src/components/buttons/sourceControlBase.tsx @@ -5,7 +5,7 @@ import { ReadCommitResult } from "isomorphic-git" import React, { createContext, useEffect, useState } from "react" import { FormattedMessage } from "react-intl" import { gitActionsContext } from "../../state/context" -import { branch, remote } from "../../types" +import { branch, remote } from "@remix-api" import { gitPluginContext } from "../gitui" import GitUIButton from "./gituibutton" diff --git a/libs/remix-ui/git/src/components/buttons/sourcecontrolbuttons.tsx b/libs/remix-ui/git/src/components/buttons/sourcecontrolbuttons.tsx index ba9e10af21..7aa8705e2a 100644 --- a/libs/remix-ui/git/src/components/buttons/sourcecontrolbuttons.tsx +++ b/libs/remix-ui/git/src/components/buttons/sourcecontrolbuttons.tsx @@ -1,16 +1,21 @@ -import { faArrowDown, faArrowUp, faArrowsUpDown, faArrowRotateRight } from "@fortawesome/free-solid-svg-icons" -import { FontAwesomeIcon } from "@fortawesome/react-fontawesome" -import { CustomTooltip } from "@remix-ui/helper" -import React, { useEffect, useState } from "react" -import { FormattedMessage } from "react-intl" -import { gitActionsContext } from "../../state/context" -import { branch, defaultGitState, gitMatomoEventTypes, remote } from "../../types" -import { gitPluginContext } from "../gitui" -import GitUIButton from "./gituibutton" -import { syncStateContext } from "./sourceControlBase" -import { sendToMatomo } from "../../lib/pluginActions" +import { faArrowDown, faArrowUp, faArrowsUpDown, faArrowRotateRight } from '@fortawesome/free-solid-svg-icons' +import { FontAwesomeIcon } from '@fortawesome/react-fontawesome' +import { CustomTooltip } from '@remix-ui/helper' +import React, { useEffect, useState } from 'react' +import { FormattedMessage } from 'react-intl' +import { gitActionsContext } from '../../state/context' +import { branch, remote } from '@remix-api' +import { defaultGitState, gitMatomoEventTypes, gitUIPanels } from '../../types' +import { gitPluginContext } from '../gitui' +import GitUIButton from './gituibutton' +import { syncStateContext } from './sourceControlBase' +import { sendToMatomo } from '../../lib/pluginActions' -export const SourceControlButtons = () => { +export interface SourceControlButtonsProps { + panel: string +} + +export const SourceControlButtons = (props: SourceControlButtonsProps) => { const context = React.useContext(gitPluginContext) const actions = React.useContext(gitActionsContext) const syncState = React.useContext(syncStateContext) @@ -28,21 +33,21 @@ export const SourceControlButtons = () => { const pull = async () => { await actions.pull({ remote: getRemote(), - ref: branch ? branch : context.currentBranch + ref: branch ? branch : context.currentBranch, }) } const push = async () => { await actions.push({ remote: getRemote(), - ref: branch ? branch : context.currentBranch + ref: branch ? branch : context.currentBranch, }) await actions.fetch({ remote: getRemote(), ref: branch ? branch : context.currentBranch, relative: false, depth: 1, - singleBranch: true + singleBranch: true, }) } @@ -51,50 +56,63 @@ export const SourceControlButtons = () => { await push() } - const refresh = async() => { + const refresh = async () => { await sendToMatomo(gitMatomoEventTypes.REFRESH) await actions.getFileStatusMatrix(null) + if (props.panel === gitUIPanels.BRANCHES) { + await actions.getBranches() + } + if (props.panel === gitUIPanels.COMMITS) { + await actions.gitlog(defaultGitState.gitLogCount) + } actions.setStateGitLogCount(defaultGitState.gitLogCount) } const buttonsDisabled = () => { - return (!context.upstream) || context.remotes.length === 0 + return !context.upstream || context.remotes.length === 0 } const getTooltipText = (id: string) => { if (buttonsDisabled()) return - return <> {getRemoteName()} + return ( + <> + {getRemoteName()} + + ) } return ( - - - -
- {syncState.commitsBehind.length ?
- {syncState.commitsBehind.length} -
: null} - -
-
-
- - -
- {syncState.commitsAhead.length ?
- {syncState.commitsAhead.length} -
: null} - -
-
-
- - - + + {props.panel === gitUIPanels.COMMITS || props.panel === gitUIPanels.SOURCECONTROL ? ( + <> + + +
+ {syncState.commitsBehind.length ?
{syncState.commitsBehind.length}
: null} + +
+
+
+ + +
+ {syncState.commitsAhead.length ?
{syncState.commitsAhead.length}
: null} + +
+
+
+ + + + + + + ) : null} }> - + + +
- ) -} \ No newline at end of file +} diff --git a/libs/remix-ui/git/src/components/disabled.tsx b/libs/remix-ui/git/src/components/disabled.tsx index fbd54d6177..1f03413be9 100644 --- a/libs/remix-ui/git/src/components/disabled.tsx +++ b/libs/remix-ui/git/src/components/disabled.tsx @@ -1,12 +1,30 @@ -import React, { useEffect, useState } from 'react' +import { appPlatformTypes, platformContext } from '@remix-ui/app' +import React, { useEffect, useState, useContext } from 'react' +import { FormattedMessage } from "react-intl" +import { pluginActionsContext } from '../state/context' +import { openCloneDialog, openFolderInSameWindow } from '../lib/pluginActions' export const Disabled = () => { + const platform = useContext(platformContext) - return ( -
- Git is currently disabled.

- If you are using RemixD you can use git on the terminal.

-
- ) + const openFolderElectron = async (path: string) => { + await openFolderInSameWindow(path) + } + + const clone = async () => { + openCloneDialog() + } + return ( + (platform === appPlatformTypes.desktop) ? +
+
+
{ await openFolderElectron(null) }} className='btn btn-primary w-100 my-1'>
+
{ await clone() }} className='btn btn-primary w-100'>
+
+ : +
+ Git is currently disabled.

+ If you are using RemixD you can use git on the terminal.

+
) } \ No newline at end of file diff --git a/libs/remix-ui/git/src/components/github/repositoryselect.tsx b/libs/remix-ui/git/src/components/github/repositoryselect.tsx index 40a9d7b4a3..72b055ba9a 100644 --- a/libs/remix-ui/git/src/components/github/repositoryselect.tsx +++ b/libs/remix-ui/git/src/components/github/repositoryselect.tsx @@ -1,7 +1,8 @@ import React, { useState, useEffect } from 'react'; import Select from 'react-select'; import { gitActionsContext } from '../../state/context'; -import { gitMatomoEventTypes, repository } from '../../types'; +import { repository } from '@remix-api'; +import { gitMatomoEventTypes } from '../../types'; import { selectStyles, selectTheme } from '../../types/styles'; import { gitPluginContext } from '../gitui'; import { sendToMatomo } from '../../lib/pluginActions'; diff --git a/libs/remix-ui/git/src/components/github/selectandclonerepositories.tsx b/libs/remix-ui/git/src/components/github/selectandclonerepositories.tsx index 5557c3f13b..9c3e879c71 100644 --- a/libs/remix-ui/git/src/components/github/selectandclonerepositories.tsx +++ b/libs/remix-ui/git/src/components/github/selectandclonerepositories.tsx @@ -1,6 +1,6 @@ import React, { useEffect, useState } from "react"; import { gitActionsContext } from "../../state/context"; -import { repository } from "../../types"; +import { repository } from "@remix-api"; import { gitPluginContext } from "../gitui"; import RepositorySelect from "./repositoryselect"; import { BranchSelect } from "./branchselect"; diff --git a/libs/remix-ui/git/src/components/gitui.tsx b/libs/remix-ui/git/src/components/gitui.tsx index b3d31fcc1f..b7444e0b8d 100644 --- a/libs/remix-ui/git/src/components/gitui.tsx +++ b/libs/remix-ui/git/src/components/gitui.tsx @@ -1,10 +1,10 @@ import React, { useEffect, useReducer, useState, useContext } from 'react' import { add, addall, checkout, checkoutfile, clone, commit, createBranch, remoteBranches, repositories, rm, getCommitChanges, diff, resolveRef, getBranchCommits, setUpstreamRemote, loadGitHubUserFromToken, getBranches, getRemotes, remoteCommits, saveGitHubCredentials, getGitHubCredentialsFromLocalStorage, fetch, pull, push, setDefaultRemote, addRemote, removeRemote, sendToGitLog, clearGitLog, getBranchDifferences, getFileStatusMatrix, init, showAlert, gitlog, setStateGitLogCount } from '../lib/gitactions' import { loadFiles, setCallBacks } from '../lib/listeners' -import { openDiff, openFile, saveToken, sendToMatomo, setModifiedDecorator, setPlugin, setUntrackedDecorator, statusChanged } from '../lib/pluginActions' +import { openDiff, openFile, openFolderInSameWindow, sendToMatomo, saveToken, setModifiedDecorator, setPlugin, setUntrackedDecorator, statusChanged } from '../lib/pluginActions' import { gitActionsContext, pluginActionsContext } from '../state/context' import { gitReducer } from '../state/gitreducer' -import { defaultGitState, defaultLoaderState, gitMatomoEventTypes, gitState, gitUIPanels, loaderState } from '../types' +import { IGitUi, defaultGitState, defaultLoaderState, gitMatomoEventTypes, gitState, gitUIPanels, loaderState } from '../types' import { Accordion, Button } from "react-bootstrap"; import { CommitMessage } from './buttons/commitmessage' import { Commits } from './panels/commits' @@ -31,8 +31,9 @@ import { GitHubCredentials } from './panels/githubcredentials' import { Setup } from './panels/setup' import { Init } from './panels/init' import { Disabled } from './disabled' -import { IGitUi } from '../types' -import { AppContext } from '@remix-ui/app' +import { AppContext, appPlatformTypes, platformContext } from '@remix-ui/app' +import { Version } from './panels/version' + export const gitPluginContext = React.createContext(defaultGitState) export const loaderContext = React.createContext(defaultLoaderState) @@ -46,6 +47,8 @@ export const GitUI = (props: IGitUi) => { const [appLoaded, setAppLoaded] = useState(false) const appContext = useContext(AppContext) + const platform = useContext(platformContext) + useEffect(() => { plugin.emit('statusChanged', { key: 'loading', @@ -59,7 +62,7 @@ export const GitUI = (props: IGitUi) => { useEffect(() => { if (!appLoaded) return - setCallBacks(plugin, gitDispatch, appContext.appStateDispatch, loaderDispatch, setActivePanel) + setCallBacks(plugin, gitDispatch, appContext.appStateDispatch, loaderDispatch, setActivePanel, platform) setPlugin(plugin, gitDispatch, loaderDispatch) loaderDispatch({ type: 'plugin', payload: true }) @@ -167,7 +170,8 @@ export const GitUI = (props: IGitUi) => { saveToken, saveGitHubCredentials, getGitHubCredentialsFromLocalStorage, - showAlert + showAlert, + openFolderInSameWindow } return ( @@ -243,6 +247,8 @@ export const GitUI = (props: IGitUi) => { + { platform === appPlatformTypes.desktop && + } diff --git a/libs/remix-ui/git/src/components/navigation/branchedetails.tsx b/libs/remix-ui/git/src/components/navigation/branchedetails.tsx index 9de954fc94..0eeac2c0c2 100644 --- a/libs/remix-ui/git/src/components/navigation/branchedetails.tsx +++ b/libs/remix-ui/git/src/components/navigation/branchedetails.tsx @@ -2,7 +2,7 @@ import { faCaretUp, faCaretDown, faCaretRight, faArrowUp, faArrowDown, faArrowRo import { FontAwesomeIcon } from "@fortawesome/react-fontawesome"; import React, { useContext, useEffect } from "react"; import { gitActionsContext } from "../../state/context"; -import { branch } from "../../types"; +import { branch } from "@remix-api"; import GitUIButton from "../buttons/gituibutton"; import { gitPluginContext } from "../gitui"; import { removeGitFromUrl } from "../../utils"; diff --git a/libs/remix-ui/git/src/components/navigation/branches.tsx b/libs/remix-ui/git/src/components/navigation/branches.tsx index 21decc6e7a..be02305932 100644 --- a/libs/remix-ui/git/src/components/navigation/branches.tsx +++ b/libs/remix-ui/git/src/components/navigation/branches.tsx @@ -3,6 +3,9 @@ import { FontAwesomeIcon } from "@fortawesome/react-fontawesome"; import React, { } from "react"; import { gitActionsContext, pluginActionsContext } from "../../state/context"; import LoaderIndicator from "./loaderindicator"; +import { gitUIPanels } from "../../types"; +import { SourceControlBase } from "../buttons/sourceControlBase"; +import { SourceControlButtons } from "../buttons/sourcecontrolbuttons"; export const BranchesNavigation = ({ eventKey, activePanel, callback }) => { const pluginactions = React.useContext(pluginActionsContext) @@ -26,6 +29,7 @@ export const BranchesNavigation = ({ eventKey, activePanel, callback }) => {
+ ); diff --git a/libs/remix-ui/git/src/components/navigation/commitdetails.tsx b/libs/remix-ui/git/src/components/navigation/commitdetails.tsx index 2e49875f52..8848aae460 100644 --- a/libs/remix-ui/git/src/components/navigation/commitdetails.tsx +++ b/libs/remix-ui/git/src/components/navigation/commitdetails.tsx @@ -3,7 +3,7 @@ import { FontAwesomeIcon } from "@fortawesome/react-fontawesome"; import React, { useContext, useEffect } from "react"; import { CommitSummary } from "../panels/commits/commitsummary"; import { ReadCommitResult } from "isomorphic-git" -import { branch } from "../../types"; +import { branch } from "@remix-api"; interface CommitDetailsNavigationProps { commit: ReadCommitResult, diff --git a/libs/remix-ui/git/src/components/navigation/commits.tsx b/libs/remix-ui/git/src/components/navigation/commits.tsx index 08798b4576..85c7dd1815 100644 --- a/libs/remix-ui/git/src/components/navigation/commits.tsx +++ b/libs/remix-ui/git/src/components/navigation/commits.tsx @@ -4,11 +4,12 @@ import { CustomTooltip } from "@remix-ui/helper"; import React, { useEffect } from "react"; import { FormattedMessage } from "react-intl"; import { pluginActionsContext } from "../../state/context"; -import { branch, remote } from "../../types"; +import { branch, remote } from "@remix-api"; import { SourceControlBase } from "../buttons/sourceControlBase"; import { SourceControlButtons } from "../buttons/sourcecontrolbuttons"; import { gitPluginContext } from "../gitui"; import LoaderIndicator from "./loaderindicator"; +import { gitUIPanels } from "../../types"; export interface CommitsNavigationProps { title: string, @@ -53,7 +54,7 @@ export const CommitsNavigation = ({ eventKey, activePanel, callback, title, bran {showButtons ? - + : null} diff --git a/libs/remix-ui/git/src/components/navigation/remotesdetails.tsx b/libs/remix-ui/git/src/components/navigation/remotesdetails.tsx index 626834feb1..4a702b1193 100644 --- a/libs/remix-ui/git/src/components/navigation/remotesdetails.tsx +++ b/libs/remix-ui/git/src/components/navigation/remotesdetails.tsx @@ -3,7 +3,8 @@ import { FontAwesomeIcon } from "@fortawesome/react-fontawesome"; import { CustomTooltip } from "@remix-ui/helper"; import React, { useContext, useEffect } from "react"; import { gitActionsContext } from "../../state/context"; -import { branch, gitMatomoEventTypes, remote } from "../../types"; +import { remote } from "@remix-api"; +import { gitMatomoEventTypes } from "../../types"; import GitUIButton from "../buttons/gituibutton"; import { gitPluginContext } from "../gitui"; import { removeGitFromUrl } from "../../utils"; diff --git a/libs/remix-ui/git/src/components/navigation/sourcecontrol.tsx b/libs/remix-ui/git/src/components/navigation/sourcecontrol.tsx index 7baf2f50e1..9f66bc9314 100644 --- a/libs/remix-ui/git/src/components/navigation/sourcecontrol.tsx +++ b/libs/remix-ui/git/src/components/navigation/sourcecontrol.tsx @@ -9,6 +9,7 @@ import { SourceControlButtons } from "../buttons/sourcecontrolbuttons"; import { gitPluginContext } from "../gitui"; import LoaderIndicator from "./loaderindicator"; import { SourceControlMenu } from "./menu/sourcecontrolmenu"; +import { gitUIPanels } from "../../types"; export const SourceControlNavigation = ({ eventKey, activePanel, callback }) => { const pluginactions = React.useContext(pluginActionsContext) @@ -35,7 +36,7 @@ export const SourceControlNavigation = ({ eventKey, activePanel, callback }) => - + diff --git a/libs/remix-ui/git/src/components/panels/branches.tsx b/libs/remix-ui/git/src/components/panels/branches.tsx index 38804b57aa..e0db3e4a4e 100644 --- a/libs/remix-ui/git/src/components/panels/branches.tsx +++ b/libs/remix-ui/git/src/components/panels/branches.tsx @@ -1,12 +1,12 @@ import React, { useEffect, useState } from "react"; import { gitActionsContext } from "../../state/context"; -import { branch, remote } from "../../types"; import GitUIButton from "../buttons/gituibutton"; import { gitPluginContext } from "../gitui"; import { LocalBranchDetails } from "./branches/localbranchdetails"; import { RemoteBranchDetails } from "./branches/remotebranchedetails"; import { faSync } from "@fortawesome/free-solid-svg-icons"; import { FontAwesomeIcon } from "@fortawesome/react-fontawesome"; +import { branch } from "@remix-api"; const pageLength = 5; @@ -73,7 +73,7 @@ export const Branches = () => { ); })} - {context.branches && remoteBranches.length > remoteBranchPage * pageLength && <> { + {context.branches && remoteBranches.length > remoteBranchPage * pageLength && <> { setRemoteBranchPage(remoteBranchPage + 1); }}>Show more

} { diff --git a/libs/remix-ui/git/src/components/panels/branches/branchdifferencedetails.tsx b/libs/remix-ui/git/src/components/panels/branches/branchdifferencedetails.tsx index c2090a87a5..b2a266c00a 100644 --- a/libs/remix-ui/git/src/components/panels/branches/branchdifferencedetails.tsx +++ b/libs/remix-ui/git/src/components/panels/branches/branchdifferencedetails.tsx @@ -3,7 +3,7 @@ import { Accordion } from "react-bootstrap"; import React, { useEffect, useState } from "react"; import { CommitDetails } from "../commits/commitdetails"; import { CommitsNavigation } from "../../navigation/commits"; -import { branch, remote } from "../../../types"; +import { branch, remote } from "@remix-api"; import { gitActionsContext } from "../../../state/context"; import { gitPluginContext } from "../../gitui"; diff --git a/libs/remix-ui/git/src/components/panels/branches/branchdifferences.tsx b/libs/remix-ui/git/src/components/panels/branches/branchdifferences.tsx index 846d0230d1..86d4584724 100644 --- a/libs/remix-ui/git/src/components/panels/branches/branchdifferences.tsx +++ b/libs/remix-ui/git/src/components/panels/branches/branchdifferences.tsx @@ -1,4 +1,4 @@ -import { branch, remote } from "../../../types"; +import { branch, remote } from "@remix-api"; import React, { useEffect, useState } from "react"; import { gitPluginContext } from "../../gitui"; import { CommitDetails } from "../commits/commitdetails"; diff --git a/libs/remix-ui/git/src/components/panels/branches/localbranchdetails.tsx b/libs/remix-ui/git/src/components/panels/branches/localbranchdetails.tsx index da592229b3..dd9ab94358 100644 --- a/libs/remix-ui/git/src/components/panels/branches/localbranchdetails.tsx +++ b/libs/remix-ui/git/src/components/panels/branches/localbranchdetails.tsx @@ -4,7 +4,8 @@ import { Accordion } from "react-bootstrap"; import { CommitDetailsNavigation } from "../../navigation/commitdetails"; import { gitActionsContext } from "../../../state/context"; import { gitPluginContext } from "../../gitui"; -import { branch, gitMatomoEventTypes } from "../../../types"; +import { branch } from "@remix-api"; +import { gitMatomoEventTypes } from "../../../types"; import { BrancheDetailsNavigation } from "../../navigation/branchedetails"; import { CommitDetailsItems } from "../commits/commitdetailsitem"; import { CommitDetails } from "../commits/commitdetails"; diff --git a/libs/remix-ui/git/src/components/panels/branches/remotebranchedetails.tsx b/libs/remix-ui/git/src/components/panels/branches/remotebranchedetails.tsx index da97dea0f2..fcff0754a3 100644 --- a/libs/remix-ui/git/src/components/panels/branches/remotebranchedetails.tsx +++ b/libs/remix-ui/git/src/components/panels/branches/remotebranchedetails.tsx @@ -4,7 +4,8 @@ import { Accordion } from "react-bootstrap"; import { CommitDetailsNavigation } from "../../navigation/commitdetails"; import { gitActionsContext } from "../../../state/context"; import { gitPluginContext } from "../../gitui"; -import { branch, gitMatomoEventTypes } from "../../../types"; +import { branch } from "@remix-api"; +import { gitMatomoEventTypes } from "../../../types"; import { BrancheDetailsNavigation } from "../../navigation/branchedetails"; import { CommitDetailsItems } from "../commits/commitdetailsitem"; import { CommitDetails } from "../commits/commitdetails"; @@ -59,7 +60,6 @@ export const RemoteBranchDetails = (props: BrancheDetailsProps) => { }) await actions.checkout({ ref: branch.name, - remote: branch.remote && branch.remote.name || null, refresh: true }); await actions.getBranches() diff --git a/libs/remix-ui/git/src/components/panels/commands/pushpull.tsx b/libs/remix-ui/git/src/components/panels/commands/pushpull.tsx index 981542f7cc..3fae193fd9 100644 --- a/libs/remix-ui/git/src/components/panels/commands/pushpull.tsx +++ b/libs/remix-ui/git/src/components/panels/commands/pushpull.tsx @@ -4,7 +4,8 @@ import { gitPluginContext } from "../../gitui"; import { selectStyles, selectTheme } from "../../../types/styles"; import Select, { Options, OptionsOrGroups } from 'react-select' import GitUIButton from "../../buttons/gituibutton"; -import { gitMatomoEventTypes, remote } from "../../../types"; +import { remote } from "@remix-api"; +import { gitMatomoEventTypes } from "../../../types"; import { relative } from "path"; import { sendToMatomo } from "../../../lib/pluginActions"; diff --git a/libs/remix-ui/git/src/components/panels/commits.tsx b/libs/remix-ui/git/src/components/panels/commits.tsx index db2907a1da..584c3f2fb4 100644 --- a/libs/remix-ui/git/src/components/panels/commits.tsx +++ b/libs/remix-ui/git/src/components/panels/commits.tsx @@ -20,7 +20,6 @@ export const Commits = () => { }; const loadNextPage = async () => { - await actions.fetch({ remote: null, ref: context.currentBranch, @@ -29,7 +28,6 @@ export const Commits = () => { singleBranch: true, quiet: true }) - await actions.setStateGitLogCount(context.gitLogCount + 5) } diff --git a/libs/remix-ui/git/src/components/panels/commits/commitdetailsitem.tsx b/libs/remix-ui/git/src/components/panels/commits/commitdetailsitem.tsx index 3a02aefd87..cf7d80ed88 100644 --- a/libs/remix-ui/git/src/components/panels/commits/commitdetailsitem.tsx +++ b/libs/remix-ui/git/src/components/panels/commits/commitdetailsitem.tsx @@ -1,4 +1,4 @@ -import { branch, commitChange } from "../../../types"; +import { branch, commitChange } from "@remix-api"; import React from "react"; import path from "path"; import { gitActionsContext, pluginActionsContext } from "../../../state/context"; diff --git a/libs/remix-ui/git/src/components/panels/remoteselect.tsx b/libs/remix-ui/git/src/components/panels/remoteselect.tsx index 8b2f6d526c..1111a84172 100644 --- a/libs/remix-ui/git/src/components/panels/remoteselect.tsx +++ b/libs/remix-ui/git/src/components/panels/remoteselect.tsx @@ -4,11 +4,12 @@ import { gitPluginContext } from "../gitui"; import { default as dateFormat } from "dateformat"; import { RemotesDetailsNavigation } from "../navigation/remotesdetails"; import { Accordion } from "react-bootstrap"; -import { branch, remote } from "../../types"; +import { remote } from "@remix-api"; import { RemoteBranchDetails } from "./branches/remotebranchedetails"; import GitUIButton from "../buttons/gituibutton"; import { FontAwesomeIcon } from "@fortawesome/react-fontawesome"; import { faSync } from "@fortawesome/free-solid-svg-icons"; +import { branch } from "@remix-api"; export interface RemoteSelectProps { remote: remote diff --git a/libs/remix-ui/git/src/components/panels/remotesimport.tsx b/libs/remix-ui/git/src/components/panels/remotesimport.tsx index 47c714f186..fc1a423de3 100644 --- a/libs/remix-ui/git/src/components/panels/remotesimport.tsx +++ b/libs/remix-ui/git/src/components/panels/remotesimport.tsx @@ -1,8 +1,8 @@ -import React, { useEffect, useState } from "react" -import { Alert, Button } from "react-bootstrap" -import { gitActionsContext } from "../../state/context" -import { repository } from "../../types" -import { gitPluginContext } from "../gitui" +import React, { useEffect, useState } from "react"; +import { Alert, Button } from "react-bootstrap"; +import { gitActionsContext } from "../../state/context"; +import { repository } from "@remix-api"; +import { gitPluginContext } from "../gitui"; import Select from 'react-select' import { selectStyles, selectTheme } from "../../types/styles" import { TokenWarning } from "./tokenWarning" diff --git a/libs/remix-ui/git/src/components/panels/sourcecontrol/sourcecontrolitem.tsx b/libs/remix-ui/git/src/components/panels/sourcecontrol/sourcecontrolitem.tsx index a28d2a6664..0a96f7b728 100644 --- a/libs/remix-ui/git/src/components/panels/sourcecontrol/sourcecontrolitem.tsx +++ b/libs/remix-ui/git/src/components/panels/sourcecontrol/sourcecontrolitem.tsx @@ -1,4 +1,4 @@ -import { commitChange, fileStatusResult, sourceControlGroup } from "../../../types"; +import { fileStatusResult, sourceControlGroup } from "../../../types"; import React from "react"; import path from "path"; import { gitActionsContext, pluginActionsContext } from "../../../state/context"; @@ -6,6 +6,7 @@ import { FontAwesomeIcon } from "@fortawesome/react-fontawesome"; import { faGlobe } from "@fortawesome/free-solid-svg-icons"; import { SourceControlItemButtons } from "./sourcontrolitembuttons"; import { removeSlash } from "../../../utils"; +import { commitChange } from "@remix-api"; export interface SourceControlItemProps { file: fileStatusResult; diff --git a/libs/remix-ui/git/src/components/panels/sourcecontrol/sourcontrolitembuttons.tsx b/libs/remix-ui/git/src/components/panels/sourcecontrol/sourcontrolitembuttons.tsx index d1ba05ef1f..572180329c 100644 --- a/libs/remix-ui/git/src/components/panels/sourcecontrol/sourcontrolitembuttons.tsx +++ b/libs/remix-ui/git/src/components/panels/sourcecontrol/sourcontrolitembuttons.tsx @@ -1,4 +1,4 @@ -import { commitChange, fileStatusResult, sourceControlGroup } from "../../../types"; +import { fileStatusResult, sourceControlGroup } from "../../../types"; import React from "react"; import path from "path"; import { gitActionsContext, pluginActionsContext } from "../../../state/context"; diff --git a/libs/remix-ui/git/src/components/panels/version.tsx b/libs/remix-ui/git/src/components/panels/version.tsx new file mode 100644 index 0000000000..ccfef84ac9 --- /dev/null +++ b/libs/remix-ui/git/src/components/panels/version.tsx @@ -0,0 +1,10 @@ +import React, { useEffect, useState } from 'react' +import { gitPluginContext } from '../gitui' +export const Version = () => { + const context = React.useContext(gitPluginContext) + return ( +
+

{context.version.includes('version') ? context.version : `Git version: ${context.version}` }

+
+ ) +} \ No newline at end of file diff --git a/libs/remix-ui/git/src/index.ts b/libs/remix-ui/git/src/index.ts index 677c174059..57959fe7e1 100644 --- a/libs/remix-ui/git/src/index.ts +++ b/libs/remix-ui/git/src/index.ts @@ -1,4 +1,4 @@ export * from './types' export { GitUI } from './components/gitui' -export { commitChange, commitChangeType, remote, branch } from './types' +export { commitChange, commitChangeType, remote, branch } from '@remix-api' export * from './types/styles' \ No newline at end of file diff --git a/libs/remix-ui/git/src/lib/gitactions.ts b/libs/remix-ui/git/src/lib/gitactions.ts index a94273badd..f7e549de2c 100644 --- a/libs/remix-ui/git/src/lib/gitactions.ts +++ b/libs/remix-ui/git/src/lib/gitactions.ts @@ -1,14 +1,13 @@ import { ReadBlobResult, ReadCommitResult } from "isomorphic-git"; import React from "react"; -import { fileStatus, fileStatusMerge, setRemoteBranchCommits, resetRemoteBranchCommits, setBranches, setCanCommit, setCommitChanges, setCommits, setCurrentBranch, setGitHubUser, setLoading, setRemoteBranches, setRemotes, setRepos, setUpstream, setLocalBranchCommits, setBranchDifferences, setRemoteAsDefault, setScopes, setLog, clearLog, setUserEmails, setCurrenHead, setStoragePayload, resetBranchDifferences, setGitLogCount, setTimestamp } from "../state/gitpayload"; -import { GitHubUser, branch, commitChange, gitActionDispatch, statusMatrixType, gitState, branchDifference, remote, gitLog, fileStatusResult, customGitApi, IGitApi, cloneInputType, fetchInputType, pullInputType, pushInputType, checkoutInput, rmInput, addInput, repository, userEmails, storage, gitMatomoEventTypes } from '../types'; +import { fileStatus, fileStatusMerge, setRemoteBranchCommits, resetRemoteBranchCommits, setBranches, setCanCommit, setCommitChanges, setCommits, setCurrentBranch, setGitHubUser, setLoading, setRemoteBranches, setRemotes, setRepos, setUpstream, setLocalBranchCommits, setBranchDifferences, setRemoteAsDefault, setScopes, setLog, clearLog, setUserEmails, setCurrenHead, setStoragePayload, resetBranchDifferences, setTimestamp, setGitLogCount } from "../state/gitpayload"; +import { gitActionDispatch, statusMatrixType, gitState, gitLog, fileStatusResult, storage, gitMatomoEventTypes } from '../types'; import { removeSlash } from "../utils"; import { disableCallBacks, enableCallBacks } from "./listeners"; import { ModalTypes, appActionTypes, AppAction } from "@remix-ui/app"; import { sendToMatomo, setFileDecorators } from "./pluginActions"; import { Plugin } from "@remixproject/engine"; -import { CustomRemixApi } from "@remix-api"; -import { app } from "electron"; +import { addInputType, branch, branchDifference, checkoutInputType, cloneInputType, commitChange, CustomRemixApi, fetchInputType, GitHubUser, pullInputType, pushInputType, remote, rmInputType, userEmails } from "@remix-api"; export const fileStatuses = [ ["new,untracked", 0, 2, 0], // new, untracked @@ -21,7 +20,7 @@ export const fileStatuses = [ ["deleted,unstaged", 1, 0, 1], // deleted, unstaged ["deleted,staged", 1, 0, 0], ["unmodified", 1, 1, 3], - ["deleted,not in git", 0, 0, 3], + ["added,deleted", 0, 0, 3], ["unstaged,modified", 1, 2, 0] ]; @@ -49,13 +48,14 @@ export const init = async () => { export const getBranches = async () => { - const branches = await plugin.call('dgitApi', "branches") + const branches = await plugin.call('dgitApi', 'branches') dispatch(setBranches(branches)); + await showCurrentBranch(); } export const getRemotes = async () => { - const remotes: remote[] = await plugin.call('dgitApi', "remotes"); + const remotes: remote[] = await plugin.call('dgitApi', 'remotes'); dispatch(setRemotes(remotes)); } @@ -65,6 +65,7 @@ export const setUpstreamRemote = async (remote: remote) => { } export const getFileStatusMatrix = async (filepaths: string[]) => { + dispatch(setLoading(true)) const fileStatusResult = await statusMatrix(filepaths); fileStatusResult.map((m) => { @@ -80,6 +81,7 @@ export const getFileStatusMatrix = async (filepaths: string[]) => { dispatch(fileStatusMerge(fileStatusResult)) setFileDecorators(fileStatusResult) } + dispatch(setLoading(false)) } @@ -108,6 +110,7 @@ export const gitlog = async (depth: number) => { dispatch(setCommits(commits)) await showCurrentBranch() dispatch(setLoading(false)) + } export const setStateGitLogCount = async (count: number) => { @@ -234,7 +237,7 @@ export const addall = async (files: fileStatusResult[]) => { } } -export const add = async (filepath: addInput) => { +export const add = async (filepath: addInputType) => { await sendToMatomo(gitMatomoEventTypes.ADD) try { if (typeof filepath.filepath === "string") { @@ -261,7 +264,7 @@ const getLastCommmit = async () => { } } -export const rm = async (args: rmInput) => { +export const rm = async (args: rmInputType) => { await sendToMatomo(gitMatomoEventTypes.RM) await plugin.call('dgitApi', 'rm', { filepath: removeSlash(args.filepath), @@ -298,7 +301,7 @@ export const checkoutfile = async (filename: string) => { } } -export const checkout = async (cmd: checkoutInput) => { +export const checkout = async (cmd: checkoutInputType) => { sendToMatomo(gitMatomoEventTypes.CHECKOUT) await disableCallBacks(); await plugin.call('fileManager', 'closeAllFiles') @@ -530,6 +533,7 @@ export const remoteBranches = async (owner: string, repo: string) => { } export const remoteCommits = async (url: string, branch: string, length: number) => { + const urlParts = url.split("/"); // check if it's github @@ -676,7 +680,9 @@ export const loadGitHubUserFromToken = async () => { } export const statusMatrix = async (filepaths: string[]) => { + const matrix = await plugin.call('dgitApi', 'status', { ref: "HEAD", filepaths: filepaths || ['.']}); + const result = (matrix || []).map((x) => { return { filename: `/${x.shift()}`, @@ -739,6 +745,7 @@ export const diff = async (commitChange: commitChange) => { } export const getCommitChanges = async (oid1: string, oid2: string, branch?: branch, remote?: remote) => { + try { let log try { @@ -751,6 +758,7 @@ export const getCommitChanges = async (oid1: string, oid2: string, branch?: bran console.log(e, 'log error') } if (log) { + const foundCommit = log.find((commit: ReadCommitResult) => commit.oid === oid2) if (!foundCommit && remote) { @@ -787,6 +795,7 @@ async function getRepoDetails(url: string) { } export const fetchBranch = async (branch: branch, page: number) => { + if (!branch.remote || !branch.remote.url) return const token = await tokenWarning(); if (page == 1) { @@ -806,6 +815,7 @@ export const fetchBranch = async (branch: branch, page: number) => { } export const getBranchDifferences = async (branch: branch, remote: remote, state: gitState) => { + if (!remote && state) { if (state.defaultRemote) { remote = state.defaultRemote diff --git a/libs/remix-ui/git/src/lib/listeners.ts b/libs/remix-ui/git/src/lib/listeners.ts index 902a6b5c81..42f450c058 100644 --- a/libs/remix-ui/git/src/lib/listeners.ts +++ b/libs/remix-ui/git/src/lib/listeners.ts @@ -1,12 +1,13 @@ import React from "react"; -import { setCanUseApp, setLoading, setRepoName, setGItHubToken, setLog, setGitHubUser, setUserEmails, setTimestamp } from "../state/gitpayload"; +import { setCanUseApp, setLoading, setRepoName, setGItHubToken, setLog, setGitHubUser, setUserEmails, setTimestamp, setDesktopWorkingDir, setVersion } from "../state/gitpayload"; import { gitActionDispatch, gitUIPanels, storage } from "../types"; import { Plugin } from "@remixproject/engine"; import { getBranches, getFileStatusMatrix, loadGitHubUserFromToken, getRemotes, gitlog, setPlugin, setStorage } from "./gitactions"; import { Profile } from "@remixproject/plugin-utils"; import { CustomRemixApi } from "@remix-api"; import { statusChanged } from "./pluginActions"; +import { appPlatformTypes } from "@remix-ui/app"; import { AppAction } from "@remix-ui/app"; let plugin: Plugin, gitDispatch: React.Dispatch, loaderDispatch: React.Dispatch, loadFileQueue: AsyncDebouncedQueue @@ -35,7 +36,7 @@ class AsyncDebouncedQueue { } } -export const setCallBacks = (viewPlugin: Plugin, gitDispatcher: React.Dispatch, appDispatcher: React.Dispatch, loaderDispatcher: React.Dispatch, setAtivePanel: React.Dispatch>) => { +export const setCallBacks = (viewPlugin: Plugin, gitDispatcher: React.Dispatch, appDispatcher: React.Dispatch, loaderDispatcher: React.Dispatch, setAtivePanel: React.Dispatch>, platform: appPlatformTypes) => { plugin = viewPlugin gitDispatch = gitDispatcher loaderDispatch = loaderDispatcher @@ -67,8 +68,39 @@ export const setCallBacks = (viewPlugin: Plugin, gitDispatcher: React.Dispatch { + + gitDispatcher(setDesktopWorkingDir(path)) + gitDispatch(setCanUseApp(path ? true : false)) + const version = await plugin.call('dgitApi', 'version') + + gitDispatch(setVersion(version)) + loadFileQueue.enqueue(async () => { + loadFiles() + }) + loadFileQueue.enqueue(async () => { + gitDispatch(setTimestamp(Date.now())) + }) + loadFileQueue.enqueue(async () => { + getBranches() + }) + loadFileQueue.enqueue(async () => { + getRemotes() + }) + }) + plugin.on("filePanel", "setWorkspace", async (x: any) => { - gitDispatch(setCanUseApp(x && !x.isLocalhost && x.name)) + + if (platform == appPlatformTypes.desktop) { + const workingDir = await plugin.call('fs', 'getWorkingDir') + gitDispatch(setCanUseApp(workingDir? true : false)) + const version = await plugin.call('dgitApi', 'version') + + gitDispatch(setVersion(version)) + } else { + gitDispatch(setCanUseApp(x && !x.isLocalhost && x.name)) + } + loadFileQueue.enqueue(async () => { loadFiles() }) @@ -111,6 +143,10 @@ export const setCallBacks = (viewPlugin: Plugin, gitDispatcher: React.Dispatch { + + loadFileQueue.enqueue(async () => { + loadFiles() + }, 10) loadFileQueue.enqueue(async () => { gitDispatch(setTimestamp(Date.now())) }, 10) diff --git a/libs/remix-ui/git/src/lib/pluginActions.ts b/libs/remix-ui/git/src/lib/pluginActions.ts index 7d9e81ee7a..d1c7a8854a 100644 --- a/libs/remix-ui/git/src/lib/pluginActions.ts +++ b/libs/remix-ui/git/src/lib/pluginActions.ts @@ -1,9 +1,10 @@ -import { commitChange, fileStatusResult, gitActionDispatch, gitMatomoEventTypes, gitState } from "../types" +import { fileStatusResult, gitActionDispatch, gitState } from "../types" +import { gitMatomoEventTypes } from "../types" import { fileDecoration, fileDecorationType } from "@remix-ui/file-decorators" import { removeSlash } from "../utils" import { getFilesByStatus } from "./fileHelpers" -import { CustomRemixApi } from "@remix-api"; +import { commitChange, CustomRemixApi } from "@remix-api"; import { Plugin } from "@remixproject/engine"; let plugin: Plugin, gitDispatch: React.Dispatch, loaderDispatch: React.Dispatch @@ -98,6 +99,13 @@ export const clearFileDecorator = async(path: string) => { await plugin.call('fileDecorator', 'clearFileDecorators', path) } +export const openFolderInSameWindow = async (path: string) => { + await plugin.call('fs', 'openFolderInSameWindow', path) +} + +export const openCloneDialog = async () => { + plugin.call('filePanel', 'clone') +} export const sendToMatomo = async (event: gitMatomoEventTypes, args?: string[]) => { const trackArgs = args ? ['trackEvent', 'git', event, ...args] : ['trackEvent', 'git', event]; plugin && await plugin.call('matomo', 'track', trackArgs); diff --git a/libs/remix-ui/git/src/state/actions.ts b/libs/remix-ui/git/src/state/actions.ts index 821c049cd0..4cd9de59e0 100644 --- a/libs/remix-ui/git/src/state/actions.ts +++ b/libs/remix-ui/git/src/state/actions.ts @@ -1,5 +1,7 @@ import { ReadCommitResult } from "isomorphic-git" -import { branch, branchDifference, commitChange, fileStatusResult, GitHubUser, gitLog, pagedCommits, remote, remoteBranch, repository, storage, userEmails } from "../types" +import { fileStatusResult, gitLog } from "../types" +import { GitHubUser, branch, branchDifference, commitChange, pagedCommits, remote, remoteBranch, repository, userEmails } from '@remix-api' +import { storage } from "../types" export interface ActionPayloadTypes { FILE_STATUS: fileStatusResult[], @@ -43,6 +45,8 @@ export interface ActionPayloadTypes { SET_LOG: gitLog CLEAR_LOG: void SET_USER_EMAILS: userEmails + DESKTOP_SET_WORKING_DIR: string + SET_VERSION: string SET_STORAGE: storage SET_TIMESTAMP: number SET_GIT_LOG_COUNT: number diff --git a/libs/remix-ui/git/src/state/context.tsx b/libs/remix-ui/git/src/state/context.tsx index e403201dde..ff59a40d91 100644 --- a/libs/remix-ui/git/src/state/context.tsx +++ b/libs/remix-ui/git/src/state/context.tsx @@ -1,12 +1,13 @@ +import { branch, addInputType, checkoutInputType, cloneInputType, commitChange, fetchInputType, pullInputType, pushInputType, remote, rmInputType } from "@remix-api" import { ReadCommitResult } from "isomorphic-git" import React from "react" -import { addInput, branch, checkoutInput, cloneInputType, commitChange, fetchInputType, fileStatusResult, gitLog, gitState, pullInputType, pushInputType, remote, rmInput } from "../types" +import { fileStatusResult, gitLog, gitState } from "../types" export interface gitActions { removeRemote(remote: remote): void clone(input: cloneInputType): Promise - add(input: addInput): Promise - rm(input: rmInput): Promise + add(input: addInputType): Promise + rm(input: rmInputType): Promise commit(message: string): Promise addall(files: fileStatusResult[]): Promise push(input: pushInputType): Promise @@ -14,7 +15,7 @@ export interface gitActions { fetch(input: fetchInputType): Promise repositories(): Promise checkoutfile(file: string): Promise - checkout(input: checkoutInput): Promise + checkout(input: checkoutInputType): Promise createBranch(branch: string): Promise remoteBranches(owner: string, repo: string): Promise getCommitChanges(oid1: string, oid2: string, branch?: branch, remote?: remote): Promise @@ -55,6 +56,7 @@ export interface pluginActions { token: string }> showAlert({ title, message }:{title: string, message: string}): Promise + openFolderInSameWindow(path: string): Promise } export const pluginActionsContext = React.createContext(null) \ No newline at end of file diff --git a/libs/remix-ui/git/src/state/gitpayload.ts b/libs/remix-ui/git/src/state/gitpayload.ts index cf6063ffc3..36fc1f837d 100644 --- a/libs/remix-ui/git/src/state/gitpayload.ts +++ b/libs/remix-ui/git/src/state/gitpayload.ts @@ -1,5 +1,7 @@ import { ReadCommitResult } from "isomorphic-git" -import { GitHubUser, branch, commitChange, fileStatusResult, remote, pagedCommits, branchDifference, gitLog, repository, userEmails, storage } from "../types" +import { fileStatusResult, gitLog } from "../types" +import { repository, pagedCommits, branch, remote, commitChange, branchDifference, GitHubUser, userEmails } from "@remix-api" +import { storage } from "../types" import { Endpoints } from "@octokit/types" export const fileStatus = (files: fileStatusResult[]) => { @@ -225,6 +227,19 @@ export const clearLog = () => { } } +export const setDesktopWorkingDir = (dir: string) => { + return { + type: 'DESKTOP_SET_WORKING_DIR', + payload: dir + } +} + +export const setVersion = (version: string) => { + return { + type: 'SET_VERSION', + payload: version + } +} export const setStoragePayload = (storage: storage) => { return { type: 'SET_STORAGE', diff --git a/libs/remix-ui/git/src/state/gitreducer.tsx b/libs/remix-ui/git/src/state/gitreducer.tsx index a44fc91b39..65ab5e57a8 100644 --- a/libs/remix-ui/git/src/state/gitreducer.tsx +++ b/libs/remix-ui/git/src/state/gitreducer.tsx @@ -1,6 +1,6 @@ -import { ReadCommitResult } from "isomorphic-git" -import { allChangedButNotStagedFiles, getFilesByStatus, getFilesWithNotModifiedStatus } from "../lib/fileHelpers" -import { branch, commitChange, defaultGitState, fileStatusResult, gitState, setRemoteBranchCommitsAction, setLocalBranchCommitsAction, setBranchDifferencesAction, setDefaultRemoteAction, setRemotesAction, setUpstreamAction } from "../types" +import { commitChange } from "@remix-api" +import { allChangedButNotStagedFiles, getFilesByStatus } from "../lib/fileHelpers" +import { defaultGitState, fileStatusResult, gitState } from "../types" import { Actions } from "./actions" export const gitReducer = (state: gitState = defaultGitState, action: Actions): gitState => { @@ -210,6 +210,17 @@ export const gitReducer = (state: gitState = defaultGitState, action: Actions): log: [] } + case 'DESKTOP_SET_WORKING_DIR': + return { + ...state, + desktopWorkingDir: action.payload + } + + case 'SET_VERSION': + return { + ...state, + version: action.payload + } case 'SET_STORAGE': return { ...state, diff --git a/libs/remix-ui/git/src/types/index.ts b/libs/remix-ui/git/src/types/index.ts index 9e846782ad..f87ee222f8 100644 --- a/libs/remix-ui/git/src/types/index.ts +++ b/libs/remix-ui/git/src/types/index.ts @@ -1,165 +1,12 @@ import { Endpoints } from "@octokit/types" -import { IRemixApi } from "@remixproject/plugin-api" -import { LibraryProfile, StatusEvents } from "@remixproject/plugin-utils" -import { CommitObject, ReadBlobResult, ReadCommitResult, StatusRow } from "isomorphic-git" -import { CustomRemixApi } from "@remix-api"; +import { GitHubUser, branch, branchDifference, commitChange, pagedCommits, remote, remoteBranch, repository, syncStatus, userEmails } from "@remix-api" +import { ReadCommitResult } from "isomorphic-git" import { Plugin } from "@remixproject/engine"; - -export type GitHubUser = Partial & { - isConnected: boolean -} - -export type userEmails = Endpoints["GET /user/emails"]["response"]["data"] +import { CustomRemixApi } from "@remix-api" export interface IGitUi { plugin: Plugin -} - -export interface IGitApi { - events: { - "checkout": () => void - "clone": () => void - "add": () => void - "rm": () => void - "commit": () => void - "branch": () => void - "init": () => void - } & StatusEvents, - methods: { - getCommitChanges(oid1: string, oid2: string): Promise - repositories(input: repositoriesInput): Promise - clone(input: cloneInputType): Promise - branches(input?: branchesInput): Promise, - remotes(): Promise, - log(cmd: { ref: string, depth?: number }): Promise, - remotecommits(input: remoteCommitsInputType): Promise - fetch(input: fetchInputType): Promise - pull(input: pullInputType): Promise - push(input: pushInputType): Promise - currentbranch(input?: currentBranchInput): Promise - branch(input: branchInputType): Promise - checkout(input: checkoutInput): Promise - add(input: addInput): Promise - rm(input: rmInput): Promise - resolveref(input: resolveRefInput): Promise - readblob(input: readBlobInput): Promise - commit(input: commitInput): Promise - addremote(input: remote): Promise - delremote(input: remote): Promise - status(input?: statusInput): Promise> - compareBranches(input: compareBranchesInput): Promise - init(input?: initInput): Promise - updateSubmodules: (input: updateSubmodulesInput) => Promise - } -} - -export type initInput = { - defaultBranch: string -} - -export type updateSubmodulesInput = { - dir?: string - token?: string -} - -export type remoteCommitsInputType = { - owner: string, repo: string, token: string, branch: string, length: number, page: number -} - -export type compareBranchesInput = { - branch: branch, remote: remote -} - -export type fetchInputType = { - remote: remote, - ref?: branch, - remoteRef?: branch, - depth?: number, - singleBranch?: boolean, - relative?: boolean, - quiet?: boolean -} - -export type pullInputType = { - remote: remote, ref: branch, remoteRef?: branch -} - -export type pushInputType = { - remote: remote, ref: branch, remoteRef?: branch, force?: boolean -} - -export type branchInputType = { - ref: string, - checkout?: boolean - refresh?: boolean - force?: boolean -} - -export type currentBranchInput = { - fs: any, - dir: string -} - -export type checkoutInput = { - ref: string, - force?: boolean, - remote?: string - refresh?: boolean - fetch?: boolean -} - -export type addInput = { - filepath: string | string[] -} - -export type rmInput = { - filepath: string -} - -export type resolveRefInput = { - ref: string -} - -export type readBlobInput = { - oid: string, - filepath: string -} - -export type commitInput = { - author: { - name: string, - email: string, - }, - message: string, -} - -export type branchesInput = { - fs?: any - dir?: string -} - -export interface cloneInputType { - url: string, - branch?: string, - depth?: number, - singleBranch?: boolean - workspaceName?: string - workspaceExists?: boolean - token?: string -} - -export interface repositoriesInput { token: string, page?: number, per_page?: number } - -export interface statusInput { ref: string, filepaths?: string[] } - -export const dGitProfile: LibraryProfile = { - name: 'dgitApi', - methods: ['clone', 'branches', 'remotes', 'getCommitChanges', 'log', 'remotecommits'], -} - -export interface customGitApi extends IRemixApi { - dgit: IGitApi -} + } export type gitState = { currentBranch: branch @@ -195,6 +42,8 @@ export type gitState = { gitHubScopes: string[] gitHubAccessToken: string log: gitLog[] + desktopWorkingDir?: string + version: string timestamp: number gitLogCount: number } @@ -205,19 +54,6 @@ export type gitLog = { export type remoteBranchIdentifier = `${string}/${string}` -export type branchDifference = { - uniqueHeadCommits: ReadCommitResult[], - uniqueRemoteCommits: ReadCommitResult[], -} - -export type pagedCommits = { - page: number, - perPage: number, - total: number, - hasNextPage: boolean, - commits: ReadCommitResult[] -} - export type loaderState = { branches: boolean remotes: boolean @@ -226,57 +62,6 @@ export type loaderState = { plugin: boolean } -export type commitChangeTypes = { - "deleted": "D" - "modified": "M" - "added": "A", - "unknown": "?" -} - -export enum syncStatus { - "sync" = "sync", - "publishBranch" = "publishBranch", - "none" = "none", -} - -export type commitChangeType = keyof commitChangeTypes - -export type commitChange = { - type: commitChangeType - path: string, - hashModified: string, - hashOriginal: string, - original?: string, - modified?: string, - readonly?: boolean -} - -export type repository = { - name: string - html_url: string - owner: { - login: string - }, - full_name: string - default_branch: string - id: number - url: string -} - -export type branch = { - name: string - remote: remote -} - -export type remote = { - name: string - url: string -} - -export type remoteBranch = { - name: string -} - export const defaultGitState: gitState = { currentBranch: { name: "", remote: { name: "", url: "" } }, currentHead: "", @@ -292,7 +77,7 @@ export const defaultGitState: gitState = { deleted: [], modified: [], allchangesnotstaged: [], - canUseApp: true, + canUseApp: false, loading: false, storage: { used: 0, @@ -317,6 +102,8 @@ export const defaultGitState: gitState = { gitHubScopes: [], gitHubAccessToken: "", log: [], + desktopWorkingDir: null, + version: "", timestamp: 0, gitLogCount: 22 } @@ -508,9 +295,14 @@ export interface clearLogAction { type: string } +export interface setDesktopWorkingDirAction { + type: string, + payload: string +} + export interface setTimeStampAction { type: string, payload: number } -export type gitActionDispatch = setTimeStampAction | setCurrentHeadAction | clearLogAction | setLogAction | setDefaultRemoteAction | setTokenAction | setUpstreamAction | setRemoteBranchCommitsAction | setLocalBranchCommitsAction | setBranchDifferencesAction | setRemotesAction | setCurrentBranchAction | fileStatusAction | setLoadingAction | setCanUseAppAction | setRepoNameAction | setCommitsAction | setBranchesAction | setReposAction | setRemoteBranchesAction +export type gitActionDispatch = setTimeStampAction |setDesktopWorkingDirAction | setCurrentHeadAction | clearLogAction | setLogAction | setDefaultRemoteAction | setTokenAction | setUpstreamAction | setRemoteBranchCommitsAction | setLocalBranchCommitsAction | setBranchDifferencesAction | setRemotesAction | setCurrentBranchAction | fileStatusAction | setLoadingAction | setCanUseAppAction | setRepoNameAction | setCommitsAction | setBranchesAction | setReposAction | setRemoteBranchesAction diff --git a/libs/remix-ui/home-tab/src/lib/components/homeTabFeatured.tsx b/libs/remix-ui/home-tab/src/lib/components/homeTabFeatured.tsx index 0db352120b..30d99e2e8d 100644 --- a/libs/remix-ui/home-tab/src/lib/components/homeTabFeatured.tsx +++ b/libs/remix-ui/home-tab/src/lib/components/homeTabFeatured.tsx @@ -92,7 +92,7 @@ function HomeTabFeatured(props:HomeTabFeaturedProps) {
- +
@@ -116,7 +116,7 @@ function HomeTabFeatured(props:HomeTabFeaturedProps) {
- +
diff --git a/libs/remix-ui/home-tab/src/lib/components/homeTabFileElectron.tsx b/libs/remix-ui/home-tab/src/lib/components/homeTabFileElectron.tsx index 1f67cfaff5..3d9fdd3c8f 100644 --- a/libs/remix-ui/home-tab/src/lib/components/homeTabFileElectron.tsx +++ b/libs/remix-ui/home-tab/src/lib/components/homeTabFileElectron.tsx @@ -32,9 +32,9 @@ export const HomeTabFileElectron = ({ plugin }: HomeTabFileProps) => {
- - - + + +
) diff --git a/libs/remix-ui/home-tab/src/lib/components/homeTabScamAlert.tsx b/libs/remix-ui/home-tab/src/lib/components/homeTabScamAlert.tsx index 0be9a99efc..14d507eb11 100644 --- a/libs/remix-ui/home-tab/src/lib/components/homeTabScamAlert.tsx +++ b/libs/remix-ui/home-tab/src/lib/components/homeTabScamAlert.tsx @@ -1,10 +1,12 @@ /* eslint-disable @typescript-eslint/no-unused-vars */ -import React from 'react' +import { appPlatformTypes, platformContext } from '@remix-ui/app' +import React, { useContext } from 'react' import { FormattedMessage } from 'react-intl' const _paq = (window._paq = window._paq || []) // eslint-disable-line function HomeTabScamAlert() { + const platform = useContext(platformContext) return (