From 14314cbab3f8fefe1a188655ef7c449c7f9e6a70 Mon Sep 17 00:00:00 2001 From: 3alpha <15694175+3alpha@users.noreply.github.com> Date: Wed, 4 Nov 2026 22:19:36 +0100 Subject: [PATCH 01/15] Modernise toolchain and dependencies Upgrade maintained packages (got 14, octokit 22, ethers 6.17, image-size 2, inquirer 12, form-data 4, tar-fs 3, dotenv 16) and drop unused or deprecated ones (@dappnode/toolkit, dockerode, graphql, request, rimraf), clearing the known lockfile advisories. - Replace the toolkit APM client with a minimal local ApmRepository. - ESLint 10 flat config with typescript-eslint 8; lint no longer rewrites files. - Mocha 12 with tsx; live Docker/IPFS/Ethereum tests move to test:integration and run in a separate, non-blocking CI job. - Frozen installs in CI and a Node 20/22/24/26 test matrix. - Narrow js-yaml 4's unknown parse results in the compose, manifest and core-manifest readers. - Stream IPFS uploads from URLs through got instead of request. - Shared test fixtures. --- .eslintrc | 9 - .github/workflows/main.yml | 20 +- .github/workflows/release.yml | 2 +- .github/workflows/test-ga-build.yml | 2 +- .../test-ga-bump-upstream-template.yml | 2 +- .github/workflows/test-ga-bump-upstream.yml | 2 +- .mocharc.yml | 13 +- README.md | 12 +- eslint.config.js | 14 + package.json | 65 +- src/assets/defaultAvatar.ts | 1 - src/dappnodesdk.ts | 5 +- src/files/compose/readCompose.ts | 6 +- src/files/manifest/compactManifestIfCore.ts | 31 +- src/files/manifest/index.ts | 2 +- src/files/manifest/readManifest.ts | 34 +- src/files/notifications/index.ts | 2 +- src/files/setupWizard/index.ts | 2 +- src/providers/apm/ApmRepository.ts | 44 + src/providers/github/githubActions.ts | 1 - .../ipfsNode/addDirFromUrls.ts | 25 +- src/releaseUploader/utils/uploadTimeout.ts | 7 + .../getReleaseDirCreationTask.ts | 12 +- src/tasks/generatePublishTxs/index.ts | 42 +- src/tasks/generatePublishTxs/types.ts | 2 +- src/timestring.d.ts | 3 + src/utils/file.ts | 3 +- src/utils/getFileHash.ts | 2 +- src/utils/verifyAvatar.ts | 7 +- src/utils/versions/getNextVersionFromApm.ts | 2 +- test/commands/build.test.ts | 2 +- test/commands/init.test.ts | 22 +- test/helpers/fixtures.ts | 22 + test/providers/apm/ApmRepository.test.ts | 143 + test/tasks/generatePublishTx.test.ts | 8 +- test/testUtils.ts | 3 +- .../versions/getNextPackageVersion.test.ts | 25 +- tsconfig.json | 12 +- yarn.lock | 4760 ++++++----------- 39 files changed, 2188 insertions(+), 3183 deletions(-) delete mode 100644 .eslintrc create mode 100644 eslint.config.js create mode 100644 src/providers/apm/ApmRepository.ts create mode 100644 src/releaseUploader/utils/uploadTimeout.ts create mode 100644 src/timestring.d.ts create mode 100644 test/helpers/fixtures.ts create mode 100644 test/providers/apm/ApmRepository.test.ts diff --git a/.eslintrc b/.eslintrc deleted file mode 100644 index 9c43d31b..00000000 --- a/.eslintrc +++ /dev/null @@ -1,9 +0,0 @@ -{ - "root": true, - "parser": "@typescript-eslint/parser", - "plugins": ["@typescript-eslint"], - "extends": ["eslint:recommended", "plugin:@typescript-eslint/recommended"], - "rules": { - "@typescript-eslint/ban-ts-comment": "warn" - } -} diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml index 1badd084..02cdcb13 100644 --- a/.github/workflows/main.yml +++ b/.github/workflows/main.yml @@ -13,13 +13,29 @@ jobs: strategy: fail-fast: false # don't cancel all jobs if some of them failed matrix: - node: ["20"] + node: ["20", "22", "24", "26"] steps: - uses: actions/checkout@v4 - name: Setup node uses: actions/setup-node@v4 with: node-version: ${{ matrix.node }} - - run: yarn install + - run: yarn install --frozen-lockfile - run: yarn lint + - run: yarn build - run: yarn test + + # Live Docker / IPFS / Ethereum checks (previously part of `yarn test`). + # Kept visible but non-blocking, since they depend on external services. + integration: + runs-on: ubuntu-latest + continue-on-error: true + steps: + - uses: actions/checkout@v4 + - name: Setup node + uses: actions/setup-node@v4 + with: + node-version: "20" + - run: yarn install --frozen-lockfile + - run: yarn build + - run: yarn test:integration diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index 25b636ce..d54fecd7 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -24,7 +24,7 @@ jobs: registry-url: https://registry.npmjs.org/ - name: Install dependencies - run: yarn + run: yarn install --frozen-lockfile - name: Compare versions run: | diff --git a/.github/workflows/test-ga-build.yml b/.github/workflows/test-ga-build.yml index 8d29e144..e8dd0170 100644 --- a/.github/workflows/test-ga-build.yml +++ b/.github/workflows/test-ga-build.yml @@ -14,7 +14,7 @@ jobs: uses: actions/setup-node@v4 with: node-version: 20.x - - run: yarn install + - run: yarn install --frozen-lockfile - run: yarn build # Simulate Github Actions run on an actual DAppNode package diff --git a/.github/workflows/test-ga-bump-upstream-template.yml b/.github/workflows/test-ga-bump-upstream-template.yml index a10a8bb5..b41d66d0 100644 --- a/.github/workflows/test-ga-bump-upstream-template.yml +++ b/.github/workflows/test-ga-bump-upstream-template.yml @@ -18,7 +18,7 @@ jobs: uses: actions/setup-node@v4 with: node-version: 20.x - - run: yarn install + - run: yarn install --frozen-lockfile - run: yarn build # Simulate Github Actions run on an actual DAppNode package diff --git a/.github/workflows/test-ga-bump-upstream.yml b/.github/workflows/test-ga-bump-upstream.yml index 8b9f4276..69b9c4ea 100644 --- a/.github/workflows/test-ga-bump-upstream.yml +++ b/.github/workflows/test-ga-bump-upstream.yml @@ -18,7 +18,7 @@ jobs: uses: actions/setup-node@v4 with: node-version: 20.x - - run: yarn install + - run: yarn install --frozen-lockfile - run: yarn build # Simulate Github Actions run on an actual DAppNode package diff --git a/.mocharc.yml b/.mocharc.yml index cf151954..802d94c7 100644 --- a/.mocharc.yml +++ b/.mocharc.yml @@ -1,9 +1,12 @@ colors: true -exit: true extension: [ts] +import: + - tsx require: - dotenv/config - - ts-node/register -node-option: - - experimental-specifier-resolution=node - - loader=ts-node/esm +spec: + - test/**/*.test.ts +ignore: + - test/commands/build.test.ts + - test/tasks/generatePublishTx.test.ts + - test/utils/versions/getNextPackageVersion.test.ts diff --git a/README.md b/README.md index 23d58fec..2ac37d7a 100644 --- a/README.md +++ b/README.md @@ -126,11 +126,21 @@ services: The dappnode SDK ueses the following internal dependencies to avoid code duplication across the `dappnodeSDK`, `DNP_DAPPMANAGER` and `sdk-publish` modules: - `@dappnode/types` -- `@dappnode/toolkit` - `@dappnode/schemas` In order to have a better developing experience these modules lives inside the DNP_DAPPMANAGER repository +## Development + +Use Node.js 20.19+, Node.js 22.13+, or Node.js 24+ for development, and install the exact locked dependencies with `yarn install --frozen-lockfile`. + +- `yarn lint` checks source and tests without changing files; `yarn lint:fix` applies automatic fixes. +- `yarn build` checks and compiles the SDK. +- `yarn test` runs deterministic regressions using temporary files, mocked Docker commands, and localhost HTTP servers. It does not need external credentials. +- `yarn test:integration` runs the live Docker/IPFS/Ethereum tests and requires those services to be available. + +Terminal builds show numbered package/architecture stages and recent complete log lines; uploads display a separate waiting-for-pinning phase after transmission. + ## License This project is licensed under the GNU General Public License v3.0 - see the [LICENSE](LICENSE) file for details diff --git a/eslint.config.js b/eslint.config.js new file mode 100644 index 00000000..a15249af --- /dev/null +++ b/eslint.config.js @@ -0,0 +1,14 @@ +import js from "@eslint/js"; +import tseslint from "typescript-eslint"; + +export default tseslint.config( + { ignores: ["dist/**", "node_modules/**", "test_files/**"] }, + js.configs.recommended, + ...tseslint.configs.recommended, + { + files: ["**/*.ts"], + rules: { + "@typescript-eslint/no-unused-vars": ["error", { caughtErrors: "none" }] + } + } +); diff --git a/package.json b/package.json index 7c4bbbd1..69d8a245 100644 --- a/package.json +++ b/package.json @@ -8,11 +8,13 @@ "bin": "dist/dappnodesdk.js", "scripts": { "tag-and-publish": "npm version patch && git push --follow-tags", - "test": "mocha \"./{,!(node_modules)/**}/*.test.ts\"", - "lint": "eslint . --ext .ts --fix", - "build": "tsc", + "test": "mocha", + "lint": "eslint src test --max-warnings 0", + "build": "node -e \"require('node:fs').rmSync('dist', { recursive: true, force: true })\" && tsc", "prepublish": "npm run build", - "pre-commit": "npm run lint && npm run test" + "pre-commit": "npm run lint && npm run test", + "test:integration": "mocha --no-config --import=tsx --require=dotenv/config --timeout 120000 \"test/commands/build.test.ts\" \"test/tasks/generatePublishTx.test.ts\" \"test/utils/versions/getNextPackageVersion.test.ts\"", + "lint:fix": "npm run lint -- --fix" }, "repository": { "type": "git", @@ -35,63 +37,60 @@ "homepage": "https://github.com/dappnode/DAppNodeSDK#readme", "dependencies": { "@dappnode/schemas": "^0.1.26", - "@dappnode/toolkit": "^0.1.21", "@dappnode/types": "^0.1.41", - "@octokit/rest": "^20.1.1", + "@octokit/rest": "^22.0.1", "async-retry": "^1.2.3", "chalk": "^2.4.2", "cli-progress": "^3.8.2", - "dockerode": "^3.3.5", - "dotenv": "^8.2.0", - "ethers": "6.3.0", + "dotenv": "^16.6.1", + "ethers": "^6.17.0", "figlet": "^1.2.3", - "form-data": "^3.0.0", - "got": "^12.6.1", - "graphql": "^16.6.0", - "image-size": "^0.8.1", - "inquirer": "^6.2.1", - "js-yaml": "^4.1.0", + "form-data": "^4.0.6", + "got": "^14.6.6", + "image-size": "^2.0.4", + "inquirer": "^12.11.1", + "js-yaml": "^4.3.2", "listr": "^0.14.3", - "lodash-es": "^4.17.21", + "lodash-es": "^4.18.1", + "log-update": "^6.1.0", "mime-types": "^2.1.24", "moment": "^2.27.0", "prettier": "^2.1.2", - "request": "^2.88.2", - "rimraf": "^3.0.2", "semver": "^7.6.0", "source-map-support": "^0.5.19", - "tar-fs": "^2.0.0", + "tar-fs": "^3.1.3", "timestring": "^5.0.1", - "yargs": "^17.7.1" + "yargs": "^17.7.1", + "wrap-ansi": "^9.0.2" }, "devDependencies": { + "@eslint/js": "^10.0.1", "@types/async-retry": "^1.4.2", "@types/chai": "^4.3.4", "@types/cli-progress": "^3.7.0", - "@types/dockerode": "^3.3.16", "@types/figlet": "^1.2.0", - "@types/inquirer": "^6.5.0", - "@types/js-yaml": "^3.12.5", + "@types/js-yaml": "^4.0.9", "@types/listr": "^0.14.2", "@types/lodash-es": "^4.17.7", "@types/mime-types": "^2.1.0", "@types/mocha": "^10.0.1", - "@types/node": "^22.7.5", + "@types/node": "^20.19.0", "@types/prettier": "^2.1.5", - "@types/request": "^2.48.5", - "@types/rimraf": "^3.0.0", "@types/semver": "^7.3.1", "@types/tar-fs": "^2.0.0", "@types/yargs": "^17.0.24", - "@typescript-eslint/eslint-plugin": "^3.5.0", - "@typescript-eslint/parser": "^3.5.0", "chai": "^5.1.0", - "eslint": "^7.3.1", - "mocha": "^10.2.0", - "ts-node": "^10.9.1", - "typescript": "^5.6.3" + "eslint": "^10.14.0", + "mocha": "^12.0.3", + "tsx": "^4.23.15", + "typescript": "~5.9.3", + "typescript-eslint": "^8.72.1" }, "engines": { - "node": ">=20.0.0" + "node": ">=20.19.0" + }, + "resolutions": { + "minimatch": "^11.0.1", + "mocha/glob": "^14.0.2" } } diff --git a/src/assets/defaultAvatar.ts b/src/assets/defaultAvatar.ts index c88c2889..84026ee4 100644 --- a/src/assets/defaultAvatar.ts +++ b/src/assets/defaultAvatar.ts @@ -1,2 +1 @@ -/* eslint-disable max-len */ export default "iVBORw0KGgoAAAANSUhEUgAAAMgAAADICAMAAACahl6sAAAABGdBTUEAALGPC/xhBQAAAAFzUkdCAK7OHOkAAAFrUExURQAAAElJSXl5eQYGBjQ0NAAAAAwMDEdwTMnJyZaWliQkJCoqKhsbGxAQEBYWFi8vL/n5+Xd3d1hYWODg4MXFxWhoaDk5OT4+PktLS7u7u/n5+erq6m5ubra2tpqamkRERDQ0NL6+vvn5+XV1dWdnZ2BgYFFRUX9/fyoqKsPDw21tbX5+fmpqaqampn19fY2Njb29vY6OjqSkpF5eXubm5mFhYe/v79nZ2YiIiNnZ2WBgYKSkpISEhDQ0NIeHh5mZmczMzPv7+11dXZycnNnZ2dzc3KysrO/v71BQUJycnEdHR8LCwpycnH9/f4yMjPb29nV1dfz8/Do6Ore3t1NTU6qqqs3NzY+Pj93d3Xh4eMfHx9vb219fX2BgYHt7e1ZWVrm5ubGxsZWVla+vr4GBgby8vOnp6cvLy8zMzODg4LKysqOjo1BQUJ+fn/v7+0xMTFJSUm1tbWhoaOXl5a6urj4+Pru7u/Pz8z4+Pkng8hIAAAB5dFJOU00HSE1NSk0AAU1NTU1NTUwOBE0FAjVNTE1JFwgMSQdNKkggTU1NTSJLDUwVPAxNTRYRShgVQQsSHBwuFU1JMiE4HRBNKSFNNz5ESCsnLEckMS1FIkU/RT1CQDI6SB83ODo0NytGQS1BSzIbOSkuJyNJRSlFR0BMPTB3Aql1AAAK30lEQVR42u2dZ0PiTBeGwfBS0pAQQwQku9KW3hHQVUSxK9h773XV1d39+e+ELTYIE4qiz8xnmOTKzJw5U859FJoPUhQIBIEgEASCQBAIAkEgCASBIBAEgkAQCAJBIAgEgSAQBIJAEIi8YrTZCncb1zPrAYPx3YKwyYC1M+QiFaCoOfuPnDVpeH8gybhvesSrUjwqOKPbioXj7wnElncv23lS8aKoOUdoc978PkCGJzNjjF5RseCCt3h51OIg1p/n2wJBKqoUNW7yb637WhOENXiOZyYISq2AKzT59eZw3cCyrQRi9Fg3f3j1sAz/CkZe61Z8AUtrgJjDsfE/RrbC6+IEJUHD2XWx3jj7xiCDA7c6p0riNUnOuT192eEVcIkf4a6+jDsffysQ9mi66DBJjWyCsX8b6BZnwcL8ZpuXk/gppWK8t5ODrw8yn93yczgmYZmEYKe7t+fhH56wbzLESHGTesa/O/lqICyr/L6YUJGU1KhwRj9bA8nnf9V6rOHONpPEP9U0fr+8kmNZbZNBLLapkxmexCo2BUbjcwcr7spmlTX4vo8vEHRlE4dRnL1zV2kxNgvE1uOLRR2E5EzHJ/rXYOo63fHPqSS7GRNa8/W2Nx5kML3pD/LV5mzKnomF03A1Ro6KqwwnaZgd4wMD3Y0EGdy/tbv0GNQcR/COi8tZG5yLnHd39Lmk2pgUvL+mjsINATnd67jWk3ImbJrgx/rXh+GcAnNvLGoX1FK1CQtb2UIdIFqtNrWyek/QmEJ2AWNe8B+atVDGByzApkcYXNIxExKHU1qp6hQV16jK47uNL+oaIP7BqL9sRBeVNhhXSms0HH2+MZFUZXOIkRMzS1abhZUB0h6JZPt4qYmCpCFp1Cb7j81ID5RfqD0bXR4z4RW7GabAVN6ufl/Z2l6AGAZTZzqn1ACkOWa1mGEkvaenrhQTWk6lYaYF0HVmL6dvJKsmXcHFVDpQBYR1b3sFKZOoZ0KZqYJHo0nPu/ccJtieh3HM3vTwGQyLljWXqpZaFKicYxfD0i1CSLwazffNxMLmh34tOvAMdMOQ3MT27igL1TCWeGxZJ1k1OSIN8r+KnqxjZNPqsTx7YDJpdZ8EOdglFUWqFpZX5uEciaQ19iNYuWFCskEwNTlxsDRZcYcNGLjD8Q095CIXwyhTW1faZoRpGlD1eXShfNU6eSAUzo2d/4xUf2b3jt9FkLBjhmSG+nMeSFcKVM2/rFoGiBp3rRbXhqH9tsJpf4JRwRtm79Dm2aANaszkT4tjTtWTWQYeBA8tpuTuC1ivpi7sLnjDzAf9U7Bf6mxnRKgJhBIWPl2Oyt8VMJ+lFu0CbCdT6/mO4mlv1VpH18C+H17rGAFW5h7Wyjzxnjy57JATtmEwkvjq31mXMGCji2DGp+sa7MBm0aqbuxWlUWbTsEbl1FLbHKmGdczw65nvKZvxhQ8WXzqYIMv4fLqa5hHaNbSVC7TLbhrDynLChFOQMBhn7wpb29mHdp0eqbgk1dU4IQIvw6HbTJltsmEKux0OE/z8z+gysXQPGGmxoSAvYQJrBvltZex+97D8hrmavL1xmKANM+dsy4SkdvTrBimtZYWb4pr8nTRPOvVNBz3+FdV7Y70gpRGDT/gXs7JZtO0Rz2FQkL3X3TyQ0uYTPgGsjEGuMTPaIt+jG0Q9K8/Ggvym0XtHDq0e+XPm2vHqHEG+FgicOwsWKZOpcI/8w63R/g6XSibM44aEB5n5Jb1Me7RsdNq/zRfknj1rtWl3xk5BU+hdwf0vtYAsadKp5RBDQC7/nNv9p2l5Rnn/4pcL7lPRfPBgc35Q87UWkM/ipnU8ApZpcIZGjauut9ZzcBDK0T2/gMPNLOLi1NfjEV+nNhDt3x14sEzbIDAYQ6Om9Ym7XYPUfQ2jwbC/dDAH5bdgGMnPHFv+bY0l6wL53Z8HD1fBF8Tg+kHoJPbydKTkx3pyJ8AthqqGIrnE4s/I4+1FS90gpZIf3RvjCbjuoHdEp3zPjjjBNq+/D3I+pIX7juxwaadL03AQ0Zud3b9wQq4Aad5+6c7/WTIFCgPf+qq5T4/61OqR9TlFQ0HEEp93n3shPyzhWshMzs4OTyecnJw5gyqWPzBrKIg4YHtyi0NOSMNM8IwKl+mSUB2vAyKyWGzukwMTVb/T9MYgvw942ex44itJvXeQP8Zop0N+33mYeeSAJJsKIjobskfz36sRiXtMBki7qskgon3tFu0rDg/x2zoHPlEtBlIyzL29kCtAlWNkz1e6RfNJ3YIg4nAMWJdEx0zqnBR4MLnA3xunrQpSsmWGqZJXiJVxn+ZuDnef3O9oYZA/zgzw0/knLYNzzFb2xVbSK4B01gVS2prbZx5xXB6VW3e9CxCN5uDRzZLyv5AHon8rkLZHhkqJQBAIAkEgCASBIBAEgkAQSCNByK33DwJu2S6Mr1veNwhGErx/p7vM9vV7AqH1rrH+02GNxGPfAQju8l5MXVW76NLSIJgCE+x37jOYWLFWBsk4dZ05TxKuulYGMdiM8DFIrQwiq3wckC8fBCReE0hX64GYEQgCQSAIBIEgEASCQBAIAvnPgAwSHwSkG4EgEASCQBAIAkEgCASBIJD/DEjhg4BoZ/EPcj5S2woxqmk5kNOaWoSem1kBAevalgAx2nzfowtErfHsGAiTncx5jG8M0h7Jjb+IxJQdmE/xwd3UWfytQHrSqduyCmw1KQyIMrHVL1g0HiQ+edtWSb2jVqkEkmNAwHr+FUGudos3EnoqtWs+YGpS71qFDVivD0T5c9lfReGmTvEKNf1l427HYDM2C4Q1gnD3NlN1zaEqIHCR5nyfGLCubTiIxWOFVoGqArLtImD1C4amfPFGgph7e6F1uXAusSYNwgLJMtiAdUrwgpDIcCNAPIWBiyBkOCYtOPqnh59fjHopAarVhM/c0oKvjxuGv87sztYHcrVWhNauUzl1xZS5jKRMBVHW9lLAOuQXwoWx89FAjSADWVFNUAE5NKM5UWK+3OCsLJMLAtZjJ20TUHoVGCVKOfa8dMykQIAcx9L4Ak7DND2m1m90uqWUaqWFi4HC7vp4goMLWBcds/5n2uSVQIBeOVDcNEHVq6aJidXjfBXtYBgp6QIIWOcgJUD44Eis90EWrSyIJezbh9VAJfX89t5oddFAWHHvwvD0tgMyYJ1gQlsD+UogeSB9AatKq2cWLvav4N4QXm7dNggfsE5xzK/+o8iTyFCVVmObvcw4BWgxkuhmPgD9evIE8HsikZ2gANezSW7Cnw0++rzrywuwakF6MNp8PbK07uSmJNBaAkoQsI5DKgnRj8mgFDtE6euTXEXp64aBlGZ/lh1YWp3D6UZLiVCkKbE4y9aUJab2tB3a9b0ErJIQTOvh3PVWtvaESnUlUrHN7mfsPFE/BW5ybE8fndXzLnWntgEpUlbtdUkWqhw336BTKDQPBJRA3JfWOfBaIGhX35ov7GnASzQq/VPS2nvcJ8ga/mq9t2vHGmhQMrsGJuRiWStIkaKHEcYV063MrPgal8WqCSnSJrP+e06ym5GEK3G+1ujnNiNpnRKkU3JydPnuxHuBclgT0gk2J42gFiS4eil0C1zjDnc+3ZQnNjOxo5hyrO+f9LDKGz3zmZuX2bG5qTbB9s5ml4Mg+dB6JJBs6qOanvyUNRqyK0qbsdnPQVlcEQgCQSAIBIEgEASCQBAIAkEgCASBIBAEgkBgyv8BoCGh7uNnhxQAAAAASUVORK5CYII="; diff --git a/src/dappnodesdk.ts b/src/dappnodesdk.ts index 17c7645c..7699f01e 100755 --- a/src/dappnodesdk.ts +++ b/src/dappnodesdk.ts @@ -46,8 +46,9 @@ dappnodesdk.options({ alias: "debug", coerce: debug => { if (debug || process.env.DEBUG) { - // @ts-ignore - global.DEBUG_MODE = true; + ( + globalThis as typeof globalThis & { DEBUG_MODE?: boolean } + ).DEBUG_MODE = true; return true; } }, diff --git a/src/files/compose/readCompose.ts b/src/files/compose/readCompose.ts index 94611422..6294295a 100644 --- a/src/files/compose/readCompose.ts +++ b/src/files/compose/readCompose.ts @@ -24,7 +24,7 @@ export function readCompose(paths?: ComposePaths[]): Compose { return merge({}, ...composes); } catch (e) { - throw Error(`Error parsing docker-compose: ${e.message}`); + throw new Error(`Error parsing docker-compose: ${e.message}`, { cause: e }); } } @@ -37,8 +37,8 @@ function loadCompose(paths?: ComposePaths): Compose { const data = readFile(composePath); const compose = yaml.load(data); - if (!compose || typeof compose === "string") + if (!compose || typeof compose !== "object" || Array.isArray(compose)) throw new Error(`Could not parse compose file: ${composePath}`); - return compose; + return compose as Compose; } diff --git a/src/files/manifest/compactManifestIfCore.ts b/src/files/manifest/compactManifestIfCore.ts index d7993693..8e4fa5e2 100644 --- a/src/files/manifest/compactManifestIfCore.ts +++ b/src/files/manifest/compactManifestIfCore.ts @@ -1,7 +1,4 @@ -import fs from "fs"; -import path from "path"; -import yaml from "js-yaml"; -import { SetupWizard, releaseFiles } from "@dappnode/types"; +import { readSetupWizardIfExists } from "../setupWizard/readSetupWizardIfExists.js"; import { readManifest } from "./readManifest.js"; import { writeManifest } from "./writeManifest.js"; @@ -16,26 +13,14 @@ import { writeManifest } from "./writeManifest.js"; * @param buildDir `build_0.1.0` */ export function compactManifestIfCore(buildDir: string): void { - const { manifest, format } = readManifest([{ dir: buildDir }]); + const { manifest, format } = readManifest([{ dir: buildDir }]); - if (manifest.type !== "dncore") return; + if (manifest.type !== "dncore") return; - const setupWizard = readSetupWizardIfExists(buildDir); - if (setupWizard) { - manifest.setupWizard = setupWizard; - } + const setupWizard = readSetupWizardIfExists([{ dir: buildDir }]); + if (setupWizard) { + manifest.setupWizard = setupWizard; + } - writeManifest(manifest, format, { dir: buildDir }); + writeManifest(manifest, format, { dir: buildDir }); } - -// Utils - -function readSetupWizardIfExists(buildDir: string): SetupWizard | null { - const files = fs.readdirSync(buildDir); - const setupWizardFile = files.find(file => - releaseFiles.setupWizard.regex.test(file) - ); - if (!setupWizardFile) return null; - const setupWizardPath = path.join(buildDir, setupWizardFile); - return yaml.load(fs.readFileSync(setupWizardPath, "utf8")); -} \ No newline at end of file diff --git a/src/files/manifest/index.ts b/src/files/manifest/index.ts index 4afb6c06..d1ae474e 100644 --- a/src/files/manifest/index.ts +++ b/src/files/manifest/index.ts @@ -4,4 +4,4 @@ export { getRepoSlugFromManifest } from "./getRepoSlugFromManifest.js"; export { readManifest } from "./readManifest.js"; export { writeManifest } from "./writeManifest.js"; export { stringifyJson } from "./stringifyJson.js"; -export { ManifestFormat, ManifestPaths } from "./types.js"; +export { ManifestFormat, type ManifestPaths } from "./types.js"; diff --git a/src/files/manifest/readManifest.ts b/src/files/manifest/readManifest.ts index 8cfcf91f..0b18754a 100644 --- a/src/files/manifest/readManifest.ts +++ b/src/files/manifest/readManifest.ts @@ -19,9 +19,10 @@ import { merge } from "lodash-es"; * @throws {Error} - Throws an error if any manifest is not in JSON format, or if there is a * problem reading or parsing the manifests. */ -export function readManifest( - paths?: ManifestPaths[] -): { manifest: Manifest; format: ManifestFormat } { +export function readManifest(paths?: ManifestPaths[]): { + manifest: Manifest; + format: ManifestFormat; +} { try { if (!paths) return loadManifest(); // Load default manifest @@ -47,16 +48,17 @@ export function readManifest( manifest: mergedManifest }; } catch (e) { - throw new Error(`Error parsing manifest: ${e.message}`); + throw new Error(`Error parsing manifest: ${e.message}`, { cause: e }); } } /** * Loads a manifest from the specified path. */ -function loadManifest( - paths?: ManifestPaths -): { manifest: Manifest; format: ManifestFormat } { +function loadManifest(paths?: ManifestPaths): { + manifest: Manifest; + format: ManifestFormat; +} { const manifestPath = findManifestPath(paths); const format = parseFormat(manifestPath); const data = readFile(manifestPath); @@ -65,16 +67,22 @@ function loadManifest( try { parsedData = yaml.load(data); } catch (e) { - throw new Error(`Error parsing manifest at ${manifestPath}: ${e.message}`); + throw new Error(`Error parsing manifest at ${manifestPath}: ${e.message}`, { + cause: e + }); } - if (!parsedData) { + if ( + !parsedData || + typeof parsedData !== "object" || + Array.isArray(parsedData) + ) { throw new Error(`Manifest at ${manifestPath} is empty or invalid.`); } return { format, - manifest: parsedData + manifest: parsedData as Manifest }; } @@ -100,8 +108,8 @@ function findManifestPath(paths?: ManifestPaths): string { } function parseFormat(filepath: string): ManifestFormat { - if (/.json$/.test(filepath)) return ManifestFormat.json; - if (/.yml$/.test(filepath)) return ManifestFormat.yml; - if (/.yaml$/.test(filepath)) return ManifestFormat.yaml; + if (/\.json$/.test(filepath)) return ManifestFormat.json; + if (/\.yml$/.test(filepath)) return ManifestFormat.yml; + if (/\.yaml$/.test(filepath)) return ManifestFormat.yaml; throw Error(`Unsupported manifest format: ${filepath}`); } diff --git a/src/files/notifications/index.ts b/src/files/notifications/index.ts index fcc72343..0bb88ddf 100644 --- a/src/files/notifications/index.ts +++ b/src/files/notifications/index.ts @@ -1,2 +1,2 @@ export { readNotificationsIfExists } from "./readNotificationsIfExists.js"; -export { NotificationsFormat, NotificationsPaths } from "./types.js"; +export { NotificationsFormat, type NotificationsPaths } from "./types.js"; diff --git a/src/files/setupWizard/index.ts b/src/files/setupWizard/index.ts index 396c69e4..97cf59cc 100644 --- a/src/files/setupWizard/index.ts +++ b/src/files/setupWizard/index.ts @@ -1,2 +1,2 @@ export { readSetupWizardIfExists } from "./readSetupWizardIfExists.js"; -export { SetupWizardFormat, SetupWizardPaths } from "./types.js"; +export { SetupWizardFormat, type SetupWizardPaths } from "./types.js"; diff --git a/src/providers/apm/ApmRepository.ts b/src/providers/apm/ApmRepository.ts new file mode 100644 index 00000000..1c882f56 --- /dev/null +++ b/src/providers/apm/ApmRepository.ts @@ -0,0 +1,44 @@ +import { + Contract, + JsonRpcProvider, + toUtf8String, + type Provider, + isValidName +} from "ethers"; +import repoAbi from "../../contracts/RepoAbi.json" with { type: "json" }; + +/** The SDK only needs ENS resolution and the latest published APM version. */ +export class ApmRepository { + private readonly provider: Provider; + + constructor(ethereumUrl: string, provider?: Provider) { + if (!ethereumUrl) throw new Error("Ethereum URL is required"); + this.provider = + provider || + new JsonRpcProvider(ethereumUrl, "mainnet", { staticNetwork: true }); + } + + async getRepoContract(name: string): Promise { + if (!isValidName(name) || !name.endsWith(".dappnode.eth")) + throw new Error(`Invalid Dappnode ENS name: ${name}`); + const address = await this.provider.resolveName(name); + if (!address) throw new Error(`Could not resolve name ${name}: NOREPO`); + return new Contract(address, repoAbi, this.provider); + } + + async getVersionAndIpfsHash({ + dnpNameOrHash + }: { + dnpNameOrHash: string; + }): Promise<{ version: string; contentUri: string }> { + const repo = await this.getRepoContract(dnpNameOrHash); + const result = await repo.getFunction("getLatest").staticCall(); + const version: unknown = result[0]; + if (!Array.isArray(version) || version.length !== 3) + throw new Error(`Invalid APM semantic version for ${dnpNameOrHash}`); + return { + version: version.map(part => String(part)).join("."), + contentUri: toUtf8String(result[2]) + }; + } +} diff --git a/src/providers/github/githubActions.ts b/src/providers/github/githubActions.ts index 119ba01c..f7e3e504 100644 --- a/src/providers/github/githubActions.ts +++ b/src/providers/github/githubActions.ts @@ -4,7 +4,6 @@ import fs from "fs"; * Returns Github Actions context. * From https://github.com/actions/toolkit/blob/c861dd8859fe5294289fcada363ce9bc71e9d260/packages/github/src/context.ts#L25 */ -// eslint-disable-next-line @typescript-eslint/explicit-module-boundary-types export function getGithubContext() { return { // The name of the webhook event that triggered the workflow. diff --git a/src/releaseUploader/ipfsNode/addDirFromUrls.ts b/src/releaseUploader/ipfsNode/addDirFromUrls.ts index 66b5757d..316caf46 100644 --- a/src/releaseUploader/ipfsNode/addDirFromUrls.ts +++ b/src/releaseUploader/ipfsNode/addDirFromUrls.ts @@ -1,6 +1,7 @@ -import { got } from "got"; +import { got, type Request } from "got"; +import { uploadTimeout } from "../utils/uploadTimeout.js"; import FormData from "form-data"; -import request from "request"; +import { PassThrough } from "stream"; import { normalizeIpfsProvider } from "./ipfsProvider.js"; /** @@ -18,9 +19,10 @@ export async function ipfsAddDirFromUrls( // Create form and append all files recursively const form = new FormData(); + const streams: Request[] = []; for (const { filepath, url } of files) { - // Using request instead of got, because got doesn't seem to work - const fileStream = request(url); + const fileStream = got.stream(url, { retry: { limit: 0 } }); + streams.push(fileStream); fileStream.on("data", chunk => { if (onProgress) onProgress(filepath, chunk.length); }); @@ -28,15 +30,26 @@ export async function ipfsAddDirFromUrls( } // Parse the ipfsProvider the a full base apiUrl - const res = await got({ + const body = new PassThrough(); + form.on("error", error => body.destroy(error)); + const upload = got({ prefixUrl: normalizeIpfsProvider(ipfsProvider), url: "api/v0/add", method: "POST", headers: form.getHeaders(), - body: form, + body, + timeout: uploadTimeout, + retry: { limit: 0 }, http2: true }); + form.pipe(body); + const res = await upload.finally(() => { + for (const stream of streams) stream.destroy(); + form.destroy(); + body.destroy(); + }); + // res.body = '{"Name":"dir/file","Hash":"Qm...","Size":"2203"}\n{"Name":"dir","Hash":"Qm...","Size":"24622"}\n' // Trim last \n, split entries by \n and then select the last which is the root directory const lastFileUnparsed = res.body.trim().split("\n").slice(-1)[0]; diff --git a/src/releaseUploader/utils/uploadTimeout.ts b/src/releaseUploader/utils/uploadTimeout.ts new file mode 100644 index 00000000..66e363c1 --- /dev/null +++ b/src/releaseUploader/utils/uploadTimeout.ts @@ -0,0 +1,7 @@ +/** + * Upload requests abort only when the connection stops moving. + * A total limit would fail healthy large uploads on slow links + * (a ~1.6 GB release needs over 3.6 Mbit/s to finish within an hour). + * The idle window also covers the server hashing/pinning after the last byte. + */ +export const uploadTimeout = { socket: 15 * 60 * 1000 } as const; diff --git a/src/tasks/buildAndUpload/getReleaseDirCreationTask.ts b/src/tasks/buildAndUpload/getReleaseDirCreationTask.ts index af5b8f73..929c22dc 100644 --- a/src/tasks/buildAndUpload/getReleaseDirCreationTask.ts +++ b/src/tasks/buildAndUpload/getReleaseDirCreationTask.ts @@ -1,7 +1,6 @@ import fs from "fs"; import path from "path"; import { ListrTask } from "listr/index.js"; -import rimraf from "rimraf"; import { PackageToBuildProps, ListrContextBuild } from "../../types.js"; import { getImageFileName } from "../../utils/getImageFileName.js"; @@ -29,14 +28,10 @@ function createReleaseDirs({ releaseDir, architectures } of packagesToBuildProps) { - console.log( - `Creating release directory for ${name} (version ${version}) at ${releaseDir}` - ); - fs.mkdirSync(releaseDir, { recursive: true }); // Ok on existing dir const releaseFiles = fs.readdirSync(releaseDir); - ctx[name] = { variant, releaseDir }; + ctx[name] = { ...ctx[name], variant, releaseDir }; const imagePaths = architectures.map(arch => getImageFileName(name, version, arch) @@ -45,6 +40,9 @@ function createReleaseDirs({ // Clean all files except the expected target images for (const filepath of releaseFiles) if (!imagePaths.includes(filepath)) - rimraf.sync(path.join(releaseDir, filepath)); + fs.rmSync(path.join(releaseDir, filepath), { + recursive: true, + force: true + }); } } diff --git a/src/tasks/generatePublishTxs/index.ts b/src/tasks/generatePublishTxs/index.ts index 99cb31a8..41b049a9 100644 --- a/src/tasks/generatePublishTxs/index.ts +++ b/src/tasks/generatePublishTxs/index.ts @@ -4,8 +4,13 @@ import { getEthereumUrl } from "../../utils/getEthereumUrl.js"; import { getPublishTxLink } from "../../utils/getLinks.js"; import { addReleaseTx } from "../../utils/releaseRecord.js"; import { defaultDir, YargsError } from "../../params.js"; -import { PackageToBuildProps, CliGlobalOptions, ListrContextPublish, TxData } from "../../types.js"; -import { ApmRepository } from "@dappnode/toolkit"; +import { + PackageToBuildProps, + CliGlobalOptions, + ListrContextPublish, + TxData +} from "../../types.js"; +import { ApmRepository } from "../../providers/apm/ApmRepository.js"; import registryAbi from "../../contracts/ApmRegistryAbi.json" with { type: "json" }; import { semverToArray } from "../../utils/semverToArray.js"; import repoAbi from "../../contracts/RepoAbi.json" with { type: "json" }; @@ -32,7 +37,7 @@ export function generatePublishTxs({ developerAddress, ethProvider, verbosityOptions, - packagesToBuildProps, + packagesToBuildProps }: { developerAddress?: string; ethProvider: string; @@ -51,7 +56,6 @@ export function generatePublishTxs({ const contractAddress = "0x0000000000000000000000000000000000000000"; for (const { manifest } of packagesToBuildProps) { - const { name: dnpName, version } = manifest; const releaseMultiHash = ctx[dnpName]?.releaseMultiHash; @@ -118,22 +122,22 @@ export async function buildTxData({ return repository ? await getTxDataForExistingRepo({ - repository, - version, - contractAddress, - contentURI, - releaseMultiHash, - dnpName: dnpName - }) + repository, + version, + contractAddress, + contentURI, + releaseMultiHash, + dnpName: dnpName + }) : await getTxDataForNewRepo({ - dnpName: dnpName, - version, - contractAddress, - contentURI, - releaseMultiHash, - developerAddress, - ethereumUrl - }); + dnpName: dnpName, + version, + contractAddress, + contentURI, + releaseMultiHash, + developerAddress, + ethereumUrl + }); } async function getRepoContractIfExists({ diff --git a/src/tasks/generatePublishTxs/types.ts b/src/tasks/generatePublishTxs/types.ts index 7c7129fb..90697c52 100644 --- a/src/tasks/generatePublishTxs/types.ts +++ b/src/tasks/generatePublishTxs/types.ts @@ -1,3 +1,3 @@ -import { ApmRepository } from "@dappnode/toolkit"; +import { ApmRepository } from "../../providers/apm/ApmRepository.js"; export type Repo = Awaited>; diff --git a/src/timestring.d.ts b/src/timestring.d.ts new file mode 100644 index 00000000..aa8d59e8 --- /dev/null +++ b/src/timestring.d.ts @@ -0,0 +1,3 @@ +declare module "timestring/index.js" { + export default function timestring(value: string): number; +} diff --git a/src/utils/file.ts b/src/utils/file.ts index 8dba6094..423c1d2b 100644 --- a/src/utils/file.ts +++ b/src/utils/file.ts @@ -10,7 +10,8 @@ export function readFile(filepath: string): string { } catch (e) { if (e.code === "ENOENT") { throw Error( - `${filepath} not found. Make sure you are in a directory with an initialized DNP.` + `${filepath} not found. Make sure you are in a directory with an initialized DNP.`, + { cause: e } ); } else { throw e; diff --git a/src/utils/getFileHash.ts b/src/utils/getFileHash.ts index 40ce2288..3d46c28e 100644 --- a/src/utils/getFileHash.ts +++ b/src/utils/getFileHash.ts @@ -12,7 +12,7 @@ export function getFileHash(path: string): Promise { const hash = crypto.createHash("sha256"); const stream = fs.createReadStream(path); - stream.on("data", (chunk: Buffer) => { + stream.on("data", (chunk: string | Buffer) => { hash.update(chunk); // Should now recognize Buffer correctly }); diff --git a/src/utils/verifyAvatar.ts b/src/utils/verifyAvatar.ts index 62c41e05..2fbd97c3 100644 --- a/src/utils/verifyAvatar.ts +++ b/src/utils/verifyAvatar.ts @@ -1,13 +1,12 @@ -import sizeOf from "image-size"; +import { imageSize } from "image-size"; +import fs from "fs"; import { CliError } from "../params.js"; const maxSize = 300; const minSize = 200; export function verifyAvatar(avatarPath: string): void { - // image-size has conflicting types to its documentation - // @ts-ignore - const { width, height } = sizeOf(avatarPath); + const { width, height } = imageSize(fs.readFileSync(avatarPath)); if (width !== height) throw new CliError(`Wrong avatar aspect ratio diff --git a/src/utils/versions/getNextVersionFromApm.ts b/src/utils/versions/getNextVersionFromApm.ts index 111c80d6..f97ee08d 100644 --- a/src/utils/versions/getNextVersionFromApm.ts +++ b/src/utils/versions/getNextVersionFromApm.ts @@ -2,7 +2,7 @@ import semver from "semver"; import { getEthereumUrl } from "../getEthereumUrl.js"; import { checkSemverType } from "../checkSemverType.js"; import { ReleaseType } from "../../types.js"; -import { ApmRepository } from "@dappnode/toolkit"; +import { ApmRepository } from "../../providers/apm/ApmRepository.js"; export async function getNextVersionFromApm({ type, diff --git a/test/commands/build.test.ts b/test/commands/build.test.ts index 3508b48c..2701bd5b 100644 --- a/test/commands/build.test.ts +++ b/test/commands/build.test.ts @@ -76,7 +76,7 @@ describe("Init and build simple package", function () { strip_compose_version: true }); - expect(readCompose([{ dir: releaseDir }]).version).to.be.undefined; + expect(readCompose([{ dir: releaseDir }]).version).to.equal(undefined); }); }); diff --git a/test/commands/init.test.ts b/test/commands/init.test.ts index df2854af..730945b0 100644 --- a/test/commands/init.test.ts +++ b/test/commands/init.test.ts @@ -37,19 +37,19 @@ describe("Init simple package repository", function () { describe("File creation", () => { it("should create a Dockerfile", () => { - expect(testPathExists(dockerfileName)).to.be.true; + expect(testPathExists(dockerfileName)).to.equal(true); }); it("should create a Dappnode manifest", () => { - expect(testPathExists(defaultManifestFileName)).to.be.true; + expect(testPathExists(defaultManifestFileName)).to.equal(true); }); it("should create a docker-compose.yml", () => { - expect(testPathExists("docker-compose.yml")).to.be.true; + expect(testPathExists("docker-compose.yml")).to.equal(true); }); it("should create a .gitignore", () => { - expect(testPathExists(".gitignore")).to.be.true; + expect(testPathExists(".gitignore")).to.equal(true); }); }); @@ -64,8 +64,8 @@ describe("Init simple package repository", function () { it("checks manifest content for correct initialization", () => { const manifestContent = JSON.parse(readTestFile(defaultManifestFileName)); - expect(manifestContent.name).to.exist; - expect(manifestContent.version).to.exist; + expect(manifestContent.name).to.not.equal(undefined); + expect(manifestContent.version).to.not.equal(undefined); }); it("checks compose file for service configuration", () => { @@ -90,7 +90,7 @@ describe("Variant initialization", function () { }); it("should create variant directories", () => { - expect(testPathExists(defaultVariantsDirName)).to.be.true; + expect(testPathExists(defaultVariantsDirName)).to.equal(true); }); it("checks for specific variant manifest", () => { @@ -105,9 +105,9 @@ describe("Variant initialization", function () { const variantManifestContent = JSON.parse( readTestFile(variantManifestPath) ); - expect(rootManifestContent.name).to.not.exist; - expect(variantManifestContent.name).to.exist; - expect(rootManifestContent.version).to.not.exist; - expect(variantManifestContent.version).to.exist; + expect(rootManifestContent.name).to.equal(undefined); + expect(variantManifestContent.name).to.not.equal(undefined); + expect(rootManifestContent.version).to.equal(undefined); + expect(variantManifestContent.version).to.not.equal(undefined); }); }); diff --git a/test/helpers/fixtures.ts b/test/helpers/fixtures.ts new file mode 100644 index 00000000..c1d5d0eb --- /dev/null +++ b/test/helpers/fixtures.ts @@ -0,0 +1,22 @@ +import fs from "fs"; +import os from "os"; +import path from "path"; + +export function temporaryDirectory(): string { + return fs.mkdtempSync(path.join(os.tmpdir(), "sdk-quality-")); +} + +export function executable(dir: string, name: string, script: string): void { + fs.mkdirSync(dir, { recursive: true }); + fs.writeFileSync(path.join(dir, name), `#!${process.execPath}\n${script}\n`, { + mode: 0o755 + }); +} + +export function useExecutables(dir: string): () => void { + const original = process.env.PATH; + process.env.PATH = `${dir}${path.delimiter}${original || ""}`; + return () => { + process.env.PATH = original; + }; +} diff --git a/test/providers/apm/ApmRepository.test.ts b/test/providers/apm/ApmRepository.test.ts new file mode 100644 index 00000000..54b75315 --- /dev/null +++ b/test/providers/apm/ApmRepository.test.ts @@ -0,0 +1,143 @@ +import { mock } from "node:test"; +import registryAbi from "../../../src/contracts/ApmRegistryAbi.json" with { type: "json" }; +import { + Contract, + Interface, + JsonRpcProvider, + toUtf8Bytes, + hexlify, + type TransactionRequest +} from "ethers"; +import { expect } from "chai"; +import { ApmRepository } from "../../../src/providers/apm/ApmRepository.js"; +import { buildTxData } from "../../../src/tasks/generatePublishTxs/index.js"; +import abi from "../../../src/contracts/RepoAbi.json" with { type: "json" }; + +const address = "0x0000000000000000000000000000000000001234"; +class LocalProvider extends JsonRpcProvider { + constructor(private readonly registered = true) { + super("http://unused", 1, { staticNetwork: true }); + } + async resolveName(): Promise { + return this.registered ? address : null; + } + async call(tx: TransactionRequest): Promise { + const contract = new Interface(abi); + expect(tx.to).to.equal(address); + expect(tx.data).to.equal(contract.encodeFunctionData("getLatest")); + return contract.encodeFunctionResult("getLatest", [ + [1, 2, 3], + address, + hexlify(toUtf8Bytes("/ipfs/QmLatest")) + ]); + } +} + +describe("minimal APM client", () => { + it("resolves ENS and decodes the existing contract ABI", async () => { + const provider = new LocalProvider(); + try { + const client = new ApmRepository("http://unused", provider); + expect( + await client.getVersionAndIpfsHash({ + dnpNameOrHash: "demo.public.dappnode.eth" + }) + ).to.deep.equal({ version: "1.2.3", contentUri: "/ipfs/QmLatest" }); + expect( + await client.getRepoContract("demo.public.dappnode.eth") + ).to.be.instanceOf(Contract); + } finally { + provider.destroy(); + } + }); + + it("preserves new-repository detection", async () => { + const provider = new LocalProvider(false); + try { + const error = await new ApmRepository("http://unused", provider) + .getRepoContract("new.public.dappnode.eth") + .catch(error => error); + expect(error.message).to.include("NOREPO"); + } finally { + provider.destroy(); + } + }); + + it("generates an existing-repository transaction without a live RPC", async () => { + const provider = new LocalProvider(); + try { + const result = await buildTxData({ + apm: new ApmRepository("http://unused", provider), + contractAddress: address, + dnpName: "demo.public.dappnode.eth", + version: "1.2.4", + releaseMultiHash: "/ipfs/QmNext", + developerAddress: address, + ethereumUrl: "http://unused" + }); + const decoded = new Interface(abi).decodeFunctionData( + "newVersion", + result.data + ); + expect(result.to).to.equal(address); + expect([...decoded[0]]).to.deep.equal([1n, 2n, 4n]); + expect(decoded[2]).to.equal(hexlify(toUtf8Bytes("/ipfs/QmNext"))); + } finally { + provider.destroy(); + } + }); + it("generates a new-repository transaction after an unresolved package name", async () => { + const provider = new LocalProvider(false); + const registry = "0x0000000000000000000000000000000000005678"; + const resolution = mock.method( + JsonRpcProvider.prototype, + "resolveName", + async () => registry + ); + try { + const result = await buildTxData({ + apm: new ApmRepository("http://unused", provider), + contractAddress: address, + dnpName: "new.public.dappnode.eth", + version: "0.1.0", + releaseMultiHash: "/ipfs/QmNew", + developerAddress: address, + ethereumUrl: "http://unused" + }); + const decoded = new Interface(registryAbi).decodeFunctionData( + "newRepoWithVersion", + result.data + ); + expect(result.to).to.equal(registry); + expect(decoded[0]).to.equal("new"); + expect(decoded[1]).to.equal(address); + expect([...decoded[2]]).to.deep.equal([0n, 1n, 0n]); + } finally { + resolution.mock.restore(); + provider.destroy(); + } + }); + + it("propagates RPC failures instead of treating them as an unpublished package", async () => { + const provider = new LocalProvider(); + const rpcFailure = new Error("RPC timeout"); + const resolution = mock.method(provider, "resolveName", async () => { + throw rpcFailure; + }); + try { + const error = await buildTxData({ + apm: new ApmRepository("http://unused", provider), + contractAddress: address, + dnpName: "demo.public.dappnode.eth", + version: "0.1.0", + releaseMultiHash: "/ipfs/QmNew", + developerAddress: address, + ethereumUrl: "http://unused" + }).catch(error => error); + expect(error).to.equal(rpcFailure); + } finally { + resolution.mock.restore(); + provider.destroy(); + } + }); +}); diff --git a/test/tasks/generatePublishTx.test.ts b/test/tasks/generatePublishTx.test.ts index dbce6e73..b7b3481b 100644 --- a/test/tasks/generatePublishTx.test.ts +++ b/test/tasks/generatePublishTx.test.ts @@ -4,7 +4,7 @@ import { buildTxData } from "../../src/tasks/generatePublishTxs/index.js"; import { writeManifest } from "../../src/files/index.js"; import { testDir, cleanTestDir } from "../testUtils.js"; import { getEthereumUrl } from "../../src/utils/getEthereumUrl.js"; -import { ApmRepository } from "@dappnode/toolkit"; +import { ApmRepository } from "../../src/providers/apm/ApmRepository.js"; // This test will create the following fake files // ./dappnode_package.json => fake manifest @@ -48,8 +48,7 @@ describe("generatePublishTx", async function () { expect(txData).to.deep.equal({ to: "0xEe66C4765696C922078e8670aA9E6d4F6fFcc455", // admin.dnp.dappnode.eth resolves to this address value: 0, - data: - "0x73053410000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000a000000000000000000000000000000000000000000000000000000000000000082f697066732f516d000000000000000000000000000000000000000000000000", + data: "0x73053410000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000a000000000000000000000000000000000000000000000000000000000000000082f697066732f516d000000000000000000000000000000000000000000000000", gasLimit: 300000, ensName: name, currentVersion: version, @@ -81,8 +80,7 @@ describe("generatePublishTx", async function () { expect(txData).to.deep.equal({ to: "0x266BFdb2124A68beB6769dC887BD655f78778923", // Registry contract address value: 0, - data: - "0x32ab6af000000000000000000000000000000000000000000000000000000000000000e0000000000000000000000000ab5801a7d398351b8be11c439e05c5b3259aec9b0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000012000000000000000000000000000000000000000000000000000000000000000086e65772d7265706f00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000082f697066732f516d000000000000000000000000000000000000000000000000", + data: "0x32ab6af000000000000000000000000000000000000000000000000000000000000000e0000000000000000000000000ab5801a7d398351b8be11c439e05c5b3259aec9b0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000012000000000000000000000000000000000000000000000000000000000000000086e65772d7265706f00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000082f697066732f516d000000000000000000000000000000000000000000000000", gasLimit: 1100000, ensName: name, currentVersion: version, diff --git a/test/testUtils.ts b/test/testUtils.ts index 6f752090..198f520d 100644 --- a/test/testUtils.ts +++ b/test/testUtils.ts @@ -1,11 +1,10 @@ import fs from "fs"; -import rimraf from "rimraf"; import { Compose, Manifest, getImageTag } from "@dappnode/types"; import path from "path"; export const testDir = "test_files"; export function cleanTestDir(): void { - rimraf.sync(testDir); + fs.rmSync(testDir, { recursive: true, force: true }); fs.mkdirSync(testDir, { recursive: true }); } diff --git a/test/utils/versions/getNextPackageVersion.test.ts b/test/utils/versions/getNextPackageVersion.test.ts index 0d1993d1..718dd20f 100644 --- a/test/utils/versions/getNextPackageVersion.test.ts +++ b/test/utils/versions/getNextPackageVersion.test.ts @@ -1,16 +1,7 @@ import { expect } from "chai"; import semver from "semver"; -import { cleanTestDir, generateCompose, testDir } from "../../testUtils.js"; -import { - defaultComposeFileName, - defaultManifestFormat -} from "../../../src/params.js"; -import { - writeCompose, - readCompose, - writeManifest, - readManifest -} from "../../../src/files/index.js"; +import { cleanTestDir, testDir } from "../../testUtils.js"; +import { writeCompose, writeManifest } from "../../../src/files/index.js"; import { Manifest } from "@dappnode/types"; import { ManifestFormat } from "../../../src/files/manifest/types.js"; import { getNextPackageVersion } from "../../../src/tasks/publish/subtasks/getFetchApmVersionsTask.js"; @@ -31,7 +22,13 @@ describe("getNextPackageVersion", function () { it("Should get the next version from APM and update manifest and compose files", async () => { // Write initial manifest and compose files writeManifest(manifest, ManifestFormat.json, { dir: testDir }); - writeCompose({ version: "3.8", services: { [dnpName]: { image: `${dnpName}:${manifest.version}` } } }, { dir: testDir }); + writeCompose( + { + version: "3.8", + services: { [dnpName]: { image: `${dnpName}:${manifest.version}` } } + }, + { dir: testDir } + ); // Fetch the next version from APM const nextVersion = await getNextPackageVersion({ @@ -41,6 +38,6 @@ describe("getNextPackageVersion", function () { }); // Ensure the next version is valid - expect(semver.valid(nextVersion)).to.be.ok; + expect(semver.valid(nextVersion)).to.not.equal(null); }); -}); \ No newline at end of file +}); diff --git a/tsconfig.json b/tsconfig.json index 3af61bd9..bc35c394 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -1,14 +1,15 @@ { "compilerOptions": { - "target": "es2019", - "lib": ["ES2020", "dom"], + "target": "es2022", + "lib": ["ES2022", "dom"], "module": "esnext", - "moduleResolution": "node", + "moduleResolution": "bundler", "esModuleInterop": true, "resolveJsonModule": true, "strictNullChecks": true, "allowJs": true, "strict": true, + "isolatedModules": true, "types": ["mocha", "node"], "outDir": "dist", "sourceMap": true, @@ -16,11 +17,6 @@ "useUnknownInCatchVariables": false, "skipLibCheck": true }, - "ts-node": { - "esm": true, - "experimentalSpecifierResolution": "node", - "experimentalResolver": true - }, "include": ["src/**/*"], "exclude": ["node_modules", "dist", "**/*.test.ts"] } diff --git a/yarn.lock b/yarn.lock index f8e6fe30..8e1d3a54 100644 --- a/yarn.lock +++ b/yarn.lock @@ -2,859 +2,815 @@ # yarn lockfile v1 -"@adraffy/ens-normalize@1.10.0": - version "1.10.0" - resolved "https://registry.yarnpkg.com/@adraffy/ens-normalize/-/ens-normalize-1.10.0.tgz#d2a39395c587e092d77cbbc80acf956a54f38bf7" - integrity sha512-nA9XHtlAkYfJxY7bce8DcN7eKxWWCWkU+1GR9d+U6MbNpfwQp8TI7vqOsBsMcHoT4mBu2kypKoSKnghEzOOq5Q== +"@adraffy/ens-normalize@1.11.1": + version "1.11.1" + resolved "https://registry.npmjs.org/@adraffy/ens-normalize/-/ens-normalize-1.11.1.tgz#6c2d657d4b2dfb37f8ea811dcb3e60843d4ac24a" + integrity sha512-nhCBV3quEgesuf7c7KYfperqSS14T8bYuvJ8PcLJp6znkZpFc0AuW4qBtr8eKVyPPe/8RSr7sglCWPU5eaxwKQ== -"@adraffy/ens-normalize@1.9.0": - version "1.9.0" - resolved "https://registry.yarnpkg.com/@adraffy/ens-normalize/-/ens-normalize-1.9.0.tgz#223572538f6bea336750039bb43a4016dcc8182d" - integrity sha512-iowxq3U30sghZotgl4s/oJRci6WPBfNO5YYgk2cIOMCHr3LeGPcsZjCEr+33Q4N+oV3OABDAtA+pyvWjbvBifQ== - -"@babel/code-frame@^7.0.0": - version "7.10.4" - resolved "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.10.4.tgz" - integrity sha512-vG6SvB6oYEhvgisZNFRmRCUkLz11c7rp+tbNTynGqc6mS1d5ATd/sGyV6W0KZZnXRKMTzZDRgQT3Ou9jhpAfUg== - dependencies: - "@babel/highlight" "^7.10.4" - -"@babel/helper-validator-identifier@^7.10.4": - version "7.10.4" - resolved "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.10.4.tgz" - integrity sha512-3U9y+43hz7ZM+rzG24Qe2mufW5KhvFg/NhnNph+i9mgCtdTCtMJuI1TMkrIUiK7Ix4PYlRF9I5dhqaLYA/ADXw== - -"@babel/highlight@^7.10.4": - version "7.10.4" - resolved "https://registry.npmjs.org/@babel/highlight/-/highlight-7.10.4.tgz" - integrity sha512-i6rgnR/YgPEQzZZnbTHHuZdlE8qyoBNalD6F+q4vAFlcMEcqmkoG+mPqJYJCo63qPf74+Y1UZsl3l6f7/RIkmA== - dependencies: - "@babel/helper-validator-identifier" "^7.10.4" - chalk "^2.0.0" - js-tokens "^4.0.0" - -"@balena/dockerignore@^1.0.2": - version "1.0.2" - resolved "https://registry.npmjs.org/@balena/dockerignore/-/dockerignore-1.0.2.tgz" - integrity sha512-wMue2Sy4GAVTk6Ic4tJVcnfdau+gx2EnG7S+uAEe+TWJFqE4YoWN4/H8MSLj4eYJKxGg26lZwboEniNiNwZQ6Q== - -"@chainsafe/is-ip@^2.0.1": - version "2.0.1" - resolved "https://registry.yarnpkg.com/@chainsafe/is-ip/-/is-ip-2.0.1.tgz#62cb285669d91f88fd9fa285048dde3882f0993b" - integrity sha512-nqSJ8u2a1Rv9FYbyI8qpDhTYujaKEyLknNrTejLYoSWmdeg+2WB7R6BZqPZYfrJzDxVi3rl6ZQuoaEvpKRZWgQ== - -"@chainsafe/netmask@^2.0.0": - version "2.0.0" - resolved "https://registry.yarnpkg.com/@chainsafe/netmask/-/netmask-2.0.0.tgz#0d4a75f47919f65011da4327a3845c9661f1038a" - integrity sha512-I3Z+6SWUoaljh3TBzCnCxjlUyN8tA+NAk5L6m9IxvCf1BENQTePzPMis97CoN/iMW1St3WN+AWCCRp+TTBRiDg== +"@cacheable/memory@^2.2.0": + version "2.2.0" + resolved "https://registry.npmjs.org/@cacheable/memory/-/memory-2.2.0.tgz#72aeb8b051f6d597d10ac8595b94ad8302bd2239" + integrity sha512-CTLKqLItRCEixEAewD3/j9DB3/o96gpTPD4eJ1v+DGOlxZRZncRQkGYqqnAGCscYd6RNeXfGeiuCphsPtqyIfQ== dependencies: - "@chainsafe/is-ip" "^2.0.1" + "@cacheable/utils" "^2.5.0" + "@keyv/bigmap" "^1.3.1" + hookified "^1.15.1" + keyv "^5.6.0" -"@cspotcode/source-map-support@^0.8.0": - version "0.8.1" - resolved "https://registry.npmjs.org/@cspotcode/source-map-support/-/source-map-support-0.8.1.tgz" - integrity sha512-IchNf6dN4tHoMFIn/7OE8LWZ19Y6q/67Bmf6vnGREv8RSbBVb9LPJxEcnwrcwX6ixSvaiGoomAUvu4YSxXrVgw== +"@cacheable/utils@^2.5.0": + version "2.5.0" + resolved "https://registry.npmjs.org/@cacheable/utils/-/utils-2.5.0.tgz#534c91113aa48fe43baedb169550b6ee070ef303" + integrity sha512-buipgOVDkkPXNR5+xBpDw7Zk2n1EvU7qBJCNUcL7rhQ//kfpOXPAvQ511Os0vpLYJ1pZnvudNytkQt2hst3wqA== dependencies: - "@jridgewell/trace-mapping" "0.3.9" + hashery "^1.5.1" + keyv "^5.6.0" "@dappnode/schemas@^0.1.26": version "0.1.26" - resolved "https://registry.yarnpkg.com/@dappnode/schemas/-/schemas-0.1.26.tgz#45ac97dd7e59fe7914b24d723a3489107733b65d" + resolved "https://registry.npmjs.org/@dappnode/schemas/-/schemas-0.1.26.tgz#45ac97dd7e59fe7914b24d723a3489107733b65d" integrity sha512-i9jkn8vDYumaTbo0mGLqm3ONyLiCYoHbRTzS47WYdWQONP/Bxou42XPqM6KFxAvyMRCv6oUCmRu0sNs4Gzq3qw== dependencies: "@dappnode/types" "^0.1.40" ajv "^8.17.1" semver "^7.5.0" -"@dappnode/toolkit@^0.1.21": - version "0.1.21" - resolved "https://registry.yarnpkg.com/@dappnode/toolkit/-/toolkit-0.1.21.tgz#f5bc8158dcb86415dae0bec0f137690361a9db80" - integrity sha512-hbggqq9xPb6kzLTFduHkJFHgQEcBFoBwpmPsPCJZDf21hlRh7+sbcxRoU/pEW48cxXLQ/O6uMFH1v44j+cREVA== - dependencies: - "@dappnode/types" "^0.1.34" - "@ipld/car" "^5.1.1" - esm "^3.2.25" - ethers "^6.9.0" - graphql "^16.6.0" - graphql-request "^6.0.0" - ipfs-unixfs-exporter "^13.1.5" - is-ipfs "^8.0.1" - kubo-rpc-client "^3.0.1" - multiformats "^11.0.2" - semver "^7.5.0" - yaml "^2.2.2" - -"@dappnode/types@^0.1.34": - version "0.1.34" - resolved "https://registry.yarnpkg.com/@dappnode/types/-/types-0.1.34.tgz#f84713687860b569e405884132a953e4ee4b8ade" - integrity sha512-07DEQVP6umDUDhDcX8m7EZMZtUUeyOeigupTWo8/oNsHuw7/V+UMCnUjYr1UsoNug2B3nRJ4V+iYQl0R/fhBEQ== - -"@dappnode/types@^0.1.40": - version "0.1.40" - resolved "https://registry.yarnpkg.com/@dappnode/types/-/types-0.1.40.tgz#d64947867d91a4b7b6b4fed4a3ae815e392cbf99" - integrity sha512-gq0PswPB4y09SLpK+MYJti841/jcFTjqoVT+rcrwvOsSEFk6KUyCLxLahFKUJ9Z5w5iBiSLeJ1kmNQk/PRvT9Q== - -"@dappnode/types@^0.1.41": +"@dappnode/types@^0.1.40", "@dappnode/types@^0.1.41": version "0.1.41" - resolved "https://registry.yarnpkg.com/@dappnode/types/-/types-0.1.41.tgz#43920962ed37574914c7e22273104028fdd0995f" + resolved "https://registry.npmjs.org/@dappnode/types/-/types-0.1.41.tgz#43920962ed37574914c7e22273104028fdd0995f" integrity sha512-lhPoVo50ZL+VimLl2laTehJIIADNzzGJgb+cgJ5a1mYYxLm3FjLAOLK+V2UII2ZfcCW7WJqOSw6gUXMRnJFRng== -"@graphql-typed-document-node/core@^3.2.0": - version "3.2.0" - resolved "https://registry.yarnpkg.com/@graphql-typed-document-node/core/-/core-3.2.0.tgz#5f3d96ec6b2354ad6d8a28bf216a1d97b5426861" - integrity sha512-mB9oAsNCm9aM3/SOv4YtBMqZbYj10R7dkq8byBqxGY/ncFwhf2oQzMV+LCRlWoDSEBJ3COiR1yeDvMtsoOsuFQ== +"@esbuild/aix-ppc64@0.28.2": + version "0.28.2" + resolved "https://registry.npmjs.org/@esbuild/aix-ppc64/-/aix-ppc64-0.28.2.tgz#bf6e10303bcf2e7c686975fa52f937ec2728d8bc" + integrity sha512-XExcO+dvLKvVtNTibSTBej1NCAbaGhWn9Ww1ZPx80qsahhPFe/8jgWP0IchNe0F3HwkU7n8ejhH8bjonqht8mQ== + +"@esbuild/android-arm64@0.28.2": + version "0.28.2" + resolved "https://registry.npmjs.org/@esbuild/android-arm64/-/android-arm64-0.28.2.tgz#0c6246bc8d2c4d172aac2db3fb1190d72bd65504" + integrity sha512-5YfKeeI8qWfBZIX+u2xZC3Zlb3Os/gLS2sbEKM+I4ZOcsWmHS2WLysCcQZDAFRslDUU5Oiq44gf6PYN1vGwG5A== + +"@esbuild/android-arm@0.28.2": + version "0.28.2" + resolved "https://registry.npmjs.org/@esbuild/android-arm/-/android-arm-0.28.2.tgz#2d84ece6a4e2684d92be26ee13d42757d831c381" + integrity sha512-kXXoiPVVGQcnIYGOeaovwOURpniDBpSq4A03qkQ+BMQqtGG6HYap3xne9C1O1yo4TR3qxlCX5IqqmX6fFo2Lqg== + +"@esbuild/android-x64@0.28.2": + version "0.28.2" + resolved "https://registry.npmjs.org/@esbuild/android-x64/-/android-x64-0.28.2.tgz#fc38d4d6358d8dc1cf53f09f7589fe436eb64801" + integrity sha512-O387ite7SzUyCcy3JQX4P4bLtEA7bLLkx+esve5JHnyYfNTxcVpXZo9jhdB0lTKN44gztELTdU7nS8Nr16Fs1Q== + +"@esbuild/darwin-arm64@0.28.2": + version "0.28.2" + resolved "https://registry.npmjs.org/@esbuild/darwin-arm64/-/darwin-arm64-0.28.2.tgz#f83afeeac1d7dac01c7a2fd012b3e451a0591fcc" + integrity sha512-n4KqkOQrraxHJcgjM1RvwbigfQKIKJVpM7xp+KsxiyUSrRdIXnt73VhrPAx0fV44hgfmIVKjxMN9J1t5jySVkw== + +"@esbuild/darwin-x64@0.28.2": + version "0.28.2" + resolved "https://registry.npmjs.org/@esbuild/darwin-x64/-/darwin-x64-0.28.2.tgz#510147c055a795588dbbe14fd6b1b8ad0a2f30de" + integrity sha512-uq6suIWYP37qzGddBKPw5QEQPi6HiLGsO7UmkpfyaYNQ3D+rN6w6WfwH+nuqcGXWvawGwxOEroO4YGnFh95azw== + +"@esbuild/freebsd-arm64@0.28.2": + version "0.28.2" + resolved "https://registry.npmjs.org/@esbuild/freebsd-arm64/-/freebsd-arm64-0.28.2.tgz#093b9200ecf0b115ba4e5e248a7485c9c5f8bd5e" + integrity sha512-n+I0BTSRIoy+d6RPKnEVwql5UwBJolytvY4mAOIEJorKlqgPII8ix6slVVrfZ5Tnj7glIZvloylbB/EJPMWEXw== + +"@esbuild/freebsd-x64@0.28.2": + version "0.28.2" + resolved "https://registry.npmjs.org/@esbuild/freebsd-x64/-/freebsd-x64-0.28.2.tgz#0be22b6df925d213e841ea87123af5df80b0faf7" + integrity sha512-78XJTJkvPs0kz2w61301PJjXl4g7q3JqiYMZ/M/yVI73EHBrCRTgkhu9oqG7vPqq+a/yadEW8aD+agKlk5xrmg== + +"@esbuild/linux-arm64@0.28.2": + version "0.28.2" + resolved "https://registry.npmjs.org/@esbuild/linux-arm64/-/linux-arm64-0.28.2.tgz#1bdbc651cda9ba9995c53ed9c71ceaa65094762d" + integrity sha512-pW4AC0P3it8c7do9MVM4p51FzHzdM/TZrerurgRcHJ2WTa1VQ1CIq18xncfpBJw4ojkiZZrKW2yIBWBP92j6Ug== + +"@esbuild/linux-arm@0.28.2": + version "0.28.2" + resolved "https://registry.npmjs.org/@esbuild/linux-arm/-/linux-arm-0.28.2.tgz#beb12ad72b84f72d28488cc1b8ee9f7eb141d753" + integrity sha512-XlDnu2q5yoqems+xay6wSAcg9DDD7K9RLKZEBOMZm3ckNpJBvOX20tSfby8KfrrhINDyv9V2YVZKY/SpoGJI8w== + +"@esbuild/linux-ia32@0.28.2": + version "0.28.2" + resolved "https://registry.npmjs.org/@esbuild/linux-ia32/-/linux-ia32-0.28.2.tgz#b81f9d55529b45c206a46a138214b1aa6879696b" + integrity sha512-CYbnj78HsIeA+DhgUKgFCfvNsTHFhMMrinUrMZpDXJXKN8T3XViTZ/+wtHeVxEWY8ewSzTFN+nRmSwO2tZaLUQ== + +"@esbuild/linux-loong64@0.28.2": + version "0.28.2" + resolved "https://registry.npmjs.org/@esbuild/linux-loong64/-/linux-loong64-0.28.2.tgz#598667241a04c99b76ed6ef940ac50038c419f98" + integrity sha512-buwkd8nsph4R+ajRvw0qM5Hja/TXQow3ptzWO2EbG/cqcIkHloRrdlBtQlshyYGTNFvfkfJ5tpPLVkY4DtsPfQ== + +"@esbuild/linux-mips64el@0.28.2": + version "0.28.2" + resolved "https://registry.npmjs.org/@esbuild/linux-mips64el/-/linux-mips64el-0.28.2.tgz#1c51eb9cea903f53d97b5af3b1841db70f5596ca" + integrity sha512-ZVykbDyk7519VwiNb9Lcj9m8XM6v5V9uKPvrEMkkEedVewf+0itkhahp4HDpgERXhwLRpWFypsGbG/J8s0QjJA== + +"@esbuild/linux-ppc64@0.28.2": + version "0.28.2" + resolved "https://registry.npmjs.org/@esbuild/linux-ppc64/-/linux-ppc64-0.28.2.tgz#63dd61f17ceb31a81227f413feac8a71bc2c51f2" + integrity sha512-CAXl+Dtd9UUuJd8pKKdwh6MLm3MUMiqMPmhZ3tTSXPqfyQ3vDl6R5hZdZ/kYojK4ofXtdfSv1tFq8XzWx3heNQ== + +"@esbuild/linux-riscv64@0.28.2": + version "0.28.2" + resolved "https://registry.npmjs.org/@esbuild/linux-riscv64/-/linux-riscv64-0.28.2.tgz#3763b08fde5cf25ab1facb8e7752edfe45fbfc27" + integrity sha512-GeXCej4IQtU1B+QlDV8W/RRvbzI3O/Stss+/bCXv4lZls5WGRtu2a+3JkA3i4qIUlMXpcHebWpF8AkJhATowuA== + +"@esbuild/linux-s390x@0.28.2": + version "0.28.2" + resolved "https://registry.npmjs.org/@esbuild/linux-s390x/-/linux-s390x-0.28.2.tgz#1a137ff293a82906eb3176385bd7e8e0e5cfb7cb" + integrity sha512-3H1weTYZPxt/WOhByszQZybS9w5lKzUn1FDMsgEChbHWQwHYQQRfBxgCcZvPhjHfKyJjIievvMmEUawJrdY9Dg== + +"@esbuild/linux-x64@0.28.2": + version "0.28.2" + resolved "https://registry.npmjs.org/@esbuild/linux-x64/-/linux-x64-0.28.2.tgz#268b36211c146ca54f8fe12c578a8d6ef8979485" + integrity sha512-4xTZr1FUmSoQW4XIWmit3tzQrUTZM+N3P0XV8xROKYF50XfI7xeO90+1bZvNwxIufQ9hDQVRJH5YhgPVF8A/HQ== + +"@esbuild/netbsd-arm64@0.28.2": + version "0.28.2" + resolved "https://registry.npmjs.org/@esbuild/netbsd-arm64/-/netbsd-arm64-0.28.2.tgz#22571ad951d62bb6accc82d8d1fad5c8c1ac0ba1" + integrity sha512-sSATRjPeDBg3pdgHoQfoYBob11Kk1FGa9lui5RIHZCoCkJa9QKlvl3/vKz2usCmYYjs7ymJR/2Nnsqe+Hjt5nw== + +"@esbuild/netbsd-x64@0.28.2": + version "0.28.2" + resolved "https://registry.npmjs.org/@esbuild/netbsd-x64/-/netbsd-x64-0.28.2.tgz#42fcc57297eb0a0ca3f5fc475291f4c1a3f7c0de" + integrity sha512-lqnzCV+mM0gIADaKihiCg6ifgfU2L3h5E33rNQBN1Y4MaVGnzryzmvvf7UHxprpQdE8hpqLolJ9Rl+SkIRDpyw== + +"@esbuild/openbsd-arm64@0.28.2": + version "0.28.2" + resolved "https://registry.npmjs.org/@esbuild/openbsd-arm64/-/openbsd-arm64-0.28.2.tgz#9eb32af104ac3dacf4edca01f596664aab0c73ef" + integrity sha512-AL2qJILH7lNjrDmCQDvdxMfAUIv8KMNZOvrwAQ8i8//ntL9FflhOyMJ8OZSMBb8/AWXe3/5v5S20y3zCoZWKoQ== + +"@esbuild/openbsd-x64@0.28.2": + version "0.28.2" + resolved "https://registry.npmjs.org/@esbuild/openbsd-x64/-/openbsd-x64-0.28.2.tgz#febed2402d6088225e91f20fb4ce2522ad0a4efd" + integrity sha512-QtiuPytchRyC4rwUKhexJdQKvDuZ6hWloi3igqPQNUJCS1/v9EiO3UTOXR6A3FoMo4fnAKbWJdqaIwhOzh8qEw== + +"@esbuild/openharmony-arm64@0.28.2": + version "0.28.2" + resolved "https://registry.npmjs.org/@esbuild/openharmony-arm64/-/openharmony-arm64-0.28.2.tgz#85641c3d466428bfbccea5f21c26836663fef5ce" + integrity sha512-WkhYDmpTjLvGlScA1rwjRUmhl4k8oXR3cIbtqWmELgU/dFeHHlEllxDvdWcNJV9rbzCexB5vz8gtNewWLgCT7Q== + +"@esbuild/sunos-x64@0.28.2": + version "0.28.2" + resolved "https://registry.npmjs.org/@esbuild/sunos-x64/-/sunos-x64-0.28.2.tgz#a736f9d8962481045fc4c3e54f5479f22c870fb4" + integrity sha512-GPMSkTOtMnv2U2F8gxe4Io6qmVs+YKyp832Etqqxr0hFngmXQ3rzwytelm3GIn7T4VviRUlf3sOgBOiTdvaf7g== + +"@esbuild/win32-arm64@0.28.2": + version "0.28.2" + resolved "https://registry.npmjs.org/@esbuild/win32-arm64/-/win32-arm64-0.28.2.tgz#ee5ab40fad186201b652a33f8a5eb149e9e42532" + integrity sha512-PIhhEkE9uPBleRBrQEJpUn7MBnibZzbGzYWPmY3x+YoVg/95zbjB4CxPPOQ8l5tYYM4mMaCthF8/1DIfBQQyWQ== + +"@esbuild/win32-ia32@0.28.2": + version "0.28.2" + resolved "https://registry.npmjs.org/@esbuild/win32-ia32/-/win32-ia32-0.28.2.tgz#c40d28a6d99a127da6711f2afd74b11cb63b06a7" + integrity sha512-YmJbfTlvU7Sdn9BB+4PRES4oB6pxgS37MAONj+hBr/cpXS1aBPKXxNnDbu+QCWPj0o9dgyxeq79g6c5P8KeuYA== + +"@esbuild/win32-x64@0.28.2": + version "0.28.2" + resolved "https://registry.npmjs.org/@esbuild/win32-x64/-/win32-x64-0.28.2.tgz#b21affb804cc167c133d95f45b3a1dc1323b9a87" + integrity sha512-5ebpxr3nWMzrL/rnUI755Jkuee0bHL/Gq0WTF9lvcpv73wAp5eu8MfBUgWK9bhWvZjj7yX8etf/8tI8Ney695g== + +"@eslint-community/eslint-utils@^4.8.0", "@eslint-community/eslint-utils@^4.9.1": + version "4.10.1" + resolved "https://registry.npmjs.org/@eslint-community/eslint-utils/-/eslint-utils-4.10.1.tgz#8911bd72b2c3640a543609e0400b8c4d2e7e7cb6" + integrity sha512-cuadcxVFE8sDK6iWJbs8Sn0av2Nrh2QSGQhVlBW9AaAHqHwjWsZHT8LJ4hFGPh7ASBV2deFdM7H/DPjulmh8rg== + dependencies: + eslint-visitor-keys "^3.4.3" + +"@eslint-community/regexpp@^4.12.2": + version "4.12.2" + resolved "https://registry.npmjs.org/@eslint-community/regexpp/-/regexpp-4.12.2.tgz#bccdf615bcf7b6e8db830ec0b8d21c9a25de597b" + integrity sha512-EriSTlt5OC9/7SXkRSCAhfSxxoSUgBm33OH+IkwbdpgoqsSsUg7y3uh+IICI/Qg4BBWr3U2i39RpmycbxMq4ew== + +"@eslint/config-array@^0.23.5": + version "0.23.5" + resolved "https://registry.npmjs.org/@eslint/config-array/-/config-array-0.23.5.tgz#56e86d243049195d8acc0c06a1b3dfdc3fa3de95" + integrity sha512-Y3kKLvC1dvTOT+oGlqNQ1XLqK6D1HU2YXPc52NmAlJZbMMWDzGYXMiPRJ8TYD39muD/OTjlZmNJ4ib7dvSrMBA== + dependencies: + "@eslint/object-schema" "^3.0.5" + debug "^4.3.1" + minimatch "^10.2.4" -"@ipld/car@^5.1.1": - version "5.1.1" - resolved "https://registry.yarnpkg.com/@ipld/car/-/car-5.1.1.tgz#14a26dc97c4783ade491ac811f61885259b9d75e" - integrity sha512-HoFTUqUJL9cPGhC9qRmHCvamfIsj1JllQSQ/Xu9/KN/VNJp8To9Ms4qiZPEMOwcrNFclfYqrahjGYbf4KL/d9A== +"@eslint/config-helpers@^0.7.0": + version "0.7.0" + resolved "https://registry.npmjs.org/@eslint/config-helpers/-/config-helpers-0.7.0.tgz#09ee4aa07b73f059ec2d4c74bf4b2ff02b322377" + integrity sha512-DObd/KKUsU+FaFv4PLxSRenpXfQWmPXXP3pPZ6/K1PCrMu2vQpMDMuQe/BqYeoLcz8ro0bVDF1RxOJgfVEdhUw== dependencies: - "@ipld/dag-cbor" "^9.0.0" - cborg "^1.9.0" - multiformats "^11.0.0" - varint "^6.0.0" + "@eslint/core" "^1.2.1" -"@ipld/dag-cbor@^9.0.0": - version "9.0.1" - resolved "https://registry.yarnpkg.com/@ipld/dag-cbor/-/dag-cbor-9.0.1.tgz#fc7c76af284b74b3a67b003a768d2c4758841272" - integrity sha512-tImDka4akO7cuD24+nRLOU1kYXoai3VZ1cMeWCFUzwhKrRXyOLfVd9RZGI6aTsE/PYvHmkFobKvTeK9NPVtajA== +"@eslint/core@^1.2.1": + version "1.2.1" + resolved "https://registry.npmjs.org/@eslint/core/-/core-1.2.1.tgz#c1da7cd1b82fa8787f98b5629fb811848a1b63ce" + integrity sha512-MwcE1P+AZ4C6DWlpin/OmOA54mmIZ/+xZuJiQd4SyB29oAJjN30UW9wkKNptW2ctp4cEsvhlLY/CsQ1uoHDloQ== dependencies: - cborg "^1.10.0" - multiformats "^11.0.0" + "@types/json-schema" "^7.0.15" -"@ipld/dag-json@^10.0.0": - version "10.1.0" - resolved "https://registry.yarnpkg.com/@ipld/dag-json/-/dag-json-10.1.0.tgz#9cad1628d9ef6df0d732d2d468adb53987d1111d" - integrity sha512-2rSvzDyGxx1NC24IsqKFTSXzAfUBlniZQRT15PEN+i177KEBsCXPfxuN/DweGIfmj3YceNyR8XOJT47pRZu7Cg== - dependencies: - cborg "^1.10.0" - multiformats "^11.0.0" +"@eslint/js@^10.0.1": + version "10.0.1" + resolved "https://registry.npmjs.org/@eslint/js/-/js-10.0.1.tgz#1e8a876f50117af8ab67e47d5ad94d38d6622583" + integrity sha512-zeR9k5pd4gxjZ0abRoIaxdc7I3nDktoXZk2qOv9gCNWx3mVwEn32VRhyLaRsDiJjTs0xq/T8mfPtyuXu7GWBcA== -"@ipld/dag-pb@^4.0.0": - version "4.0.3" - resolved "https://registry.yarnpkg.com/@ipld/dag-pb/-/dag-pb-4.0.3.tgz#2fedd3804ad46ea6206be9302bfed5d3a0af26b3" - integrity sha512-bOe+Z2ZJs9pmP/aIUBYMTdXq0i5z1x71qXeOIIhZvnKFLuzTIbbW0u5b7OfTGzUEbSv1dkUZBIXa7G/+OA8dnA== +"@eslint/object-schema@^3.0.5": + version "3.0.5" + resolved "https://registry.npmjs.org/@eslint/object-schema/-/object-schema-3.0.5.tgz#88e9bf4d11d2b19c082e78ebe7ce88724a5eb091" + integrity sha512-vqTaUEgxzm+YDSdElad6PiRoX4t8VGDjCtt05zn4nU810UIx/uNEV7/lZJ6KwFThKZOzOxzXy48da+No7HZaMw== + +"@eslint/plugin-kit@^0.7.3": + version "0.7.3" + resolved "https://registry.npmjs.org/@eslint/plugin-kit/-/plugin-kit-0.7.3.tgz#cc7268cc36405b331ef92db1bc37971f21d66fe1" + integrity sha512-IkO+/KEUvwbVpiURZg+P7zF74z5Jxe0UgJxVni+RtoHQ6IZieXaO02kmadomap/q+l6bc/jdPGGqTjhuZnuz1Q== dependencies: - multiformats "^11.0.0" + "@eslint/core" "^1.2.1" + levn "^0.4.1" -"@jridgewell/resolve-uri@^3.0.3": - version "3.1.0" - resolved "https://registry.npmjs.org/@jridgewell/resolve-uri/-/resolve-uri-3.1.0.tgz" - integrity sha512-F2msla3tad+Mfht5cJq7LSXcdudKTWCVYUgw6pLFOOHSTtZlj6SWNYAp+AhuqLmWdBO2X5hPrLcu8cVP8fy28w== - -"@jridgewell/sourcemap-codec@^1.4.10": - version "1.4.14" - resolved "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.4.14.tgz" - integrity sha512-XPSJHWmi394fuUuzDnGz1wiKqWfo1yXecHQMRf2l6hztTO+nPru658AyDngaBe7isIxEkRsPR3FZh+s7iVa4Uw== - -"@jridgewell/trace-mapping@0.3.9": - version "0.3.9" - resolved "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.9.tgz" - integrity sha512-3Belt6tdc8bPgAtbcmdtNJlirVoTmEb5e2gC94PnkwEW9jI6CAHUeoG85tjWP5WquqfavoMtMwiG4P926ZKKuQ== - dependencies: - "@jridgewell/resolve-uri" "^3.0.3" - "@jridgewell/sourcemap-codec" "^1.4.10" - -"@libp2p/crypto@^1.0.11": - version "1.0.17" - resolved "https://registry.yarnpkg.com/@libp2p/crypto/-/crypto-1.0.17.tgz#e64043328c0c866bf7f4cc8560b4f483e9c745dc" - integrity sha512-Oeg0Eb/EvAho0gVkOgemXEgrVxWaT3x/DpFgkBdZ9qGxwq75w/E/oPc7souqBz+l1swfz37GWnwV7bIb4Xv5Ag== - dependencies: - "@libp2p/interface-keys" "^1.0.2" - "@libp2p/interfaces" "^3.2.0" - "@noble/ed25519" "^1.6.0" - "@noble/secp256k1" "^1.5.4" - multiformats "^11.0.0" - node-forge "^1.1.0" - protons-runtime "^5.0.0" - uint8arraylist "^2.4.3" - uint8arrays "^4.0.2" - -"@libp2p/interface-connection@^4.0.0": - version "4.0.0" - resolved "https://registry.yarnpkg.com/@libp2p/interface-connection/-/interface-connection-4.0.0.tgz#fcc830ca891820fac89a4c6bd4fcc2df4874f49b" - integrity sha512-6xx/NmEc84HX7QmsjSC3hHredQYjHv4Dkf4G27adAPf+qN+vnPxmQ7gaTnk243a0++DOFTbZ2gKX/15G2B6SRg== +"@humanfs/core@^0.19.2": + version "0.19.2" + resolved "https://registry.npmjs.org/@humanfs/core/-/core-0.19.2.tgz#a8272ca03b2acf492670222b2320b6c421bfde60" + integrity sha512-UhXNm+CFMWcbChXywFwkmhqjs3PRCmcSa/hfBgLIb7oQ5HNb1wS0icWsGtSAUNgefHeI+eBrA8I1fxmbHsGdvA== dependencies: - "@libp2p/interface-peer-id" "^2.0.0" - "@libp2p/interfaces" "^3.0.0" - "@multiformats/multiaddr" "^12.0.0" - it-stream-types "^1.0.4" - uint8arraylist "^2.1.2" + "@humanfs/types" "^0.15.0" -"@libp2p/interface-keychain@^2.0.0": - version "2.0.5" - resolved "https://registry.yarnpkg.com/@libp2p/interface-keychain/-/interface-keychain-2.0.5.tgz#6ce104f38cf07ad72c9dfbe471a689f4ea4b4687" - integrity sha512-mb7QNgn9fIvC7CaJCi06GJ+a6DN6RVT9TmEi0NmedZGATeCArPeWWG7r7IfxNVXb9cVOOE1RzV1swK0ZxEJF9Q== +"@humanfs/node@^0.16.8": + version "0.16.8" + resolved "https://registry.npmjs.org/@humanfs/node/-/node-0.16.8.tgz#8f800cccc13f4f8cd3116e2d9c0a94939da3e3ed" + integrity sha512-gE1eQNZ3R++kTzFUpdGlpmy8kDZD/MLyHqDwqjkVQI0JMdI1D51sy1H958PNXYkM2rAac7e5/CnIKZrHtPh3BQ== dependencies: - "@libp2p/interface-peer-id" "^2.0.0" - multiformats "^11.0.0" + "@humanfs/core" "^0.19.2" + "@humanfs/types" "^0.15.0" + "@humanwhocodes/retry" "^0.4.0" -"@libp2p/interface-keys@^1.0.2": - version "1.0.8" - resolved "https://registry.yarnpkg.com/@libp2p/interface-keys/-/interface-keys-1.0.8.tgz#2c6b55136113ae7cf78133d3c459cdf0455b29ae" - integrity sha512-CJ1SlrwuoHMquhEEWS77E+4vv7hwB7XORkqzGQrPQmA9MRdIEZRS64bA4JqCLUDa4ltH0l+U1vp0oZHLT67NEA== +"@humanfs/types@^0.15.0": + version "0.15.0" + resolved "https://registry.npmjs.org/@humanfs/types/-/types-0.15.0.tgz#f2a09f62012390b2bff3fc6fb248ddec8c09a090" + integrity sha512-ZZ1w0aoQkwuUuC7Yf+7sdeaNfqQiiLcSRbfI08oAxqLtpXQr9AIVX7Ay7HLDuiLYAaFPu8oBYNq/QIi9URHJ3Q== -"@libp2p/interface-peer-id@^2.0.0", "@libp2p/interface-peer-id@^2.0.2": - version "2.0.2" - resolved "https://registry.yarnpkg.com/@libp2p/interface-peer-id/-/interface-peer-id-2.0.2.tgz#6302e70b6fc17c451bc3daa11447d059357bcc32" - integrity sha512-9pZp9zhTDoVwzRmp0Wtxw0Yfa//Yc0GqBCJi3EznBDE6HGIAVvppR91wSh2knt/0eYg0AQj7Y35VSesUTzMCUg== - dependencies: - multiformats "^11.0.0" +"@humanwhocodes/module-importer@^1.0.1": + version "1.0.1" + resolved "https://registry.npmjs.org/@humanwhocodes/module-importer/-/module-importer-1.0.1.tgz#af5b2691a22b44be847b0ca81641c5fb6ad0172c" + integrity sha512-bxveV4V8v5Yb4ncFTT3rPSgZBOpCkjfK0y4oVVVJwIuDVBRMDXrPyXRL988i5ap9m9bnyEEjWfm5WkBmtffLfA== -"@libp2p/interface-peer-info@^1.0.2": - version "1.0.10" - resolved "https://registry.yarnpkg.com/@libp2p/interface-peer-info/-/interface-peer-info-1.0.10.tgz#566026de95a0817b9e853c982b313541b7960c0b" - integrity sha512-HQlo8NwQjMyamCHJrnILEZz+YwEOXCB2sIIw3slIrhVUYeYlTaia1R6d9umaAeLHa255Zmdm4qGH8rJLRqhCcg== - dependencies: - "@libp2p/interface-peer-id" "^2.0.0" - "@multiformats/multiaddr" "^12.0.0" +"@humanwhocodes/retry@^0.4.0", "@humanwhocodes/retry@^0.4.2": + version "0.4.3" + resolved "https://registry.npmjs.org/@humanwhocodes/retry/-/retry-0.4.3.tgz#c2b9d2e374ee62c586d3adbea87199b1d7a7a6ba" + integrity sha512-bV0Tgo9K4hfPCek+aMAn81RppFKv2ySDQeMoSZuvTASywNTnVJCArCZE2FWqpvIatKu7VMRLWlR1EazvVhDyhQ== -"@libp2p/interface-pubsub@^3.0.0": - version "3.0.7" - resolved "https://registry.yarnpkg.com/@libp2p/interface-pubsub/-/interface-pubsub-3.0.7.tgz#cc1c7c47c883daddd2b84d83d719b3826943be3b" - integrity sha512-+c74EVUBTfw2sx1GE/z/IjsYO6dhur+ukF0knAppeZsRQ1Kgg6K5R3eECtT28fC6dBWLjFpAvW/7QGfiDAL4RA== - dependencies: - "@libp2p/interface-connection" "^4.0.0" - "@libp2p/interface-peer-id" "^2.0.0" - "@libp2p/interfaces" "^3.0.0" - it-pushable "^3.0.0" - uint8arraylist "^2.1.2" - -"@libp2p/interfaces@^3.0.0", "@libp2p/interfaces@^3.2.0", "@libp2p/interfaces@^3.3.1": - version "3.3.2" - resolved "https://registry.yarnpkg.com/@libp2p/interfaces/-/interfaces-3.3.2.tgz#5d8079be845b0960939b5b18880e785a4714465a" - integrity sha512-p/M7plbrxLzuQchvNwww1Was7ZeGE2NaOFulMaZBYIihU8z3fhaV+a033OqnC/0NTX/yhfdNOG7znhYq3XoR/g== - -"@libp2p/logger@^2.0.0": - version "2.0.7" - resolved "https://registry.yarnpkg.com/@libp2p/logger/-/logger-2.0.7.tgz#9a3996242b4a9edb8a9d825c8accaf62f617c5c6" - integrity sha512-Zp9C9lMNGfVFTMVc7NvxuxMvIE6gyxDapQc/TqZH02IuIDl1JpZyCgNILr0APd8wcUxwvwRXYNf3kQ0Lmz7tuQ== - dependencies: - "@libp2p/interface-peer-id" "^2.0.0" - debug "^4.3.3" - interface-datastore "^8.0.0" - multiformats "^11.0.0" - -"@libp2p/logger@^2.0.5": - version "2.1.1" - resolved "https://registry.yarnpkg.com/@libp2p/logger/-/logger-2.1.1.tgz#e12e6c320ea64252af954bcec996895098d1cd36" - integrity sha512-2UbzDPctg3cPupF6jrv6abQnAUTrbLybNOj0rmmrdGm1cN2HJ1o/hBu0sXuq4KF9P1h/eVRn1HIRbVIEKnEJrA== - dependencies: - "@libp2p/interface-peer-id" "^2.0.2" - "@multiformats/multiaddr" "^12.1.3" - debug "^4.3.4" - interface-datastore "^8.2.0" - multiformats "^11.0.2" +"@inquirer/ansi@^1.0.2": + version "1.0.2" + resolved "https://registry.npmjs.org/@inquirer/ansi/-/ansi-1.0.2.tgz#674a4c4d81ad460695cb2a1fc69d78cd187f337e" + integrity sha512-S8qNSZiYzFd0wAcyG5AXCvUHC5Sr7xpZ9wZ2py9XR88jUz8wooStVx5M6dRzczbBWjic9NP7+rY0Xi7qqK/aMQ== + +"@inquirer/checkbox@^4.3.2": + version "4.3.2" + resolved "https://registry.npmjs.org/@inquirer/checkbox/-/checkbox-4.3.2.tgz#e1483e6519d6ffef97281a54d2a5baa0d81b3f3b" + integrity sha512-VXukHf0RR1doGe6Sm4F0Em7SWYLTHSsbGfJdS9Ja2bX5/D5uwVOEjr07cncLROdBvmnvCATYEWlHqYmXv2IlQA== + dependencies: + "@inquirer/ansi" "^1.0.2" + "@inquirer/core" "^10.3.2" + "@inquirer/figures" "^1.0.15" + "@inquirer/type" "^3.0.10" + yoctocolors-cjs "^2.1.3" + +"@inquirer/confirm@^5.1.21": + version "5.1.21" + resolved "https://registry.npmjs.org/@inquirer/confirm/-/confirm-5.1.21.tgz#610c4acd7797d94890a6e2dde2c98eb1e891dd12" + integrity sha512-KR8edRkIsUayMXV+o3Gv+q4jlhENF9nMYUZs9PA2HzrXeHI8M5uDag70U7RJn9yyiMZSbtF5/UexBtAVtZGSbQ== + dependencies: + "@inquirer/core" "^10.3.2" + "@inquirer/type" "^3.0.10" + +"@inquirer/core@^10.3.2": + version "10.3.2" + resolved "https://registry.npmjs.org/@inquirer/core/-/core-10.3.2.tgz#535979ff3ff4fe1e7cc4f83e2320504c743b7e20" + integrity sha512-43RTuEbfP8MbKzedNqBrlhhNKVwoK//vUFNW3Q3vZ88BLcrs4kYpGg+B2mm5p2K/HfygoCxuKwJJiv8PbGmE0A== + dependencies: + "@inquirer/ansi" "^1.0.2" + "@inquirer/figures" "^1.0.15" + "@inquirer/type" "^3.0.10" + cli-width "^4.1.0" + mute-stream "^2.0.0" + signal-exit "^4.1.0" + wrap-ansi "^6.2.0" + yoctocolors-cjs "^2.1.3" + +"@inquirer/editor@^4.2.23": + version "4.2.23" + resolved "https://registry.npmjs.org/@inquirer/editor/-/editor-4.2.23.tgz#fe046a3bfdae931262de98c1052437d794322e0b" + integrity sha512-aLSROkEwirotxZ1pBaP8tugXRFCxW94gwrQLxXfrZsKkfjOYC1aRvAZuhpJOb5cu4IBTJdsCigUlf2iCOu4ZDQ== + dependencies: + "@inquirer/core" "^10.3.2" + "@inquirer/external-editor" "^1.0.3" + "@inquirer/type" "^3.0.10" + +"@inquirer/expand@^4.0.23": + version "4.0.23" + resolved "https://registry.npmjs.org/@inquirer/expand/-/expand-4.0.23.tgz#a38b5f32226d75717c370bdfed792313b92bdc05" + integrity sha512-nRzdOyFYnpeYTTR2qFwEVmIWypzdAx/sIkCMeTNTcflFOovfqUk+HcFhQQVBftAh9gmGrpFj6QcGEqrDMDOiew== + dependencies: + "@inquirer/core" "^10.3.2" + "@inquirer/type" "^3.0.10" + yoctocolors-cjs "^2.1.3" + +"@inquirer/external-editor@^1.0.3": + version "1.0.3" + resolved "https://registry.npmjs.org/@inquirer/external-editor/-/external-editor-1.0.3.tgz#c23988291ee676290fdab3fd306e64010a6d13b8" + integrity sha512-RWbSrDiYmO4LbejWY7ttpxczuwQyZLBUyygsA9Nsv95hpzUWwnNTVQmAq3xuh7vNwCp07UTmE5i11XAEExx4RA== + dependencies: + chardet "^2.1.1" + iconv-lite "^0.7.0" + +"@inquirer/figures@^1.0.15": + version "1.0.15" + resolved "https://registry.npmjs.org/@inquirer/figures/-/figures-1.0.15.tgz#dbb49ed80df11df74268023b496ac5d9acd22b3a" + integrity sha512-t2IEY+unGHOzAaVM5Xx6DEWKeXlDDcNPeDyUpsRc6CUhBfU3VQOEl+Vssh7VNp1dR8MdUJBWhuObjXCsVpjN5g== + +"@inquirer/input@^4.3.1": + version "4.3.1" + resolved "https://registry.npmjs.org/@inquirer/input/-/input-4.3.1.tgz#778683b4c4c4d95d05d4b05c4a854964b73565b4" + integrity sha512-kN0pAM4yPrLjJ1XJBjDxyfDduXOuQHrBB8aLDMueuwUGn+vNpF7Gq7TvyVxx8u4SHlFFj4trmj+a2cbpG4Jn1g== + dependencies: + "@inquirer/core" "^10.3.2" + "@inquirer/type" "^3.0.10" + +"@inquirer/number@^3.0.23": + version "3.0.23" + resolved "https://registry.npmjs.org/@inquirer/number/-/number-3.0.23.tgz#3fdec2540d642093fd7526818fd8d4bdc7335094" + integrity sha512-5Smv0OK7K0KUzUfYUXDXQc9jrf8OHo4ktlEayFlelCjwMXz0299Y8OrI+lj7i4gCBY15UObk76q0QtxjzFcFcg== + dependencies: + "@inquirer/core" "^10.3.2" + "@inquirer/type" "^3.0.10" + +"@inquirer/password@^4.0.23": + version "4.0.23" + resolved "https://registry.npmjs.org/@inquirer/password/-/password-4.0.23.tgz#b9f5187c8c92fd7aa9eceb9d8f2ead0d7e7b000d" + integrity sha512-zREJHjhT5vJBMZX/IUbyI9zVtVfOLiTO66MrF/3GFZYZ7T4YILW5MSkEYHceSii/KtRk+4i3RE7E1CUXA2jHcA== + dependencies: + "@inquirer/ansi" "^1.0.2" + "@inquirer/core" "^10.3.2" + "@inquirer/type" "^3.0.10" + +"@inquirer/prompts@^7.10.1": + version "7.10.1" + resolved "https://registry.npmjs.org/@inquirer/prompts/-/prompts-7.10.1.tgz#e1436c0484cf04c22548c74e2cd239e989d5f847" + integrity sha512-Dx/y9bCQcXLI5ooQ5KyvA4FTgeo2jYj/7plWfV5Ak5wDPKQZgudKez2ixyfz7tKXzcJciTxqLeK7R9HItwiByg== + dependencies: + "@inquirer/checkbox" "^4.3.2" + "@inquirer/confirm" "^5.1.21" + "@inquirer/editor" "^4.2.23" + "@inquirer/expand" "^4.0.23" + "@inquirer/input" "^4.3.1" + "@inquirer/number" "^3.0.23" + "@inquirer/password" "^4.0.23" + "@inquirer/rawlist" "^4.1.11" + "@inquirer/search" "^3.2.2" + "@inquirer/select" "^4.4.2" + +"@inquirer/rawlist@^4.1.11": + version "4.1.11" + resolved "https://registry.npmjs.org/@inquirer/rawlist/-/rawlist-4.1.11.tgz#313c8c3ffccb7d41e990c606465726b4a898a033" + integrity sha512-+LLQB8XGr3I5LZN/GuAHo+GpDJegQwuPARLChlMICNdwW7OwV2izlCSCxN6cqpL0sMXmbKbFcItJgdQq5EBXTw== + dependencies: + "@inquirer/core" "^10.3.2" + "@inquirer/type" "^3.0.10" + yoctocolors-cjs "^2.1.3" + +"@inquirer/search@^3.2.2": + version "3.2.2" + resolved "https://registry.npmjs.org/@inquirer/search/-/search-3.2.2.tgz#4cc6fd574dcd434e4399badc37c742c3fd534ac8" + integrity sha512-p2bvRfENXCZdWF/U2BXvnSI9h+tuA8iNqtUKb9UWbmLYCRQxd8WkvwWvYn+3NgYaNwdUkHytJMGG4MMLucI1kA== + dependencies: + "@inquirer/core" "^10.3.2" + "@inquirer/figures" "^1.0.15" + "@inquirer/type" "^3.0.10" + yoctocolors-cjs "^2.1.3" + +"@inquirer/select@^4.4.2": + version "4.4.2" + resolved "https://registry.npmjs.org/@inquirer/select/-/select-4.4.2.tgz#2ac8fca960913f18f1d1b35323ed8fcd27d89323" + integrity sha512-l4xMuJo55MAe+N7Qr4rX90vypFwCajSakx59qe/tMaC1aEHWLyw68wF4o0A4SLAY4E0nd+Vt+EyskeDIqu1M6w== + dependencies: + "@inquirer/ansi" "^1.0.2" + "@inquirer/core" "^10.3.2" + "@inquirer/figures" "^1.0.15" + "@inquirer/type" "^3.0.10" + yoctocolors-cjs "^2.1.3" + +"@inquirer/type@^3.0.10": + version "3.0.10" + resolved "https://registry.npmjs.org/@inquirer/type/-/type-3.0.10.tgz#11ed564ec78432a200ea2601a212d24af8150d50" + integrity sha512-BvziSRxfz5Ov8ch0z/n3oijRSEcEsHnhggm4xFZe93DHcUCTlutlq9Ox4SVENAfcRD22UQq7T/atg9Wr3k09eA== + +"@isaacs/nonrecursive-glob-match@^1.0.3": + version "1.0.3" + resolved "https://registry.npmjs.org/@isaacs/nonrecursive-glob-match/-/nonrecursive-glob-match-1.0.3.tgz#7f6724fd8a6ca315d6bb7f63f0e4d079060da246" + integrity sha512-SI7kyKHq4XXDRozw+r9GlRZkia1ZkFrpLW98r2IC2Bpr8YkFGE3fvjzmxCG0x78A++69HmDNrDvSMYBZmHGpKA== -"@libp2p/peer-id@^2.0.0": - version "2.0.3" - resolved "https://registry.yarnpkg.com/@libp2p/peer-id/-/peer-id-2.0.3.tgz#7299d74eae7b2526123d941bdb2d08462704c79a" - integrity sha512-eZX+5ByUAzh8DrfjCan0spZGpvF7SxEBz4tOPoBMBCuKJJLr+8EokBO/5E3ceIw04f5+lAcD3CO3bccuKomp3Q== - dependencies: - "@libp2p/interface-peer-id" "^2.0.0" - "@libp2p/interfaces" "^3.2.0" - multiformats "^11.0.0" - uint8arrays "^4.0.2" - -"@multiformats/mafmt@^11.0.3": - version "11.1.2" - resolved "https://registry.yarnpkg.com/@multiformats/mafmt/-/mafmt-11.1.2.tgz#c03ef4022c795b7f230b136f2f974fc263eac4f1" - integrity sha512-3n1o5eLU7WzTAPLuz3AodV7Iql6NWf7Ws8fqVaGT7o5nDDabUPYGBm2cZuh3OrqmwyCY61LrNUIsjzivU6UdpQ== - dependencies: - "@multiformats/multiaddr" "^12.0.0" - -"@multiformats/multiaddr-to-uri@^9.0.1": - version "9.0.7" - resolved "https://registry.yarnpkg.com/@multiformats/multiaddr-to-uri/-/multiaddr-to-uri-9.0.7.tgz#44881352b1d9d98b53451982cd433f0f45ad7e24" - integrity sha512-i3ldtPMN6XJt+MCi34hOl0wGuGEHfWWMw6lmNag5BpckPwPTf9XGOOFMmh7ed/uO3Vjah/g173iOe61HTQVoBA== - dependencies: - "@multiformats/multiaddr" "^12.0.0" - -"@multiformats/multiaddr@^11.0.0", "@multiformats/multiaddr@^11.1.5": - version "11.6.1" - resolved "https://registry.yarnpkg.com/@multiformats/multiaddr/-/multiaddr-11.6.1.tgz#ec46984a298e715e27a398434c087856db5f3185" - integrity sha512-doST0+aB7/3dGK9+U5y3mtF3jq85KGbke1QiH0KE1F5mGQ9y56mFebTeu2D9FNOm+OT6UHb8Ss8vbSnpGjeLNw== - dependencies: - "@chainsafe/is-ip" "^2.0.1" - dns-over-http-resolver "^2.1.0" - err-code "^3.0.1" - multiformats "^11.0.0" - uint8arrays "^4.0.2" - varint "^6.0.0" - -"@multiformats/multiaddr@^12.0.0", "@multiformats/multiaddr@^12.1.3": - version "12.1.3" - resolved "https://registry.yarnpkg.com/@multiformats/multiaddr/-/multiaddr-12.1.3.tgz#aff5aa61ec19c5320f0b756e88c3bbaac8d1c7af" - integrity sha512-rNcS3njkkSwuGF4x58L47jGH5kBXBfJPNsWnrt0gujhNYn6ReDt1je7vEU5/ddrVj0TStgxw+Hm+TkYDK0b60w== - dependencies: - "@chainsafe/is-ip" "^2.0.1" - "@chainsafe/netmask" "^2.0.0" - "@libp2p/interfaces" "^3.3.1" - dns-over-http-resolver "^2.1.0" - multiformats "^11.0.0" - uint8arrays "^4.0.2" - varint "^6.0.0" - -"@multiformats/murmur3@^2.0.0": - version "2.1.4" - resolved "https://registry.yarnpkg.com/@multiformats/murmur3/-/murmur3-2.1.4.tgz#e93cce560c381f8326b2271facf2ea04f6fd8a66" - integrity sha512-qHHmZKD1Dy6PDi35pAowE1pQtnH7gwaJpUE/Ju+cOYVdWD4T8VVtKAumGCxwd31JKyNC0W1IzAaHQz1dnXXvBw== +"@keyv/bigmap@^1.3.1": + version "1.3.1" + resolved "https://registry.npmjs.org/@keyv/bigmap/-/bigmap-1.3.1.tgz#fc82fa83947e7ff68c6798d08907db842771ef2c" + integrity sha512-WbzE9sdmQtKy8vrNPa9BRnwZh5UF4s1KTmSK0KUVLo3eff5BlQNNWDnFOouNpKfPKDnms9xynJjsMYjMaT/aFQ== dependencies: - multiformats "^11.0.0" - murmurhash3js-revisited "^3.0.0" + hashery "^1.4.0" + hookified "^1.15.0" + +"@keyv/serialize@^1.1.1": + version "1.1.1" + resolved "https://registry.npmjs.org/@keyv/serialize/-/serialize-1.1.1.tgz#0c01dd3a3483882af7cf3878d4e71d505c81fc4a" + integrity sha512-dXn3FZhPv0US+7dtJsIi2R+c7qWYiReoEh5zUntWCf4oSpMNib8FDhSoed6m3QyZdx5hK7iLFkYk3rNxwt8vTA== "@noble/curves@1.2.0": version "1.2.0" - resolved "https://registry.yarnpkg.com/@noble/curves/-/curves-1.2.0.tgz#92d7e12e4e49b23105a2555c6984d41733d65c35" + resolved "https://registry.npmjs.org/@noble/curves/-/curves-1.2.0.tgz#92d7e12e4e49b23105a2555c6984d41733d65c35" integrity sha512-oYclrNgRaM9SsBUBVbb8M6DTV7ZHRTKugureoYEncY5c65HOmRzvSiTE3y5CYaPYJA/GVkrhXEoF0M3Ya9PMnw== dependencies: "@noble/hashes" "1.3.2" -"@noble/ed25519@^1.6.0": - version "1.7.3" - resolved "https://registry.yarnpkg.com/@noble/ed25519/-/ed25519-1.7.3.tgz#57e1677bf6885354b466c38e2b620c62f45a7123" - integrity sha512-iR8GBkDt0Q3GyaVcIu7mSsVIqnFbkbRzGLWlvhwunacoLwt4J3swfKhfaM6rN6WY+TBGoYT1GtT1mIh2/jGbRQ== - -"@noble/hashes@1.1.2": - version "1.1.2" - resolved "https://registry.yarnpkg.com/@noble/hashes/-/hashes-1.1.2.tgz#e9e035b9b166ca0af657a7848eb2718f0f22f183" - integrity sha512-KYRCASVTv6aeUi1tsF8/vpyR7zpfs3FUzy2Jqm+MU+LmUKhQ0y2FpfwqkCcxSg2ua4GALJd8k2R76WxwZGbQpA== - "@noble/hashes@1.3.2": version "1.3.2" - resolved "https://registry.yarnpkg.com/@noble/hashes/-/hashes-1.3.2.tgz#6f26dbc8fbc7205873ce3cee2f690eba0d421b39" + resolved "https://registry.npmjs.org/@noble/hashes/-/hashes-1.3.2.tgz#6f26dbc8fbc7205873ce3cee2f690eba0d421b39" integrity sha512-MVC8EAQp7MvEcm30KWENFjgR+Mkmf+D189XJTkFIlwohU5hcBbn1ZkKq7KVTi2Hme3PMGF390DaL52beVrIihQ== -"@noble/secp256k1@1.7.1", "@noble/secp256k1@^1.5.4": - version "1.7.1" - resolved "https://registry.yarnpkg.com/@noble/secp256k1/-/secp256k1-1.7.1.tgz#b251c70f824ce3ca7f8dc3df08d58f005cc0507c" - integrity sha512-hOUk6AyBFmqVrv7k5WAw/LpszxVbj9gGN4JRkIX52fdFAj1UA61KXmZDvqVEm+pOyec3+fIeZB02LYa/pWOArw== - -"@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/core@^5.0.2": - 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": +"@octokit/auth-token@^6.0.0": + version "6.0.0" + resolved "https://registry.npmjs.org/@octokit/auth-token/-/auth-token-6.0.0.tgz#b02e9c08a2d8937df09a2a981f226ad219174c53" + integrity sha512-P4YJBPdPSpWTQ1NU4XYdvHvXJJDxM6YwpS0FZHRgP7YFkdVxsWcpWGy/NVqlAA7PcPCnMacXlRm1y2PFZRWL/w== + +"@octokit/core@^7.0.6": + version "7.0.8" + resolved "https://registry.npmjs.org/@octokit/core/-/core-7.0.8.tgz#bc8c05bc3a0200d1f453d4fe59c9053a7446c9f3" + integrity sha512-L7y8eYc+AwxGr2PWI4WFt1VG4TiJ66c26BD16mXpYIlXxG0SMigM1+m4aTSlYyBr5BlQsGAlz8uDCoZN4SEMcg== + dependencies: + "@octokit/auth-token" "^6.0.0" + "@octokit/graphql" "^9.0.5" + "@octokit/request" "^10.0.16" + "@octokit/request-error" "^7.1.2" + "@octokit/types" "^18.0.0" + before-after-hook "^4.0.0" + universal-user-agent "^7.0.0" + +"@octokit/endpoint@^11.0.5": + version "11.0.5" + resolved "https://registry.npmjs.org/@octokit/endpoint/-/endpoint-11.0.5.tgz#d7ec88843bfeeea692fee97b52e7c2cdc0393db4" + integrity sha512-iXa654H3yFafF/ieHkukfbgWo2rmXD2ceD0ZOtrPhw1bc3FDch1d9N/TNs0FQ1/cIbwb7kspUX8jzIs8nzb9DQ== + dependencies: + "@octokit/types" "^18.0.0" + universal-user-agent "^7.0.2" + +"@octokit/graphql@^9.0.5": version "9.0.5" - resolved "https://registry.yarnpkg.com/@octokit/endpoint/-/endpoint-9.0.5.tgz#e6c0ee684e307614c02fc6ac12274c50da465c44" - integrity sha512-ekqR4/+PCLkEBF6qgj8WqJfvDq65RH85OAgrtnVp1mSxaXF03u2xW/hUdweGS5654IlC0wkNYC18Z50tSYTAFw== + resolved "https://registry.npmjs.org/@octokit/graphql/-/graphql-9.0.5.tgz#da0bc3584d79f958e5373b5ed1e98425ca5efdc0" + integrity sha512-bt/hm03LeU6Vy7FwTrkkC9p3XGT/lBwClglMqxBSe5/q0E5CdJTXeAqEI0vlw89/LF/G6tryTIH8HirZ3prMVg== dependencies: - "@octokit/types" "^13.1.0" - universal-user-agent "^6.0.0" + "@octokit/request" "^10.0.16" + "@octokit/types" "^18.0.0" + universal-user-agent "^7.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/openapi-types@^27.0.0": + version "27.0.0" + resolved "https://registry.npmjs.org/@octokit/openapi-types/-/openapi-types-27.0.0.tgz#374ea53781965fd02a9d36cacb97e152cefff12d" + integrity sha512-whrdktVs1h6gtR+09+QsNk2+FO+49j6ga1c55YZudfEG+oKJVvJLQi3zkOm5JjiUXAagWK2tI2kTGKJ2Ys7MGA== -"@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/openapi-types@^29.0.1": + version "29.0.1" + resolved "https://registry.npmjs.org/@octokit/openapi-types/-/openapi-types-29.0.1.tgz#05895cc8ae328058e7af75b608c4c97f0bc1bc00" + integrity sha512-9qWOMFNxxLokERcms42rU0PTLqQmVs7g5E41TI4mCOxmpFayD1rfC7XxOL55cG9MBZLFlC31BrR37myMKardwg== -"@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== +"@octokit/plugin-paginate-rest@^14.0.0": + version "14.0.0" + resolved "https://registry.npmjs.org/@octokit/plugin-paginate-rest/-/plugin-paginate-rest-14.0.0.tgz#44dc9fff2dacb148d4c5c788b573ddc044503026" + integrity sha512-fNVRE7ufJiAA3XUrha2omTA39M6IXIc6GIZLvlbsm8QOQCYvpq/LkMNGyFlB1d8hTDzsAXa3OKtybdMAYsV/fw== dependencies: - "@octokit/types" "^13.5.0" + "@octokit/types" "^16.0.0" -"@octokit/plugin-request-log@^4.0.0": - version "4.0.1" - resolved "https://registry.yarnpkg.com/@octokit/plugin-request-log/-/plugin-request-log-4.0.1.tgz#98a3ca96e0b107380664708111864cb96551f958" - integrity sha512-GihNqNpGHorUrO7Qa9JbAl0dbLnqJVrV8OXe2Zm5/Y4wFkZQDfTreBzVmiRfJVfE4mClXdihHnbpyyO9FSX4HA== +"@octokit/plugin-request-log@^6.0.0": + version "6.0.0" + resolved "https://registry.npmjs.org/@octokit/plugin-request-log/-/plugin-request-log-6.0.0.tgz#de1c1e557df6c08adb631bf78264fa741e01b317" + integrity sha512-UkOzeEN3W91/eBq9sPZNQ7sUBvYCqYbrrD8gTbBuGtHEuycE4/awMXcYvx6sVYo7LypPhmQwwpUe4Yyu4QZN5Q== -"@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== +"@octokit/plugin-rest-endpoint-methods@^17.0.0": + version "17.0.0" + resolved "https://registry.npmjs.org/@octokit/plugin-rest-endpoint-methods/-/plugin-rest-endpoint-methods-17.0.0.tgz#8c54397d3a4060356a1c8a974191ebf945924105" + integrity sha512-B5yCyIlOJFPqUUeiD0cnBJwWJO8lkJs5d8+ze9QDP6SvfiXSz1BF+91+0MeI1d2yxgOhU/O+CvtiZ9jSkHhFAw== dependencies: - "@octokit/types" "^13.5.0" + "@octokit/types" "^16.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== +"@octokit/request-error@^7.1.2": + version "7.1.2" + resolved "https://registry.npmjs.org/@octokit/request-error/-/request-error-7.1.2.tgz#0477f3ec1034869205f8bd80560f2bc55b659973" + integrity sha512-XZRuT3xZ84D3gYErI1DZvhJ33dCWVV6uzBtWkaBB4TvA/L6eOeTZodxLFVB44bBEEo3vEx7y00UfX1tBLrtLRg== dependencies: - "@octokit/types" "^13.1.0" - deprecation "^2.0.0" - once "^1.4.0" + "@octokit/types" "^18.0.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== +"@octokit/request@^10.0.16": + version "10.0.16" + resolved "https://registry.npmjs.org/@octokit/request/-/request-10.0.16.tgz#b548f8f848ffe4ccf5082142fac096fe7b8222b2" + integrity sha512-A0zWGjHzISIb+9ccG8s0dq7LKO5zVpJLRICjgUb+sJxEWqn8RUHB1rD3AE51+PECvXHIxqZ1VVvs4fHTSD9nUQ== dependencies: - "@octokit/endpoint" "^9.0.1" - "@octokit/request-error" "^5.1.0" - "@octokit/types" "^13.1.0" - universal-user-agent "^6.0.0" + "@octokit/endpoint" "^11.0.5" + "@octokit/request-error" "^7.1.2" + "@octokit/types" "^18.0.0" + content-type "^3.0.0" + json-with-bigint "^3.5.12" + universal-user-agent "^7.0.2" -"@octokit/rest@^20.1.1": - version "20.1.1" - resolved "https://registry.yarnpkg.com/@octokit/rest/-/rest-20.1.1.tgz#ec775864f53fb42037a954b9a40d4f5275b3dc95" - integrity sha512-MB4AYDsM5jhIHro/dq4ix1iWTLGToIGk6cWF5L6vanFaMble5jTX/UBQyiv05HsWnwUtY8JrfHy2LWfKwihqMw== +"@octokit/rest@^22.0.1": + version "22.0.1" + resolved "https://registry.npmjs.org/@octokit/rest/-/rest-22.0.1.tgz#4d866c32b76b711d3f736f91992e2b534163b416" + integrity sha512-Jzbhzl3CEexhnivb1iQ0KJ7s5vvjMWcmRtq5aUsKmKDrRW6z3r84ngmiFKFvpZjpiU/9/S6ITPFRpn5s/3uQJw== dependencies: - "@octokit/core" "^5.0.2" - "@octokit/plugin-paginate-rest" "11.3.1" - "@octokit/plugin-request-log" "^4.0.0" - "@octokit/plugin-rest-endpoint-methods" "13.2.2" + "@octokit/core" "^7.0.6" + "@octokit/plugin-paginate-rest" "^14.0.0" + "@octokit/plugin-request-log" "^6.0.0" + "@octokit/plugin-rest-endpoint-methods" "^17.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== +"@octokit/types@^16.0.0": + version "16.0.0" + resolved "https://registry.npmjs.org/@octokit/types/-/types-16.0.0.tgz#fbd7fa590c2ef22af881b1d79758bfaa234dbb7c" + integrity sha512-sKq+9r1Mm4efXW1FCk7hFSeJo4QKreL/tTbR0rz/qx/r1Oa2VV83LTA/H/MuCOX7uCIJmQVRKBcbmWoySjAnSg== dependencies: - "@octokit/openapi-types" "^22.2.0" + "@octokit/openapi-types" "^27.0.0" -"@protobufjs/aspromise@^1.1.1", "@protobufjs/aspromise@^1.1.2": - version "1.1.2" - resolved "https://registry.yarnpkg.com/@protobufjs/aspromise/-/aspromise-1.1.2.tgz#9b8b0cc663d669a7d8f6f5d0893a14d348f30fbf" - integrity sha512-j+gKExEuLmKwvz3OgROXtrJ2UG2x8Ch2YZUxahh+s1F2HZ+wAceUNLkvy6zKCPVRkU++ZWQrdxsUeQXmcg4uoQ== - -"@protobufjs/base64@^1.1.2": - version "1.1.2" - resolved "https://registry.yarnpkg.com/@protobufjs/base64/-/base64-1.1.2.tgz#4c85730e59b9a1f1f349047dbf24296034bb2735" - integrity sha512-AZkcAA5vnN/v4PDqKyMR5lx7hZttPDgClv83E//FMNhR2TMcLUhfRUBHCmSl0oi9zMgDDqRUJkSxO3wm85+XLg== - -"@protobufjs/codegen@^2.0.4": - version "2.0.4" - resolved "https://registry.yarnpkg.com/@protobufjs/codegen/-/codegen-2.0.4.tgz#7ef37f0d010fb028ad1ad59722e506d9262815cb" - integrity sha512-YyFaikqM5sH0ziFZCN3xDC7zeGaB/d0IUb9CATugHWbd1FRFwWwt4ld4OYMPWu5a3Xe01mGAULCdqhMlPl29Jg== - -"@protobufjs/eventemitter@^1.1.0": - version "1.1.0" - resolved "https://registry.yarnpkg.com/@protobufjs/eventemitter/-/eventemitter-1.1.0.tgz#355cbc98bafad5978f9ed095f397621f1d066b70" - integrity sha512-j9ednRT81vYJ9OfVuXG6ERSTdEL1xVsNgqpkxMsbIabzSo3goCjDIveeGv5d03om39ML71RdmrGNjG5SReBP/Q== - -"@protobufjs/fetch@^1.1.0": - version "1.1.0" - resolved "https://registry.yarnpkg.com/@protobufjs/fetch/-/fetch-1.1.0.tgz#ba99fb598614af65700c1619ff06d454b0d84c45" - integrity sha512-lljVXpqXebpsijW71PZaCYeIcE5on1w5DlQy5WH6GLbFryLUrBD4932W/E2BSpfRJWseIL4v/KPgBFxDOIdKpQ== +"@octokit/types@^18.0.0": + version "18.0.0" + resolved "https://registry.npmjs.org/@octokit/types/-/types-18.0.0.tgz#763eeebafb488d8ea8a8322eafb2d9b1885d2844" + integrity sha512-l6bAF43PNxkJp6g+W4PjoUSSkxHomXw2nOum5CTftJz1NlV3vu93NImgOYtLf6CbBUb5j+fiuzW0PPQ5JTSvZA== dependencies: - "@protobufjs/aspromise" "^1.1.1" - "@protobufjs/inquire" "^1.1.0" - -"@protobufjs/float@^1.0.2": - version "1.0.2" - resolved "https://registry.yarnpkg.com/@protobufjs/float/-/float-1.0.2.tgz#5e9e1abdcb73fc0a7cb8b291df78c8cbd97b87d1" - integrity sha512-Ddb+kVXlXst9d+R9PfTIxh1EdNkgoRe5tOX6t01f1lYWOvJnSPDBlG241QLzcyPdoNTsblLUdujGSE4RzrTZGQ== - -"@protobufjs/inquire@^1.1.0": - version "1.1.0" - resolved "https://registry.yarnpkg.com/@protobufjs/inquire/-/inquire-1.1.0.tgz#ff200e3e7cf2429e2dcafc1140828e8cc638f089" - integrity sha512-kdSefcPdruJiFMVSbn801t4vFK7KB/5gd2fYvrxhuJYg8ILrmn9SKSX2tZdV6V+ksulWqS7aXjBcRXl3wHoD9Q== - -"@protobufjs/path@^1.1.2": - version "1.1.2" - resolved "https://registry.yarnpkg.com/@protobufjs/path/-/path-1.1.2.tgz#6cc2b20c5c9ad6ad0dccfd21ca7673d8d7fbf68d" - integrity sha512-6JOcJ5Tm08dOHAbdR3GrvP+yUUfkjG5ePsHYczMFLq3ZmMkAD98cDgcT2iA1lJ9NVwFd4tH/iSSoe44YWkltEA== - -"@protobufjs/pool@^1.1.0": - version "1.1.0" - resolved "https://registry.yarnpkg.com/@protobufjs/pool/-/pool-1.1.0.tgz#09fd15f2d6d3abfa9b65bc366506d6ad7846ff54" - integrity sha512-0kELaGSIDBKvcgS4zkjz1PeddatrjYcmMWOlAuAPwAeccUrPHdUqo/J6LiymHHEiJT5NrF1UVwxY14f+fy4WQw== - -"@protobufjs/utf8@^1.1.0": - version "1.1.0" - resolved "https://registry.yarnpkg.com/@protobufjs/utf8/-/utf8-1.1.0.tgz#a777360b5b39a1a2e5106f8e858f2fd2d060c570" - integrity sha512-Vvn3zZrhQZkkBE8LSuW3em98c0FwgO4nxzv6OdSxPKJIEKY2bGbHn+mhGIPerzI4twdxaP8/0+06HBpwf345Lw== + "@octokit/openapi-types" "^29.0.1" "@samverschueren/stream-to-observable@^0.3.0": - version "0.3.0" - resolved "https://registry.npmjs.org/@samverschueren/stream-to-observable/-/stream-to-observable-0.3.0.tgz" - integrity sha512-MI4Xx6LHs4Webyvi6EbspgyAb4D2Q2VtnCQ1blOJcoLS6mVa8lNN2rkIy1CVxfTUpoyIbCTkXES1rLXztFD1lg== + version "0.3.1" + resolved "https://registry.npmjs.org/@samverschueren/stream-to-observable/-/stream-to-observable-0.3.1.tgz#a21117b19ee9be70c379ec1877537ef2e1c63301" + integrity sha512-c/qwwcHyafOQuVQJj0IlBjf5yYgBI7YPJ77k4fOJYesb41jio65eaJODRUmfYKhTOFBrIZ66kgvGPlNbjuoRdQ== dependencies: any-observable "^0.3.0" -"@sindresorhus/is@^5.2.0": - version "5.6.0" - resolved "https://registry.yarnpkg.com/@sindresorhus/is/-/is-5.6.0.tgz#41dd6093d34652cddb5d5bdeee04eafc33826668" - integrity sha512-TV7t8GKYaJWsn00tFDqBw8+Uqmr8A0fRU1tvTQhyZzGv0sJCGRQL3JGMI3ucuKo3XIZdUP+Lx7/gh2t3lewy7g== - -"@szmarczak/http-timer@^5.0.1": - version "5.0.1" - resolved "https://registry.yarnpkg.com/@szmarczak/http-timer/-/http-timer-5.0.1.tgz#c7c1bf1141cdd4751b0399c8fc7b8b664cd5be3a" - integrity sha512-+PmQX0PiAYPMeVYe237LJAYvOMYW1j2rH5YROyS3b4CTVJum34HfRvKvAzozHAQG0TnHNdUfY9nCeUyRAs//cw== - dependencies: - defer-to-connect "^2.0.1" - -"@tsconfig/node10@^1.0.7": - version "1.0.9" - resolved "https://registry.npmjs.org/@tsconfig/node10/-/node10-1.0.9.tgz" - integrity sha512-jNsYVVxU8v5g43Erja32laIDHXeoNvFEpX33OK4d6hljo3jDhCBDhx5dhCCTMWUojscpAagGiRkBKxpdl9fxqA== - -"@tsconfig/node12@^1.0.7": - version "1.0.11" - resolved "https://registry.npmjs.org/@tsconfig/node12/-/node12-1.0.11.tgz" - integrity sha512-cqefuRsh12pWyGsIoBKJA9luFu3mRxCA+ORZvA4ktLSzIuCUtWVxGIuXigEwO5/ywWFMZ2QEGKWvkZG1zDMTag== - -"@tsconfig/node14@^1.0.0": - version "1.0.3" - resolved "https://registry.npmjs.org/@tsconfig/node14/-/node14-1.0.3.tgz" - integrity sha512-ysT8mhdixWK6Hw3i1V2AeRqZ5WfXg1G43mqoYlM2nc6388Fq5jcXyr5mRsqViLx/GJYdoL0bfXD8nmF+Zn/Iow== +"@sec-ant/readable-stream@^0.4.1": + version "0.4.1" + resolved "https://registry.npmjs.org/@sec-ant/readable-stream/-/readable-stream-0.4.1.tgz#60de891bb126abfdc5410fdc6166aca065f10a0c" + integrity sha512-831qok9r2t8AlxLko40y2ebgSDhenenCatLVeW/uBtnHPyhHOvG0C7TvfgecV+wHzIm5KUICgzmVpWS+IMEAeg== -"@tsconfig/node16@^1.0.2": - version "1.0.3" - resolved "https://registry.npmjs.org/@tsconfig/node16/-/node16-1.0.3.tgz" - integrity sha512-yOlFc+7UtL/89t2ZhjPvvB/DeAr3r+Dq58IgzsFkOAvVC6NMJXmCGjbptdXdR9qsX7pKcTL+s87FtYREi2dEEQ== +"@sindresorhus/is@^7.0.1": + version "7.2.0" + resolved "https://registry.npmjs.org/@sindresorhus/is/-/is-7.2.0.tgz#7c594e1a64336d2008d99d814056d459421504d4" + integrity sha512-P1Cz1dWaFfR4IR+U13mqqiGsLFf1KbayybWwdd2vfctdV6hDpUkgCY0nKOLLTMSoRd/jJNjtbqzf13K8DCCXQw== "@types/async-retry@^1.4.2": - version "1.4.2" - resolved "https://registry.npmjs.org/@types/async-retry/-/async-retry-1.4.2.tgz" - integrity sha512-GUDuJURF0YiJZ+CBjNQA0+vbP/VHlJbB0sFqkzsV7EcOPRfurVonXpXKAt3w8qIjM1TEzpz6hc6POocPvHOS3w== + version "1.4.9" + resolved "https://registry.npmjs.org/@types/async-retry/-/async-retry-1.4.9.tgz#47d118e835864d633b5208a78a6907b1b44e50bc" + integrity sha512-s1ciZQJzRh3708X/m3vPExr5KJlzlZJvXsKpbtE2luqNcbROr64qU+3KpJsYHqWMeaxI839OvXf9PrUSw1Xtyg== dependencies: "@types/retry" "*" -"@types/caseless@*": - version "0.12.2" - resolved "https://registry.npmjs.org/@types/caseless/-/caseless-0.12.2.tgz" - integrity sha512-6ckxMjBBD8URvjB6J3NcnuAn5Pkl7t3TizAg+xdlzzQGSPSmBcXf8KoIH0ua/i+tio+ZRUHEXp0HEmvaR4kt0w== - "@types/chai@^4.3.4": - version "4.3.4" - resolved "https://registry.npmjs.org/@types/chai/-/chai-4.3.4.tgz" - integrity sha512-KnRanxnpfpjUTqTCXslZSEdLfXExwgNxYPdiO2WGUj8+HDjFi8R3k5RVKPeSCzLjCcshCAtVO2QBbVuAV4kTnw== + version "4.3.20" + resolved "https://registry.npmjs.org/@types/chai/-/chai-4.3.20.tgz#cb291577ed342ca92600430841a00329ba05cecc" + integrity sha512-/pC9HAB5I/xMlc5FP77qjCnI16ChlJfW0tGa0IUcFn38VJrTV6DeZ60NU5KZBtaOZqjdpwTWohz5HU1RrhiYxQ== "@types/cli-progress@^3.7.0": - version "3.7.0" - resolved "https://registry.npmjs.org/@types/cli-progress/-/cli-progress-3.7.0.tgz" - integrity sha512-h/f9+pomRHSodXOPgBjlLEESWhv2Z34pP5djmruylvEZ7MzTd1pljOmdsBpVh3uCGjTVOzb2ux8ZaXYqyPFgpQ== + version "3.11.6" + resolved "https://registry.npmjs.org/@types/cli-progress/-/cli-progress-3.11.6.tgz#94b334ebe4190f710e51c1bf9b4fedb681fa9e45" + integrity sha512-cE3+jb9WRlu+uOSAugewNpITJDt1VF8dHOopPO4IABFc3SXYL5WE/+PTz/FCdZRRfIujiWW3n3aMbv1eIGVRWA== dependencies: "@types/node" "*" -"@types/color-name@^1.1.1": - version "1.1.1" - resolved "https://registry.npmjs.org/@types/color-name/-/color-name-1.1.1.tgz" - integrity sha512-rr+OQyAjxze7GgWrSaJwydHStIhHq2lvY3BOC2Mj7KnzI7XK0Uw1TOOdI9lDoajEbSWLiYgoo4f1R51erQfhPQ== - -"@types/docker-modem@*": - version "3.0.2" - resolved "https://registry.npmjs.org/@types/docker-modem/-/docker-modem-3.0.2.tgz" - integrity sha512-qC7prjoEYR2QEe6SmCVfB1x3rfcQtUr1n4x89+3e0wSTMQ/KYCyf+/RAA9n2tllkkNc6//JMUZePdFRiGIWfaQ== - dependencies: - "@types/node" "*" - "@types/ssh2" "*" +"@types/esrecurse@^4.3.1": + version "4.3.1" + resolved "https://registry.npmjs.org/@types/esrecurse/-/esrecurse-4.3.1.tgz#6f636af962fbe6191b830bd676ba5986926bccec" + integrity sha512-xJBAbDifo5hpffDBuHl0Y8ywswbiAp/Wi7Y/GtAgSlZyIABppyurxVueOPE8LUQOxdlgi6Zqce7uoEpqNTeiUw== -"@types/dockerode@^3.3.16": - version "3.3.16" - resolved "https://registry.npmjs.org/@types/dockerode/-/dockerode-3.3.16.tgz" - integrity sha512-ZAX2VrkTjwjk1808T8m6vMr+CFXSLiDD+tkEkLThI+v83AfzlYQZEWfZKwFyk1PWopSXkdDunmIhrF7sxt+zWg== - dependencies: - "@types/docker-modem" "*" - "@types/node" "*" - -"@types/eslint-visitor-keys@^1.0.0": - version "1.0.0" - resolved "https://registry.npmjs.org/@types/eslint-visitor-keys/-/eslint-visitor-keys-1.0.0.tgz" - integrity sha512-OCutwjDZ4aFS6PB1UZ988C4YgwlBHJd6wCeQqaLdmadZ/7e+w79+hbMUFC1QXDNCmdyoRfAFdm0RypzwR+Qpag== +"@types/estree@^1.0.6", "@types/estree@^1.0.8": + version "1.0.10" + resolved "https://registry.npmjs.org/@types/estree/-/estree-1.0.10.tgz#8a4a266065af8c2fcf5983153cd97c11b313d0c6" + integrity sha512-lTyOMnOcmRBzdCv6/4zUZCrEhV0xrqQiUZBZtVcbmLHBXKLnN8q89v/wKRF/Q0HbwVsqbIG3o5HDoFl9sduM+g== "@types/figlet@^1.2.0": - version "1.2.0" - resolved "https://registry.npmjs.org/@types/figlet/-/figlet-1.2.0.tgz" - integrity sha512-TDZkNpYfkc3X8yv7w1QBziZmmxzNfGKX+YjeNkMpmSiNV0QOdNf9G5cEZB3FH1/oaqpSQEdxuDzURdju2L3lng== - -"@types/glob@*": - version "7.1.3" - resolved "https://registry.npmjs.org/@types/glob/-/glob-7.1.3.tgz" - integrity sha512-SEYeGAIQIQX8NN6LDKprLjbrd5dARM5EXsd8GI/A5l0apYI1fGMWgPHSe4ZKL4eozlAyI+doUE9XbYS4xCkQ1w== + version "1.12.0" + resolved "https://registry.npmjs.org/@types/figlet/-/figlet-1.12.0.tgz#93815add81d19f318cfcf61ff606afaf704e87ff" + integrity sha512-tPv140QqwGL4Jot2fzTxC6Oy8BVdHEZe4SJDlRuRkywfksv8kMCbTYvtuN9mJCm41HlgRhwb5rRaiH6FE5Hm9g== dependencies: - "@types/minimatch" "*" - "@types/node" "*" + figlet "*" -"@types/http-cache-semantics@^4.0.2": - version "4.0.4" - resolved "https://registry.yarnpkg.com/@types/http-cache-semantics/-/http-cache-semantics-4.0.4.tgz#b979ebad3919799c979b17c72621c0bc0a31c6c4" - integrity sha512-1m0bIFVc7eJWyve9S0RnuRgcQqF/Xd5QsUZAZeQFr1Q3/p9JWoQQEqmVy+DPTNpGXwhgIetAoYF8JSc33q29QA== - -"@types/inquirer@^6.5.0": - version "6.5.0" - resolved "https://registry.npmjs.org/@types/inquirer/-/inquirer-6.5.0.tgz" - integrity sha512-rjaYQ9b9y/VFGOpqBEXRavc3jh0a+e6evAbI31tMda8VlPaSy0AZJfXsvmIe3wklc7W6C3zCSfleuMXR7NOyXw== - dependencies: - "@types/through" "*" - rxjs "^6.4.0" +"@types/http-cache-semantics@^4.2.0": + version "4.2.0" + resolved "https://registry.npmjs.org/@types/http-cache-semantics/-/http-cache-semantics-4.2.0.tgz#f6a7788f438cbfde15f29acad46512b4c01913b3" + integrity sha512-L3LgimLHXtGkWikKnsPg0/VFx9OGZaC+eN1u4r+OB1XRqH3meBIAVC2zr1WdMH+RHmnRkqliQAOHNJ/E0j/e0Q== -"@types/js-yaml@^3.12.5": - version "3.12.5" - resolved "https://registry.npmjs.org/@types/js-yaml/-/js-yaml-3.12.5.tgz" - integrity sha512-JCcp6J0GV66Y4ZMDAQCXot4xprYB+Zfd3meK9+INSJeVZwJmHAW30BBEEkPzXswMXuiyReUGOP3GxrADc9wPww== +"@types/js-yaml@^4.0.9": + version "4.0.9" + resolved "https://registry.npmjs.org/@types/js-yaml/-/js-yaml-4.0.9.tgz#cd82382c4f902fed9691a2ed79ec68c5898af4c2" + integrity sha512-k4MGaQl5TGo/iipqb2UDG2UwjXziSWkh0uysQelTlJpX1qGlpUZYm8PnO4DxG1qBomtJUdYJ6qR6xdIah10JLg== -"@types/json-schema@^7.0.3": - version "7.0.5" - resolved "https://registry.npmjs.org/@types/json-schema/-/json-schema-7.0.5.tgz" - integrity sha512-7+2BITlgjgDhH0vvwZU/HZJVyk+2XUlvxXe8dFMedNX/aMkaOq++rMAFXc0tM7ij15QaWlbdQASBR9dihi+bDQ== +"@types/json-schema@^7.0.15": + version "7.0.15" + resolved "https://registry.npmjs.org/@types/json-schema/-/json-schema-7.0.15.tgz#596a1747233694d50f6ad8a7869fcb6f56cf5841" + integrity sha512-5+fP8P8MFNC+AyZCDxrB2pkZFPGzqQWUzpSeuuVLvm8VMcorNYavBqoFcxK8bQz4Qsbn4oUEEem4wDLfcysGHA== "@types/listr@^0.14.2": - version "0.14.2" - resolved "https://registry.npmjs.org/@types/listr/-/listr-0.14.2.tgz" - integrity sha512-wCipMbQr3t2UHTm90LldVp+oTBj1TX6zvpkCJcWS4o8nn6kS8SN93oUvKJAgueIRZ5M36yOlFmScqBxYH8Ajig== + version "0.14.10" + resolved "https://registry.npmjs.org/@types/listr/-/listr-0.14.10.tgz#c675fca3ae2030c2ce52fa9b2839fdb6de47568b" + integrity sha512-g5/EazbMACM1JrM/oGtW28vXo4Bv0E03/FIsqqIXbR/CztuHEgR8QAJDrB1Y5bQH7/ISQh0jNV3v65NM29HgAQ== dependencies: "@types/node" "*" rxjs "^6.5.1" "@types/lodash-es@^4.17.7": - version "4.17.7" - resolved "https://registry.npmjs.org/@types/lodash-es/-/lodash-es-4.17.7.tgz" - integrity sha512-z0ptr6UI10VlU6l5MYhGwS4mC8DZyYer2mCoyysZtSF7p26zOX8UpbrV0YpNYLGS8K4PUFIyEr62IMFFjveSiQ== + version "4.17.12" + resolved "https://registry.npmjs.org/@types/lodash-es/-/lodash-es-4.17.12.tgz#65f6d1e5f80539aa7cfbfc962de5def0cf4f341b" + integrity sha512-0NgftHUcV4v34VhXm8QBSftKVXtbkBG3ViCjs6+eJ5a6y6Mi/jiFGPc1sC7QK+9BFhWrURE3EOggmWaSxL9OzQ== dependencies: "@types/lodash" "*" "@types/lodash@*": - version "4.14.191" - resolved "https://registry.npmjs.org/@types/lodash/-/lodash-4.14.191.tgz" - integrity sha512-BdZ5BCCvho3EIXw6wUCXHe7rS53AIDPLE+JzwgT+OsJk53oBfbSmZZ7CX4VaRoN78N+TJpFi9QPlfIVNmJYWxQ== + version "4.17.27" + resolved "https://registry.npmjs.org/@types/lodash/-/lodash-4.17.27.tgz#15fb73275b64dbfe49e2ae8376bb469b352a47a7" + integrity sha512-VenMRv/eKNrspX9v3H4dbmjsrnCOYdYBG3kxXKk3dG6X+urBGcj2Prww3xw1U5K4FV/mE4h5GbWd0szEKf+9ew== "@types/mime-types@^2.1.0": - version "2.1.0" - resolved "https://registry.npmjs.org/@types/mime-types/-/mime-types-2.1.0.tgz" - integrity sha1-nKUs2jY/aZxpRmwqbM2q2RPqenM= + version "2.1.4" + resolved "https://registry.npmjs.org/@types/mime-types/-/mime-types-2.1.4.tgz#93a1933e24fed4fb9e4adc5963a63efcbb3317a2" + integrity sha512-lfU4b34HOri+kAY5UheuFMWPDOI+OPceBSHZKp69gEyTL/mmJ4cnU6Y/rlme3UL3GyOn6Y42hyIEw0/q8sWx5w== -"@types/minimatch@*": - version "3.0.3" - resolved "https://registry.npmjs.org/@types/minimatch/-/minimatch-3.0.3.tgz" - integrity sha512-tHq6qdbT9U1IRSGf14CL0pUlULksvY9OZ+5eEgl1N7t+OA3tGvNpxJCzuKQlsNgCVwbAs670L1vcVQi8j9HjnA== +"@types/mocha@^10.0.1": + version "10.0.10" + resolved "https://registry.npmjs.org/@types/mocha/-/mocha-10.0.10.tgz#91f62905e8d23cbd66225312f239454a23bebfa0" + integrity sha512-xPyYSz1cMPnJQhl0CLMH68j3gprKZaTjG3s5Vi+fDgx+uhG9NOXwbVt52eFS8ECyXhyKcjDLCBEqBExKuiZb7Q== -"@types/minimatch@^3.0.4": - version "3.0.5" - resolved "https://registry.yarnpkg.com/@types/minimatch/-/minimatch-3.0.5.tgz#1001cc5e6a3704b83c236027e77f2f58ea010f40" - integrity sha512-Klz949h02Gz2uZCMGwDUSDS1YBlTdDDgbWHi+81l29tQALUtvz4rAYi5uoVhE5Lagoq6DeqAUlbrHvW/mXDgdQ== +"@types/node@*": + version "26.6.6" + resolved "https://registry.npmjs.org/@types/node/-/node-26.6.6.tgz#9ed7b5817e728ed9216ef7c5b7d373fe3b777104" + integrity sha512-MzQj+8Kx3XI40OmUAE6Qoh58ZMNstNNMwn2nfd3qWsfe7nDNSqJNzes4njhz6AHwrSHOffSLwXU6yb474Q4aog== + dependencies: + undici-types "~8.9.0" -"@types/mocha@^10.0.1": - version "10.0.1" - resolved "https://registry.npmjs.org/@types/mocha/-/mocha-10.0.1.tgz" - integrity sha512-/fvYntiO1GeICvqbQ3doGDIP97vWmvFt83GKguJ6prmQM2iXZfFcq6YE8KteFyRtX2/h5Hf91BYvPodJKFYv5Q== - -"@types/node@*", "@types/node@^18.11.18": - version "18.15.11" - resolved "https://registry.npmjs.org/@types/node/-/node-18.15.11.tgz" - integrity sha512-E5Kwq2n4SbMzQOn6wnmBjuK9ouqlURrcZDVfbo9ftDDTFt3nk7ZKK4GMOzoYgnpQJKcxwQw+lGaBvvlMo0qN/Q== - -"@types/node@18.15.13": - version "18.15.13" - resolved "https://registry.yarnpkg.com/@types/node/-/node-18.15.13.tgz#f64277c341150c979e42b00e4ac289290c9df469" - integrity sha512-N+0kuo9KgrUQ1Sn/ifDXsvg0TTleP7rIy4zOBGECxAljqvqfqpTfzx0Q1NUedOixRMBfe2Whhb056a42cWs26Q== - -"@types/node@>=13.7.0": - version "20.2.3" - resolved "https://registry.yarnpkg.com/@types/node/-/node-20.2.3.tgz#b31eb300610c3835ac008d690de6f87e28f9b878" - integrity sha512-pg9d0yC4rVNWQzX8U7xb4olIOFuuVL9za3bzMT2pu2SU0SNEi66i2qrvhE2qt0HvkhuCaWJu7pLNOt/Pj8BIrw== - -"@types/node@^18.0.0": - version "18.16.14" - resolved "https://registry.yarnpkg.com/@types/node/-/node-18.16.14.tgz#ab67bb907f1146afc6fedb9ce60ae8a99c989631" - integrity sha512-+ImzUB3mw2c5ISJUq0punjDilUQ5GnUim0ZRvchHIWJmOC0G+p0kzhXBqj6cDjK0QdPFwzrHWgrJp3RPvCG5qg== - -"@types/node@^22.7.5": +"@types/node@22.7.5": version "22.7.5" - resolved "https://registry.yarnpkg.com/@types/node/-/node-22.7.5.tgz#cfde981727a7ab3611a481510b473ae54442b92b" + resolved "https://registry.npmjs.org/@types/node/-/node-22.7.5.tgz#cfde981727a7ab3611a481510b473ae54442b92b" integrity sha512-jML7s2NAzMWc//QSJ1a3prpk78cOPchGvXJsC3C6R6PSMoooztvRVQEz89gmBTBY1SPMaqo5teB4uNHPdetShQ== dependencies: undici-types "~6.19.2" -"@types/prettier@^2.1.5": - version "2.1.5" - resolved "https://registry.npmjs.org/@types/prettier/-/prettier-2.1.5.tgz" - integrity sha512-UEyp8LwZ4Dg30kVU2Q3amHHyTn1jEdhCIE59ANed76GaT1Vp76DD3ZWSAxgCrw6wJ0TqeoBpqmfUHiUDPs//HQ== - -"@types/request@^2.48.5": - version "2.48.5" - resolved "https://registry.npmjs.org/@types/request/-/request-2.48.5.tgz" - integrity sha512-/LO7xRVnL3DxJ1WkPGDQrp4VTV1reX9RkC85mJ+Qzykj2Bdw+mG15aAfDahc76HtknjzE16SX/Yddn6MxVbmGQ== +"@types/node@^20.19.0": + version "20.19.43" + resolved "https://registry.npmjs.org/@types/node/-/node-20.19.43.tgz#fcecf580ba42a0db55cf404c372c97973c376c97" + integrity sha512-6oYBAi5ikg4Pl+kGsoYtawUMBT2zZMCvPNF7pVLnHZfd1zf38DRiWn/gT01RYCdUqkv7Fhr+C9ot4/tb+2sVvA== dependencies: - "@types/caseless" "*" - "@types/node" "*" - "@types/tough-cookie" "*" - form-data "^2.5.0" + undici-types "~6.21.0" -"@types/retry@*": - version "0.12.0" - resolved "https://registry.npmjs.org/@types/retry/-/retry-0.12.0.tgz" - integrity sha512-wWKOClTTiizcZhXnPY4wikVAwmdYHp8q6DmC+EJUzAMsycb7HB32Kh9RN4+0gExjmPmZSAQjgURXIGATPegAvA== +"@types/prettier@^2.1.5": + version "2.7.3" + resolved "https://registry.npmjs.org/@types/prettier/-/prettier-2.7.3.tgz#3e51a17e291d01d17d3fc61422015a933af7a08f" + integrity sha512-+68kP9yzs4LMp7VNh8gdzMSPZFL44MLGqiHWvttYJe+6qnuVr4Ek9wSBQoveqY/r+LwjCcU29kNVkidwim+kYA== -"@types/rimraf@^3.0.0": - version "3.0.0" - resolved "https://registry.npmjs.org/@types/rimraf/-/rimraf-3.0.0.tgz" - integrity sha512-7WhJ0MdpFgYQPXlF4Dx+DhgvlPCfz/x5mHaeDQAKhcenvQP1KCpLQ18JklAqeGMYSAT2PxLpzd0g2/HE7fj7hQ== - dependencies: - "@types/glob" "*" - "@types/node" "*" +"@types/retry@*": + version "0.12.5" + resolved "https://registry.npmjs.org/@types/retry/-/retry-0.12.5.tgz#f090ff4bd8d2e5b940ff270ab39fd5ca1834a07e" + integrity sha512-3xSjTp3v03X/lSQLkczaN9UIEwJMoMCA1+Nb5HfbJEQWogdeQIyVtTvxPXDQjZ5zws8rFQfVfRdz03ARihPJgw== "@types/semver@^7.3.1": - version "7.3.1" - resolved "https://registry.npmjs.org/@types/semver/-/semver-7.3.1.tgz" - integrity sha512-ooD/FJ8EuwlDKOI6D9HWxgIgJjMg2cuziXm/42npDC8y4NjxplBUn9loewZiBNCt44450lHAU0OSb51/UqXeag== - dependencies: - "@types/node" "*" - -"@types/ssh2@*": - version "1.11.11" - resolved "https://registry.npmjs.org/@types/ssh2/-/ssh2-1.11.11.tgz" - integrity sha512-LdnE7UBpvHCgUznvn2fwLt2hkaENcKPFqOyXGkvyTLfxCXBN6roc1RmECNYuzzbHePzD3PaAov5rri9hehzx9Q== - dependencies: - "@types/node" "^18.11.18" + version "7.8.0" + resolved "https://registry.npmjs.org/@types/semver/-/semver-7.8.0.tgz#0bfe3ec51f5e9615bc317174cd5b88ea08b7fc2f" + integrity sha512-1mAINjtQCXXeLkJ9ehXkwOcBpqtLxiVtKhpUf83DdRNdQKV0iXZpaHYqRr7nj+wvxuJzoAmAwXI+sCNMv1CzLQ== "@types/tar-fs@^2.0.0": - version "2.0.0" - resolved "https://registry.npmjs.org/@types/tar-fs/-/tar-fs-2.0.0.tgz" - integrity sha512-3H2HmxuT1OCZYXi1KG5xIjbpv97JjdLSRByH13YhHK8lr+GaJndJ91IuQfHxn23BQRaWHf2LTnlHPQcQDzt8vw== + version "2.0.4" + resolved "https://registry.npmjs.org/@types/tar-fs/-/tar-fs-2.0.4.tgz#7c7502d281d436db0ad0f78282acef71da02a292" + integrity sha512-ipPec0CjTmVDWE+QKr9cTmIIoTl7dFG/yARCM5MqK8i6CNLIG1P8x4kwDsOQY1ChZOZjH0wO9nvfgBvWl4R3kA== dependencies: "@types/node" "*" "@types/tar-stream" "*" "@types/tar-stream@*": - version "2.1.0" - resolved "https://registry.npmjs.org/@types/tar-stream/-/tar-stream-2.1.0.tgz" - integrity sha512-s1UQxQUVMHbSkCC0X4qdoiWgHF8DoyY1JjQouFsnk/8ysoTdBaiCHud/exoAZzKDbzAXVc+ah6sczxGVMAohFw== - dependencies: - "@types/node" "*" - -"@types/through@*": - version "0.0.30" - resolved "https://registry.npmjs.org/@types/through/-/through-0.0.30.tgz" - integrity sha512-FvnCJljyxhPM3gkRgWmxmDZyAQSiBQQWLI0A0VFL0K7W1oRUrPJSqNO0NvTnLkBcotdlp3lKvaT0JrnyRDkzOg== + version "3.1.5" + resolved "https://registry.npmjs.org/@types/tar-stream/-/tar-stream-3.1.5.tgz#b8084b982b1f4464fec86832bbad08d7f509e6b8" + integrity sha512-zCUA6CSDw0t2cpQiZixpyzfubpeuVZmBr5wztvuCG4bhy7reX/9wGXdZxEzz2CjMFLQ32UPR/01jzUUSRJeCeQ== dependencies: "@types/node" "*" -"@types/tough-cookie@*": - version "4.0.0" - resolved "https://registry.npmjs.org/@types/tough-cookie/-/tough-cookie-4.0.0.tgz" - integrity sha512-I99sngh224D0M7XgW1s120zxCt3VYQ3IQsuw3P3jbq5GG4yc79+ZjyKznyOGIQrflfylLgcfekeZW/vk0yng6A== - "@types/yargs-parser@*": - version "15.0.0" - resolved "https://registry.npmjs.org/@types/yargs-parser/-/yargs-parser-15.0.0.tgz" - integrity sha512-FA/BWv8t8ZWJ+gEOnLLd8ygxH/2UFbAvgEonyfN6yWGLKc7zVjbpl2Y4CTjid9h2RfgPP6SEt6uHwEOply00yw== + version "21.0.3" + resolved "https://registry.npmjs.org/@types/yargs-parser/-/yargs-parser-21.0.3.tgz#815e30b786d2e8f0dcd85fd5bcf5e1a04d008f15" + integrity sha512-I4q9QU9MQv4oEOz4tAHJtNz1cwuLxn2F3xcc2iV5WdqLPpUnj30aUuxt1mAxYTG+oe8CZMV/+6rU4S4gRDzqtQ== "@types/yargs@^17.0.24": - version "17.0.24" - resolved "https://registry.npmjs.org/@types/yargs/-/yargs-17.0.24.tgz" - integrity sha512-6i0aC7jV6QzQB8ne1joVZ0eSFIstHsCrobmOtghM11yGlH0j43FKL2UhWdELkyps0zuf7qVTUVCCR+tgSlyLLw== + version "17.0.35" + resolved "https://registry.npmjs.org/@types/yargs/-/yargs-17.0.35.tgz#07013e46aa4d7d7d50a49e15604c1c5340d4eb24" + integrity sha512-qUHkeCyQFxMXg79wQfTtfndEC+N9ZZg76HJftDJp+qH2tV7Gj4OJi7l+PiWwJ+pWtW8GwSmqsDj/oymhrTWXjg== dependencies: "@types/yargs-parser" "*" -"@typescript-eslint/eslint-plugin@^3.5.0": - version "3.5.0" - resolved "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-3.5.0.tgz" - integrity sha512-m4erZ8AkSjoIUOf8s4k2V1xdL2c1Vy0D3dN6/jC9d7+nEqjY3gxXCkgi3gW/GAxPaA4hV8biaCoTVdQmfAeTCQ== - dependencies: - "@typescript-eslint/experimental-utils" "3.5.0" - debug "^4.1.1" - functional-red-black-tree "^1.0.1" - regexpp "^3.0.0" - semver "^7.3.2" - tsutils "^3.17.1" - -"@typescript-eslint/experimental-utils@3.5.0": - version "3.5.0" - resolved "https://registry.npmjs.org/@typescript-eslint/experimental-utils/-/experimental-utils-3.5.0.tgz" - integrity sha512-zGNOrVi5Wz0jcjUnFZ6QUD0MCox5hBuVwemGCew2qJzUX5xPoyR+0EzS5qD5qQXL/vnQ8Eu+nv03tpeFRwLrDg== - dependencies: - "@types/json-schema" "^7.0.3" - "@typescript-eslint/types" "3.5.0" - "@typescript-eslint/typescript-estree" "3.5.0" - eslint-scope "^5.0.0" - eslint-utils "^2.0.0" - -"@typescript-eslint/parser@^3.5.0": - version "3.5.0" - resolved "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-3.5.0.tgz" - integrity sha512-sU07VbYB70WZHtgOjH/qfAp1+OwaWgrvD1Km1VXqRpcVxt971PMTU7gJtlrCje0M+Sdz7xKAbtiyIu+Y6QdnVA== - dependencies: - "@types/eslint-visitor-keys" "^1.0.0" - "@typescript-eslint/experimental-utils" "3.5.0" - "@typescript-eslint/types" "3.5.0" - "@typescript-eslint/typescript-estree" "3.5.0" - eslint-visitor-keys "^1.1.0" - -"@typescript-eslint/types@3.5.0": - version "3.5.0" - resolved "https://registry.npmjs.org/@typescript-eslint/types/-/types-3.5.0.tgz" - integrity sha512-Dreqb5idi66VVs1QkbAwVeDmdJG+sDtofJtKwKCZXIaBsINuCN7Jv5eDIHrS0hFMMiOvPH9UuOs4splW0iZe4Q== - -"@typescript-eslint/typescript-estree@3.5.0": - version "3.5.0" - resolved "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-3.5.0.tgz" - integrity sha512-Na71ezI6QP5WVR4EHxwcBJgYiD+Sre9BZO5iJK2QhrmRPo/42+b0no/HZIrdD1sjghzlYv7t+7Jis05M1uMxQg== - dependencies: - "@typescript-eslint/types" "3.5.0" - "@typescript-eslint/visitor-keys" "3.5.0" - debug "^4.1.1" - glob "^7.1.6" - is-glob "^4.0.1" - lodash "^4.17.15" - semver "^7.3.2" - tsutils "^3.17.1" - -"@typescript-eslint/visitor-keys@3.5.0": - version "3.5.0" - resolved "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-3.5.0.tgz" - integrity sha512-7cTp9rcX2sz9Z+zua9MCOX4cqp5rYyFD5o8LlbSpXrMTXoRdngTtotRZEkm8+FNMHPWYFhitFK+qt/brK8BVJQ== - dependencies: - eslint-visitor-keys "^1.1.0" - -acorn-jsx@^5.2.0: - version "5.2.0" - resolved "https://registry.npmjs.org/acorn-jsx/-/acorn-jsx-5.2.0.tgz" - integrity sha512-HiUX/+K2YpkpJ+SzBffkM/AQ2YE03S0U1kjTLVpoJdhZMOWy8qvXVN9JdLqv2QsaQ6MPYQIuNmwD8zOiYUofLQ== - -acorn-walk@^8.1.1: - version "8.2.0" - resolved "https://registry.npmjs.org/acorn-walk/-/acorn-walk-8.2.0.tgz" - integrity sha512-k+iyHEuPgSw6SbuDpGQM+06HQUa04DZ3o+F6CSzXMvvI5KMvnaEqXe+YVe555R9nn6GPt404fos4wcgpw12SDA== - -acorn@^7.2.0: - version "7.3.1" - resolved "https://registry.npmjs.org/acorn/-/acorn-7.3.1.tgz" - integrity sha512-tLc0wSnatxAQHVHUapaHdz72pi9KUyHjq5KyHjGg9Y8Ifdc79pTh2XvI6I1/chZbnM7QtNKzh66ooDogPZSleA== - -acorn@^8.4.1: - version "8.8.2" - resolved "https://registry.npmjs.org/acorn/-/acorn-8.8.2.tgz" - integrity sha512-xjIYgE8HBrkpd/sJqOGNspf8uHG+NOHGOw6a/Urj8taM2EXfdNAH2oFcPeIFfsv3+kz/mJrS5VuMqbNLjCa2vw== - -aes-js@4.0.0-beta.3: - version "4.0.0-beta.3" - resolved "https://registry.yarnpkg.com/aes-js/-/aes-js-4.0.0-beta.3.tgz#da2253f0ff03a0b3a9e445c8cbdf78e7fda7d48c" - integrity sha512-/xJX0/VTPcbc5xQE2VUP91y1xN8q/rDfhEzLm+vLc3hYvb5+qHCnpJRuFcrKn63zumK/sCwYYzhG8HP78JYSTA== +"@typescript-eslint/eslint-plugin@8.72.1": + version "8.72.1" + resolved "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-8.72.1.tgz#95e29de63ce7ed793eb1c6efd9f8b802ce808262" + integrity sha512-5CokTWXpmbylfFabsbvHC0CAw3XLaGnoa+nFJX5FR592h/LoZsENUE6p/rg5xvkKrFEXz6pYmgI29AgXc2N3BQ== + dependencies: + "@eslint-community/regexpp" "^4.12.2" + "@typescript-eslint/scope-manager" "8.72.1" + "@typescript-eslint/type-utils" "8.72.1" + "@typescript-eslint/utils" "8.72.1" + "@typescript-eslint/visitor-keys" "8.72.1" + ignore "^7.0.5" + natural-compare "^1.4.0" + ts-api-utils "^2.5.0" + +"@typescript-eslint/parser@8.72.1": + version "8.72.1" + resolved "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-8.72.1.tgz#7370b68dadc3819b9aac68ea340bd8b43ee62379" + integrity sha512-ZGwZP4OCfyA0AQTpEAMWz+rtX01DRhQWW5hB0ucKDEIX5U7jdmPSaMx94rQfaPAQzIYz2BimOgKOJtjfpRFQ9g== + dependencies: + "@typescript-eslint/scope-manager" "8.72.1" + "@typescript-eslint/types" "8.72.1" + "@typescript-eslint/typescript-estree" "8.72.1" + "@typescript-eslint/visitor-keys" "8.72.1" + debug "^4.4.3" + +"@typescript-eslint/project-service@8.72.1": + version "8.72.1" + resolved "https://registry.npmjs.org/@typescript-eslint/project-service/-/project-service-8.72.1.tgz#1d09902a9c23f6cfab779e5acc78a45abf540add" + integrity sha512-fAuVMkwdO/huI8nyo/WKnNKf6Gag93S56Rh3Ts5mGcavwSdaN8tRg1gCeIGX8PF+nzp1BjGfO4gHhGzW1J6jTg== + dependencies: + "@typescript-eslint/tsconfig-utils" "^8.72.1" + "@typescript-eslint/types" "^8.72.1" + debug "^4.4.3" + +"@typescript-eslint/scope-manager@8.72.1": + version "8.72.1" + resolved "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-8.72.1.tgz#a0fb4dfe5aa2b0149b7a2d1fd00d947992b13067" + integrity sha512-lC/t6eMCZZQAAKZEYGL6RDVSuFehpdmMT6h+nJIjIa6oylN/PwDgDVtEIbB7O9xFfZYtZAYLoLlDNWKJhtF+uQ== + dependencies: + "@typescript-eslint/types" "8.72.1" + "@typescript-eslint/visitor-keys" "8.72.1" + +"@typescript-eslint/tsconfig-utils@8.72.1", "@typescript-eslint/tsconfig-utils@^8.72.1": + version "8.72.1" + resolved "https://registry.npmjs.org/@typescript-eslint/tsconfig-utils/-/tsconfig-utils-8.72.1.tgz#07394c85095ee38455e76bc221ba23650af73e44" + integrity sha512-e4D5R5vpeAEPBxT2BAzsFQL3sbwyeeeo5+aczgNSRK1V734jE7pTqaGFU+fXapWEQwnZbpFaTn32+Z8DwS6OTg== + +"@typescript-eslint/type-utils@8.72.1": + version "8.72.1" + resolved "https://registry.npmjs.org/@typescript-eslint/type-utils/-/type-utils-8.72.1.tgz#f1f592f63bd9726de21191aae3ccf64a813914b8" + integrity sha512-iY2wlmyrXJmx4yxUGP3aYCFF3cA/6ShddOKmLU2dx7LnEykbAM8WThlxZEfd1NddqceF6eJmZUayxx9oKIYNlg== + dependencies: + "@typescript-eslint/types" "8.72.1" + "@typescript-eslint/typescript-estree" "8.72.1" + "@typescript-eslint/utils" "8.72.1" + debug "^4.4.3" + ts-api-utils "^2.5.0" + +"@typescript-eslint/types@8.72.1", "@typescript-eslint/types@^8.72.1": + version "8.72.1" + resolved "https://registry.npmjs.org/@typescript-eslint/types/-/types-8.72.1.tgz#067d8f738c294611e33a1425ae43ac9b9c2f24e3" + integrity sha512-LmE5IhQet1BWOWEXqBrVtBPsMAOQ6Nzk35d+WLh3mk4EUF33sqlfxjio1MdYeSvKSG5skactKKuixBIKXhL4Rw== + +"@typescript-eslint/typescript-estree@8.72.1": + version "8.72.1" + resolved "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-8.72.1.tgz#e93b9cc3a56bf12f5fed857bb8f4963cce7924ee" + integrity sha512-DAlUoUV93hIvrtIQLwCbmZQYVZwOMhiHJrOVUUIWicFZaIYjTRqlY3I/NZevfkLmSqkNHRu2qYDcq9lrn16oOQ== + dependencies: + "@typescript-eslint/project-service" "8.72.1" + "@typescript-eslint/tsconfig-utils" "8.72.1" + "@typescript-eslint/types" "8.72.1" + "@typescript-eslint/visitor-keys" "8.72.1" + debug "^4.4.3" + minimatch "^10.2.2" + semver "^7.7.3" + tinyglobby "^0.2.15" + ts-api-utils "^2.5.0" + +"@typescript-eslint/utils@8.72.1": + version "8.72.1" + resolved "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-8.72.1.tgz#f210c1bf4a25aa1306df80c702ed30bbbc9b4d3d" + integrity sha512-5v5liypurJBFHCBNqh/RjsymAD+VWcE0djuGY/BUqp5fC3Qn+luWDEksjuTtWjPn6i5zQlUtkZCRG/CYG0yCkA== + dependencies: + "@eslint-community/eslint-utils" "^4.9.1" + "@typescript-eslint/scope-manager" "8.72.1" + "@typescript-eslint/types" "8.72.1" + "@typescript-eslint/typescript-estree" "8.72.1" + +"@typescript-eslint/visitor-keys@8.72.1": + version "8.72.1" + resolved "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-8.72.1.tgz#c7aec9883b44ef795f1b8200df81d9d44d355de7" + integrity sha512-SB8xqipSzZHUePCCLNeYxqnxq83X61/qzNhjQGbTfjxGZIeOEP7tBgWYX05Tcd6CgE02WdTJnh5b8kMZJ/+bnQ== + dependencies: + "@typescript-eslint/types" "8.72.1" + eslint-visitor-keys "^5.0.0" + +acorn-jsx@^5.3.2: + version "5.3.2" + resolved "https://registry.npmjs.org/acorn-jsx/-/acorn-jsx-5.3.2.tgz#7ed5bb55908b3b2f1bc55c6af1653bada7f07937" + integrity sha512-rq9s+JNhf0IChjtDXxllJ7g41oZk5SlXtp0LHwyA5cejwn7vKmKp4pPri6YEePv2PU65sAsegbXtIinmDFDXgQ== + +acorn@^8.16.0: + version "8.19.0" + resolved "https://registry.npmjs.org/acorn/-/acorn-8.19.0.tgz#6b26fd97ce1cc9dc50bdf7ad305e9f1384d4f28a" + integrity sha512-oJlA3XiRm7Cyk6qFD2Jn8ak9B7jSy0qy00ADO3+8dpT0LSjFihQYv4C02LFCSYJV3Q37xYwwRy5m+IpIiUzqWw== aes-js@4.0.0-beta.5: version "4.0.0-beta.5" - resolved "https://registry.yarnpkg.com/aes-js/-/aes-js-4.0.0-beta.5.tgz#8d2452c52adedebc3a3e28465d858c11ca315873" + resolved "https://registry.npmjs.org/aes-js/-/aes-js-4.0.0-beta.5.tgz#8d2452c52adedebc3a3e28465d858c11ca315873" integrity sha512-G965FqalsNyrPqgEGON7nIx1e/OVENSgiEIzyC63haUMuvNnwIgIjMs52hlTCKhkBny7A2ORNlfY9Zu+jmGk1Q== -ajv@^6.10.0, ajv@^6.10.2: - version "6.12.6" - resolved "https://registry.npmjs.org/ajv/-/ajv-6.12.6.tgz" - integrity sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g== - dependencies: - fast-deep-equal "^3.1.1" - fast-json-stable-stringify "^2.0.0" - json-schema-traverse "^0.4.1" - uri-js "^4.2.2" - -ajv@^6.5.5: - version "6.12.3" - resolved "https://registry.npmjs.org/ajv/-/ajv-6.12.3.tgz" - integrity sha512-4K0cK3L1hsqk9xIb2z9vs/XU+PGJZ9PNpJRDS9YLzmNdX6jmVPfamLvTJr0aDAusnHyCHO6MjzlkAsgtqp9teA== +ajv@^6.14.0: + version "6.15.0" + resolved "https://registry.npmjs.org/ajv/-/ajv-6.15.0.tgz#07e982c74626167aa7a2495c53817892d7139492" + integrity sha512-fgFx7Hfoq60ytK2c7DhnF8jIvzYgOMxfugjLOSMHjLIPgenqa7S7oaagATUq99mV6IYvN2tRmC0wnTYX6iPbMw== dependencies: fast-deep-equal "^3.1.1" fast-json-stable-stringify "^2.0.0" @@ -862,327 +818,235 @@ ajv@^6.5.5: uri-js "^4.2.2" ajv@^8.17.1: - version "8.17.1" - resolved "https://registry.yarnpkg.com/ajv/-/ajv-8.17.1.tgz#37d9a5c776af6bc92d7f4f9510eba4c0a60d11a6" - integrity sha512-B/gBuNg5SiMTrPkC+A2+cW0RszwxYmn6VYxB/inlBStS5nx6xHIt/ehKRhIMhqusl7a8LjQoZnjCs5vhwxOQ1g== + version "8.20.0" + resolved "https://registry.npmjs.org/ajv/-/ajv-8.20.0.tgz#304b3636add88ba7d936760dd50ece006dea95f9" + integrity sha512-Thbli+OlOj+iMPYFBVBfJ3OmCAnaSyNn4M1vz9T6Gka5Jt9ba/HIR56joy65tY6kx/FCF5VXNB819Y7/GUrBGA== dependencies: fast-deep-equal "^3.1.3" fast-uri "^3.0.1" json-schema-traverse "^1.0.0" require-from-string "^2.0.2" -ansi-colors@4.1.1: - version "4.1.1" - resolved "https://registry.npmjs.org/ansi-colors/-/ansi-colors-4.1.1.tgz" - integrity sha512-JoX0apGbHaUJBNl6yF+p6JAFYZ666/hhCGKN5t9QFjbJQKUU/g8MNbFDbvfrgKXvI1QpZplPOnwIo99lX/AAmA== - -ansi-colors@^3.2.1: - version "3.2.4" - resolved "https://registry.npmjs.org/ansi-colors/-/ansi-colors-3.2.4.tgz" - integrity sha512-hHUXGagefjN2iRrID63xckIvotOXOojhQKWIPUZ4mNUZ9nLZW+7FMNoE1lOkEhNWYsx/7ysGIuJYCiMAA9FnrA== - -ansi-escapes@^3.0.0, ansi-escapes@^3.2.0: +ansi-escapes@^3.0.0: version "3.2.0" - resolved "https://registry.npmjs.org/ansi-escapes/-/ansi-escapes-3.2.0.tgz" + resolved "https://registry.npmjs.org/ansi-escapes/-/ansi-escapes-3.2.0.tgz#8780b98ff9dbf5638152d1f1fe5c1d7b4442976b" integrity sha512-cBhpre4ma+U0T1oM5fXg7Dy1Jw7zzwv7lt/GoCpr+hDQJoYnKVPLL4dCvSEFMmQurOQvSrwT7SL/DAlhBI97RQ== +ansi-escapes@^7.0.0: + version "7.3.0" + resolved "https://registry.npmjs.org/ansi-escapes/-/ansi-escapes-7.3.0.tgz#5395bb74b2150a4a1d6e3c2565f4aeca78d28627" + integrity sha512-BvU8nYgGQBxcmMuEeUEmNTvrMVjJNSH7RgW24vXexN4Ven6qCvy4TntnvlnwnMLTVlcRQQdbRY8NKnaIoeWDNg== + dependencies: + environment "^1.0.0" + ansi-regex@^2.0.0: version "2.1.1" - resolved "https://registry.npmjs.org/ansi-regex/-/ansi-regex-2.1.1.tgz" - integrity sha1-w7M6te42DYbg5ijwRorn7yfWVN8= + resolved "https://registry.npmjs.org/ansi-regex/-/ansi-regex-2.1.1.tgz#c3b33ab5ee360d86e0e628f0468ae7ef27d654df" + integrity sha512-TIGnTpdo+E3+pCyAluZvtED5p5wCqLdezCyhPZzKPcxvFplEt4i+W7OONCKgeZFT3+y5NZZfOOS/Bdcanm1MYA== ansi-regex@^3.0.0: version "3.0.1" - resolved "https://registry.npmjs.org/ansi-regex/-/ansi-regex-3.0.1.tgz" + resolved "https://registry.npmjs.org/ansi-regex/-/ansi-regex-3.0.1.tgz#123d6479e92ad45ad897d4054e3c7ca7db4944e1" integrity sha512-+O9Jct8wf++lXxxFc4hc8LsjaSq0HFzzL7cVsw8pRDIPdjKD2mT4ytDZlLuSBZ4cLKZFXIrMGO7DbQCtMJJMKw== -ansi-regex@^4.1.0: - version "4.1.1" - resolved "https://registry.npmjs.org/ansi-regex/-/ansi-regex-4.1.1.tgz" - integrity sha512-ILlv4k/3f6vfQ4OoP2AGvirOktlQ98ZEL1k9FaQjxa3L1abBgbuTDAdPOpvbGncC0BTVQrl+OM8xZGK6tWXt7g== - -ansi-regex@^5.0.0, ansi-regex@^5.0.1: +ansi-regex@^5.0.1: version "5.0.1" - resolved "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz" + resolved "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz#082cb2c89c9fe8659a311a53bd6a4dc5301db304" integrity sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ== +ansi-regex@^6.2.2: + version "6.5.0" + resolved "https://registry.npmjs.org/ansi-regex/-/ansi-regex-6.5.0.tgz#83f070e17628d0031eb33eb2315a72d8bb11d2a0" + integrity sha512-zhvbbbdt1kbw7EJ9OQoxmQcuaNR9P5kTj7e/YdmOSU10aHWbycofJxA6jKfoEy3vlLdctOF9ZHaxLtmSm998wQ== + ansi-styles@^2.2.1: version "2.2.1" - resolved "https://registry.npmjs.org/ansi-styles/-/ansi-styles-2.2.1.tgz" - integrity sha1-tDLdM1i2NM914eRmQ2gkBTPB3b4= + resolved "https://registry.npmjs.org/ansi-styles/-/ansi-styles-2.2.1.tgz#b432dd3358b634cf75e1e4664368240533c1ddbe" + integrity sha512-kmCevFghRiWM7HB5zTPULl4r9bVFSWjz62MhqizDGUrq2NWuNMQyuv4tHHoKJHs69M/MF64lEcHdYIocrdWQYA== -ansi-styles@^3.2.0, ansi-styles@^3.2.1: +ansi-styles@^3.2.1: version "3.2.1" - resolved "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz" + resolved "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz#41fbb20243e50b12be0f04b8dedbf07520ce841d" integrity sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA== dependencies: color-convert "^1.9.0" ansi-styles@^4.0.0: version "4.3.0" - resolved "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz" + resolved "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz#edd803628ae71c04c85ae7a0906edad34b648937" integrity sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg== dependencies: color-convert "^2.0.1" -ansi-styles@^4.1.0: - version "4.2.1" - resolved "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.2.1.tgz" - integrity sha512-9VGjrMsG1vePxcSweQsN20KY/c4zN0h9fLjqAbwbPfahM3t+NL+M9HC8xeXG2I8pX5NoamTGNuomEUFI7fcUjA== - dependencies: - "@types/color-name" "^1.1.1" - color-convert "^2.0.1" +ansi-styles@^6.2.1: + version "6.2.3" + resolved "https://registry.npmjs.org/ansi-styles/-/ansi-styles-6.2.3.tgz#c044d5dcc521a076413472597a1acb1f103c4041" + integrity sha512-4Dj6M28JB+oAH8kFkTLUo+a2jwOFkuqb3yucU0CANcRRUbxS0cP0nZYCGjcc3BNXwRIsUVmDGgzawme7zvJHvg== any-observable@^0.3.0: version "0.3.0" - resolved "https://registry.npmjs.org/any-observable/-/any-observable-0.3.0.tgz" + resolved "https://registry.npmjs.org/any-observable/-/any-observable-0.3.0.tgz#af933475e5806a67d0d7df090dd5e8bef65d119b" integrity sha512-/FQM1EDkTsf63Ub2C6O7GuYFDsSXUwsaZDurV0np41ocwq0jthUAYCmhBX9f+KwlaCgIuWyr/4WlUQUBfKfZog== -any-signal@^3.0.0, any-signal@^3.0.1: - version "3.0.1" - resolved "https://registry.yarnpkg.com/any-signal/-/any-signal-3.0.1.tgz#49cae34368187a3472e31de28fb5cb1430caa9a6" - integrity sha512-xgZgJtKEa9YmDqXodIgl7Fl1C8yNXr8w6gXjqK3LW4GcEiYT+6AQfJSE/8SPsEpLLmcvbv8YU+qet94UewHxqg== - -anymatch@~3.1.2: - version "3.1.3" - resolved "https://registry.npmjs.org/anymatch/-/anymatch-3.1.3.tgz" - integrity sha512-KMReFUr0B4t+D+OBkjR3KYqvocp2XaSzO55UcB6mgQMd3KbcE+mWTyvVV7D/zsdEbNnV6acZUutkiHQXvTr1Rw== - dependencies: - normalize-path "^3.0.0" - picomatch "^2.0.4" - -arg@^4.1.0: - version "4.1.3" - resolved "https://registry.npmjs.org/arg/-/arg-4.1.3.tgz" - integrity sha512-58S9QDqG0Xx27YwPSt9fJxivjYl432YCwfDMfZ+71RAqUrZef7LrKQZ3LHLOwCS4FLNBplP533Zx895SeOCHvA== - -argparse@^1.0.7: - version "1.0.10" - resolved "https://registry.npmjs.org/argparse/-/argparse-1.0.10.tgz" - integrity sha512-o5Roy6tNG4SL/FOkCAN6RzjiakZS25RLYFrcMttJqbdd8BWrnA+fGz57iN5Pb06pvBGvl5gQ0B48dJlslXvoTg== - dependencies: - sprintf-js "~1.0.2" - argparse@^2.0.1: version "2.0.1" - resolved "https://registry.npmjs.org/argparse/-/argparse-2.0.1.tgz" + resolved "https://registry.npmjs.org/argparse/-/argparse-2.0.1.tgz#246f50f3ca78a3240f6c997e8a9bd1eac49e4b38" integrity sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q== -asn1@^0.2.4, asn1@~0.2.3: - version "0.2.6" - resolved "https://registry.npmjs.org/asn1/-/asn1-0.2.6.tgz" - integrity sha512-ix/FxPn0MDjeyJ7i/yoHGFt/EX6LyNbxSEhPPXODPL+KB0VPk86UYfL0lMdy+KCnv+fmvIzySwaK5COwqVbWTQ== - dependencies: - safer-buffer "~2.1.0" - -assert-plus@1.0.0, assert-plus@^1.0.0: - version "1.0.0" - resolved "https://registry.npmjs.org/assert-plus/-/assert-plus-1.0.0.tgz" - integrity sha1-8S4PPF13sLHN2RRpQuTpbB5N1SU= +argparse@^3.0.3: + version "3.0.4" + resolved "https://registry.npmjs.org/argparse/-/argparse-3.0.4.tgz#ba802dd75fdc3d5bdcb4339b713d62c6c5d4565d" + integrity sha512-fwWK3Zq22l4XJJjx5mcBHGikIk+hJqO+32dPm0Jur7+rtG5x1scOjSfdT9ZKeWHPpsya/l0HHK4tDImBkTrtvA== assertion-error@^2.0.1: version "2.0.1" - resolved "https://registry.yarnpkg.com/assertion-error/-/assertion-error-2.0.1.tgz#f641a196b335690b1070bf00b6e7593fec190bf7" + resolved "https://registry.npmjs.org/assertion-error/-/assertion-error-2.0.1.tgz#f641a196b335690b1070bf00b6e7593fec190bf7" integrity sha512-Izi8RQcffqCeNVgFigKli1ssklIbpHnCYc6AknXGYoB6grJqyeby7jv12JUQgmTAnIDnbck1uxksT4dzN3PWBA== -astral-regex@^1.0.0: - version "1.0.0" - resolved "https://registry.npmjs.org/astral-regex/-/astral-regex-1.0.0.tgz" - integrity sha512-+Ryf6g3BKoRc7jfp7ad8tM4TtMiaWvbF/1/sQcZPkkS7ag3D5nMBCe2UfOTONtAkaG0tO0ij3C5Lwmf1EiyjHg== - async-retry@^1.2.3: - version "1.3.1" - resolved "https://registry.npmjs.org/async-retry/-/async-retry-1.3.1.tgz" - integrity sha512-aiieFW/7h3hY0Bq5d+ktDBejxuwR78vRu9hDUdR8rNhSaQ29VzPL4AoIRG7D/c7tdenwOcKvgPM6tIxB3cB6HA== + version "1.3.3" + resolved "https://registry.npmjs.org/async-retry/-/async-retry-1.3.3.tgz#0e7f36c04d8478e7a58bdbed80cedf977785f280" + integrity sha512-wfr/jstw9xNi/0teMHrRW7dsz3Lt5ARhYNZ2ewpadnhaIp5mbALhOAP+EAdsC7t4Z6wqsDVv9+W6gm1Dk9mEyw== dependencies: - retry "0.12.0" + retry "0.13.1" asynckit@^0.4.0: version "0.4.0" - resolved "https://registry.npmjs.org/asynckit/-/asynckit-0.4.0.tgz" - integrity sha1-x57Zf380y48robyXkLzDZkdLS3k= - -aws-sign2@~0.7.0: - version "0.7.0" - resolved "https://registry.npmjs.org/aws-sign2/-/aws-sign2-0.7.0.tgz" - integrity sha1-tG6JCTSpWR8tL2+G1+ap8bP+dqg= - -aws4@^1.8.0: - version "1.10.0" - resolved "https://registry.npmjs.org/aws4/-/aws4-1.10.0.tgz" - integrity sha512-3YDiu347mtVtjpyV3u5kVqQLP242c06zwDOgpeRnybmXlYYsLbtTrUBUm8i8srONt+FWobl5aibnU1030PeeuA== - -balanced-match@^1.0.0: - version "1.0.0" - resolved "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.0.tgz" - integrity sha1-ibTRmasr7kneFk6gK4nORi1xt2c= - -base64-js@^1.0.2: - version "1.3.1" - resolved "https://registry.npmjs.org/base64-js/-/base64-js-1.3.1.tgz" - integrity sha512-mLQ4i2QO1ytvGWFWmcngKO//JXAQueZvwEKtjgQFM4jIK0kU+ytMfplL8j+n5mspOfjHwoAg+9yhb7BwAHm36g== - -base64-js@^1.3.1: - version "1.5.1" - resolved "https://registry.yarnpkg.com/base64-js/-/base64-js-1.5.1.tgz#1b1b440160a5bf7ad40b650f095963481903930a" - integrity sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA== + resolved "https://registry.npmjs.org/asynckit/-/asynckit-0.4.0.tgz#c79ed97f7f34cb8f2ba1bc9790bcc366474b4b79" + integrity sha512-Oei9OH4tRh0YqU3GxhX79dM/mwVgvbZJaSNaRk+bshkj0S5cfHcgYakreBjrHwatXKbz+IoIdYLxrKim2MjW0Q== -bcrypt-pbkdf@^1.0.0, bcrypt-pbkdf@^1.0.2: - version "1.0.2" - resolved "https://registry.npmjs.org/bcrypt-pbkdf/-/bcrypt-pbkdf-1.0.2.tgz" - integrity sha1-pDAdOJtqQ/m2f/PKEaP2Y342Dp4= - dependencies: - tweetnacl "^0.14.3" - -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== - -binary-extensions@^2.0.0: - version "2.2.0" - resolved "https://registry.npmjs.org/binary-extensions/-/binary-extensions-2.2.0.tgz" - integrity sha512-jDctJ/IVQbZoJykoeHbhXpOlNBqGNcwXJKJog42E5HDPUwQTSdjCHdihjj0DlnheQ7blbT6dHOafNAiS8ooQKA== +b4a@^1.6.4, b4a@^1.8.1, b4a@^1.9.0: + version "1.9.0" + resolved "https://registry.npmjs.org/b4a/-/b4a-1.9.0.tgz#6336313b6e76b299c397afa68676ec6ebc788845" + integrity sha512-dpfcF9fDNR6++cthXR67iyhgqWy9CBouAvIWhIntzBG6cvK/cnIPiZQjBwi/ZqjjBEDGfoNDtmB0kTjroOJ3pQ== -bl@^4.0.1: - version "4.0.3" - resolved "https://registry.npmjs.org/bl/-/bl-4.0.3.tgz" - integrity sha512-fs4G6/Hu4/EE+F75J8DuN/0IpQqNjAdC7aEQv7Qt8MHGUH7Ckv2MwTEEeN9QehD0pfIDkMI1bkHYkKy7xHyKIg== - dependencies: - buffer "^5.5.0" - inherits "^2.0.4" - readable-stream "^3.4.0" +balanced-match@^4.0.2: + version "4.0.4" + resolved "https://registry.npmjs.org/balanced-match/-/balanced-match-4.0.4.tgz#bfb10662feed8196a2c62e7c68e17720c274179a" + integrity sha512-BLrgEcRTwX2o6gGxGOCNyMvGSp35YofuYzw9h1IMTRmKqttAZZVU67bdb9Pr2vUHA8+j3i2tJfjO6C6+4myGTA== + +bare-buffer@^3.0.0: + version "3.7.1" + resolved "https://registry.npmjs.org/bare-buffer/-/bare-buffer-3.7.1.tgz#dcd2fb7907cfe7df0cf18cb752a04ae2a41140bc" + integrity sha512-cIjZnSO+y89ykVX9x96OVnA6tGORBn7vGJ/e3PCbBHMEyfMNG/ixzOS0lLa6saMlWcs69bSKjxFyDwjK152OMg== + +bare-events@^2.5.4, bare-events@^2.7.0: + version "2.9.2" + resolved "https://registry.npmjs.org/bare-events/-/bare-events-2.9.2.tgz#01d377b64c3c7167b28b52da7add3221aecf2d7f" + integrity sha512-AIPKioV7/Y/8KfZ3AAhjPJxLLbY49S64Ym5DakZlUg75qQiTgUq9hEJoEwa4eUezPUlXRy/i5NpsKvo9jgKmoA== + +bare-fs@^4.0.1, bare-fs@^4.8.2: + version "4.8.4" + resolved "https://registry.npmjs.org/bare-fs/-/bare-fs-4.8.4.tgz#f342288e7e5d9d8e79917078e1f45950507828c5" + integrity sha512-MPC2eyrpbk3A873sK4y6rk+Iv4o2enxTjHZ8zH3HO0mjrpm5XjnguY2XmfidIsDV6vnjpbMBKUAJpV0ISD2SsQ== + dependencies: + bare-events "^2.5.4" + bare-path "^3.0.0" + bare-stream "^2.6.4" + bare-url "^2.2.2" + fast-fifo "^1.3.2" + +bare-path@^3.0.0: + version "3.1.2" + resolved "https://registry.npmjs.org/bare-path/-/bare-path-3.1.2.tgz#67261bc74a9ba0105ba139b8638f218c09e8d82e" + integrity sha512-ZyKbsuuqK6Ag0K8pX6V5Txq6XeJRvY+wXucnFGRjiyVYP9YWDpIQugk/b+enRYrEYBJaqLzghRQpXPMR7341Nw== -blob-to-it@^2.0.0: - version "2.0.3" - resolved "https://registry.yarnpkg.com/blob-to-it/-/blob-to-it-2.0.3.tgz#ea76abbe7a158d77683a0b155de5ed8dd4c703f4" - integrity sha512-Z3CAVpJMwB9B/lp+hOGEyD+6Rx690v1EBj37Wf/eF7ltXZEu2ppd2H9w/FFNGlx36PW5tsoynTNt2HwkgNV9hw== +bare-stream@^2.6.4: + version "2.13.4" + resolved "https://registry.npmjs.org/bare-stream/-/bare-stream-2.13.4.tgz#61d448a268d1efd992103aae6bd729332f278ac0" + integrity sha512-PcrQ8lVLbiJscNm1Kez+Yp4Gy4AHGcN1lzwjvf5NybWen7VvEgUfyfnXYJ2zNqWnzOfCb1Abq6lH8ti0syQszA== dependencies: - browser-readablestream-to-it "^2.0.0" + b4a "^1.8.1" + streamx "^2.25.0" + teex "^1.0.1" -brace-expansion@^1.1.7: - version "1.1.11" - resolved "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz" - integrity sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA== +bare-url@^2.2.2: + version "2.5.6" + resolved "https://registry.npmjs.org/bare-url/-/bare-url-2.5.6.tgz#7f7a96c459bd432bec43f797c0afca1325cb9b5f" + integrity sha512-iqkXHkW65De+BT14nHLiBFbNuJ/DdMrZaVNJ1IXPctpK6b1olUJ5Qmy8QBvwROajTiGztso2n82kFEvCsNG7Rg== dependencies: - balanced-match "^1.0.0" - concat-map "0.0.1" + bare-buffer "^3.0.0" + bare-path "^3.0.0" -brace-expansion@^2.0.1: - version "2.0.1" - resolved "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.1.tgz" - integrity sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA== - dependencies: - balanced-match "^1.0.0" +before-after-hook@^4.0.0: + version "4.0.0" + resolved "https://registry.npmjs.org/before-after-hook/-/before-after-hook-4.0.0.tgz#cf1447ab9160df6a40f3621da64d6ffc36050cb9" + integrity sha512-q6tR3RPqIB1pMiTRMFcZwuG5T8vwp+vUvEG0vuI6B+Rikh5BfPp2fQ82c925FOs+b0lcFQ8CFrL+KbilfZFhOQ== -braces@~3.0.2: - version "3.0.2" - resolved "https://registry.npmjs.org/braces/-/braces-3.0.2.tgz" - integrity sha512-b8um+L1RzM3WDSzvhm6gIz1yfTbBt6YTlcEKAvsmqCZZFw46z626lVj9j1yEPW33H5H+lBQpZMP1k8l+78Ha0A== +brace-expansion@^5.0.12: + version "5.0.12" + resolved "https://registry.npmjs.org/brace-expansion/-/brace-expansion-5.0.12.tgz#995fbb4750a77c4d16a7dc942ff2ca6ef8e675ec" + integrity sha512-YovQ3rzhaLMIrDjNDMkNS01tea93qhEhG5xy8f6+R0l+dw3Ki+5sCoIoI942iuLZTHWogWktgwVDhU09iNEimQ== dependencies: - fill-range "^7.0.1" - -browser-readablestream-to-it@^1.0.0: - version "1.0.3" - resolved "https://registry.yarnpkg.com/browser-readablestream-to-it/-/browser-readablestream-to-it-1.0.3.tgz#ac3e406c7ee6cdf0a502dd55db33bab97f7fba76" - integrity sha512-+12sHB+Br8HIh6VAMVEG5r3UXCyESIgDW7kzk3BjIXa43DVqVwL7GC5TW3jeh+72dtcH99pPVpw0X8i0jt+/kw== - -browser-readablestream-to-it@^2.0.0: - version "2.0.3" - resolved "https://registry.yarnpkg.com/browser-readablestream-to-it/-/browser-readablestream-to-it-2.0.3.tgz#8c08c7c0d98aa1b4098fd19cb147a6028b188470" - integrity sha512-kFLXH4FWJNZbbIEeqZMCYfVPQx6glf3e1mReo3bB3xbn1o/YWbHsYpxIGo2rfNsmPqv7I+Fg4qObvtvbAq4DbA== + balanced-match "^4.0.2" -browser-stdout@1.3.1: +browser-stdout@^1.3.1: version "1.3.1" - resolved "https://registry.npmjs.org/browser-stdout/-/browser-stdout-1.3.1.tgz" + resolved "https://registry.npmjs.org/browser-stdout/-/browser-stdout-1.3.1.tgz#baa559ee14ced73452229bad7326467c61fabd60" integrity sha512-qhAVI1+Av2X7qelOfAIYwXONood6XlZE/fXaBSmW/T5SzLAmCgzi+eiWE7fUvbHaeNBQH13UftjpXxsfLkMpgw== buffer-from@^1.0.0: - version "1.1.1" - resolved "https://registry.npmjs.org/buffer-from/-/buffer-from-1.1.1.tgz" - integrity sha512-MQcXEUbCKtEo7bhqEs6560Hyd4XaovZlO/k9V3hjVUF/zwW7KBVdSK4gIt/bzwS9MbR5qob+F5jusZsb0YQK2A== - -buffer@^5.5.0: - version "5.6.0" - resolved "https://registry.npmjs.org/buffer/-/buffer-5.6.0.tgz" - integrity sha512-/gDYp/UtU0eA1ys8bOs9J6a+E/KWIY+DZ+Q2WESNUA0jFRsJOc0SNUO6xJ5SGA1xueg3NL65W6s+NY5l9cunuw== - dependencies: - base64-js "^1.0.2" - ieee754 "^1.1.4" - -buffer@^6.0.1, buffer@^6.0.3: - version "6.0.3" - resolved "https://registry.yarnpkg.com/buffer/-/buffer-6.0.3.tgz#2ace578459cc8fbe2a70aaa8f52ee63b6a74c6c6" - integrity sha512-FTiCpNxtwiZZHEZbcbTIcZjERVICn9yq/pDFkTl95/AxzD1naBctN7YO68riM/gLSDY7sdrMby8hofADYuuqOA== - dependencies: - base64-js "^1.3.1" - ieee754 "^1.2.1" - -buildcheck@~0.0.6: - version "0.0.6" - resolved "https://registry.yarnpkg.com/buildcheck/-/buildcheck-0.0.6.tgz#89aa6e417cfd1e2196e3f8fe915eb709d2fe4238" - integrity sha512-8f9ZJCUXyT1M35Jx7MkBgmBMo3oHTTBIPLiY9xyL0pl3T5RwcPEY8cUHr5LBNfu/fk6c2T4DJZuVM/8ZZT2D2A== + version "1.1.2" + resolved "https://registry.npmjs.org/buffer-from/-/buffer-from-1.1.2.tgz#2b146a6fd72e80b4f55d255f35ed59a3a9a41bd5" + integrity sha512-E+XQCRwSbaaiChtv6k6Dwgc+bx+Bs6vuKJHHl5kox/BaKbhiXzqQOwK4cO22yElGp2OCmjwVhT3HmxgyPGnJfQ== -busboy@^1.6.0: - version "1.6.0" - resolved "https://registry.yarnpkg.com/busboy/-/busboy-1.6.0.tgz#966ea36a9502e43cdb9146962523b92f531f6893" - integrity sha512-8SFQbg/0hQ9xy3UNTB0YEnsNBbWfhf7RtnzpL7TkBiTBRfrQ9Fxcnz7VJsleJpyp6rVLvXiuORqjlHi5q+PYuA== - dependencies: - streamsearch "^1.1.0" +byte-counter@^0.1.0: + version "0.1.0" + resolved "https://registry.npmjs.org/byte-counter/-/byte-counter-0.1.0.tgz#c49760b5790e50e942a0d57a57b3fc0e94488dcc" + integrity sha512-jheRLVMeUKrDBjVw2O5+k4EvR4t9wtxHL+bo/LxfkxsVeuGMy3a5SEGgXdAFA4FSzTrU8rQXQIrsZ3oBq5a0pQ== cacheable-lookup@^7.0.0: version "7.0.0" - resolved "https://registry.yarnpkg.com/cacheable-lookup/-/cacheable-lookup-7.0.0.tgz#3476a8215d046e5a3202a9209dd13fec1f933a27" + resolved "https://registry.npmjs.org/cacheable-lookup/-/cacheable-lookup-7.0.0.tgz#3476a8215d046e5a3202a9209dd13fec1f933a27" integrity sha512-+qJyx4xiKra8mZrcwhjMRMUhD5NR1R8esPkzIYxX96JiecFoxAXFuz/GpR3+ev4PE1WamHip78wV0vcmPQtp8w== -cacheable-request@^10.2.8: - version "10.2.14" - resolved "https://registry.yarnpkg.com/cacheable-request/-/cacheable-request-10.2.14.tgz#eb915b665fda41b79652782df3f553449c406b9d" - integrity sha512-zkDT5WAF4hSSoUgyfg5tFIxz8XQK+25W/TLVojJTMKBaxevLBBtLxgqguAuVQB8PVW79FVjHcU+GJ9tVbDZ9mQ== +cacheable-request@^13.0.12: + version "13.0.19" + resolved "https://registry.npmjs.org/cacheable-request/-/cacheable-request-13.0.19.tgz#2c8a3b6b4cc37ea6906cc182f5b838e5822b2f97" + integrity sha512-SVXGH037+Mo1aIMO5B2UcleR43FGjFdN+M8JObSyEoQ2Mn4CODRWx28gN5jiTF0n5ItsgtIZfyargMNs8GX4kg== dependencies: - "@types/http-cache-semantics" "^4.0.2" - get-stream "^6.0.1" - http-cache-semantics "^4.1.1" - keyv "^4.5.3" + "@types/http-cache-semantics" "^4.2.0" + get-stream "^9.0.1" + http-cache-semantics "^4.2.0" + keyv "^5.6.0" mimic-response "^4.0.0" - normalize-url "^8.0.0" - responselike "^3.0.0" - -callsites@^3.0.0: - version "3.1.0" - resolved "https://registry.npmjs.org/callsites/-/callsites-3.1.0.tgz" - integrity sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ== + normalize-url "^8.1.1" + responselike "^4.0.2" -camelcase@^6.0.0: - version "6.3.0" - resolved "https://registry.npmjs.org/camelcase/-/camelcase-6.3.0.tgz" - integrity sha512-Gmy6FhYlCY7uOElZUSbxo2UCDH8owEk996gkbrpsgGtrJLM3J7jGxl9Ic7Qwwj4ivOE5AWZWRMecDdF7hqGjFA== - -caseless@~0.12.0: - version "0.12.0" - resolved "https://registry.npmjs.org/caseless/-/caseless-0.12.0.tgz" - integrity sha1-G2gcIf+EAzyCZUMJBolCDRhxUdw= +cacheable@^2.5.0: + version "2.5.0" + resolved "https://registry.npmjs.org/cacheable/-/cacheable-2.5.0.tgz#d142d41043e5a865f6053cc70ef4e3ad068bd5ce" + integrity sha512-60cyAOytib/OzBw1JNSoSV/boK1AtHryDIjvVBk7XbN4ugfkM3+Sry7fEjNgPMGgOjuaZPAp8ruZ0Cxafwyq9g== + dependencies: + "@cacheable/memory" "^2.2.0" + "@cacheable/utils" "^2.5.0" + hookified "^1.15.0" + keyv "^5.6.0" + qified "^0.10.1" -cborg@^1.10.0, cborg@^1.9.0: - version "1.10.2" - resolved "https://registry.yarnpkg.com/cborg/-/cborg-1.10.2.tgz#83cd581b55b3574c816f82696307c7512db759a1" - integrity sha512-b3tFPA9pUr2zCUiCfRd2+wok2/LBSNUMKOuRRok+WlvvAgEt/PlbgPTsZUcwCOs53IJvLgTp0eotwtosE6njug== +call-bind-apply-helpers@^1.0.1, call-bind-apply-helpers@^1.0.2: + version "1.0.2" + resolved "https://registry.npmjs.org/call-bind-apply-helpers/-/call-bind-apply-helpers-1.0.2.tgz#4b5428c222be985d79c3d82657479dbe0b59b2d6" + integrity sha512-Sp1ablJ0ivDkSzjcaJdxEunN5/XvksFJ2sMBFfq6x0ryhQV/2b/KwFe21cMpmHtPOSij8K99/wSfoEuTObmuMQ== + dependencies: + es-errors "^1.3.0" + function-bind "^1.1.2" chai@^5.1.0: - version "5.1.0" - resolved "https://registry.yarnpkg.com/chai/-/chai-5.1.0.tgz#648cf2d8b5d16f32646612e22ffd12dc617ef960" - integrity sha512-kDZ7MZyM6Q1DhR9jy7dalKohXQ2yrlXkk59CR52aRKxJrobmlBNqnFQxX9xOX8w+4mz8SYlKJa/7D7ddltFXCw== + version "5.3.3" + resolved "https://registry.npmjs.org/chai/-/chai-5.3.3.tgz#dd3da955e270916a4bd3f625f4b919996ada7e06" + integrity sha512-4zNhdJD/iOjSH0A05ea+Ke6MU5mmpQcbQsSOkgdaUMJ9zTlDTD/GYlwohmIE2u0gaxHYiVHEn1Fw9mZ/ktJWgw== dependencies: assertion-error "^2.0.1" - check-error "^2.0.0" + check-error "^2.1.1" deep-eql "^5.0.1" loupe "^3.1.0" pathval "^2.0.0" chalk@^1.0.0, chalk@^1.1.3: version "1.1.3" - resolved "https://registry.npmjs.org/chalk/-/chalk-1.1.3.tgz" - integrity sha1-qBFcVeSnAv5NFQq9OHKCKn4J/Jg= + resolved "https://registry.npmjs.org/chalk/-/chalk-1.1.3.tgz#a8115c55e4a702fe4d150abd3872822a7e09fc98" + integrity sha512-U3lRVLMSlsCfjqYPbLyVv11M9CPW4I728d6TCKMAOJueEeB9/8o+eSsMnxPJD+Q+K909sdESg7C+tIkoH6on1A== dependencies: ansi-styles "^2.2.1" escape-string-regexp "^1.0.2" @@ -1190,101 +1054,69 @@ chalk@^1.0.0, chalk@^1.1.3: strip-ansi "^3.0.0" supports-color "^2.0.0" -chalk@^2.0.0, chalk@^2.4.1, chalk@^2.4.2: +chalk@^2.4.1, chalk@^2.4.2: version "2.4.2" - resolved "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz" + resolved "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz#cd42541677a54333cf541a49108c1432b44c9424" integrity sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ== dependencies: ansi-styles "^3.2.1" escape-string-regexp "^1.0.5" supports-color "^5.3.0" -chalk@^4.0.0: - version "4.1.0" - resolved "https://registry.npmjs.org/chalk/-/chalk-4.1.0.tgz" - integrity sha512-qwx12AxXe2Q5xQ43Ac//I6v5aXTipYrSESdOgzrN+9XjgEpyjpKuvSGaN4qE93f7TQTlerQQ8S+EQ0EyDoVL1A== - dependencies: - ansi-styles "^4.1.0" - supports-color "^7.1.0" - -chalk@^4.1.0: - version "4.1.2" - resolved "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz" - integrity sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA== - dependencies: - ansi-styles "^4.1.0" - supports-color "^7.1.0" - -chardet@^0.7.0: - version "0.7.0" - resolved "https://registry.npmjs.org/chardet/-/chardet-0.7.0.tgz" - integrity sha512-mT8iDcrh03qDGRRmoA2hmBJnxpllMR+0/0qlzjqZES6NdiWDcZkCNAk4rPFZ9Q85r27unkiNNg8ZOiwZXBHwcA== +chardet@^2.1.1: + version "2.2.0" + resolved "https://registry.npmjs.org/chardet/-/chardet-2.2.0.tgz#005d664f2cbd4961888d2e2c32c5a69e59d8eec4" + integrity sha512-rddelWYNPRrXq6PtNEN2S3f6t9ILzvqaN5pVgi4kqt9jHQaXIial9PznB5iSPVlQSLNaaH22ItWz3EJtQ10+OA== -check-error@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/check-error/-/check-error-2.0.0.tgz#589a4f201b6256fd93a2d165089fe43d2676d8c6" - integrity sha512-tjLAOBHKVxtPoHe/SA7kNOMvhCRdCJ3vETdeY0RuAc9popf+hyaSV6ZEg9hr4cpWF7jmo/JSWEnLDrnijS9Tog== - -chokidar@3.5.3: - version "3.5.3" - resolved "https://registry.npmjs.org/chokidar/-/chokidar-3.5.3.tgz" - integrity sha512-Dr3sfKRP6oTcjf2JmUmFJfeVMvXBdegxB0iVQ5eb2V10uFJUCAS8OByZdVAyVb8xXNz3GjjTgj9kLWsZTqE6kw== - dependencies: - anymatch "~3.1.2" - braces "~3.0.2" - glob-parent "~5.1.2" - is-binary-path "~2.1.0" - is-glob "~4.0.1" - normalize-path "~3.0.0" - readdirp "~3.6.0" - optionalDependencies: - fsevents "~2.3.2" +check-error@^2.1.1: + version "2.1.3" + resolved "https://registry.npmjs.org/check-error/-/check-error-2.1.3.tgz#2427361117b70cca8dc89680ead32b157019caf5" + integrity sha512-PAJdDJusoxnwm1VwW07VWwUN1sl7smmC3OKggvndJFadxxDRyFJBX/ggnu/KE4kQAB7a3Dp8f/YXC1FlUprWmA== -chownr@^1.1.1: - version "1.1.4" - resolved "https://registry.npmjs.org/chownr/-/chownr-1.1.4.tgz" - integrity sha512-jJ0bqzaylmJtVnNgzTeSOs8DPavpbYgEr/b0YL8/2GO3xJEhInFmhKMUnEJQjZumK7KXGFhUy89PrsJWlakBVg== +chokidar@^5.0.0: + version "5.0.0" + resolved "https://registry.npmjs.org/chokidar/-/chokidar-5.0.0.tgz#949c126a9238a80792be9a0265934f098af369a5" + integrity sha512-TQMmc3w+5AxjpL8iIiwebF73dRDF4fBIieAqGn9RGCWaEVwQ6Fb2cGe31Yns0RRIzii5goJ1Y7xbMwo1TxMplw== + dependencies: + readdirp "^5.0.0" cli-cursor@^2.0.0, cli-cursor@^2.1.0: version "2.1.0" - resolved "https://registry.npmjs.org/cli-cursor/-/cli-cursor-2.1.0.tgz" - integrity sha1-s12sN2R5+sw+lHR9QdDQ9SOP/LU= + resolved "https://registry.npmjs.org/cli-cursor/-/cli-cursor-2.1.0.tgz#b35dac376479facc3e94747d41d0d0f5238ffcb5" + integrity sha512-8lgKz8LmCRYZZQDpRyT2m5rKJ08TnU4tR9FFFW2rxpxR1FzWi4PQ/NfyODchAatHaUgnSPVcx/R5w6NuTBzFiw== dependencies: restore-cursor "^2.0.0" +cli-cursor@^5.0.0: + version "5.0.0" + resolved "https://registry.npmjs.org/cli-cursor/-/cli-cursor-5.0.0.tgz#24a4831ecf5a6b01ddeb32fb71a4b2088b0dce38" + integrity sha512-aCj4O5wKyszjMmDT4tZj93kxyydN/K5zPWSCe6/0AV/AA1pqe5ZBIw0a2ZfPQV7lL5/yb5HsUreJ6UFAF1tEQw== + dependencies: + restore-cursor "^5.0.0" + cli-progress@^3.8.2: - version "3.8.2" - resolved "https://registry.npmjs.org/cli-progress/-/cli-progress-3.8.2.tgz" - integrity sha512-qRwBxLldMSfxB+YGFgNRaj5vyyHe1yMpVeDL79c+7puGujdKJHQHydgqXDcrkvQgJ5U/d3lpf6vffSoVVUftVQ== + version "3.12.0" + resolved "https://registry.npmjs.org/cli-progress/-/cli-progress-3.12.0.tgz#807ee14b66bcc086258e444ad0f19e7d42577942" + integrity sha512-tRkV3HJ1ASwm19THiiLIXLO7Im7wlTuKnvkYaTkyoAPefqjNg7W7DHKUlGRxy9vxDvbyCYQkQozvptuMkGCg8A== dependencies: - colors "^1.1.2" - string-width "^4.2.0" + string-width "^4.2.3" cli-truncate@^0.2.1: version "0.2.1" - resolved "https://registry.npmjs.org/cli-truncate/-/cli-truncate-0.2.1.tgz" - integrity sha1-nxXPuwcFAFNpIWxiasfQWrkN1XQ= + resolved "https://registry.npmjs.org/cli-truncate/-/cli-truncate-0.2.1.tgz#9f15cfbb0705005369216c626ac7d05ab90dd574" + integrity sha512-f4r4yJnbT++qUPI9NR4XLDLq41gQ+uqnPItWG0F5ZkehuNiTTa3EY0S4AqTSUOeJ7/zU41oWPQSNkW5BqPL9bg== dependencies: slice-ansi "0.0.4" string-width "^1.0.1" -cli-width@^2.0.0: - version "2.2.1" - resolved "https://registry.npmjs.org/cli-width/-/cli-width-2.2.1.tgz" - integrity sha512-GRMWDxpOB6Dgk2E5Uo+3eEBvtOOlimMmpbFiKuLFnQzYDavtLFY3K5ona41jgN/WdRZtG7utuVSVTL4HbZHGkw== - -cliui@^7.0.2: - version "7.0.4" - resolved "https://registry.npmjs.org/cliui/-/cliui-7.0.4.tgz" - integrity sha512-OcRE68cOsVMXp1Yvonl/fzkQOyjLSu/8bhPDfQt0e0/Eb283TKP20Fs2MqoPsr9SwA595rRCA+QMzYc9nBP+JQ== - dependencies: - string-width "^4.2.0" - strip-ansi "^6.0.0" - wrap-ansi "^7.0.0" +cli-width@^4.1.0: + version "4.1.0" + resolved "https://registry.npmjs.org/cli-width/-/cli-width-4.1.0.tgz#42daac41d3c254ef38ad8ac037672130173691c5" + integrity sha512-ouuZd4/dm2Sw5Gmqy6bGyNNNe1qt9RpmxveLSO7KcgsTnU7RXfsw+/bukWGo1abgBiMAic068rclZsO4IWmmxQ== cliui@^8.0.1: version "8.0.1" - resolved "https://registry.npmjs.org/cliui/-/cliui-8.0.1.tgz" + resolved "https://registry.npmjs.org/cliui/-/cliui-8.0.1.tgz#0c04b075db02cbfe60dc8e6cf2f5486b1a3608aa" integrity sha512-BSeNnyus75C4//NQ9gQt1/csTXyo/8Sb+afLAkzAptFuMsod9HFokGNudZpi/oQV73hnVK+sR+5PVRMd+Dr7YQ== dependencies: string-width "^4.2.0" @@ -1293,1302 +1125,743 @@ cliui@^8.0.1: code-point-at@^1.0.0: version "1.1.0" - resolved "https://registry.npmjs.org/code-point-at/-/code-point-at-1.1.0.tgz" - integrity sha1-DQcLTQQ6W+ozovGkDi7bPZpMz3c= + resolved "https://registry.npmjs.org/code-point-at/-/code-point-at-1.1.0.tgz#0d070b4d043a5bea33a2f1a40e2edb3d9a4ccf77" + integrity sha512-RpAVKQA5T63xEj6/giIbUEtZwJ4UFIc3ZtvEkiaUERylqe8xb5IvqcgOurZLahv93CLKfxcw5YI+DZcUBRyLXA== color-convert@^1.9.0: version "1.9.3" - resolved "https://registry.npmjs.org/color-convert/-/color-convert-1.9.3.tgz" + resolved "https://registry.npmjs.org/color-convert/-/color-convert-1.9.3.tgz#bb71850690e1f136567de629d2d5471deda4c1e8" integrity sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg== dependencies: color-name "1.1.3" color-convert@^2.0.1: version "2.0.1" - resolved "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz" + resolved "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz#72d3a68d598c9bdb3af2ad1e84f21d896abd4de3" integrity sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ== dependencies: color-name "~1.1.4" color-name@1.1.3: version "1.1.3" - resolved "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz" - integrity sha1-p9BVi9icQveV3UIyj3QIMcpTvCU= + resolved "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz#a7d0558bd89c42f795dd42328f740831ca53bc25" + integrity sha512-72fSenhMw2HZMTVHeCA9KCmpEIbzWiQsjN+BHcBbS9vr1mtt+vJjPdksIBNUmKAW8TFUDPJK5SUU3QhE9NEXDw== color-name@~1.1.4: version "1.1.4" - resolved "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz" + resolved "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz#c2a09a87acbde69543de6f63fa3995c826c536a2" integrity sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA== -colors@^1.1.2: - version "1.4.0" - resolved "https://registry.npmjs.org/colors/-/colors-1.4.0.tgz" - integrity sha512-a+UqTh4kgZg/SlGvfbzDHpgRu7AAQOmmqRHJnxhRZICKFUT91brVhNNt58CMWU9PsBbv3PDCZUHbVxuDiH2mtA== - -combined-stream@^1.0.6, combined-stream@^1.0.8, combined-stream@~1.0.6: +combined-stream@^1.0.8: version "1.0.8" - resolved "https://registry.npmjs.org/combined-stream/-/combined-stream-1.0.8.tgz" + resolved "https://registry.npmjs.org/combined-stream/-/combined-stream-1.0.8.tgz#c3d45a8b34fd730631a110a8a2520682b31d5a7f" integrity sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg== dependencies: delayed-stream "~1.0.0" -concat-map@0.0.1: - version "0.0.1" - resolved "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz" - integrity sha1-2Klr13/Wjfd5OnMDajug1UBdR3s= - -core-util-is@1.0.2: - version "1.0.2" - resolved "https://registry.npmjs.org/core-util-is/-/core-util-is-1.0.2.tgz" - integrity sha1-tf1UIgqivFq1eqtxQMlAdUUDwac= - -cpu-features@~0.0.4: - version "0.0.7" - resolved "https://registry.yarnpkg.com/cpu-features/-/cpu-features-0.0.7.tgz#81ba93e1d0a729fd25132a54c3ff689c37b542f7" - integrity sha512-fjzFmsUKKCrC9GrM1eQTvQx18e+kjXFzjRLvJPNEDjk31+bJ6ZiV6uchv/hzbzXVIgbWdrEyyX1IFKwse65+8w== - dependencies: - buildcheck "~0.0.6" - nan "^2.17.0" - -create-require@^1.1.0: - version "1.1.1" - resolved "https://registry.npmjs.org/create-require/-/create-require-1.1.1.tgz" - integrity sha512-dcKFX3jn0MpIaXjisoRvexIJVEKzaq7z2rZKxf+MSr9TkdmHmsU4m2lcLojrj/FHl8mk5VxMmYA+ftRkP/3oKQ== +commander@^14.0.0: + version "14.0.3" + resolved "https://registry.npmjs.org/commander/-/commander-14.0.3.tgz#425d79b48f9af82fcd9e4fc1ea8af6c5ec07bbc2" + integrity sha512-H+y0Jo/T1RZ9qPP4Eh1pkcQcLRglraJaSLoyOtHxu6AapkjWVCy2Sit1QQ4x3Dng8qDlSsZEet7g5Pq06MvTgw== -cross-fetch@^3.1.5: - version "3.1.6" - resolved "https://registry.yarnpkg.com/cross-fetch/-/cross-fetch-3.1.6.tgz#bae05aa31a4da760969756318feeee6e70f15d6c" - integrity sha512-riRvo06crlE8HiqOwIpQhxwdOk4fOeR7FVM/wXoxchFEqMNUjvbs3bfo4OTgMEMHzppd4DxFBDbyySj8Cv781g== - dependencies: - node-fetch "^2.6.11" +content-type@^3.0.0: + version "3.1.1" + resolved "https://registry.npmjs.org/content-type/-/content-type-3.1.1.tgz#7c80289f1a03ae3fc1f8399c388d22ae44d1394f" + integrity sha512-GW4qUsfFo59d0HbUibDlWv5wPz+vAAcaTWbKIuKCf0JkC7wWkSyf8f13IpXn5JkeMlB2P8iTSSIjwXljorg2vA== -cross-spawn@^7.0.2: - version "7.0.3" - resolved "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.3.tgz" - integrity sha512-iRDPJKUPVEND7dHPO8rkbOnPpyDygcDFtWjpeWNCgy8WP2rXcxXL8TskReQl6OrB2G7+UJrags1q15Fudc7G6w== +cross-spawn@^7.0.6: + version "7.0.6" + resolved "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.6.tgz#8a58fe78f00dcd70c370451759dfbfaf03e8ee9f" + integrity sha512-uV2QOWP2nWzsy2aMp8aRibhi9dlzF5Hgh5SHaB9OiTGEyDTiJJyx0uy51QXdyWbtAHNua4XJzUKca3OzKUd3vA== dependencies: path-key "^3.1.0" shebang-command "^2.0.0" which "^2.0.1" -dag-jose@^4.0.0: - version "4.0.0" - resolved "https://registry.yarnpkg.com/dag-jose/-/dag-jose-4.0.0.tgz#4e65f62af58dd5203b2b094eb52142ffe0cdec1d" - integrity sha512-tw595L3UYoOUT9dSJPbBEG/qpRpw24kRZxa5SLRnlnr+g5L7O8oEs1d3W5TiVA1oJZbthVsf0Vi3zFN66qcEBA== - dependencies: - "@ipld/dag-cbor" "^9.0.0" - multiformats "^11.0.0" - -dashdash@^1.12.0: - version "1.14.1" - resolved "https://registry.npmjs.org/dashdash/-/dashdash-1.14.1.tgz" - integrity sha1-hTz6D3y+L+1d4gMmuN1YEDX24vA= - dependencies: - assert-plus "^1.0.0" - date-fns@^1.27.2: version "1.30.1" - resolved "https://registry.npmjs.org/date-fns/-/date-fns-1.30.1.tgz" + resolved "https://registry.npmjs.org/date-fns/-/date-fns-1.30.1.tgz#2e71bf0b119153dbb4cc4e88d9ea5acfb50dc05c" integrity sha512-hBSVCvSmWC+QypYObzwGOd9wqdDpOt+0wl0KbU+R+uuZBS1jN8VsD1ss3irQDknRj5NvxiTF6oj/nDRnN/UQNw== -debug@4.3.4, debug@^4.3.1, debug@^4.3.3, 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.0.1, debug@^4.1.1: - version "4.1.1" - resolved "https://registry.npmjs.org/debug/-/debug-4.1.1.tgz" - integrity sha512-pYAIzeRo8J6KPEaJ0VWOh5Pzkbw/RetuzehGM7QRRX5he4fPHx2rdKMB256ehJCkX+XRQm16eZLqLNS8RSZXZw== +debug@^4.3.1, debug@^4.3.2, debug@^4.3.5, debug@^4.4.3: + version "4.4.3" + resolved "https://registry.npmjs.org/debug/-/debug-4.4.3.tgz#c6ae432d9bd9662582fce08709b038c58e9e3d6a" + integrity sha512-RGwwWnwQvkVfavKVt22FGLw+xYSdzARwm0ru6DhTVA3umU5hZc28V3kO4stgYryrTlLpuvgI9GiijltAjNbcqA== dependencies: - ms "^2.1.1" - -decamelize@^4.0.0: - version "4.0.0" - resolved "https://registry.npmjs.org/decamelize/-/decamelize-4.0.0.tgz" - integrity sha512-9iE1PgSik9HeIIw2JO94IidnE3eBoQrFJ3w7sFuzSX4DpmZ3v5sZpUiV5Swcf6mQEF+Y0ru8Neo+p+nyh2J+hQ== + ms "^2.1.3" -decompress-response@^6.0.0: - version "6.0.0" - resolved "https://registry.yarnpkg.com/decompress-response/-/decompress-response-6.0.0.tgz#ca387612ddb7e104bd16d85aab00d5ecf09c66fc" - integrity sha512-aW35yZM6Bb/4oJlZncMH2LCoZtJXTRxES17vE3hoRiowU2kWHaJKFkSBDnDR+cm9J+9QhXmREyIfv0pji9ejCQ== +decompress-response@^10.0.0: + version "10.0.0" + resolved "https://registry.npmjs.org/decompress-response/-/decompress-response-10.0.0.tgz#d8abd2a4c136c3b99b49a08d1f9a709fe35675a4" + integrity sha512-oj7KWToJuuxlPr7VV0vabvxEIiqNMo+q0NueIiL3XhtwC6FVOX7Hr1c0C4eD0bmf7Zr+S/dSf2xvkH3Ad6sU3Q== dependencies: - mimic-response "^3.1.0" + mimic-response "^4.0.0" deep-eql@^5.0.1: - version "5.0.1" - resolved "https://registry.yarnpkg.com/deep-eql/-/deep-eql-5.0.1.tgz#21ea2c0d561a4d08cdd99c417ac584e0fb121385" - integrity sha512-nwQCf6ne2gez3o1MxWifqkciwt0zhl0LO1/UwVu4uMBuPmflWM4oQ70XMqHqnBJA+nhzncaqL9HVL6KkHJ28lw== + version "5.0.2" + resolved "https://registry.npmjs.org/deep-eql/-/deep-eql-5.0.2.tgz#4b756d8d770a9257300825d52a2c2cff99c3a341" + integrity sha512-h5k/5U50IJJFpzfL6nO9jaaumfjO/f2NjK/oYB2Djzm4p9L+3T9qWpZqZ2hAbLPuuYq9wrU08WQyBTL5GbPk5Q== deep-is@^0.1.3: - version "0.1.3" - resolved "https://registry.npmjs.org/deep-is/-/deep-is-0.1.3.tgz" - integrity sha1-s2nW+128E+7PUk+RsHD+7cNXzzQ= - -defer-to-connect@^2.0.1: - version "2.0.1" - resolved "https://registry.yarnpkg.com/defer-to-connect/-/defer-to-connect-2.0.1.tgz#8016bdb4143e4632b77a3449c6236277de520587" - integrity sha512-4tvttepXG1VaYGrRibk5EwJd1t4udunSOVMdLSAL6mId1ix438oPwPZMALY41FCijukO1L0twNcGsdzS7dHgDg== + version "0.1.4" + resolved "https://registry.npmjs.org/deep-is/-/deep-is-0.1.4.tgz#a6f2dce612fadd2ef1f519b73551f17e85199831" + integrity sha512-oIPzksmTg4/MriiaYGO+okXDT7ztn/w3Eptv/+gSIdMdKsJo0u4CfYNFJPy+4SKMuCqGw2wxnA+URMg3t8a/bQ== delayed-stream@~1.0.0: version "1.0.0" - resolved "https://registry.npmjs.org/delayed-stream/-/delayed-stream-1.0.0.tgz" - integrity sha1-3zrhmayt+31ECqrgsp4icrJOxhk= + resolved "https://registry.npmjs.org/delayed-stream/-/delayed-stream-1.0.0.tgz#df3ae199acadfb7d440aaae0b29e2272b24ec619" + integrity sha512-ZySD7Nf91aLB0RxL4KGrKHBXl7Eds1DAmEdcoVawXnLD7SDhpNgtuII2aAkg7a7QS41jxPSZ17p4VdGnMHk3MQ== -deprecation@^2.0.0: - version "2.3.1" - resolved "https://registry.npmjs.org/deprecation/-/deprecation-2.3.1.tgz" - integrity sha512-xmHIy4F3scKVwMsQ4WnVaS8bHOx0DmVwRywosKhaILI0ywMDWPtBSku2HNxRvF7jtwDRsoEwYQSfbxj8b7RlJQ== +diff@^9.0.0: + version "9.0.0" + resolved "https://registry.npmjs.org/diff/-/diff-9.0.0.tgz#297c31cd7c280f13dfe335791ec2063bd4a73a6f" + integrity sha512-svtcdpS8CgJyqAjEQIXdb3OjhFVVYjzGAPO8WGCmRbrml64SPw/jJD4GoE98aR7r25A0XcgrK3F02yw9R/vhQw== -diff@5.0.0: - version "5.0.0" - resolved "https://registry.npmjs.org/diff/-/diff-5.0.0.tgz" - integrity sha512-/VTCrvm5Z0JGty/BWHljh+BAiw3IK+2j87NGMu8Nwc/f48WoDAC395uomO9ZD117ZOBaHmkX1oyLvkVM/aIT3w== - -diff@^4.0.1: - version "4.0.2" - resolved "https://registry.npmjs.org/diff/-/diff-4.0.2.tgz" - integrity sha512-58lmxKSA4BNyLz+HHMUzlOEpg09FV+ev6ZMe3vJihgdxzgcwZ8VoEEPmALCZG9LmqfVoNMMKpttIYTVG6uDY7A== +dotenv@^16.6.1: + version "16.6.1" + resolved "https://registry.npmjs.org/dotenv/-/dotenv-16.6.1.tgz#773f0e69527a8315c7285d5ee73c4459d20a8020" + integrity sha512-uBq4egWHTcTt33a72vpSG0z3HnPuIl6NqYcTrKEg2azoEyl2hpW0zqlxysq2pK9HlDIHyHyakeYaYnSAwd8bow== -dns-over-http-resolver@^2.1.0: - version "2.1.1" - resolved "https://registry.yarnpkg.com/dns-over-http-resolver/-/dns-over-http-resolver-2.1.1.tgz#a3ff3fd7614cea7a4b72594eaf12fb3c85080456" - integrity sha512-Lm/eXB7yAQLJ5WxlBGwYfBY7utduXPZykcSmcG6K7ozM0wrZFvxZavhT6PqI0kd/5CUTfev/RrEFQqyU4CGPew== - dependencies: - debug "^4.3.1" - native-fetch "^4.0.2" - receptacle "^1.3.2" - undici "^5.12.0" - -docker-modem@^3.0.0: - version "3.0.8" - resolved "https://registry.npmjs.org/docker-modem/-/docker-modem-3.0.8.tgz" - integrity sha512-f0ReSURdM3pcKPNS30mxOHSbaFLcknGmQjwSfmbcdOw1XWKXVhukM3NJHhr7NpY9BIyyWQb0EBo3KQvvuU5egQ== - dependencies: - debug "^4.1.1" - readable-stream "^3.5.0" - split-ca "^1.0.1" - ssh2 "^1.11.0" - -dockerode@^3.3.5: - version "3.3.5" - resolved "https://registry.npmjs.org/dockerode/-/dockerode-3.3.5.tgz" - integrity sha512-/0YNa3ZDNeLr/tSckmD69+Gq+qVNhvKfAHNeZJBnp7EOP6RGKV8ORrJHkUn20So5wU+xxT7+1n5u8PjHbfjbSA== - dependencies: - "@balena/dockerignore" "^1.0.2" - docker-modem "^3.0.0" - tar-fs "~2.0.1" - -doctrine@^3.0.0: - version "3.0.0" - resolved "https://registry.npmjs.org/doctrine/-/doctrine-3.0.0.tgz" - integrity sha512-yS+Q5i3hBf7GBkd4KG8a7eBNNWNGLTaEwwYWUijIYM7zrlYDM0BFXHjjPWlWZ1Rg7UaddZeIDmi9jF3HmqiQ2w== - dependencies: - esutils "^2.0.2" - -dotenv@^8.2.0: - version "8.2.0" - resolved "https://registry.npmjs.org/dotenv/-/dotenv-8.2.0.tgz" - integrity sha512-8sJ78ElpbDJBHNeBzUbUVLsqKdccaa/BXF1uPTw3GrvQTBgrQrtObr2mUrE38vzYd8cEv+m/JBfDLioYcfXoaw== - -ecc-jsbn@~0.1.1: - version "0.1.2" - resolved "https://registry.npmjs.org/ecc-jsbn/-/ecc-jsbn-0.1.2.tgz" - integrity sha1-OoOpBOVDUyh4dMVkt1SThoSamMk= - dependencies: - jsbn "~0.1.0" - safer-buffer "^2.1.0" - -electron-fetch@^1.7.2: - version "1.9.1" - resolved "https://registry.yarnpkg.com/electron-fetch/-/electron-fetch-1.9.1.tgz#e28bfe78d467de3f2dec884b1d72b8b05322f30f" - integrity sha512-M9qw6oUILGVrcENMSRRefE1MbHPIz0h79EKIeJWK9v563aT9Qkh8aEHPO1H5vi970wPirNY+jO9OpFoLiMsMGA== +dunder-proto@^1.0.1: + version "1.0.1" + resolved "https://registry.npmjs.org/dunder-proto/-/dunder-proto-1.0.1.tgz#d7ae667e1dc83482f8b70fd0f6eefc50da30f58a" + integrity sha512-KIN/nDJBQRcXw0MLVhZE9iQHmG68qAVIBg9CqmUYjmQIhgij9U5MFvrqkUL5FbtyyzZuOeOt0zdeRe4UY7ct+A== dependencies: - encoding "^0.1.13" + call-bind-apply-helpers "^1.0.1" + es-errors "^1.3.0" + gopd "^1.2.0" elegant-spinner@^1.0.1: version "1.0.1" - resolved "https://registry.npmjs.org/elegant-spinner/-/elegant-spinner-1.0.1.tgz" - integrity sha1-2wQ1IcldfjA/2PNFvtwzSc+wcp4= + resolved "https://registry.npmjs.org/elegant-spinner/-/elegant-spinner-1.0.1.tgz#db043521c95d7e303fd8f345bedc3349cfb0729e" + integrity sha512-B+ZM+RXvRqQaAmkMlO/oSe5nMUOaUnyfGYCEHoR8wrXsZR2mA0XVibsxV1bvTwxdRWah1PkQqso2EzhILGHtEQ== -emoji-regex@^7.0.1: - version "7.0.3" - resolved "https://registry.npmjs.org/emoji-regex/-/emoji-regex-7.0.3.tgz" - integrity sha512-CwBLREIQ7LvYFB0WyRvwhq5N5qPhc6PMjD6bYggFlI5YyDgl+0vxq5VHbMOFqLg7hfWzmu8T5Z1QofhmTIhItA== +emoji-regex@^10.3.0: + version "10.6.0" + resolved "https://registry.npmjs.org/emoji-regex/-/emoji-regex-10.6.0.tgz#bf3d6e8f7f8fd22a65d9703475bc0147357a6b0d" + integrity sha512-toUI84YS5YmxW219erniWD0CIVOo46xGKColeNQRgOzDorgBi1v4D71/OFzgD9GO2UGKIv1C3Sp8DAn0+j5w7A== emoji-regex@^8.0.0: version "8.0.0" - resolved "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz" + resolved "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz#e818fd69ce5ccfcb404594f842963bf53164cc37" integrity sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A== -encoding@^0.1.13: - version "0.1.13" - resolved "https://registry.yarnpkg.com/encoding/-/encoding-0.1.13.tgz#56574afdd791f54a8e9b2785c0582a2d26210fa9" - 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" - integrity sha512-+uw1inIHVPQoaVuHzRyXd21icM+cnt4CzD5rW+NC1wjOUSTOs+Te7FOv7AhN7vS9x/oIyhLP5PR1H+phQAHu5Q== +end-of-stream@^1.1.0: + version "1.4.5" + resolved "https://registry.npmjs.org/end-of-stream/-/end-of-stream-1.4.5.tgz#7344d711dea40e0b74abc2ed49778743ccedb08c" + integrity sha512-ooEGc6HP26xXq/N+GCGOT0JKCLDGrq2bQUZrQ7gyrJiZANJ/8YDTxTpQBXGMn+WbIQXNVpyWymm7KYVICQnyOg== dependencies: once "^1.4.0" -enquirer@^2.3.5: - version "2.3.5" - resolved "https://registry.npmjs.org/enquirer/-/enquirer-2.3.5.tgz" - integrity sha512-BNT1C08P9XD0vNg3J475yIUG+mVdp9T6towYFHUv897X0KoHBjB1shyrNmhmtHWKP17iSWgo7Gqh7BBuzLZMSA== +environment@^1.0.0: + version "1.1.0" + resolved "https://registry.npmjs.org/environment/-/environment-1.1.0.tgz#8e86c66b180f363c7ab311787e0259665f45a9f1" + integrity sha512-xUtoPkMggbz0MPyPiIWr1Kp4aeWJjDZ6SMvURhimjdZgsRuDplF5/s9hcgGhyXMhs+6vpnuoiZ2kFiu3FMnS8Q== + +es-define-property@^1.0.1: + version "1.0.1" + resolved "https://registry.npmjs.org/es-define-property/-/es-define-property-1.0.1.tgz#983eb2f9a6724e9303f61addf011c72e09e0b0fa" + integrity sha512-e3nRfgfUZ4rNGL232gUgX06QNyyez04KdjFrF+LTRoOXmrOgFKDg4BCdsjW8EnT69eqdYGmRpJwiPVYNrCaW3g== + +es-errors@^1.3.0: + version "1.3.0" + resolved "https://registry.npmjs.org/es-errors/-/es-errors-1.3.0.tgz#05f75a25dab98e4fb1dcd5e1472c0546d5057c8f" + integrity sha512-Zf5H2Kxt2xjTvbJvP2ZWLEICxA6j+hAmMzIlypy4xcBg1vKVnx89Wy0GbS+kf5cwCVFFzdCFh2XSCFNULS6csw== + +es-object-atoms@^1.0.0, es-object-atoms@^1.1.1: + version "1.1.2" + resolved "https://registry.npmjs.org/es-object-atoms/-/es-object-atoms-1.1.2.tgz#a2d0b373205724dfa525d23b0c3e1b1ca582c99b" + integrity sha512-HWcBoN6NileqtSydK2FqHbS/LoDd2pqrnQHLyJzBj4kOp/ky2MWMN694xOfkK8/SnUsW2DH7EfyVlydKCsm1Zw== dependencies: - ansi-colors "^3.2.1" + es-errors "^1.3.0" -err-code@^3.0.1: - version "3.0.1" - resolved "https://registry.yarnpkg.com/err-code/-/err-code-3.0.1.tgz#a444c7b992705f2b120ee320b09972eef331c920" - integrity sha512-GiaH0KJUewYok+eeY05IIgjtAe4Yltygk9Wqp1V5yVWLdhf0hYZchRjNIT9bb0mSwRcIusT3cx7PJUf3zEIfUA== +es-set-tostringtag@^2.1.0: + version "2.1.0" + resolved "https://registry.npmjs.org/es-set-tostringtag/-/es-set-tostringtag-2.1.0.tgz#f31dbbe0c183b00a6d26eb6325c810c0fd18bd4d" + integrity sha512-j6vWzfrGVfyXxge+O0x5sh6cvxAog0a/4Rdd2K36zCMV5eJ+/+tOAngRO8cODMNWbVRdVlmGZQL2YS3yR8bIUA== + dependencies: + es-errors "^1.3.0" + get-intrinsic "^1.2.6" + has-tostringtag "^1.0.2" + hasown "^2.0.2" + +esbuild@~0.28.0: + version "0.28.2" + resolved "https://registry.npmjs.org/esbuild/-/esbuild-0.28.2.tgz#0f43bd1bad955b72d24e2261e3abe5957ccf0816" + integrity sha512-HKVLS8dvII+xoKW9kmqxbRKrnWEXfJJr/FZhhJmiqIB0e053QNYFqOBouTMO/k5sID4MvCiUCvv8b9M4h32wIA== + optionalDependencies: + "@esbuild/aix-ppc64" "0.28.2" + "@esbuild/android-arm" "0.28.2" + "@esbuild/android-arm64" "0.28.2" + "@esbuild/android-x64" "0.28.2" + "@esbuild/darwin-arm64" "0.28.2" + "@esbuild/darwin-x64" "0.28.2" + "@esbuild/freebsd-arm64" "0.28.2" + "@esbuild/freebsd-x64" "0.28.2" + "@esbuild/linux-arm" "0.28.2" + "@esbuild/linux-arm64" "0.28.2" + "@esbuild/linux-ia32" "0.28.2" + "@esbuild/linux-loong64" "0.28.2" + "@esbuild/linux-mips64el" "0.28.2" + "@esbuild/linux-ppc64" "0.28.2" + "@esbuild/linux-riscv64" "0.28.2" + "@esbuild/linux-s390x" "0.28.2" + "@esbuild/linux-x64" "0.28.2" + "@esbuild/netbsd-arm64" "0.28.2" + "@esbuild/netbsd-x64" "0.28.2" + "@esbuild/openbsd-arm64" "0.28.2" + "@esbuild/openbsd-x64" "0.28.2" + "@esbuild/openharmony-arm64" "0.28.2" + "@esbuild/sunos-x64" "0.28.2" + "@esbuild/win32-arm64" "0.28.2" + "@esbuild/win32-ia32" "0.28.2" + "@esbuild/win32-x64" "0.28.2" escalade@^3.1.1: - version "3.1.1" - resolved "https://registry.npmjs.org/escalade/-/escalade-3.1.1.tgz" - integrity sha512-k0er2gUkLf8O0zKJiAhmkTnJlTvINGv7ygDNPbeIsX/TJjGJZHuh9B2UxbsaEkmlEo9MfhrSzmhIlhRlI2GXnw== - -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== + version "3.2.0" + resolved "https://registry.npmjs.org/escalade/-/escalade-3.2.0.tgz#011a3f69856ba189dffa7dc8fcce99d2a87903e5" + integrity sha512-WUj2qlxaQtO4g6Pq5c29GTcWGDyd8itL8zTlipgECz3JesAiiOKotd8JU6otB3PACgG6xkJUyVhboMS+bje/jA== escape-string-regexp@^1.0.2, escape-string-regexp@^1.0.5: version "1.0.5" - resolved "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz" - integrity sha1-G2HAViGQqN/2rjuyzwIAyhMLhtQ= + resolved "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz#1b61c0562190a8dff6ae3bb2cf0200ca130b86d4" + integrity sha512-vbRorB5FUQWvla16U8R/qgaFIya2qGzwDrNmCZuYKrbdSUMG6I1ZCGQRefkRVhuOkIGVne7BQ35DSfo1qvJqFg== -eslint-scope@^5.0.0, eslint-scope@^5.1.0: - version "5.1.0" - resolved "https://registry.npmjs.org/eslint-scope/-/eslint-scope-5.1.0.tgz" - integrity sha512-iiGRvtxWqgtx5m8EyQUJihBloE4EnYeGE/bz1wSPwJE6tZuJUtHlhqDM4Xj2ukE8Dyy1+HCZ4hE0fzIVMzb58w== - dependencies: - esrecurse "^4.1.0" - estraverse "^4.1.1" +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#14ba83a5d373e3d311e5afca29cf5bfad965bf34" + integrity sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA== -eslint-utils@^2.0.0: - version "2.1.0" - resolved "https://registry.npmjs.org/eslint-utils/-/eslint-utils-2.1.0.tgz" - integrity sha512-w94dQYoauyvlDc43XnGB8lU3Zt713vNChgt4EWwhXAP2XkBvndfxF0AgIqKOOasjPIPzj9JqgwkwbCYD0/V3Zg== +eslint-scope@^9.1.2: + version "9.1.2" + resolved "https://registry.npmjs.org/eslint-scope/-/eslint-scope-9.1.2.tgz#b9de6ace2fab1cff24d2e58d85b74c8fcea39802" + integrity sha512-xS90H51cKw0jltxmvmHy2Iai1LIqrfbw57b79w/J7MfvDfkIkFZ+kj6zC3BjtUwh150HsSSdxXZcsuv72miDFQ== dependencies: - eslint-visitor-keys "^1.1.0" + "@types/esrecurse" "^4.3.1" + "@types/estree" "^1.0.8" + esrecurse "^4.3.0" + estraverse "^5.2.0" -eslint-visitor-keys@^1.1.0, eslint-visitor-keys@^1.2.0: - version "1.3.0" - resolved "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-1.3.0.tgz" - integrity sha512-6J72N8UNa462wa/KFODt/PJ3IU60SDpC3QXC1Hjc1BXXpfL2C9R5+AU7jhe0F6GREqVMh4Juu+NY7xn+6dipUQ== - -eslint@^7.3.1: - version "7.3.1" - resolved "https://registry.npmjs.org/eslint/-/eslint-7.3.1.tgz" - integrity sha512-cQC/xj9bhWUcyi/RuMbRtC3I0eW8MH0jhRELSvpKYkWep3C6YZ2OkvcvJVUeO6gcunABmzptbXBuDoXsjHmfTA== - dependencies: - "@babel/code-frame" "^7.0.0" - ajv "^6.10.0" - chalk "^4.0.0" - cross-spawn "^7.0.2" - debug "^4.0.1" - doctrine "^3.0.0" - enquirer "^2.3.5" - eslint-scope "^5.1.0" - eslint-utils "^2.0.0" - eslint-visitor-keys "^1.2.0" - espree "^7.1.0" - esquery "^1.2.0" +eslint-visitor-keys@^3.4.3: + version "3.4.3" + resolved "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-3.4.3.tgz#0cd72fe8550e3c2eae156a96a4dddcd1c8ac5800" + integrity sha512-wpc+LXeiyiisxPlEkUzU6svyS1frIO3Mgxj1fdy7Pm8Ygzguax2N3Fa/D/ag1WqbOprdI+uY6wMUl8/a2G+iag== + +eslint-visitor-keys@^5.0.0, eslint-visitor-keys@^5.0.1: + version "5.0.1" + resolved "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-5.0.1.tgz#9e3c9489697824d2d4ce3a8ad12628f91e9f59be" + integrity sha512-tD40eHxA35h0PEIZNeIjkHoDR4YjjJp34biM0mDvplBe//mB+IHCqHDGV7pxF+7MklTvighcCPPZC7ynWyjdTA== + +eslint@^10.14.0: + version "10.14.0" + resolved "https://registry.npmjs.org/eslint/-/eslint-10.14.0.tgz#b7574df08d11d9eaa04222f09606674a0ea51db9" + integrity sha512-T0pNsxkb9IKmtQjhpK3d7nWOpFv+YHuMbTJnSVMoQblF0onvXfErrtp4V1jHtsQPan7dKaGVD0q1WCXnzMF31A== + dependencies: + "@eslint-community/eslint-utils" "^4.8.0" + "@eslint-community/regexpp" "^4.12.2" + "@eslint/config-array" "^0.23.5" + "@eslint/config-helpers" "^0.7.0" + "@eslint/core" "^1.2.1" + "@eslint/plugin-kit" "^0.7.3" + "@humanfs/node" "^0.16.8" + "@humanwhocodes/module-importer" "^1.0.1" + "@humanwhocodes/retry" "^0.4.2" + "@types/estree" "^1.0.6" + ajv "^6.14.0" + cross-spawn "^7.0.6" + debug "^4.3.2" + escape-string-regexp "^4.0.0" + eslint-scope "^9.1.2" + eslint-visitor-keys "^5.0.1" + espree "^11.2.0" + esquery "^1.7.0" esutils "^2.0.2" - file-entry-cache "^5.0.1" - functional-red-black-tree "^1.0.1" - glob-parent "^5.0.0" - globals "^12.1.0" - ignore "^4.0.6" - import-fresh "^3.0.0" + fast-deep-equal "^3.1.3" + file-entry-cache "11.1.5 || >11.1.6 <12" + find-up "^5.0.0" + glob-parent "^6.0.2" + ignore "^5.2.0" imurmurhash "^0.1.4" is-glob "^4.0.0" - js-yaml "^3.13.1" json-stable-stringify-without-jsonify "^1.0.1" - levn "^0.4.1" - lodash "^4.17.14" - minimatch "^3.0.4" + minimatch "^10.2.6" natural-compare "^1.4.0" - optionator "^0.9.1" - progress "^2.0.0" - regexpp "^3.1.0" - semver "^7.2.1" - strip-ansi "^6.0.0" - strip-json-comments "^3.1.0" - table "^5.2.3" - text-table "^0.2.0" - v8-compile-cache "^2.0.3" - -esm@^3.2.25: - version "3.2.25" - resolved "https://registry.yarnpkg.com/esm/-/esm-3.2.25.tgz#342c18c29d56157688ba5ce31f8431fbb795cc10" - integrity sha512-U1suiZ2oDVWv4zPO56S0NcR5QriEahGtdN2OR6FiOG4WJvcjBVFB0qI4+eKoWFH483PKGuLuu6V8Z4T5g63UVA== - -espree@^7.1.0: - version "7.1.0" - resolved "https://registry.npmjs.org/espree/-/espree-7.1.0.tgz" - integrity sha512-dcorZSyfmm4WTuTnE5Y7MEN1DyoPYy1ZR783QW1FJoenn7RailyWFsq/UL6ZAAA7uXurN9FIpYyUs3OfiIW+Qw== - dependencies: - acorn "^7.2.0" - acorn-jsx "^5.2.0" - eslint-visitor-keys "^1.2.0" - -esprima@^4.0.0: - version "4.0.1" - resolved "https://registry.npmjs.org/esprima/-/esprima-4.0.1.tgz" - integrity sha512-eGuFFw7Upda+g4p+QHvnW0RyTX/SVeJBDM/gCtMARO0cLuT2HcEKnTPvhjV6aGeqrCB/sbNop0Kszm0jsaWU4A== + optionator "^0.9.3" -esquery@^1.2.0: - version "1.3.1" - resolved "https://registry.npmjs.org/esquery/-/esquery-1.3.1.tgz" - integrity sha512-olpvt9QG0vniUBZspVRN6lwB7hOZoTRtT+jzR+tS4ffYx2mzbw+z0XCOk44aaLYKApNX5nMm+E+P6o25ip/DHQ== +espree@^11.2.0: + version "11.2.0" + resolved "https://registry.npmjs.org/espree/-/espree-11.2.0.tgz#01d5e47dc332aaba3059008362454a8cc34ccaa5" + integrity sha512-7p3DrVEIopW1B1avAGLuCSh1jubc01H2JHc8B4qqGblmg5gI9yumBgACjWo4JlIc04ufug4xJ3SQI8HkS/Rgzw== dependencies: - estraverse "^5.1.0" + acorn "^8.16.0" + acorn-jsx "^5.3.2" + eslint-visitor-keys "^5.0.1" -esrecurse@^4.1.0: - version "4.2.1" - resolved "https://registry.npmjs.org/esrecurse/-/esrecurse-4.2.1.tgz" - integrity sha512-64RBB++fIOAXPw3P9cy89qfMlvZEXZkqqJkjqqXIvzP5ezRZjW+lPWjw35UX/3EhUPFYbg5ER4JYgDw4007/DQ== +esquery@^1.7.0: + version "1.7.0" + resolved "https://registry.npmjs.org/esquery/-/esquery-1.7.0.tgz#08d048f261f0ddedb5bae95f46809463d9c9496d" + integrity sha512-Ap6G0WQwcU/LHsvLwON1fAQX9Zp0A2Y6Y/cJBl9r/JbW90Zyg4/zbG6zzKa2OTALELarYHmKu0GhpM5EO+7T0g== dependencies: - estraverse "^4.1.0" + estraverse "^5.1.0" -estraverse@^4.1.0, estraverse@^4.1.1: +esrecurse@^4.3.0: version "4.3.0" - resolved "https://registry.npmjs.org/estraverse/-/estraverse-4.3.0.tgz" - integrity sha512-39nnKffWz8xN1BU/2c79n9nB9HDzo0niYUqx6xyqUnyoAnQyyWpOTdZEeiCch8BBu515t4wp9ZmgVfVhn9EBpw== + resolved "https://registry.npmjs.org/esrecurse/-/esrecurse-4.3.0.tgz#7ad7964d679abb28bee72cec63758b1c5d2c9921" + integrity sha512-KmfKL3b6G+RXvP8N1vr3Tq1kL/oCFgn2NYXEtqP8/L3pKapUA4G8cFVaoF3SU323CD4XypR/ffioHmkti6/Tag== + dependencies: + estraverse "^5.2.0" -estraverse@^5.1.0: - version "5.1.0" - resolved "https://registry.npmjs.org/estraverse/-/estraverse-5.1.0.tgz" - integrity sha512-FyohXK+R0vE+y1nHLoBM7ZTyqRpqAlhdZHCWIWEviFLiGB8b04H6bQs8G+XTthacvT8VuwvteiP7RJSxMs8UEw== +estraverse@^5.1.0, estraverse@^5.2.0: + version "5.3.0" + resolved "https://registry.npmjs.org/estraverse/-/estraverse-5.3.0.tgz#2eea5290702f26ab8fe5370370ff86c965d21123" + integrity sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA== esutils@^2.0.2: version "2.0.3" - resolved "https://registry.npmjs.org/esutils/-/esutils-2.0.3.tgz" + resolved "https://registry.npmjs.org/esutils/-/esutils-2.0.3.tgz#74d2eb4de0b8da1293711910d50775b9b710ef64" integrity sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g== -ethers@6.3.0: - version "6.3.0" - resolved "https://registry.yarnpkg.com/ethers/-/ethers-6.3.0.tgz#c61efaafa2bd9a4d9f0c799d932ef3b5cd4bd37d" - integrity sha512-CKFYvTne1YT4S1glTiu7TgGsj0t6c6GAD7evrIk8zbeUb6nK8dcUPAiAWM8uDX/1NmRTvLM9+1Vnn49hwKtEzw== - dependencies: - "@adraffy/ens-normalize" "1.9.0" - "@noble/hashes" "1.1.2" - "@noble/secp256k1" "1.7.1" - aes-js "4.0.0-beta.3" - tslib "2.4.0" - ws "8.5.0" - -ethers@^6.9.0: - version "6.10.0" - resolved "https://registry.yarnpkg.com/ethers/-/ethers-6.10.0.tgz#20f3c63c60d59a993f8090ad423d8a3854b3b1cd" - integrity sha512-nMNwYHzs6V1FR3Y4cdfxSQmNgZsRj1RiTU25JwvnJLmyzw9z3SKxNc2XKDuiXXo/v9ds5Mp9m6HBabgYQQ26tA== +ethers@^6.17.0: + version "6.17.0" + resolved "https://registry.npmjs.org/ethers/-/ethers-6.17.0.tgz#ad85ee1fc45fe2d95cb1e21c4e3ff9f7f1b093cc" + integrity sha512-BpyrpIPJ3ydEVow8zGaz1DuPS7YU8DcWxuBnY9a0UA/lvAPwrMr+EPXsfrul628SRaekPNeIM4UFh/91GWZang== dependencies: - "@adraffy/ens-normalize" "1.10.0" + "@adraffy/ens-normalize" "1.11.1" "@noble/curves" "1.2.0" "@noble/hashes" "1.3.2" - "@types/node" "18.15.13" + "@types/node" "22.7.5" aes-js "4.0.0-beta.5" - tslib "2.4.0" - ws "8.5.0" + tslib "2.7.0" + ws "8.21.0" -eventemitter3@^4.0.7: - version "4.0.7" - resolved "https://registry.yarnpkg.com/eventemitter3/-/eventemitter3-4.0.7.tgz#2de9b68f6528d5644ef5c59526a1b4a07306169f" - integrity sha512-8guHBZCwKnFhYdHr2ysuRWErTwhoN2X8XELRlrRwpmfeY2jjuUN4taQMsULKUVo1K4DvZl+0pgfyoysHxvmvEw== - -extend@~3.0.2: - version "3.0.2" - resolved "https://registry.npmjs.org/extend/-/extend-3.0.2.tgz" - integrity sha512-fjquC59cD7CyW6urNXK0FBufkZcoiGG80wTuPujX590cB5Ttln20E2UB4S/WARVqhXffZl2LNgS+gQdPIIim/g== - -external-editor@^3.0.3: - version "3.1.0" - resolved "https://registry.npmjs.org/external-editor/-/external-editor-3.1.0.tgz" - integrity sha512-hMQ4CX1p1izmuLYyZqLMO/qGNw10wSv9QDCPfzXfyFrOaCSSoRfqE1Kf1s5an66J5JZC62NewG+mK49jOCtQew== +events-universal@^1.0.0: + version "1.0.1" + resolved "https://registry.npmjs.org/events-universal/-/events-universal-1.0.1.tgz#b56a84fd611b6610e0a2d0f09f80fdf931e2dfe6" + integrity sha512-LUd5euvbMLpwOF8m6ivPCbhQeSiYVNb8Vs0fQ8QjXo0JTkEHpz8pxdQf0gStltaPpw0Cca8b39KxvK9cfKRiAw== dependencies: - chardet "^0.7.0" - iconv-lite "^0.4.24" - tmp "^0.0.33" - -extsprintf@1.3.0: - version "1.3.0" - resolved "https://registry.npmjs.org/extsprintf/-/extsprintf-1.3.0.tgz" - integrity sha1-lpGEQOMEGnpBT4xS48V06zw+HgU= - -extsprintf@^1.2.0: - version "1.4.0" - resolved "https://registry.npmjs.org/extsprintf/-/extsprintf-1.4.0.tgz" - integrity sha1-4mifjzVvrWLMplo6kcXfX5VRaS8= + bare-events "^2.7.0" fast-deep-equal@^3.1.1, fast-deep-equal@^3.1.3: version "3.1.3" - resolved "https://registry.yarnpkg.com/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz#3a7d56b559d6cbc3eb512325244e619a65c6c525" + resolved "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz#3a7d56b559d6cbc3eb512325244e619a65c6c525" integrity sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q== -fast-fifo@^1.0.0: - version "1.2.0" - resolved "https://registry.yarnpkg.com/fast-fifo/-/fast-fifo-1.2.0.tgz#2ee038da2468e8623066dee96958b0c1763aa55a" - integrity sha512-NcvQXt7Cky1cNau15FWy64IjuO8X0JijhTBBrJj1YlxlDfRkJXNaK9RFUjwpfDPzMdv7wB38jr53l9tkNLxnWg== +fast-fifo@^1.3.2: + version "1.3.2" + resolved "https://registry.npmjs.org/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" + resolved "https://registry.npmjs.org/fast-json-stable-stringify/-/fast-json-stable-stringify-2.1.0.tgz#874bf69c6f404c2b5d99c481341399fd55892633" integrity sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw== fast-levenshtein@^2.0.6: version "2.0.6" - resolved "https://registry.npmjs.org/fast-levenshtein/-/fast-levenshtein-2.0.6.tgz" - integrity sha1-PYpcZog6FqMMqGQ+hR8Zuqd5eRc= + resolved "https://registry.npmjs.org/fast-levenshtein/-/fast-levenshtein-2.0.6.tgz#3d8a5c66883a16a30ca8643e851f19baa7797917" + integrity sha512-DCXu6Ifhqcks7TZKY3Hxp3y6qphY5SJZmrWMDrKcERSOXWQdMhU9Ig/PYrzyw/ul9jOIyh0N4M0tbC5hodg8dw== fast-uri@^3.0.1: - version "3.0.6" - resolved "https://registry.yarnpkg.com/fast-uri/-/fast-uri-3.0.6.tgz#88f130b77cfaea2378d56bf970dea21257a68748" - integrity sha512-Atfo14OibSv5wAp4VWNsFYE1AchQRTv9cBGWET4pZWHzYshFSS9NQI6I57rdKn9croWVMbYFbLhJ+yJvmZIIHw== + version "3.1.9" + resolved "https://registry.npmjs.org/fast-uri/-/fast-uri-3.1.9.tgz#f1deba822b1d6ac79da2f860e872a63470cff203" + integrity sha512-hS/0Wt3Ya043oKXs0sIxrMpKQITXhMLIrVAKKXi4gozGC9v7YRWVnXIZzjNPTO02M9BdxLCWqK1yRXgNziVyJQ== -figlet@^1.2.3: - version "1.4.0" - resolved "https://registry.npmjs.org/figlet/-/figlet-1.4.0.tgz" - integrity sha512-CxxIjEKHlqGosgXaIA+sikGDdV6KZOOlzPJnYuPgQlOSHZP5h9WIghYI30fyXnwEVeSH7Hedy72gC6zJrFC+SQ== +fdir@^6.5.0: + version "6.5.0" + resolved "https://registry.npmjs.org/fdir/-/fdir-6.5.0.tgz#ed2ab967a331ade62f18d077dae192684d50d350" + integrity sha512-tIbYtZbucOs0BRGqPJkshJUYdL+SDH7dVM8gjy+ERp3WAUjLEFJE+02kanyHtwjWOnwrKYBiwAmM0p4kLJAnXg== + +figlet@*, figlet@^1.2.3: + version "1.12.0" + resolved "https://registry.npmjs.org/figlet/-/figlet-1.12.0.tgz#3e9c3a12f112db9479bd5ae4b87bc2b337b9a1af" + integrity sha512-Ith3WsUi0N/EqGt+0/F6XnWhT04sohhH2tT0Dq7GdUmWbMTIoCbg2Jq9qKggmTO62ST5kRCfB311EmIMbizGyA== + dependencies: + commander "^14.0.0" figures@^1.7.0: version "1.7.0" - resolved "https://registry.npmjs.org/figures/-/figures-1.7.0.tgz" - integrity sha1-y+Hjr/zxzUS4DK3+0o3Hk6lwHS4= + resolved "https://registry.npmjs.org/figures/-/figures-1.7.0.tgz#cbe1e3affcf1cd44b80cadfed28dc793a9701d2e" + integrity sha512-UxKlfCRuCBxSXU4C6t9scbDyWZ4VlaFFdojKtzJuSkuOBQ5CNFum+zZXFwHjo+CxBC1t6zlYPgHIgFjL8ggoEQ== dependencies: escape-string-regexp "^1.0.5" object-assign "^4.1.0" figures@^2.0.0: version "2.0.0" - resolved "https://registry.npmjs.org/figures/-/figures-2.0.0.tgz" - integrity sha1-OrGi0qYsi/tDGgyUy3l6L84nyWI= + resolved "https://registry.npmjs.org/figures/-/figures-2.0.0.tgz#3ab1a2d2a62c8bfb431a0c94cb797a2fce27c962" + integrity sha512-Oa2M9atig69ZkfwiApY8F2Yy+tzMbazyvqv21R0NsSC8floSOC09BbT1ITWAdoMGQvJ/aZnR1KMwdx9tvHnTNA== dependencies: escape-string-regexp "^1.0.5" -file-entry-cache@^5.0.1: - version "5.0.1" - resolved "https://registry.npmjs.org/file-entry-cache/-/file-entry-cache-5.0.1.tgz" - integrity sha512-bCg29ictuBaKUwwArK4ouCaqDgLZcysCFLmM/Yn/FDoqndh/9vNuQfXRDvTuXKLxfD/JtZQGKFT8MGcJBK644g== +"file-entry-cache@11.1.5 || >11.1.6 <12": + version "11.1.5" + resolved "https://registry.npmjs.org/file-entry-cache/-/file-entry-cache-11.1.5.tgz#c8210eb055de63e68685ccfb6a017e386d4577d0" + integrity sha512-+PFTHITI08JIGhnNpGNI8T8inUpgZfk3GNEqfT9R2zZV2iFXg3CvqzSl/uEhs7TSGujYRELEANyDvS8Fj7+S7Q== dependencies: - flat-cache "^2.0.1" + flat-cache "^6.1.23" -fill-range@^7.0.1: - version "7.0.1" - resolved "https://registry.npmjs.org/fill-range/-/fill-range-7.0.1.tgz" - integrity sha512-qOo9F+dMUmC2Lcb4BbVvnKJxTPjCm+RRpe4gDuGrzkL7mEVl/djYSu2OdQ2Pa302N4oqkSg9ir6jaLWJ2USVpQ== - dependencies: - to-regex-range "^5.0.1" +find-up-simple@^1.0.1: + version "1.0.1" + resolved "https://registry.npmjs.org/find-up-simple/-/find-up-simple-1.0.1.tgz#18fb90ad49e45252c4d7fca56baade04fa3fca1e" + integrity sha512-afd4O7zpqHeRyg4PfDQsXmlDe2PfdHtJt6Akt8jOWaApLOZk5JXs6VMR29lz03pRe9mpykrRCYIYxaJYcfpncQ== -find-up@5.0.0: +find-up@^5.0.0: version "5.0.0" - resolved "https://registry.npmjs.org/find-up/-/find-up-5.0.0.tgz" + resolved "https://registry.npmjs.org/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" -flat-cache@^2.0.1: - version "2.0.1" - resolved "https://registry.npmjs.org/flat-cache/-/flat-cache-2.0.1.tgz" - integrity sha512-LoQe6yDuUMDzQAEH8sgmh4Md6oZnc/7PjtwjNFSzveXqSHt6ka9fPBuso7IGf9Rz4uqnSnWiFH2B/zj24a5ReA== +flat-cache@^6.1.23: + version "6.1.23" + resolved "https://registry.npmjs.org/flat-cache/-/flat-cache-6.1.23.tgz#735dc888c271868d7301b3bbb8edba5028afb61d" + integrity sha512-f++BY9pTk+983xK1FLzlLpmM0i0z+jHmx3QESGkURMXujQZz1k5wzwX6hjnQ8goaD0B+sYnDK1yZ6MTyZfUaqA== dependencies: - flatted "^2.0.0" - rimraf "2.6.3" - write "1.0.3" - -flat@^5.0.2: - version "5.0.2" - resolved "https://registry.npmjs.org/flat/-/flat-5.0.2.tgz" - integrity sha512-b6suED+5/3rTpUBdG1gupIl8MPFCAMA0QXwmljLhvCUKcUvdE4gWky9zpuGCcXHOsz4J9wPGNWq6OKpmIzz3hQ== - -flatted@^2.0.0: - version "2.0.2" - resolved "https://registry.npmjs.org/flatted/-/flatted-2.0.2.tgz" - integrity sha512-r5wGx7YeOwNWNlCA0wQ86zKyDLMQr+/RB8xy74M4hTphfmjlijTSSXGuH8rnvKZnfT9i+75zmd8jcKdMR4O6jA== + cacheable "^2.5.0" + flatted "^3.4.2" + hookified "^1.15.0" -forever-agent@~0.6.1: - version "0.6.1" - resolved "https://registry.npmjs.org/forever-agent/-/forever-agent-0.6.1.tgz" - integrity sha1-+8cfDEGt6zf5bFd60e1C2P2sypE= - -form-data-encoder@^2.1.2: - version "2.1.4" - resolved "https://registry.yarnpkg.com/form-data-encoder/-/form-data-encoder-2.1.4.tgz#261ea35d2a70d48d30ec7a9603130fa5515e9cd5" - integrity sha512-yDYSgNMraqvnxiEXO4hi88+YZxaHC6QKzb5N84iRCTDeRO7ZALpir/lVmf/uXUhnwUr2O4HU8s/n6x+yNjQkHw== +flatted@^3.4.2: + version "3.4.4" + resolved "https://registry.npmjs.org/flatted/-/flatted-3.4.4.tgz#aeeca2a506303f0cee61c59e6c9f2a88d2f29fc6" + integrity sha512-5+ybhBZANEJxaH3X5evAFatUxLfEHSr7n6kYJ+1Qd0mUqr4eu9gIf6GDbWHf8RJijHrjjO8G+la14SlL2SeS1Q== -form-data@^2.5.0: - version "2.5.1" - resolved "https://registry.npmjs.org/form-data/-/form-data-2.5.1.tgz" - integrity sha512-m21N3WOmEEURgk6B9GLOE4RuWOFf28Lhh9qGYeNlGq4VDXUlJy2th2slBNU8Gp8EzloYZOibZJ7t5ecIrFSjVA== - dependencies: - asynckit "^0.4.0" - combined-stream "^1.0.6" - mime-types "^2.1.12" +form-data-encoder@^4.0.2: + version "4.1.0" + resolved "https://registry.npmjs.org/form-data-encoder/-/form-data-encoder-4.1.0.tgz#497cedc94810bd5d53b99b5d4f6c152d5cbc9db2" + integrity sha512-G6NsmEW15s0Uw9XnCg+33H3ViYRyiM0hMrMhhqQOR8NFc5GhYrI+6I3u7OTw7b91J2g8rtvMBZJDbcGb2YUniw== -form-data@^3.0.0: - version "3.0.0" - resolved "https://registry.npmjs.org/form-data/-/form-data-3.0.0.tgz" - integrity sha512-CKMFDglpbMi6PyN+brwB9Q/GOw0eAnsrEZDgcsH5Krhz5Od/haKHAX0NmQfha2zPPz0JpWzA7GJHGSnvCRLWsg== +form-data@^4.0.6: + version "4.0.6" + resolved "https://registry.npmjs.org/form-data/-/form-data-4.0.6.tgz#28e864e1b786dbebb68db1f452f9635278665827" + integrity sha512-vKatAh4SlVfgbv+YtmhiRjhEMJsYpsG1Y2rMQtR+SVSbytsSD1YGzDIcrAJmdFec88u/+VoGmxnl+80gL1tRCQ== dependencies: asynckit "^0.4.0" combined-stream "^1.0.8" - mime-types "^2.1.12" + es-set-tostringtag "^2.1.0" + hasown "^2.0.4" + mime-types "^2.1.35" -form-data@~2.3.2: +fsevents@~2.3.3: version "2.3.3" - resolved "https://registry.npmjs.org/form-data/-/form-data-2.3.3.tgz" - integrity sha512-1lLKB2Mu3aGP1Q/2eCOx0fNbRMe7XdwktwOruhfqqd0rIJWwN4Dh+E3hrPSlDCXnSR7UtZ1N38rVXm+6+MEhJQ== - dependencies: - asynckit "^0.4.0" - combined-stream "^1.0.6" - mime-types "^2.1.12" - -fs-constants@^1.0.0: - version "1.0.0" - resolved "https://registry.npmjs.org/fs-constants/-/fs-constants-1.0.0.tgz" - integrity sha512-y6OAwoSIf7FyjMIv94u+b5rdheZEjzR63GTyZJm5qh4Bi+2YgwLCcI/fPFZkL5PSixOt6ZNKm+w+Hfp/Bciwow== - -fs.realpath@^1.0.0: - version "1.0.0" - resolved "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz" - integrity sha1-FQStJSMVjKpA20onh8sBQRmU6k8= - -fsevents@~2.3.2: - version "2.3.2" - resolved "https://registry.npmjs.org/fsevents/-/fsevents-2.3.2.tgz" - integrity sha512-xiqMQR4xAeHTuB9uWm+fFRcIOgKBMiOBP+eXiyT7jsgVCq1bkVygt00oASowB7EdtpOHaaPgKt812P9ab+DDKA== + resolved "https://registry.npmjs.org/fsevents/-/fsevents-2.3.3.tgz#cac6407785d03675a2a5e1a5305c697b347d90d6" + integrity sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw== -functional-red-black-tree@^1.0.1: - version "1.0.1" - resolved "https://registry.npmjs.org/functional-red-black-tree/-/functional-red-black-tree-1.0.1.tgz" - integrity sha1-GwqzvVU7Kg1jmdKcDj6gslIHgyc= +function-bind@^1.1.2: + version "1.1.2" + resolved "https://registry.npmjs.org/function-bind/-/function-bind-1.1.2.tgz#2c02d864d97f3ea6c8830c464cbd11ab6eab7a1c" + integrity sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA== 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" + resolved "https://registry.npmjs.org/get-caller-file/-/get-caller-file-2.0.5.tgz#4f94412a82db32f36e3b0b9741f8a97feb031f7e" integrity sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg== -get-func-name@^2.0.1: - 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-iterator@^1.0.2: - version "1.0.2" - resolved "https://registry.yarnpkg.com/get-iterator/-/get-iterator-1.0.2.tgz#cd747c02b4c084461fac14f48f6b45a80ed25c82" - integrity sha512-v+dm9bNVfOYsY1OrhaCrmyOcYoSeVvbt+hHZ0Au+T+p1y+0Uyj9aMaGIeUTT6xdpRbWzDeYKvfOslPhggQMcsg== - -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== +get-east-asian-width@^1.0.0, get-east-asian-width@^1.3.1: + version "1.7.0" + resolved "https://registry.npmjs.org/get-east-asian-width/-/get-east-asian-width-1.7.0.tgz#7ee99f0bd5ab7c622002deeabba232923726d1d4" + integrity sha512-XjH1AECxf0giL2V1aU8vKyRR2ppRUb5c0EvT7zuJTokQ74bNo52zOtghqdWIqrhUD79fo3x0WfKZdOqxF6LG1Q== -getpass@^0.1.1: - version "0.1.7" - resolved "https://registry.npmjs.org/getpass/-/getpass-0.1.7.tgz" - integrity sha1-Xv+OPmhNVprkyysSgmBOi6YhSfo= +get-intrinsic@^1.2.6: + version "1.3.0" + resolved "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.3.0.tgz#743f0e3b6964a93a5491ed1bffaae054d7f98d01" + integrity sha512-9fSjSaos/fRIVIp+xSJlE6lfwhES7LNtKaCBIamHsjr2na1BiABJPo0mOjjz8GJDURarmCPGqaiVg5mfjb98CQ== + dependencies: + call-bind-apply-helpers "^1.0.2" + es-define-property "^1.0.1" + es-errors "^1.3.0" + es-object-atoms "^1.1.1" + function-bind "^1.1.2" + get-proto "^1.0.1" + gopd "^1.2.0" + has-symbols "^1.1.0" + hasown "^2.0.2" + math-intrinsics "^1.1.0" + +get-proto@^1.0.1: + version "1.0.1" + resolved "https://registry.npmjs.org/get-proto/-/get-proto-1.0.1.tgz#150b3f2743869ef3e851ec0c49d15b1d14d00ee1" + integrity sha512-sTSfBjoXBp89JvIKIefqw7U2CCebsc74kiY6awiGogKtoSGbgjYE/G/+l9sF3MWFPNc9IcoOC4ODfKHfxFmp0g== dependencies: - assert-plus "^1.0.0" + dunder-proto "^1.0.1" + es-object-atoms "^1.0.0" -glob-parent@^5.0.0, glob-parent@~5.1.2: - version "5.1.2" - resolved "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.2.tgz" - integrity sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow== +get-stream@^9.0.1: + version "9.0.1" + resolved "https://registry.npmjs.org/get-stream/-/get-stream-9.0.1.tgz#95157d21df8eb90d1647102b63039b1df60ebd27" + integrity sha512-kVCxPF3vQM/N0B1PmoqVUqgHP+EeVjmZSQn+1oCRPxd2P21P2F19lIgbR3HBosbB1PUhOAoctJnfEn2GbN2eZA== dependencies: - is-glob "^4.0.1" - -glob@7.2.0: - version "7.2.0" - resolved "https://registry.npmjs.org/glob/-/glob-7.2.0.tgz" - 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@^7.1.3, glob@^7.1.6: - version "7.1.6" - resolved "https://registry.npmjs.org/glob/-/glob-7.1.6.tgz" - integrity sha512-LwaxwyZ72Lk7vZINtNNrywX0ZuLyStrdDtabefZKAY5ZGJhVtgdznluResxNmPitE0SAO+O26sWTHeKSI2wMBA== - 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" - -globals@^12.1.0: - version "12.4.0" - resolved "https://registry.npmjs.org/globals/-/globals-12.4.0.tgz" - integrity sha512-BWICuzzDvDoH54NHKCseDanAhE3CeDorgDL5MT6LMXXj2WCnd9UC2szdk4AWLfjdgNBCXLUanXYcpBBKOSWGwg== - dependencies: - type-fest "^0.8.1" - -got@^12.6.1: - version "12.6.1" - resolved "https://registry.yarnpkg.com/got/-/got-12.6.1.tgz#8869560d1383353204b5a9435f782df9c091f549" - integrity sha512-mThBblvlAF1d4O5oqyvN+ZxLAYwIJK7bpMxgYqPD9okW0C3qm5FFn7k811QrcuEBwaogR3ngOFoCfs6mRv7teQ== - dependencies: - "@sindresorhus/is" "^5.2.0" - "@szmarczak/http-timer" "^5.0.1" - cacheable-lookup "^7.0.0" - cacheable-request "^10.2.8" - decompress-response "^6.0.0" - form-data-encoder "^2.1.2" - get-stream "^6.0.1" - http2-wrapper "^2.1.10" - lowercase-keys "^3.0.0" - p-cancelable "^3.0.0" - responselike "^3.0.0" + "@sec-ant/readable-stream" "^0.4.1" + is-stream "^4.0.1" -graphql-request@^6.0.0: - version "6.1.0" - resolved "https://registry.yarnpkg.com/graphql-request/-/graphql-request-6.1.0.tgz#f4eb2107967af3c7a5907eb3131c671eac89be4f" - integrity sha512-p+XPfS4q7aIpKVcgmnZKhMNqhltk20hfXtkaIkTfjjmiKMJ5xrt5c743cL03y/K7y1rg3WrIC49xGiEQ4mxdNw== +glob-parent@^6.0.2: + version "6.0.2" + resolved "https://registry.npmjs.org/glob-parent/-/glob-parent-6.0.2.tgz#6d237d99083950c79290f24c7642a3de9a28f9e3" + integrity sha512-XxwI8EOhVQgWp6iDL+3b0r86f4d6AX6zSU55HfB4ydCEuXLXc5FcYeOu+nnGftS4TEju/11rt4KJPTMgbfmv4A== dependencies: - "@graphql-typed-document-node/core" "^3.2.0" - cross-fetch "^3.1.5" + is-glob "^4.0.3" -graphql@^16.6.0: - version "16.6.0" - resolved "https://registry.yarnpkg.com/graphql/-/graphql-16.6.0.tgz#c2dcffa4649db149f6282af726c8c83f1c7c5fdb" - integrity sha512-KPIBPDlW7NxrbT/eh4qPXz5FiFdL5UbaA0XUNz2Rp3Z3hqBSkbj0GVjwFDztsWVauZUWsbKHgMg++sk8UX0bkw== - -hamt-sharding@^3.0.0: - version "3.0.2" - resolved "https://registry.yarnpkg.com/hamt-sharding/-/hamt-sharding-3.0.2.tgz#a3fba1e4e6b58469388a0e1458768c78c0cd95f6" - integrity sha512-f0DzBD2tSmLFdFsLAvOflIBqFPjerbA7BfmwO8mVho/5hXwgyyYhv+ijIzidQf/DpDX3bRjAQvhGoBFj+DBvPw== +glob@^13.0.0, glob@^14.0.2: + version "14.0.3" + resolved "https://registry.npmjs.org/glob/-/glob-14.0.3.tgz#71e124649b3e28fdb09bdb07ef478b10c68fd6e1" + integrity sha512-A1vjIwC3qpdCso45Iw127gnp7sPhqgY8lUQhDrArIs+GbmfaaVPFuoyy7WyLT9EPZCRZ7j7aLdwUhQmHWesEow== dependencies: - sparse-array "^1.3.1" - uint8arrays "^4.0.2" + minimatch "^11.0.2" + minipass "^7.1.3" + path-scurry "^3.0.0" -har-schema@^2.0.0: - version "2.0.0" - resolved "https://registry.npmjs.org/har-schema/-/har-schema-2.0.0.tgz" - integrity sha1-qUwiJOvKwEeCoNkDVSHyRzW37JI= +gopd@^1.2.0: + version "1.2.0" + resolved "https://registry.npmjs.org/gopd/-/gopd-1.2.0.tgz#89f56b8217bdbc8802bd299df6d7f1081d7e51a1" + integrity sha512-ZUKRh6/kUFoAiTAtTYPZJ3hw9wNxx+BIBOijnlG9PnrJsCcSjs1wyyD6vJpaYtgnzDrKYRSqf3OO6Rfa93xsRg== -har-validator@~5.1.3: - version "5.1.3" - resolved "https://registry.npmjs.org/har-validator/-/har-validator-5.1.3.tgz" - integrity sha512-sNvOCzEQNr/qrvJgc3UG/kD4QtlHycrzwS+6mfTrrSq97BvaYcPZZI1ZSqGSPR73Cxn4LKTD4PttRwfU7jWq5g== +got@^14.6.6: + version "14.6.6" + resolved "https://registry.npmjs.org/got/-/got-14.6.6.tgz#5adf7f576f89de8e291fd782e8b277f9bcc8e6c0" + integrity sha512-QLV1qeYSo5l13mQzWgP/y0LbMr5Plr5fJilgAIwgnwseproEbtNym8xpLsDzeZ6MWXgNE6kdWGBjdh3zT/Qerg== dependencies: - ajv "^6.5.5" - har-schema "^2.0.0" + "@sindresorhus/is" "^7.0.1" + byte-counter "^0.1.0" + cacheable-lookup "^7.0.0" + cacheable-request "^13.0.12" + decompress-response "^10.0.0" + form-data-encoder "^4.0.2" + http2-wrapper "^2.2.1" + keyv "^5.5.3" + lowercase-keys "^3.0.0" + p-cancelable "^4.0.1" + responselike "^4.0.2" + type-fest "^4.26.1" has-ansi@^2.0.0: version "2.0.0" - resolved "https://registry.npmjs.org/has-ansi/-/has-ansi-2.0.0.tgz" - integrity sha1-NPUEnOHs3ysGSa8+8k5F7TVBbZE= + resolved "https://registry.npmjs.org/has-ansi/-/has-ansi-2.0.0.tgz#34f5049ce1ecdf2b0649af3ef24e45ed35416d91" + integrity sha512-C8vBJ8DwUCx19vhm7urhTuUsr4/IyP6l4VzNQDv+ryHQObW3TTTp9yB68WpYgRe2bbaGuZ/se74IqFeVnMnLZg== dependencies: ansi-regex "^2.0.0" has-flag@^3.0.0: version "3.0.0" - resolved "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz" - integrity sha1-tdRU3CGZriJWmfNGfloH87lVuv0= + resolved "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz#b5d454dc2199ae225699f3467e5a07f3b955bafd" + integrity sha512-sKJf1+ceQBr4SMkvQnBDNDtf4TXpVhVGateu0t918bl30FnbE2m4vNLX+VWe/dpjlb+HugGYzW7uQXH98HPEYw== has-flag@^4.0.0: version "4.0.0" - resolved "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz" + resolved "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz#944771fd9c81c81265c4d6941860da06bb59479b" integrity sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ== -he@1.2.0: - version "1.2.0" - resolved "https://registry.npmjs.org/he/-/he-1.2.0.tgz" - integrity sha512-F/1DnUGPopORZi0ni+CvrCgHQ5FyEAHRLSApuYWMmrbSwoN2Mn/7k+Gl38gJnR7yyDZk6WLXwiGod1JOWNDKGw== - -http-cache-semantics@^4.1.1: - version "4.2.0" - resolved "https://registry.yarnpkg.com/http-cache-semantics/-/http-cache-semantics-4.2.0.tgz#205f4db64f8562b76a4ff9235aa5279839a09dd5" - integrity sha512-dTxcvPXqPvXBQpq5dUr6mEMJX4oIEFv6bwom3FDwKRDsuIjjJGANqhBuoAn9c1RQJIdAKav33ED65E2ys+87QQ== +has-symbols@^1.0.3, has-symbols@^1.1.0: + version "1.1.0" + resolved "https://registry.npmjs.org/has-symbols/-/has-symbols-1.1.0.tgz#fc9c6a783a084951d0b971fe1018de813707a338" + integrity sha512-1cDNdwJ2Jaohmb3sg4OmKaMBwuC48sYni5HUw2DvsC8LjGTLK9h+eb1X6RyuOHe4hT0ULCW68iomhjUoKUqlPQ== -http-signature@~1.2.0: - version "1.2.0" - resolved "https://registry.npmjs.org/http-signature/-/http-signature-1.2.0.tgz" - integrity sha1-muzZJRFHcvPZW2WmCruPfBj7rOE= +has-tostringtag@^1.0.2: + version "1.0.2" + resolved "https://registry.npmjs.org/has-tostringtag/-/has-tostringtag-1.0.2.tgz#2cdc42d40bef2e5b4eeab7c01a73c54ce7ab5abc" + integrity sha512-NqADB8VjPFLM2V0VvHUewwwsw0ZWBaIdgo+ieHtK3hasLz4qeCRjYcqfB6AQrBggRKppKF8L52/VqdVsO47Dlw== dependencies: - assert-plus "^1.0.0" - jsprim "^1.2.2" - sshpk "^1.7.0" + has-symbols "^1.0.3" -http2-wrapper@^2.1.10: - version "2.2.1" - resolved "https://registry.yarnpkg.com/http2-wrapper/-/http2-wrapper-2.2.1.tgz#310968153dcdedb160d8b72114363ef5fce1f64a" - integrity sha512-V5nVw1PAOgfI3Lmeaj2Exmeg7fenjhRUgz1lPSezy1CuhPYbgQtbQj4jZfEAEMlaL+vupsvhjqCyjzob0yxsmQ== - dependencies: - quick-lru "^5.1.1" - resolve-alpn "^1.2.0" - -iconv-lite@^0.4.24: - version "0.4.24" - resolved "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.4.24.tgz" - integrity sha512-v3MXnZAcvnywkTUEZomIActle7RXXeedOR31wwl7VlyoXO4Qi9arvSenNQWne1TcRwhCL1HwLI21bEqdpj8/rA== +hashery@^1.4.0, hashery@^1.5.1: + version "1.5.1" + resolved "https://registry.npmjs.org/hashery/-/hashery-1.5.1.tgz#4ba82ad54911ac617467870845d57a9fe508a400" + integrity sha512-iZyKG96/JwPz1N55vj2Ie2vXbhu440zfUfJvSwEqEbeLluk7NnapfGqa7LH0mOsnDxTF85Mx8/dyR6HfqcbmbQ== dependencies: - safer-buffer ">= 2.1.2 < 3" + hookified "^1.15.0" -iconv-lite@^0.6.2: - version "0.6.3" - resolved "https://registry.yarnpkg.com/iconv-lite/-/iconv-lite-0.6.3.tgz#a52f80bf38da1952eb5c681790719871a1a72501" - integrity sha512-4fCk79wshMdzMp2rH06qWrJE4iolqLhCUH+OiuIgU++RB0+94NlDL81atO7GX55uUKueo0txHNtvEyI6D7WdMw== +hasown@^2.0.2, hasown@^2.0.4: + version "2.0.4" + resolved "https://registry.npmjs.org/hasown/-/hasown-2.0.4.tgz#8c62d8cb90beb2aad5d0a5b67581ad9854c3f003" + integrity sha512-T2UbfbBEF32wiepXIsMlTW9+dDYC6wMh/t/vYA4tuOMKqWz/n3vr1NFSxQiyP+zk2mXsoMA/i/7qV6LKut1t1A== dependencies: - safer-buffer ">= 2.1.2 < 3.0.0" + function-bind "^1.1.2" -ieee754@^1.1.4: - version "1.1.13" - resolved "https://registry.npmjs.org/ieee754/-/ieee754-1.1.13.tgz" - integrity sha512-4vf7I2LYV/HaWerSo3XmlMkp5eZ83i+/CDluXi/IGTs/O1sejBNhTtnxzmRZfvOUqj7lZjqHkeTvpgSFDlWZTg== +hookified@^1.15.0, hookified@^1.15.1: + version "1.15.1" + resolved "https://registry.npmjs.org/hookified/-/hookified-1.15.1.tgz#b1fafeaa5489cdc29cb85546a8f837ed4ffbbcb6" + integrity sha512-MvG/clsADq1GPM2KGo2nyfaWVyn9naPiXrqIe4jYjXNZQt238kWyOGrsyc/DmRAQ+Re6yeo6yX/yoNCG5KAEVg== -ieee754@^1.2.1: - version "1.2.1" - resolved "https://registry.yarnpkg.com/ieee754/-/ieee754-1.2.1.tgz#8eb7a10a63fff25d15a57b001586d177d1b0d352" - integrity sha512-dcyqhDvX1C46lXZcVqCpK+FtMRQVdIMN6/Df5js2zouUsqG7I6sFxitIC+7KYK29KdXOLHdu9zL4sFnoVQnqaA== +hookified@^2.1.1: + version "2.2.0" + resolved "https://registry.npmjs.org/hookified/-/hookified-2.2.0.tgz#1d024ac1668973dd5bcc4a96ab9ccdb7639ef8d4" + integrity sha512-p/LgFzRN5FeoD3DLS6bkUapeye6E4SI6yJs6KetENd18S+FBthqYq2amJUWpt5z0EQwwHemidjY5OqJGEKm5uA== -ignore@^4.0.6: - version "4.0.6" - resolved "https://registry.npmjs.org/ignore/-/ignore-4.0.6.tgz" - integrity sha512-cyFDKrqc/YdcWFniJhzI42+AzS+gNwmUzOSFcRCQYwySuBBBy/KjuxWLZ/FHEH6Moq1NizMOBWyTcv8O4OZIMg== +http-cache-semantics@^4.2.0: + version "4.3.0" + resolved "https://registry.npmjs.org/http-cache-semantics/-/http-cache-semantics-4.3.0.tgz#09eead3b16c6d85552857cc3fbd888d8353a2aaf" + integrity sha512-M5t5LlJpS1UHMjvwRQVdFHvPISGeLAxNcrWuJkeGh0KxsqCHZ1O3NXZU/8x7cD0BDcGW8kapxMKTvwlqrNkHkA== -image-size@^0.8.1: - version "0.8.3" - resolved "https://registry.npmjs.org/image-size/-/image-size-0.8.3.tgz" - integrity sha512-SMtq1AJ+aqHB45c3FsB4ERK0UCiA2d3H1uq8s+8T0Pf8A3W4teyBQyaFaktH6xvZqh+npwlKU7i4fJo0r7TYTg== +http2-wrapper@^2.2.1: + version "2.2.4" + resolved "https://registry.npmjs.org/http2-wrapper/-/http2-wrapper-2.2.4.tgz#6aee653365fe19051e970cc466e179929d43cef0" + integrity sha512-y5jx4isTOKEC5Hu1lswc+IxytGlqDmwF1qJtk9qIS8l1KVxuHO5g522UfmErt1H2pMcH/xq+KiFQUB8aVWIABA== dependencies: - queue "6.0.1" + quick-lru "^5.1.1" + resolve-alpn "^1.2.0" -import-fresh@^3.0.0: - version "3.2.1" - resolved "https://registry.npmjs.org/import-fresh/-/import-fresh-3.2.1.tgz" - integrity sha512-6e1q1cnWP2RXD9/keSkxHScg508CdXqXWgWBaETNhyuBFz+kUZlKboh+ISK+bU++DmbHimVBrOz/zzPe0sZ3sQ== +iconv-lite@^0.7.0: + version "0.7.3" + resolved "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.7.3.tgz#84ee12f963e7de50bc01a13e160a078b3b0f415f" + integrity sha512-IKXpvIzjnC9XTAUbVBcMfGS0EPaIXtW6v+zr+RRp+hqULEpo0owZax6wyRwPOJbWbzjYspQwusTsfVr0ifh4uQ== dependencies: - parent-module "^1.0.0" - resolve-from "^4.0.0" - -imurmurhash@^0.1.4: - version "0.1.4" - resolved "https://registry.npmjs.org/imurmurhash/-/imurmurhash-0.1.4.tgz" - integrity sha1-khi5srkoojixPcT7a21XbyMUU+o= + safer-buffer ">= 2.1.2 < 3.0.0" -indent-string@^3.0.0: - version "3.2.0" - resolved "https://registry.npmjs.org/indent-string/-/indent-string-3.2.0.tgz" - integrity sha1-Sl/W0nzDMvN+VBmlBNu4NxBckok= +ignore@^5.2.0: + version "5.3.2" + resolved "https://registry.npmjs.org/ignore/-/ignore-5.3.2.tgz#3cd40e729f3643fd87cb04e50bf0eb722bc596f5" + integrity sha512-hsBTNUqQTDwkWtcdYI2i06Y/nUBEsNEDJKjWdigLvegy8kDuJAS8uRlpkkcQpyEXL0Z/pjDy5HBmMjRCJ2gq+g== -inflight@^1.0.4: - version "1.0.6" - resolved "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz" - integrity sha1-Sb1jMdfQLQwJvJEKEHW6gWW1bfk= - dependencies: - once "^1.3.0" - wrappy "1" +ignore@^7.0.5: + version "7.0.14" + resolved "https://registry.npmjs.org/ignore/-/ignore-7.0.14.tgz#a52b081dfb4d77e947e04d5f9e320b16f1873959" + integrity sha512-wCBiZ77u1tuWde6G/nfOtLaCTYcFDU5yCzARzK10y+rLhzYoL7a7yEemcopcc2Mzow7gZOIjnV2ym1NYmdiJOQ== -inherits@2, inherits@^2.0.3, inherits@^2.0.4, inherits@~2.0.3: +image-size@^2.0.4: version "2.0.4" - resolved "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz" - integrity sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ== + resolved "https://registry.npmjs.org/image-size/-/image-size-2.0.4.tgz#bbc1933173e4ee1adbbdf9d4958ded15fdb710e3" + integrity sha512-QRUkFFsRV/6fuESxb9Vkq+a0LkSrgKXuc2NEqfikiXxxN/G3tjWt5EVUlMaImRBZRZK/jRBEbYvpPYZL8t08Zw== -inquirer@^6.2.1: - version "6.5.2" - resolved "https://registry.npmjs.org/inquirer/-/inquirer-6.5.2.tgz" - integrity sha512-cntlB5ghuB0iuO65Ovoi8ogLHiWGs/5yNrtUcKjFhSSiVeAIVpD7koaSU9RM8mpXw5YDi9RdYXGQMaOURB7ycQ== - dependencies: - ansi-escapes "^3.2.0" - chalk "^2.4.2" - cli-cursor "^2.1.0" - cli-width "^2.0.0" - external-editor "^3.0.3" - figures "^2.0.0" - lodash "^4.17.12" - mute-stream "0.0.7" - run-async "^2.2.0" - rxjs "^6.4.0" - string-width "^2.1.0" - strip-ansi "^5.1.0" - through "^2.3.6" - -interface-blockstore@^5.0.0: - version "5.2.0" - resolved "https://registry.yarnpkg.com/interface-blockstore/-/interface-blockstore-5.2.0.tgz#150216529cf56bf43c2aebd3070f4351d1169ef4" - integrity sha512-lLW6fNP3PkBKghK9BsLuV8VMquL/o2lInomrTUizY/p4n7vxzVn3YT7qGTHywZzCcMIBeGMneDApGe21TNkg+g== - dependencies: - interface-store "^5.0.0" - multiformats "^11.0.2" - -interface-datastore@^7.0.0: - version "7.0.4" - resolved "https://registry.yarnpkg.com/interface-datastore/-/interface-datastore-7.0.4.tgz#f09ae4e2896f57f876d5d742a59e982fb3f42891" - integrity sha512-Q8LZS/jfFFHz6XyZazLTAc078SSCoa27ZPBOfobWdpDiFO7FqPA2yskitUJIhaCgxNK8C+/lMBUTBNfVIDvLiw== - dependencies: - interface-store "^3.0.0" - nanoid "^4.0.0" - uint8arrays "^4.0.2" - -interface-datastore@^8.0.0: - version "8.2.0" - resolved "https://registry.yarnpkg.com/interface-datastore/-/interface-datastore-8.2.0.tgz#70076985ac17dcdb35b33c2b0f957480ce6489e1" - integrity sha512-rDMAcpCGxWMubRk2YQuSEHl11bc0xcZeBZzfLvqhoZJdByUWeo7YDJUdgyRKgD6liGXVYirtDkFU9nyn9xl2hg== - dependencies: - interface-store "^5.0.0" - nanoid "^4.0.0" - uint8arrays "^4.0.2" - -interface-datastore@^8.2.0: - version "8.2.3" - resolved "https://registry.yarnpkg.com/interface-datastore/-/interface-datastore-8.2.3.tgz#491f6e90da963dbbb23d44c97aaae38959a797de" - integrity sha512-5U6BfK7cR4oSngm4pqYZBBAX7tpLI4YCOa3Ifz/EJEaEV2mmlloH5qP8ADWCVFk6vP1MPT925JJkt3kFIi7iWQ== - dependencies: - interface-store "^5.0.0" - nanoid "^4.0.0" - uint8arrays "^4.0.2" - -interface-store@^3.0.0: - version "3.0.4" - resolved "https://registry.yarnpkg.com/interface-store/-/interface-store-3.0.4.tgz#670d95ef45f3b7061d154c3cbfaf39a538167ad7" - integrity sha512-OjHUuGXbH4eXSBx1TF1tTySvjLldPLzRSYYXJwrEQI+XfH5JWYZofr0gVMV4F8XTwC+4V7jomDYkvGRmDSRKqQ== - -interface-store@^5.0.0: - version "5.1.0" - resolved "https://registry.yarnpkg.com/interface-store/-/interface-store-5.1.0.tgz#1735cead844fe452d62c307fafbaaa1d261e6ff3" - integrity sha512-mjUwX3XSoreoxCS3sXS3pSRsGnUjl9T06KBqt/T7AgE9Sgp4diH64ZyURJKnj2T5WmCvTbC0Dm+mwQV5hfLSBQ== - -ipfs-core-types@^0.14.0: - version "0.14.0" - resolved "https://registry.yarnpkg.com/ipfs-core-types/-/ipfs-core-types-0.14.0.tgz#a301d534f5261aad2254da393cb09f9cd36b6742" - integrity sha512-qO1xVO3n5m7scTXXtMz8hDTLdwXInnwqadIDQpXC446BIlaYyRWUvLcFQ2bOjQql9/CPNTaPHzjzr5Y1XxqpJw== - dependencies: - "@ipld/dag-pb" "^4.0.0" - "@libp2p/interface-keychain" "^2.0.0" - "@libp2p/interface-peer-id" "^2.0.0" - "@libp2p/interface-peer-info" "^1.0.2" - "@libp2p/interface-pubsub" "^3.0.0" - "@multiformats/multiaddr" "^11.0.0" - "@types/node" "^18.0.0" - interface-datastore "^7.0.0" - ipfs-unixfs "^9.0.0" - multiformats "^11.0.0" - -ipfs-core-utils@^0.18.0: - version "0.18.0" - resolved "https://registry.yarnpkg.com/ipfs-core-utils/-/ipfs-core-utils-0.18.0.tgz#c528c6cfb231d3a1a0d5420d0a3506615d26f4b4" - integrity sha512-7N/KfsOPGJu9mwN8EQwrW9HXgS5RNM3WUyjIMWk49KlpYmsXectXuC9i6npI1vn1W/oUaIOZt3lHx37jecnepw== - dependencies: - "@libp2p/logger" "^2.0.0" - "@multiformats/multiaddr" "^11.0.0" - "@multiformats/multiaddr-to-uri" "^9.0.1" - any-signal "^3.0.0" - blob-to-it "^2.0.0" - browser-readablestream-to-it "^2.0.0" - err-code "^3.0.1" - ipfs-core-types "^0.14.0" - ipfs-unixfs "^9.0.0" - ipfs-utils "^9.0.13" - it-all "^2.0.0" - it-map "^2.0.0" - it-peekable "^2.0.0" - it-to-stream "^1.0.0" - merge-options "^3.0.4" - multiformats "^11.0.0" - nanoid "^4.0.0" - parse-duration "^1.0.0" - timeout-abort-controller "^3.0.0" - uint8arrays "^4.0.2" - -ipfs-unixfs-exporter@^13.1.5: - version "13.1.5" - resolved "https://registry.yarnpkg.com/ipfs-unixfs-exporter/-/ipfs-unixfs-exporter-13.1.5.tgz#345ab63c10671af926630447c40059f8d8107533" - integrity sha512-O5aMawsHoe4DaYk5FFil2EPrNOaU3pkHC6qUR5JMnW7es93W3b/RjJoO7AyDL1rpb+M3K0oRu86Yc5wLNQQ8jg== - dependencies: - "@ipld/dag-cbor" "^9.0.0" - "@ipld/dag-pb" "^4.0.0" - "@multiformats/murmur3" "^2.0.0" - err-code "^3.0.1" - hamt-sharding "^3.0.0" - interface-blockstore "^5.0.0" - ipfs-unixfs "^11.0.0" - it-filter "^3.0.2" - it-last "^3.0.2" - it-map "^3.0.3" - it-parallel "^3.0.0" - it-pipe "^3.0.1" - it-pushable "^3.1.0" - multiformats "^11.0.0" - p-queue "^7.3.0" - progress-events "^1.0.0" - uint8arrays "^4.0.2" - -ipfs-unixfs@^11.0.0: - version "11.0.1" - resolved "https://registry.yarnpkg.com/ipfs-unixfs/-/ipfs-unixfs-11.0.1.tgz#7232e888b15a785aef7a5bd4dedf1861401f3b63" - integrity sha512-SD9dqn14bfgMfkPstsR/2Av3zCzYMj2ntQJab4HZucgX4nNV6K7guZh4Hf3kiL8ONff1Ogft1ekFU083DIKEdQ== - dependencies: - err-code "^3.0.1" - protons-runtime "^5.0.0" - uint8arraylist "^2.4.3" - -ipfs-unixfs@^9.0.0: - version "9.0.1" - resolved "https://registry.yarnpkg.com/ipfs-unixfs/-/ipfs-unixfs-9.0.1.tgz#d06e688e07ef4ce08d610337ba2fe8c143c386e7" - integrity sha512-jh2CbXyxID+v3jLml9CqMwjdSS9ZRnsGfQGGPOfem0/hT/L48xUeTPvh7qLFWkZcIMhZtG+fnS1teei8x5uGBg== - dependencies: - err-code "^3.0.1" - protobufjs "^7.0.0" - -ipfs-utils@^9.0.13, ipfs-utils@^9.0.7: - version "9.0.14" - resolved "https://registry.yarnpkg.com/ipfs-utils/-/ipfs-utils-9.0.14.tgz#24f5fda1f4567685eb32bca2543d518f95fd8704" - integrity sha512-zIaiEGX18QATxgaS0/EOQNoo33W0islREABAcxXE8n7y2MGAlB+hdsxXn4J0hGZge8IqVQhW8sWIb+oJz2yEvg== - dependencies: - any-signal "^3.0.0" - browser-readablestream-to-it "^1.0.0" - buffer "^6.0.1" - electron-fetch "^1.7.2" - err-code "^3.0.1" - is-electron "^2.2.0" - iso-url "^1.1.5" - it-all "^1.0.4" - it-glob "^1.0.1" - it-to-stream "^1.0.0" - merge-options "^3.0.4" - nanoid "^3.1.20" - native-fetch "^3.0.0" - node-fetch "^2.6.8" - react-native-fetch-api "^3.0.0" - stream-to-it "^0.2.2" - -is-binary-path@~2.1.0: - version "2.1.0" - resolved "https://registry.npmjs.org/is-binary-path/-/is-binary-path-2.1.0.tgz" - integrity sha512-ZMERYes6pDydyuGidse7OsHxtbI7WVeUEozgR/g7rd0xUimYNlvZRE/K2MgZTjWy725IfelLeVcEM97mmtRGXw== - dependencies: - binary-extensions "^2.0.0" +imurmurhash@^0.1.4: + version "0.1.4" + resolved "https://registry.npmjs.org/imurmurhash/-/imurmurhash-0.1.4.tgz#9218b9b2b928a238b13dc4fb6b6d576f231453ea" + integrity sha512-JmXMZ6wuvDmLiHEml9ykzqO6lwFbof0GG4IkcGaENdCRDDmMVnny7s5HsIgHCbaq0w2MyPhDqkhTUgS2LU2PHA== -is-electron@^2.2.0: - version "2.2.2" - resolved "https://registry.yarnpkg.com/is-electron/-/is-electron-2.2.2.tgz#3778902a2044d76de98036f5dc58089ac4d80bb9" - integrity sha512-FO/Rhvz5tuw4MCWkpMzHFKWD2LsfHzIb7i6MdPYZ/KW7AlxawyLkqdy+jPZP1WubqEADE3O4FUENlJHDfQASRg== +indent-string@^3.0.0: + version "3.2.0" + resolved "https://registry.npmjs.org/indent-string/-/indent-string-3.2.0.tgz#4a5fd6d27cc332f37e5419a504dbb837105c9289" + integrity sha512-BYqTHXTGUIvg7t1r4sJNKcbDZkL92nkXA8YtRpbjFHRHGDL/NtUeiBJMeE60kIFN/Mg8ESaWQvftaYMGJzQZCQ== + +inquirer@^12.11.1: + version "12.11.1" + resolved "https://registry.npmjs.org/inquirer/-/inquirer-12.11.1.tgz#3f5770b9ec926b0909e463e42c766f2664f2cc96" + integrity sha512-9VF7mrY+3OmsAfjH3yKz/pLbJ5z22E23hENKw3/LNSaA/sAt3v49bDRY+Ygct1xwuKT+U+cBfTzjCPySna69Qw== + dependencies: + "@inquirer/ansi" "^1.0.2" + "@inquirer/core" "^10.3.2" + "@inquirer/prompts" "^7.10.1" + "@inquirer/type" "^3.0.10" + mute-stream "^2.0.0" + run-async "^4.0.6" + rxjs "^7.8.2" is-extglob@^2.1.1: version "2.1.1" - resolved "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz" - integrity sha1-qIwCU1eR8C7TfHahueqXc8gz+MI= + resolved "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz#a88c02535791f02ed37c76a1b9ea9773c833f8c2" + integrity sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ== is-fullwidth-code-point@^1.0.0: version "1.0.0" - resolved "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-1.0.0.tgz" - integrity sha1-754xOG8DGn8NZDr4L95QxFfvAMs= + resolved "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-1.0.0.tgz#ef9e31386f031a7f0d643af82fde50c457ef00cb" + integrity sha512-1pqUqRjkhPJ9miNq9SwMfdvi6lBJcd6eFxvfaivQhaH3SgisfiuudvFntdKOmxuee/77l+FPjKrQjWvmPjWrRw== dependencies: number-is-nan "^1.0.0" is-fullwidth-code-point@^2.0.0: version "2.0.0" - resolved "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-2.0.0.tgz" - integrity sha1-o7MKXE8ZkYMWeqq5O+764937ZU8= + resolved "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-2.0.0.tgz#a3b30a5c4f199183167aaab93beefae3ddfb654f" + integrity sha512-VHskAKYM8RfSFXwee5t5cbN5PZeq1Wrh6qd5bkyiXIf6UQcN6w/A0eXM9r6t8d+GYOh+o6ZhiEnb88LN/Y8m2w== is-fullwidth-code-point@^3.0.0: version "3.0.0" - resolved "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz" + resolved "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz#f116f8064fe90b3f7844a38997c0b75051269f1d" integrity sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg== -is-glob@^4.0.0, is-glob@^4.0.1: - version "4.0.1" - resolved "https://registry.npmjs.org/is-glob/-/is-glob-4.0.1.tgz" - integrity sha512-5G0tKtBTFImOqDnLB2hG6Bp2qcKEFduo4tZu9MT/H6NQv/ghhy30o55ufafxJ/LdH79LLs2Kfrn85TLKyA7BUg== +is-fullwidth-code-point@^5.0.0: + version "5.1.0" + resolved "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-5.1.0.tgz#046b2a6d4f6b156b2233d3207d4b5a9783999b98" + integrity sha512-5XHYaSyiqADb4RnZ1Bdad6cPp8Toise4TzEjcOYDHZkTCbKgiUl7WTUCpNWHuxmDt91wnsZBc9xinNzopv3JMQ== dependencies: - is-extglob "^2.1.1" + get-east-asian-width "^1.3.1" -is-glob@~4.0.1: +is-glob@^4.0.0, is-glob@^4.0.3: version "4.0.3" - resolved "https://registry.npmjs.org/is-glob/-/is-glob-4.0.3.tgz" + resolved "https://registry.npmjs.org/is-glob/-/is-glob-4.0.3.tgz#64f61e42cbbb2eec2071a9dac0b28ba1e65d5084" integrity sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg== dependencies: is-extglob "^2.1.1" -is-ipfs@^8.0.1: - version "8.0.1" - resolved "https://registry.yarnpkg.com/is-ipfs/-/is-ipfs-8.0.1.tgz#23aefd086d32a7fce7b180bc55bf71313a641415" - integrity sha512-hoBSElmPath3aDdtaOpVZsuCh2SXTqvLML+H75S7iDgKdqNmENJ6tsRucP1HLfpqEyZ/uIlj/+ZBxIC/F8B5Eg== - dependencies: - "@multiformats/mafmt" "^11.0.3" - "@multiformats/multiaddr" "^11.0.0" - iso-url "^1.1.3" - multiformats "^11.0.0" - uint8arrays "^4.0.2" - -is-number@^7.0.0: - version "7.0.0" - resolved "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz" - integrity sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng== - is-observable@^1.1.0: version "1.1.0" - resolved "https://registry.npmjs.org/is-observable/-/is-observable-1.1.0.tgz" + resolved "https://registry.npmjs.org/is-observable/-/is-observable-1.1.0.tgz#b3e986c8f44de950867cab5403f5a3465005975e" integrity sha512-NqCa4Sa2d+u7BWc6CukaObG3Fh+CU9bvixbpcXYhy2VvYS7vVGIdAgnIS5Ks3A/cqk4rebLJ9s8zBstT2aKnIA== dependencies: symbol-observable "^1.1.0" -is-plain-obj@^2.1.0: - version "2.1.0" - resolved "https://registry.npmjs.org/is-plain-obj/-/is-plain-obj-2.1.0.tgz" - integrity sha512-YWnfyRwxL/+SsrWYfOpUtz5b3YD+nyfkHvjbcanzk8zgyO4ASD67uVMRt8k5bM4lLMDnXfriRhOpemw+NfT1eA== +is-path-inside@^4.0.0: + version "4.0.0" + resolved "https://registry.npmjs.org/is-path-inside/-/is-path-inside-4.0.0.tgz#805aeb62c47c1b12fc3fd13bfb3ed1e7430071db" + integrity sha512-lJJV/5dYS+RcL8uQdBDW9c9uWFLLBNRyFhnAKXw5tVqLlKZ4RMGZKv+YQ/IA3OhD+RpbJa1LLFM1FQPGyIXvOA== is-promise@^2.1.0: version "2.2.2" - resolved "https://registry.npmjs.org/is-promise/-/is-promise-2.2.2.tgz" + resolved "https://registry.npmjs.org/is-promise/-/is-promise-2.2.2.tgz#39ab959ccbf9a774cf079f7b40c7a26f763135f1" integrity sha512-+lP4/6lKUBfQjZ2pdxThZvLUAafmZb8OAxFb8XXtiQmS35INgr85hdOGoEs124ez1FCnZJt6jau/T+alh58QFQ== is-stream@^1.1.0: version "1.1.0" - resolved "https://registry.npmjs.org/is-stream/-/is-stream-1.1.0.tgz" - integrity sha1-EtSj3U5o4Lec6428hBc66A2RykQ= + resolved "https://registry.npmjs.org/is-stream/-/is-stream-1.1.0.tgz#12d4a3dd4e68e0b79ceb8dbc84173ae80d91ca44" + integrity sha512-uQPm8kcs47jx38atAcWTVxyltQYoPT68y9aWYdV6yWXSyW8mzSat0TL6CiWdZeCdF3KrAvpVtnHbTv4RN+rqdQ== -is-typedarray@~1.0.0: - version "1.0.0" - resolved "https://registry.npmjs.org/is-typedarray/-/is-typedarray-1.0.0.tgz" - integrity sha1-5HnICFjfDBsR3dppQPlgEfzaSpo= +is-stream@^4.0.1: + version "4.0.1" + resolved "https://registry.npmjs.org/is-stream/-/is-stream-4.0.1.tgz#375cf891e16d2e4baec250b85926cffc14720d9b" + integrity sha512-Dnz92NInDqYckGEUJv689RbRiTSEHCQ7wOVeALbkOz999YpqT46yMRIGtSNl2iCL1waAZSx40+h59NV/EwzV/A== 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" - integrity sha512-knxG2q4UC3u8stRGyAVJCOdxFmv5DZiRcdlIaAQXAbSfJya+OhopNotLQrstBhququ4ZpuKbDc/8S6mgXgPFPw== - -isexe@^2.0.0: - version "2.0.0" - resolved "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz" - integrity sha1-6PvzdNxVb/iUehDcsFctYz8s+hA= - -iso-url@^1.1.3, iso-url@^1.1.5: - version "1.2.1" - resolved "https://registry.yarnpkg.com/iso-url/-/iso-url-1.2.1.tgz#db96a49d8d9a64a1c889fc07cc525d093afb1811" - integrity sha512-9JPDgCN4B7QPkLtYAAOrEuAWvP9rWvR5offAr0/SeF046wIkglqH3VXgYYP6NcsKslH80UIVgmPqNe3j7tG2ng== - -isstream@~0.1.2: - version "0.1.2" - resolved "https://registry.npmjs.org/isstream/-/isstream-0.1.2.tgz" - integrity sha1-R+Y/evVa+m+S4VAOaQ64uFKcCZo= - -it-all@^1.0.4: - version "1.0.6" - resolved "https://registry.yarnpkg.com/it-all/-/it-all-1.0.6.tgz#852557355367606295c4c3b7eff0136f07749335" - integrity sha512-3cmCc6Heqe3uWi3CVM/k51fa/XbMFpQVzFoDsV0IZNHSQDyAXl3c4MjHkFX5kF3922OGj7Myv1nSEUgRtcuM1A== - -it-all@^2.0.0: - version "2.0.1" - resolved "https://registry.yarnpkg.com/it-all/-/it-all-2.0.1.tgz#45d530ecf6e13fb81d7ba583cdfd55ffdb376b05" - integrity sha512-9UuJcCRZsboz+HBQTNOau80Dw+ryGaHYFP/cPYzFBJBFcfDathMYnhHk4t52en9+fcyDGPTdLB+lFc1wzQIroA== - -it-filter@^3.0.2: - version "3.0.2" - resolved "https://registry.yarnpkg.com/it-filter/-/it-filter-3.0.2.tgz#19ddf6185ea21d417e6075d5796c799fa2633b69" - integrity sha512-Hhzp5anX7tmKOBqTPasBYTPlq7l4Xk4lMBfLB5GfKZnL9WCc6pr8M9Waud4nHh3s9neb4xwDWk7KQsEapgWyJw== - dependencies: - it-peekable "^3.0.0" - -it-first@^2.0.0: - version "2.0.1" - resolved "https://registry.yarnpkg.com/it-first/-/it-first-2.0.1.tgz#75d66b254c385ae3a1906def060a69006a437cef" - integrity sha512-noC1oEQcWZZMUwq7VWxHNLML43dM+5bviZpfmkxkXlvBe60z7AFRqpZSga9uQBo792jKv9otnn1IjA4zwgNARw== - -it-glob@^1.0.1: - version "1.0.2" - resolved "https://registry.yarnpkg.com/it-glob/-/it-glob-1.0.2.tgz#bab9b04d6aaac42884502f3a0bfee84c7a29e15e" - integrity sha512-Ch2Dzhw4URfB9L/0ZHyY+uqOnKvBNeS/SMcRiPmJfpHiM0TsUZn+GkpcZxAoF3dJVdPm/PuIk3A4wlV7SUo23Q== - dependencies: - "@types/minimatch" "^3.0.4" - minimatch "^3.0.4" - -it-last@^2.0.0: - version "2.0.1" - resolved "https://registry.yarnpkg.com/it-last/-/it-last-2.0.1.tgz#a6f3253459cb77e917aeada3b2c4ae9f3e66c64b" - integrity sha512-uVMedYW0wa2Cx0TAmcOCLbfuLLII7+vyURmhKa8Zovpd+aBTMsmINtsta2n364wJ5qsEDBH+akY1sUtAkaYBlg== - -it-last@^3.0.2: - version "3.0.2" - resolved "https://registry.yarnpkg.com/it-last/-/it-last-3.0.2.tgz#b012d88d2cc0d1e01eedf2b5114cefd94cef6c9b" - integrity sha512-aWoA5moJ7XSKe7+YuutBKhySroDDWkfjpo+UknekPh1M5YYdK4YNSPDarR+7o/NqRwzazwgzCi2UZzU0oqsprQ== - -it-map@^2.0.0: - version "2.0.1" - resolved "https://registry.yarnpkg.com/it-map/-/it-map-2.0.1.tgz#d5251fd6b222d6ee39293d406a3f8fce54fb9220" - integrity sha512-a2GcYDHiAh/eSU628xlvB56LA98luXZnniH2GlD0IdBzf15shEq9rBeb0Rg3o1SWtNILUAwqmQxEXcewGCdvmQ== - -it-map@^3.0.3: - version "3.0.3" - resolved "https://registry.yarnpkg.com/it-map/-/it-map-3.0.3.tgz#42be39fc68dc9b0d70cfd8ac4b8311d4b5cd7f22" - integrity sha512-Yf89GJYeYUZb2NZzWkvFHm3IBXlxro74i2vGRmpf8BYau3BhlaS37ieDenJEdYzkTGJhL/EbM1jPPw/KGVVVIw== - dependencies: - it-peekable "^3.0.0" - -it-merge@^3.0.0: - version "3.0.1" - resolved "https://registry.yarnpkg.com/it-merge/-/it-merge-3.0.1.tgz#20cc293593586e5afcbfed8ba88a94def5ccfcfa" - integrity sha512-I6hjU1ABO+k3xY1H6JtCSDXvUME88pxIXSgKeT4WI5rPYbQzpr98ldacVuG95WbjaJxKl6Qot6lUdxduLBQPHA== - dependencies: - it-pushable "^3.1.0" - -it-parallel@^3.0.0: - version "3.0.3" - resolved "https://registry.yarnpkg.com/it-parallel/-/it-parallel-3.0.3.tgz#b02f1d6459418c7253ecf13e367111560a616491" - integrity sha512-Q5KmdvERHCOLDcgKqrzQ+yiMCdG6H9h7ZL3Zjx/Tx9xhZy8txSKoy+EiCgWZFs0rfYvxJhk6UkOpKLzJ1zM9ZA== - dependencies: - p-defer "^4.0.0" - -it-peekable@^2.0.0: - version "2.0.1" - resolved "https://registry.yarnpkg.com/it-peekable/-/it-peekable-2.0.1.tgz#1e118610473aa511efc70f3bb7a7066178728dd3" - integrity sha512-fJ/YTU9rHRhGJOM2hhQKKEfRM6uKB9r4yGGFLBHqp72ACC8Yi6+7/FhuBAMG8cpN6mLoj9auVX7ZJ3ul6qFpTA== - -it-peekable@^3.0.0: - version "3.0.1" - resolved "https://registry.yarnpkg.com/it-peekable/-/it-peekable-3.0.1.tgz#530953f735359c10503e961c059602f8a366a1a5" - integrity sha512-5zBfkf6e+YoxxWV0YDXMwdQKnc7eeTX6xo3WYPm/8dIoctIiDnddInRWOW+83W/8/76sbnpWqqsO4gSyXandeQ== - -it-pipe@^3.0.1: - version "3.0.1" - resolved "https://registry.yarnpkg.com/it-pipe/-/it-pipe-3.0.1.tgz#b25720df82f4c558a8532602b5fbc37bbe4e7ba5" - integrity sha512-sIoNrQl1qSRg2seYSBH/3QxWhJFn9PKYvOf/bHdtCBF0bnghey44VyASsWzn5dAx0DCDDABq1hZIuzKmtBZmKA== - dependencies: - it-merge "^3.0.0" - it-pushable "^3.1.2" - it-stream-types "^2.0.1" - -it-pushable@^3.0.0, it-pushable@^3.1.0, it-pushable@^3.1.2: - version "3.1.3" - resolved "https://registry.yarnpkg.com/it-pushable/-/it-pushable-3.1.3.tgz#b6f4a1e0236502f12b5661b40468b629799baf0e" - integrity sha512-f50iQ85HISS6DaWCyrqf9QJ6G/kQtKIMf9xZkgZgyOvxEQDfn8OfYcLXXquCqgoLboxQtAW1ZFZyFIAsLHDtJw== - -it-stream-types@^1.0.4: - version "1.0.5" - resolved "https://registry.yarnpkg.com/it-stream-types/-/it-stream-types-1.0.5.tgz#9c72e6adefdea9dac69d0a28fbea783deebd508d" - integrity sha512-I88Ka1nHgfX62e5mi5LLL+oueqz7Ltg0bUdtsUKDe9SoUqbQPf2Mp5kxDTe9pNhHQGs4pvYPAINwuZ1HAt42TA== - -it-stream-types@^2.0.1: - version "2.0.1" - resolved "https://registry.yarnpkg.com/it-stream-types/-/it-stream-types-2.0.1.tgz#69cb4d7e79e707b8257a8997e02751ccb6c3af32" - integrity sha512-6DmOs5r7ERDbvS4q8yLKENcj6Yecr7QQTqWApbZdfAUTEC947d+PEha7PCqhm//9oxaLYL7TWRekwhoXl2s6fg== - -it-to-stream@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/it-to-stream/-/it-to-stream-1.0.0.tgz#6c47f91d5b5df28bda9334c52782ef8e97fe3a4a" - integrity sha512-pLULMZMAB/+vbdvbZtebC0nWBTbG581lk6w8P7DfIIIKUfa8FbY7Oi0FxZcFPbxvISs7A9E+cMpLDBc1XhpAOA== - dependencies: - buffer "^6.0.3" - fast-fifo "^1.0.0" - get-iterator "^1.0.2" - p-defer "^3.0.0" - p-fifo "^1.0.0" - readable-stream "^3.6.0" + resolved "https://registry.npmjs.org/is-unicode-supported/-/is-unicode-supported-0.1.0.tgz#3f26c76a809593b52bfa2ecb5710ed2779b522a7" + integrity sha512-knxG2q4UC3u8stRGyAVJCOdxFmv5DZiRcdlIaAQXAbSfJya+OhopNotLQrstBhququ4ZpuKbDc/8S6mgXgPFPw== -js-tokens@^4.0.0: - version "4.0.0" - resolved "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz" - integrity sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ== +isexe@^2.0.0: + version "2.0.0" + resolved "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz#e8fbf374dc556ff8947a10dcb0572d633f2cfa10" + integrity sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw== -js-yaml@4.1.0, js-yaml@^4.1.0: - version "4.1.0" - resolved "https://registry.yarnpkg.com/js-yaml/-/js-yaml-4.1.0.tgz#c1fb65f8f5017901cdd2c951864ba18458a10602" - integrity sha512-wpxZs9NoxZaJESJGIZTyDEaYpl0FKSA+FB9aJiyemKhMwkxQg63h4T1KJgUGHpTqPDNRcmmYLugrRjJlBtWvRA== +js-yaml@^4.3.2: + version "4.3.2" + resolved "https://registry.npmjs.org/js-yaml/-/js-yaml-4.3.2.tgz#8e44fb14a2643c59726bb15787b5f1512cb3d3fb" + integrity sha512-SFNOvSJ+Dgf/9An904Yx+CgSlIPCkIpao4qo51lpee25TIRejdH3rhR4EZMGoNx3/TP3O+wzWuiTFl4sqbltzA== dependencies: argparse "^2.0.1" -js-yaml@^3.13.1: - version "3.14.0" - resolved "https://registry.npmjs.org/js-yaml/-/js-yaml-3.14.0.tgz" - integrity sha512-/4IbIeHcD9VMHFqDR/gQ7EdZdLimOvW2DdcxFjdyyZ9NsbS+ccrXqVWDtab/lRl5AlUqmpBx8EhPaWR+OtY17A== +js-yaml@^5.0.0: + version "5.5.0" + resolved "https://registry.npmjs.org/js-yaml/-/js-yaml-5.5.0.tgz#ec843f09ffb2a54b6758a41eee109a1815d16442" + integrity sha512-paNr4LFIFPjeeSmwNYdrb8FafLLG/Cr2Af3GjbsHJ5CxIjH4r0c2emlmRdAtpPAieP1gRVzk6buBbVP5gBMGAg== dependencies: - argparse "^1.0.7" - esprima "^4.0.0" - -jsbn@~0.1.0: - version "0.1.1" - resolved "https://registry.npmjs.org/jsbn/-/jsbn-0.1.1.tgz" - integrity sha1-peZUwuWi3rXyAdls77yoDA7y9RM= - -json-buffer@3.0.1: - version "3.0.1" - resolved "https://registry.npmjs.org/json-buffer/-/json-buffer-3.0.1.tgz" - integrity sha512-4bV5BfR2mqfQTJm+V5tPPdf+ZpuhiIvTuAB5g8kcrXOZpTT/QwwVRWBywX1ozr6lEuPdbHxwaJlm9G6mI2sfSQ== + argparse "^3.0.3" 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" + resolved "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz#69f6a87d9513ab8bb8fe63bdb0979c448e684660" integrity sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg== json-schema-traverse@^1.0.0: version "1.0.0" - resolved "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-1.0.0.tgz" + resolved "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-1.0.0.tgz#ae7bcb3656ab77a73ba5c49bf654f38e6b6860e2" integrity sha512-NM8/P9n3XjXhIZn1lLhkFaACTOURQXjWhV4BA/RnOv8xvgqtqpAX9IO4mRQxSx1Rlo4tqzeqb0sOlruaOy3dug== -json-schema@0.4.0: - version "0.4.0" - resolved "https://registry.npmjs.org/json-schema/-/json-schema-0.4.0.tgz" - integrity sha512-es94M3nTIfsEPisRafak+HDLfHXnKBhV3vU5eqPcS3flIWqcxJWgXHXiey3YrpaNsanY5ei1VoYEbOzijuq9BA== - json-stable-stringify-without-jsonify@^1.0.1: version "1.0.1" - resolved "https://registry.npmjs.org/json-stable-stringify-without-jsonify/-/json-stable-stringify-without-jsonify-1.0.1.tgz" - integrity sha1-nbe1lJatPzz+8wp1FC0tkwrXJlE= - -json-stringify-safe@~5.0.1: - version "5.0.1" - resolved "https://registry.npmjs.org/json-stringify-safe/-/json-stringify-safe-5.0.1.tgz" - integrity sha1-Epai1Y/UXxmg9s4B1lcB4sc1tus= + resolved "https://registry.npmjs.org/json-stable-stringify-without-jsonify/-/json-stable-stringify-without-jsonify-1.0.1.tgz#9db7b59496ad3f3cfef30a75142d2d930ad72651" + integrity sha512-Bdboy+l7tA3OGW6FjyFHWkP5LuByj1Tk33Ljyq0axyzdk9//JSi2u3fP1QSmd1KNwq6VOKYGlAu87CisVir6Pw== -jsprim@^1.2.2: - version "1.4.2" - resolved "https://registry.npmjs.org/jsprim/-/jsprim-1.4.2.tgz" - integrity sha512-P2bSOMAc/ciLz6DzgjVlGJP9+BrJWu5UDGK70C2iweC5QBIeFf0ZXRvGjEj2uYgrY2MkAAhsSWHDWlFtEroZWw== - dependencies: - assert-plus "1.0.0" - extsprintf "1.3.0" - json-schema "0.4.0" - verror "1.10.0" +json-with-bigint@^3.5.12: + version "3.5.12" + resolved "https://registry.npmjs.org/json-with-bigint/-/json-with-bigint-3.5.12.tgz#9f6bf722a9847ed72fa9b217b2b66181227c454c" + integrity sha512-uwbF/wSSuOgC7qqlq27Xp5B6a2MHVug3t0idZdTqu0JnlFvgJuH7ju+KAk/J06C7GfhoYy2gnb9wz2INqcne7w== -keyv@^4.5.3: - version "4.5.4" - resolved "https://registry.yarnpkg.com/keyv/-/keyv-4.5.4.tgz#a879a99e29452f942439f2a405e3af8b31d4de93" - integrity sha512-oxVHkHR/EJf2CNXnWxRLW6mg7JyCCUcG0DtEGmL2ctUo1PNTin1PUil+r/+4r5MpVgC/fn1kjsx7mjSujKqIpw== +keyv@^5.5.3, keyv@^5.6.0: + version "5.6.0" + resolved "https://registry.npmjs.org/keyv/-/keyv-5.6.0.tgz#03044074c6b4d072d0a62c7b9fa649537baf0105" + integrity sha512-CYDD3SOtsHtyXeEORYRx2qBtpDJFjRTGXUtmNEMGyzYOKj1TE3tycdlho7kA1Ufx9OYWZzg52QFBGALTirzDSw== dependencies: - json-buffer "3.0.1" - -kubo-rpc-client@^3.0.1: - version "3.0.1" - resolved "https://registry.yarnpkg.com/kubo-rpc-client/-/kubo-rpc-client-3.0.1.tgz#61e4c64ccab6bf1bb6147dc8c45a423b95638fa7" - integrity sha512-2SMH/eCZlwR/4e9Aqr0HC1gJvCDTsgBRWRdu4LjHLrRwGsmDAl32vK4PkwkKfYwgJMHY3lgA6eZzaOLzrPwxFg== - dependencies: - "@ipld/dag-cbor" "^9.0.0" - "@ipld/dag-json" "^10.0.0" - "@ipld/dag-pb" "^4.0.0" - "@libp2p/crypto" "^1.0.11" - "@libp2p/logger" "^2.0.5" - "@libp2p/peer-id" "^2.0.0" - "@multiformats/multiaddr" "^11.1.5" - any-signal "^3.0.1" - dag-jose "^4.0.0" - err-code "^3.0.1" - ipfs-core-utils "^0.18.0" - ipfs-utils "^9.0.7" - it-first "^2.0.0" - it-last "^2.0.0" - merge-options "^3.0.4" - multiformats "^11.0.0" - parse-duration "^1.0.2" - stream-to-it "^0.2.4" - uint8arrays "^4.0.3" + "@keyv/serialize" "^1.1.1" levn@^0.4.1: version "0.4.1" - resolved "https://registry.npmjs.org/levn/-/levn-0.4.1.tgz" + resolved "https://registry.npmjs.org/levn/-/levn-0.4.1.tgz#ae4562c007473b932a6200d403268dd2fffc6ade" integrity sha512-+bT2uH4E5LGE7h/n3evcS/sQlJXCpIp6ym8OWJ5eV6+67Dsql/LaaT7qJBAt2rzfoa/5QBGBhxDix1dMt2kQKQ== dependencies: prelude-ls "^1.2.1" @@ -2596,12 +1869,12 @@ levn@^0.4.1: listr-silent-renderer@^1.1.1: version "1.1.1" - resolved "https://registry.npmjs.org/listr-silent-renderer/-/listr-silent-renderer-1.1.1.tgz" - integrity sha1-kktaN1cVN3C/Go4/v3S4u/P5JC4= + resolved "https://registry.npmjs.org/listr-silent-renderer/-/listr-silent-renderer-1.1.1.tgz#924b5a3757153770bf1a8e3fbf74b8bbf3f9242e" + integrity sha512-L26cIFm7/oZeSNVhWB6faeorXhMg4HNlb/dS/7jHhr708jxlXrtrBWo4YUxZQkc6dGoxEAe6J/D3juTRBUzjtA== listr-update-renderer@^0.5.0: version "0.5.0" - resolved "https://registry.npmjs.org/listr-update-renderer/-/listr-update-renderer-0.5.0.tgz" + resolved "https://registry.npmjs.org/listr-update-renderer/-/listr-update-renderer-0.5.0.tgz#4ea8368548a7b8aecb7e06d8c95cb45ae2ede6a2" integrity sha512-tKRsZpKz8GSGqoI/+caPmfrypiaq+OQCbd+CovEC24uk1h952lVj5sC7SqyFUm+OaJ5HN/a1YLt5cit2FMNsFA== dependencies: chalk "^1.1.3" @@ -2615,7 +1888,7 @@ listr-update-renderer@^0.5.0: listr-verbose-renderer@^0.5.0: version "0.5.0" - resolved "https://registry.npmjs.org/listr-verbose-renderer/-/listr-verbose-renderer-0.5.0.tgz" + resolved "https://registry.npmjs.org/listr-verbose-renderer/-/listr-verbose-renderer-0.5.0.tgz#f1132167535ea4c1261102b9f28dac7cba1e03db" integrity sha512-04PDPqSlsqIOaaaGZ+41vq5FejI9auqTInicFRndCBgE3bXG8D6W1I+mWhk+1nqbHmyhla/6BUrd5OSiHwKRXw== dependencies: chalk "^2.4.1" @@ -2625,7 +1898,7 @@ listr-verbose-renderer@^0.5.0: listr@^0.14.3: version "0.14.3" - resolved "https://registry.npmjs.org/listr/-/listr-0.14.3.tgz" + resolved "https://registry.npmjs.org/listr/-/listr-0.14.3.tgz#2fea909604e434be464c50bddba0d496928fa586" integrity sha512-RmAl7su35BFd/xoMamRjpIE4j3v+L28o8CT5YhAXQJm1fD+1l9ngXY8JAQRJ+tFK2i5njvi0iRUKV09vPwA0iA== dependencies: "@samverschueren/stream-to-observable" "^0.3.0" @@ -2640,1240 +1913,723 @@ listr@^0.14.3: locate-path@^6.0.0: version "6.0.0" - resolved "https://registry.npmjs.org/locate-path/-/locate-path-6.0.0.tgz" + resolved "https://registry.npmjs.org/locate-path/-/locate-path-6.0.0.tgz#55321eb309febbc59c4801d931a72452a681d286" integrity sha512-iPZK6eYjbxRu3uB4/WZ3EsEIMJFMqAoopl3R+zuq0UjcAm/MO6KCweDgPfP3elTztoKP3KtnVHxTn2NHBSDVUw== dependencies: p-locate "^5.0.0" -lodash-es@^4.17.21: - version "4.17.21" - resolved "https://registry.npmjs.org/lodash-es/-/lodash-es-4.17.21.tgz" - integrity sha512-mKnC+QJ9pWVzv+C4/U3rRsHapFfHvQFoFB92e52xeyGMcX6/OlIl78je1u8vePzYZSkkogMPJ2yjxxsb89cxyw== - -lodash@^4.17.12, lodash@^4.17.14, 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: - version "4.1.0" - resolved "https://registry.npmjs.org/log-symbols/-/log-symbols-4.1.0.tgz" - integrity sha512-8XPvpAA8uyhfteu8pIvQxpJZ7SYYdpUivZpGy6sFsBuKRY/7rQGavedeB8aK+Zkyq6upMFVL/9AW6vOYzfRyLg== - dependencies: - chalk "^4.1.0" - is-unicode-supported "^0.1.0" +lodash-es@^4.18.1: + version "4.18.1" + resolved "https://registry.npmjs.org/lodash-es/-/lodash-es-4.18.1.tgz#b962eeb80d9d983a900bf342961fb7418ca10b1d" + integrity sha512-J8xewKD/Gk22OZbhpOVSwcs60zhd95ESDwezOFuA3/099925PdHJ7OFHNTGtajL3AlZkykD32HykiMo+BIBI8A== log-symbols@^1.0.2: version "1.0.2" - resolved "https://registry.npmjs.org/log-symbols/-/log-symbols-1.0.2.tgz" - integrity sha1-N2/3tY6jCGoPCfrMdGF+ylAeGhg= + resolved "https://registry.npmjs.org/log-symbols/-/log-symbols-1.0.2.tgz#376ff7b58ea3086a0f09facc74617eca501e1a18" + integrity sha512-mmPrW0Fh2fxOzdBbFv4g1m6pR72haFLPJ2G5SJEELf1y+iaQrDG6cWCPjy54RHYbZAt7X+ls690Kw62AdWXBzQ== dependencies: chalk "^1.0.0" log-update@^2.3.0: version "2.3.0" - resolved "https://registry.npmjs.org/log-update/-/log-update-2.3.0.tgz" - integrity sha1-iDKP19HOeTiykoN0bwsbwSayRwg= + resolved "https://registry.npmjs.org/log-update/-/log-update-2.3.0.tgz#88328fd7d1ce7938b29283746f0b1bc126b24708" + integrity sha512-vlP11XfFGyeNQlmEn9tJ66rEW1coA/79m5z6BCkudjbAGE83uhAcGYrBFwfs3AdLiLzGRusRPAbSPK9xZteCmg== dependencies: ansi-escapes "^3.0.0" cli-cursor "^2.0.0" wrap-ansi "^3.0.1" -long@^5.0.0: - version "5.2.3" - resolved "https://registry.yarnpkg.com/long/-/long-5.2.3.tgz#a3ba97f3877cf1d778eccbcb048525ebb77499e1" - integrity sha512-lcHwpNoggQTObv5apGNCTdJrO69eHOZMi4BNC+rTLER8iHAqGrUVeLh/irVIM7zTw2bOXA8T6uNPeujwOLg/2Q== +log-update@^6.1.0: + version "6.1.0" + resolved "https://registry.npmjs.org/log-update/-/log-update-6.1.0.tgz#1a04ff38166f94647ae1af562f4bd6a15b1b7cd4" + integrity sha512-9ie8ItPR6tjY5uYJh8K/Zrv/RMZ5VOlOWvtZdEHYSTFKZfIBPQa9tOAEeAWhd+AnIneLJ22w5fjOYtoutpWq5w== + dependencies: + ansi-escapes "^7.0.0" + cli-cursor "^5.0.0" + slice-ansi "^7.1.0" + strip-ansi "^7.1.0" + wrap-ansi "^9.0.0" loupe@^3.1.0: - version "3.1.0" - resolved "https://registry.yarnpkg.com/loupe/-/loupe-3.1.0.tgz#46ef1a4ffee73145f5c0a627536d754787c1ea2a" - integrity sha512-qKl+FrLXUhFuHUoDJG7f8P8gEMHq9NFS0c6ghXG1J0rldmZFQZoNVv/vyirE9qwCIhWZDsvEFd1sbFu3GvRQFg== - dependencies: - get-func-name "^2.0.1" + version "3.2.1" + resolved "https://registry.npmjs.org/loupe/-/loupe-3.2.1.tgz#0095cf56dc5b7a9a7c08ff5b1a8796ec8ad17e76" + integrity sha512-CdzqowRJCeLU72bHvWqwRBBlLcMEtIvGrlvef74kMnV2AolS9Y8xUv1I0U/MNAWMhBlKIoyuEgoJ0t/bbwHbLQ== lowercase-keys@^3.0.0: version "3.0.0" - resolved "https://registry.yarnpkg.com/lowercase-keys/-/lowercase-keys-3.0.0.tgz#c5e7d442e37ead247ae9db117a9d0a467c89d4f2" + resolved "https://registry.npmjs.org/lowercase-keys/-/lowercase-keys-3.0.0.tgz#c5e7d442e37ead247ae9db117a9d0a467c89d4f2" integrity sha512-ozCC6gdQ+glXOQsveKD0YsDy8DSQFjDTz4zyzEHNV5+JP5D62LmfDZ6o1cycFx9ouG940M5dE8C8CTewdj2YWQ== -lru-cache@^6.0.0: - version "6.0.0" - resolved "https://registry.yarnpkg.com/lru-cache/-/lru-cache-6.0.0.tgz#6d6fe6570ebd96aaf90fcad1dafa3b2566db3a94" - integrity sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA== - dependencies: - yallist "^4.0.0" - -make-error@^1.1.1: - version "1.3.6" - resolved "https://registry.npmjs.org/make-error/-/make-error-1.3.6.tgz" - integrity sha512-s8UhlNe7vPKomQhC1qFelMokr/Sc3AgNbso3n74mVPA5LTZwkB9NlXf4XPamLxJE8h0gh73rM94xvwRT2CVInw== +lru-cache@^11.0.0: + version "11.5.3" + resolved "https://registry.npmjs.org/lru-cache/-/lru-cache-11.5.3.tgz#a7767b4034e35269562d2b9da2b185b5df70c421" + integrity sha512-U4N8FgzmWxc8k1VH8Kr6lQg18U7Fjvby6wXHVRX/ZZ7IwWbRMgrRbP0Wrb5q5NVinryp4SQampHKdvtecItxUg== -merge-options@^3.0.4: - version "3.0.4" - resolved "https://registry.yarnpkg.com/merge-options/-/merge-options-3.0.4.tgz#84709c2aa2a4b24c1981f66c179fe5565cc6dbb7" - integrity sha512-2Sug1+knBjkaMsMgf1ctR1Ujx+Ayku4EdJN4Z+C2+JzoeF7A3OZ9KM2GY0CpQS51NR61LTurMJrRKPhSs3ZRTQ== - dependencies: - is-plain-obj "^2.1.0" +math-intrinsics@^1.1.0: + version "1.1.0" + resolved "https://registry.npmjs.org/math-intrinsics/-/math-intrinsics-1.1.0.tgz#a0dd74be81e2aa5c2f27e65ce283605ee4e2b7f9" + integrity sha512-/IXtbwEk5HTPyEwyKX6hGkYXxM9nbj64B+ilVJnC/R6B0pH5G4V3b0pVbL7DBj4tkhBAppbQUlf6F6Xl9LHu1g== -mime-db@1.44.0: - version "1.44.0" - resolved "https://registry.npmjs.org/mime-db/-/mime-db-1.44.0.tgz" - integrity sha512-/NOTfLrsPBVeH7YtFPgsVWveuL+4SjjYxaQ1xtM1KMFj7HdxlBlxeyNLzhyJVx7r4rZGJAZ/6lkKCitSc/Nmpg== +mime-db@1.52.0: + version "1.52.0" + resolved "https://registry.npmjs.org/mime-db/-/mime-db-1.52.0.tgz#bbabcdc02859f4987301c856e3387ce5ec43bf70" + integrity sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg== -mime-types@^2.1.12, mime-types@^2.1.24, mime-types@~2.1.19: - version "2.1.27" - resolved "https://registry.npmjs.org/mime-types/-/mime-types-2.1.27.tgz" - integrity sha512-JIhqnCasI9yD+SsmkquHBxTSEuZdQX5BuQnS2Vc7puQQQ+8yiP5AY5uWhpdv4YL4VM5c6iliiYWPgJ/nJQLp7w== +mime-types@^2.1.24, mime-types@^2.1.35: + version "2.1.35" + resolved "https://registry.npmjs.org/mime-types/-/mime-types-2.1.35.tgz#381a871b62a734450660ae3deee44813f70d959a" + integrity sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw== dependencies: - mime-db "1.44.0" + mime-db "1.52.0" mimic-fn@^1.0.0: version "1.2.0" - resolved "https://registry.npmjs.org/mimic-fn/-/mimic-fn-1.2.0.tgz" + resolved "https://registry.npmjs.org/mimic-fn/-/mimic-fn-1.2.0.tgz#820c86a39334640e99516928bd03fca88057d022" integrity sha512-jf84uxzwiuiIVKiOLpfYk7N46TSy8ubTonmneY9vrpHNAnp0QBt2BxWV9dO3/j+BoVAb+a5G6YDPW3M5HOdMWQ== -mimic-response@^3.1.0: - version "3.1.0" - resolved "https://registry.yarnpkg.com/mimic-response/-/mimic-response-3.1.0.tgz#2d1d59af9c1b129815accc2c46a022a5ce1fa3c9" - integrity sha512-z0yWI+4FDrrweS8Zmt4Ej5HdJmky15+L2e6Wgn3+iK5fWzb6T3fhNFq2+MeTRb064c6Wr4N/wv0DzQTjNzHNGQ== +mimic-function@^5.0.0: + version "5.0.1" + resolved "https://registry.npmjs.org/mimic-function/-/mimic-function-5.0.1.tgz#acbe2b3349f99b9deaca7fb70e48b83e94e67076" + integrity sha512-VP79XUPxV2CigYP3jWwAUFSku2aKqBH7uTAapFWCBqutsbmDo96KY5o8uh6U+/YSIn5OxJnXp73beVkpqMIGhA== mimic-response@^4.0.0: version "4.0.0" - resolved "https://registry.yarnpkg.com/mimic-response/-/mimic-response-4.0.0.tgz#35468b19e7c75d10f5165ea25e75a5ceea7cf70f" + resolved "https://registry.npmjs.org/mimic-response/-/mimic-response-4.0.0.tgz#35468b19e7c75d10f5165ea25e75a5ceea7cf70f" integrity sha512-e5ISH9xMYU0DzrT+jl8q2ze9D6eWBto+I8CNpe+VI+K2J/F/k3PdkdTdz4wvGVH4NTpo+NRYTVIuMQEMMcsLqg== -minimatch@5.0.1: - version "5.0.1" - resolved "https://registry.npmjs.org/minimatch/-/minimatch-5.0.1.tgz" - integrity sha512-nLDxIFRyhDblz3qMuq+SoRZED4+miJ/G+tdDrjkkkRnjAsBexeGpgjLEQ0blJy7rHhR2b93rhQY4SvyWu9v03g== +minimatch@^10.2.2, minimatch@^10.2.4, minimatch@^10.2.6, minimatch@^11.0.1, minimatch@^11.0.2: + version "11.0.4" + resolved "https://registry.npmjs.org/minimatch/-/minimatch-11.0.4.tgz#3ed156790c2754647ee94dab305a3f93cd16481e" + integrity sha512-/UJ1dEoVQTjPNDh6SGlUo+ueLMmoHTas4q+8yaAR/5t6nLAIiBDJtoYUh20IYleix7ehiQkgczb84PE3uzHkxg== dependencies: - brace-expansion "^2.0.1" + "@isaacs/nonrecursive-glob-match" "^1.0.3" + brace-expansion "^5.0.12" -minimatch@^3.0.4: - 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" - -minimist@^1.2.5: - version "1.2.8" - resolved "https://registry.npmjs.org/minimist/-/minimist-1.2.8.tgz" - integrity sha512-2yyAR8qBkN3YuheJanUpWC5U3bb5osDywNB8RzDVlDwDHbocAJveqqj1u8+SVD7jkWT4yvsHCpWqqWqAxb0zCA== - -mkdirp-classic@^0.5.2: - version "0.5.3" - resolved "https://registry.npmjs.org/mkdirp-classic/-/mkdirp-classic-0.5.3.tgz" - integrity sha512-gKLcREMhtuZRwRAfqP3RFW+TK4JqApVBtOIftVgjuABpAtpxhPGaDcfvbhNvD0B8iD1oUr/txX35NjcaY6Ns/A== - -mkdirp@^0.5.1: - version "0.5.5" - resolved "https://registry.npmjs.org/mkdirp/-/mkdirp-0.5.5.tgz" - integrity sha512-NKmAlESf6jMGym1++R0Ra7wvhV+wFW63FaSOFPwRahvea0gMUcGUhVeAg/0BC0wiv9ih5NYPB1Wn1UEI1/L+xQ== - dependencies: - minimist "^1.2.5" - -mocha@^10.2.0: - version "10.2.0" - resolved "https://registry.npmjs.org/mocha/-/mocha-10.2.0.tgz" - integrity sha512-IDY7fl/BecMwFHzoqF2sg/SHHANeBoMMXFlS9r0OXKDssYE1M5O43wUY/9BVPeIvfH2zmEbBfseqN9gBQZzXkg== - dependencies: - ansi-colors "4.1.1" - browser-stdout "1.3.1" - chokidar "3.5.3" - debug "4.3.4" - diff "5.0.0" - escape-string-regexp "4.0.0" - find-up "5.0.0" - glob "7.2.0" - he "1.2.0" - js-yaml "4.1.0" - log-symbols "4.1.0" - minimatch "5.0.1" - ms "2.1.3" - nanoid "3.3.3" - serialize-javascript "6.0.0" - strip-json-comments "3.1.1" - supports-color "8.1.1" - workerpool "6.2.1" - yargs "16.2.0" - yargs-parser "20.2.4" - yargs-unparser "2.0.0" +minipass@^7.1.2, minipass@^7.1.3: + version "7.1.3" + resolved "https://registry.npmjs.org/minipass/-/minipass-7.1.3.tgz#79389b4eb1bb2d003a9bba87d492f2bd37bdc65b" + integrity sha512-tEBHqDnIoM/1rXME1zgka9g6Q2lcoCkxHLuc7ODJ5BxbP5d4c2Z5cGgtXAku59200Cx7diuHTOYfSBD8n6mm8A== + +mocha@^12.0.3: + version "12.0.3" + resolved "https://registry.npmjs.org/mocha/-/mocha-12.0.3.tgz#f3022f5684f5a8306323dd5ab4d0f881a90cd031" + integrity sha512-beammieDdiWdkjANWeWPpkxUROYGi5FN88fPOkLiticz7HTg3Y+Pho3EYE6SUdcuWnZ3h2WD8EXCA55JF4o6wg== + dependencies: + browser-stdout "^1.3.1" + chokidar "^5.0.0" + debug "^4.3.5" + diff "^9.0.0" + find-up-simple "^1.0.1" + glob "^13.0.0" + is-path-inside "^4.0.0" + is-unicode-supported "^0.1.0" + js-yaml "^5.0.0" + minimatch "^10.2.2" + ms "^2.1.3" + picocolors "^1.1.1" + serialize-javascript "^7.1.1" + strip-json-comments "^5.0.3" + supports-color "^8.1.1" + workerpool "^10.0.0" moment@^2.27.0: - version "2.29.4" - resolved "https://registry.npmjs.org/moment/-/moment-2.29.4.tgz" - integrity sha512-5LC9SOxjSc2HF6vO2CyuTDNivEdoz2IvyJJGj6X8DJ0eFyfszE0QiEd+iXmBvUP3WHxSjFH/vIsA0EN00cgr8w== - -ms@2.1.2, ms@^2.1.1: - version "2.1.2" - resolved "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz" - integrity sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w== + version "2.31.0" + resolved "https://registry.npmjs.org/moment/-/moment-2.31.0.tgz#6e19184e8005a9dfc61c9351263d4d6ea2ace7aa" + integrity sha512-0acOTfMiWOheYS4eoWb80yYMb/JLvVv9SHbs2PehaDzfUG0Bw855SKyk0IKTnPGa5+U2bmi3W68l1+sGLX/pvw== -ms@2.1.3: +ms@^2.1.3: version "2.1.3" - resolved "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz" + resolved "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz#574c8138ce1d2b5861f0b44579dbadd60c6615b2" integrity sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA== -multiformats@^11.0.0, multiformats@^11.0.2: - version "11.0.2" - resolved "https://registry.yarnpkg.com/multiformats/-/multiformats-11.0.2.tgz#b14735efc42cd8581e73895e66bebb9752151b60" - integrity sha512-b5mYMkOkARIuVZCpvijFj9a6m5wMVLC7cf/jIPd5D/ARDOfLC5+IFkbgDXQgcU2goIsTD/O9NY4DI/Mt4OGvlg== - -murmurhash3js-revisited@^3.0.0: - version "3.0.0" - resolved "https://registry.yarnpkg.com/murmurhash3js-revisited/-/murmurhash3js-revisited-3.0.0.tgz#6bd36e25de8f73394222adc6e41fa3fac08a5869" - integrity sha512-/sF3ee6zvScXMb1XFJ8gDsSnY+X8PbOyjIuBhtgis10W2Jx4ZjIhikUCIF9c4gpJxVnQIsPAFrSwTCuAjicP6g== - -mute-stream@0.0.7: - version "0.0.7" - resolved "https://registry.npmjs.org/mute-stream/-/mute-stream-0.0.7.tgz" - integrity sha1-MHXOk7whuPq0PhvE2n6BFe0ee6s= - -nan@^2.16.0, nan@^2.17.0: - version "2.17.0" - resolved "https://registry.yarnpkg.com/nan/-/nan-2.17.0.tgz#c0150a2368a182f033e9aa5195ec76ea41a199cb" - integrity sha512-2ZTgtl0nJsO0KQCjEpxcIr5D+Yv90plTitZt9JBfQvVJDS5seMl3FOvsh3+9CoYWXf/1l5OaZzzF6nDm4cagaQ== - -nanoid@3.3.3: - version "3.3.3" - resolved "https://registry.npmjs.org/nanoid/-/nanoid-3.3.3.tgz" - integrity sha512-p1sjXuopFs0xg+fPASzQ28agW1oHD7xDsd9Xkf3T15H3c/cifrFHVwrh74PdoklAPi+i7MdRsE47vm2r6JoB+w== - -nanoid@^3.1.20: - version "3.3.6" - resolved "https://registry.yarnpkg.com/nanoid/-/nanoid-3.3.6.tgz#443380c856d6e9f9824267d960b4236ad583ea4c" - integrity sha512-BGcqMMJuToF7i1rt+2PWSNVnWIkGCU78jBG3RxO/bZlnZPK2Cmi2QaffxGO/2RvWi9sL+FAiRiXMgsyxQ1DIDA== - -nanoid@^4.0.0: - version "4.0.2" - resolved "https://registry.yarnpkg.com/nanoid/-/nanoid-4.0.2.tgz#140b3c5003959adbebf521c170f282c5e7f9fb9e" - integrity sha512-7ZtY5KTCNheRGfEFxnedV5zFiORN1+Y1N6zvPTnHQd8ENUvfaDBeuJDZb2bN/oXwXxu3qkTXDzy57W5vAmDTBw== - -native-fetch@^3.0.0: - version "3.0.0" - resolved "https://registry.yarnpkg.com/native-fetch/-/native-fetch-3.0.0.tgz#06ccdd70e79e171c365c75117959cf4fe14a09bb" - integrity sha512-G3Z7vx0IFb/FQ4JxvtqGABsOTIqRWvgQz6e+erkB+JJD6LrszQtMozEHI4EkmgZQvnGHrpLVzUWk7t4sJCIkVw== - -native-fetch@^4.0.2: - version "4.0.2" - resolved "https://registry.yarnpkg.com/native-fetch/-/native-fetch-4.0.2.tgz#75c8a44c5f3bb021713e5e24f2846750883e49af" - integrity sha512-4QcVlKFtv2EYVS5MBgsGX5+NWKtbDbIECdUXDBGDMAZXq3Jkv9zf+y8iS7Ub8fEdga3GpYeazp9gauNqXHJOCg== +mute-stream@^2.0.0: + version "2.0.0" + resolved "https://registry.npmjs.org/mute-stream/-/mute-stream-2.0.0.tgz#a5446fc0c512b71c83c44d908d5c7b7b4c493b2b" + integrity sha512-WWdIxpyjEn+FhQJQQv9aQAYlHoNVdzIzUySNV1gHUPDSdZJ3yZn7pAAbQcV7B56Mvu881q9FZV+0Vx2xC44VWA== natural-compare@^1.4.0: version "1.4.0" - resolved "https://registry.npmjs.org/natural-compare/-/natural-compare-1.4.0.tgz" - integrity sha1-Sr6/7tdUHywnrPspvbvRXI1bpPc= - -node-fetch@^2.6.11, node-fetch@^2.6.8: - version "2.6.11" - resolved "https://registry.yarnpkg.com/node-fetch/-/node-fetch-2.6.11.tgz#cde7fc71deef3131ef80a738919f999e6edfff25" - integrity sha512-4I6pdBY1EthSqDmJkiNk3JIT8cswwR9nfeW/cPdUagJYEQG7R95WRH74wpz7ma8Gh/9dI9FP+OU+0E4FvtA55w== - dependencies: - whatwg-url "^5.0.0" - -node-forge@^1.1.0: - version "1.3.1" - resolved "https://registry.yarnpkg.com/node-forge/-/node-forge-1.3.1.tgz#be8da2af243b2417d5f646a770663a92b7e9ded3" - integrity sha512-dPEtOeMvF9VMcYV/1Wb8CPoVAXtp6MKMlcbAt4ddqmGqUJ6fQZFXkNZNkNlfevtNkGtaSoXf/vNNNSvgrdXwtA== - -normalize-path@^3.0.0, normalize-path@~3.0.0: - version "3.0.0" - resolved "https://registry.npmjs.org/normalize-path/-/normalize-path-3.0.0.tgz" - integrity sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA== + resolved "https://registry.npmjs.org/natural-compare/-/natural-compare-1.4.0.tgz#4abebfeed7541f2c27acfb29bdbbd15c8d5ba4f7" + integrity sha512-OWND8ei3VtNC9h7V60qff3SVobHr996CTwgxubgyQYEpg290h9J0buyECNNJexkFm5sOajh5G116RYA1c8ZMSw== -normalize-url@^8.0.0: - version "8.0.2" - resolved "https://registry.yarnpkg.com/normalize-url/-/normalize-url-8.0.2.tgz#3b343a42f837e4dae2b01917c04e8de3782e9170" - integrity sha512-Ee/R3SyN4BuynXcnTaekmaVdbDAEiNrHqjQIA37mHU8G9pf7aaAD4ZX3XjBLo6rsdcxA/gtkcNYZLt30ACgynw== +normalize-url@^8.1.1: + version "8.1.1" + resolved "https://registry.npmjs.org/normalize-url/-/normalize-url-8.1.1.tgz#751a20c8520e5725404c06015fea21d7567f25ef" + integrity sha512-JYc0DPlpGWB40kH5g07gGTrYuMqV653k3uBKY6uITPWds3M0ov3GaWGp9lbE3Bzngx8+XkfzgvASb9vk9JDFXQ== number-is-nan@^1.0.0: version "1.0.1" - resolved "https://registry.npmjs.org/number-is-nan/-/number-is-nan-1.0.1.tgz" - integrity sha1-CXtgK1NCKlIsGvuHkDGDNpQaAR0= - -oauth-sign@~0.9.0: - version "0.9.0" - resolved "https://registry.npmjs.org/oauth-sign/-/oauth-sign-0.9.0.tgz" - integrity sha512-fexhUFFPTGV8ybAtSIGbV6gOkSv8UtRbDBnAyLQw4QPKkgNlsH2ByPGtMUqdWkos6YCRmAqViwgZrJc/mRDzZQ== + resolved "https://registry.npmjs.org/number-is-nan/-/number-is-nan-1.0.1.tgz#097b602b53422a522c1afb8790318336941a011d" + integrity sha512-4jbtZXNAsfZbAHiiqjLPBiCl16dES1zI4Hpzzxw61Tk+loF+sBDBKx1ICKKKwIqQ7M0mFn1TmkN7euSncWgHiQ== object-assign@^4.1.0: version "4.1.1" - resolved "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz" - integrity sha1-IQmtx5ZYh8/AXLvUQsrIv7s2CGM= + resolved "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz#2109adc7965887cfc05cbbd442cac8bfbb360863" + integrity sha512-rJgTQnkUnH1sFw8yT6VSU3zD3sWmu6sZhIseY8VX+GRu3P6F7Fu+JNDoXfklElbLJSnc3FUQHVe4cU5hj+BcUg== -once@^1.3.0, once@^1.3.1, once@^1.4.0: +once@^1.3.1, once@^1.4.0: version "1.4.0" - resolved "https://registry.npmjs.org/once/-/once-1.4.0.tgz" - integrity sha1-WDsap3WWHUsROsF9nFC6753Xa9E= + resolved "https://registry.npmjs.org/once/-/once-1.4.0.tgz#583b1aa775961d4b113ac17d9c50baef9dd76bd1" + integrity sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w== dependencies: wrappy "1" onetime@^2.0.0: version "2.0.1" - resolved "https://registry.npmjs.org/onetime/-/onetime-2.0.1.tgz" - integrity sha1-BnQoIw/WdEOyeUsiu6UotoZ5YtQ= + resolved "https://registry.npmjs.org/onetime/-/onetime-2.0.1.tgz#067428230fd67443b2794b22bba528b6867962d4" + integrity sha512-oyyPpiMaKARvvcgip+JV+7zci5L8D1W9RZIz2l1o08AM3pfspitVWnPt3mzHcBPp12oYMTy0pqrFs/C+m3EwsQ== dependencies: mimic-fn "^1.0.0" -optionator@^0.9.1: - version "0.9.1" - resolved "https://registry.npmjs.org/optionator/-/optionator-0.9.1.tgz" - integrity sha512-74RlY5FCnhq4jRxVUPKDaRwrVNXMqsGsiW6AJw4XK8hmtm10wC0ypZBLw5IIp85NZMr91+qd1RvvENwg7jjRFw== +onetime@^7.0.0: + version "7.0.0" + resolved "https://registry.npmjs.org/onetime/-/onetime-7.0.0.tgz#9f16c92d8c9ef5120e3acd9dd9957cceecc1ab60" + integrity sha512-VXJjc87FScF88uafS3JllDgvAm+c/Slfz06lorj2uAY34rlUu0Nt+v8wreiImcrgAjjIHp1rXpTDlLOGw29WwQ== + dependencies: + mimic-function "^5.0.0" + +optionator@^0.9.3: + version "0.9.4" + resolved "https://registry.npmjs.org/optionator/-/optionator-0.9.4.tgz#7ea1c1a5d91d764fb282139c88fe11e182a3a734" + integrity sha512-6IpQ7mKUxRcZNLIObR0hz7lxsapSSIYNZJwXPGeF0mTVqGKFIXj1DQcMoT22S3ROcLyY/rz0PWaWZ9ayWmad9g== dependencies: deep-is "^0.1.3" fast-levenshtein "^2.0.6" levn "^0.4.1" prelude-ls "^1.2.1" type-check "^0.4.0" - word-wrap "^1.2.3" - -os-tmpdir@~1.0.2: - version "1.0.2" - resolved "https://registry.npmjs.org/os-tmpdir/-/os-tmpdir-1.0.2.tgz" - integrity sha1-u+Z0BseaqFxc/sdm/lc0VV36EnQ= - -p-cancelable@^3.0.0: - version "3.0.0" - resolved "https://registry.yarnpkg.com/p-cancelable/-/p-cancelable-3.0.0.tgz#63826694b54d61ca1c20ebcb6d3ecf5e14cd8050" - integrity sha512-mlVgR3PGuzlo0MmTdk4cXqXWlwQDLnONTAg6sm62XkMJEiRxN3GL3SffkYvqwonbkJBcrI7Uvv5Zh9yjvn2iUw== + word-wrap "^1.2.5" -p-defer@^3.0.0: - version "3.0.0" - resolved "https://registry.yarnpkg.com/p-defer/-/p-defer-3.0.0.tgz#d1dceb4ee9b2b604b1d94ffec83760175d4e6f83" - integrity sha512-ugZxsxmtTln604yeYd29EGrNhazN2lywetzpKhfmQjW/VJmhpDmWbiX+h0zL8V91R0UXkhb3KtPmyq9PZw3aYw== - -p-defer@^4.0.0: - version "4.0.0" - resolved "https://registry.yarnpkg.com/p-defer/-/p-defer-4.0.0.tgz#8082770aeeb10eb6b408abe91866738741ddd5d2" - integrity sha512-Vb3QRvQ0Y5XnF40ZUWW7JfLogicVh/EnA5gBIvKDJoYpeI82+1E3AlB9yOcKFS0AhHrWVnAQO39fbR0G99IVEQ== - -p-fifo@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/p-fifo/-/p-fifo-1.0.0.tgz#e29d5cf17c239ba87f51dde98c1d26a9cfe20a63" - integrity sha512-IjoCxXW48tqdtDFz6fqo5q1UfFVjjVZe8TC1QRflvNUJtNfCUhxOUw6MOVZhDPjqhSzc26xKdugsO17gmzd5+A== - dependencies: - fast-fifo "^1.0.0" - p-defer "^3.0.0" +p-cancelable@^4.0.1: + version "4.0.1" + resolved "https://registry.npmjs.org/p-cancelable/-/p-cancelable-4.0.1.tgz#2d1edf1ab8616b72c73db41c4bc9ecdd10af640e" + integrity sha512-wBowNApzd45EIKdO1LaU+LrMBwAcjfPaYtVzV3lmfM3gf8Z4CHZsiIqlM8TZZ8okYvh5A1cP6gTfCRQtwUpaUg== p-limit@^3.0.2: version "3.1.0" - resolved "https://registry.npmjs.org/p-limit/-/p-limit-3.1.0.tgz" + resolved "https://registry.npmjs.org/p-limit/-/p-limit-3.1.0.tgz#e1daccbe78d0d1388ca18c64fea38e3e57e3706b" integrity sha512-TYOanM3wGwNGsZN2cVTYPArw454xnXj5qmWF1bEoAc4+cU/ol7GVh7odevjp1FNHduHc3KZMcFduxU5Xc6uJRQ== dependencies: yocto-queue "^0.1.0" p-locate@^5.0.0: version "5.0.0" - resolved "https://registry.npmjs.org/p-locate/-/p-locate-5.0.0.tgz" + resolved "https://registry.npmjs.org/p-locate/-/p-locate-5.0.0.tgz#83c8315c6785005e3bd021839411c9e110e6d834" integrity sha512-LaNjtRWUBY++zB5nE/NwcaoMylSPk+S+ZHNB1TzdbMJMny6dynpAGt7X/tl/QYq3TIeE6nxHppbo2LGymrG5Pw== dependencies: p-limit "^3.0.2" p-map@^2.0.0: version "2.1.0" - resolved "https://registry.npmjs.org/p-map/-/p-map-2.1.0.tgz" + resolved "https://registry.npmjs.org/p-map/-/p-map-2.1.0.tgz#310928feef9c9ecc65b68b17693018a665cea175" integrity sha512-y3b8Kpd8OAN444hxfBbFfj1FY/RjtTd8tzYwhUqNYXx0fXx2iX4maP4Qr6qhIKbQXI02wTLAda4fYUbDagTUFw== -p-queue@^7.3.0: - version "7.3.4" - resolved "https://registry.yarnpkg.com/p-queue/-/p-queue-7.3.4.tgz#7ef7d89b6c1a0563596d98adbc9dc404e9ed4a84" - integrity sha512-esox8CWt0j9EZECFvkFl2WNPat8LN4t7WWeXq73D9ha0V96qPRufApZi4ZhPwXAln1uVVal429HVVKPa2X0yQg== - dependencies: - eventemitter3 "^4.0.7" - p-timeout "^5.0.2" - -p-timeout@^5.0.2: - version "5.1.0" - resolved "https://registry.yarnpkg.com/p-timeout/-/p-timeout-5.1.0.tgz#b3c691cf4415138ce2d9cfe071dba11f0fee085b" - integrity sha512-auFDyzzzGZZZdHz3BtET9VEz0SE/uMEAx7uWfGPucfzEwwe/xH0iVeZibQmANYE/hp9T2+UUZT5m+BKyrDp3Ew== - -parent-module@^1.0.0: - version "1.0.1" - resolved "https://registry.npmjs.org/parent-module/-/parent-module-1.0.1.tgz" - integrity sha512-GQ2EWRpQV8/o+Aw8YqtfZZPfNRWZYkbidE9k5rpl/hC3vtHHBfGm2Ifi6qWV+coDGkrUKZAxE3Lot5kcsRlh+g== - dependencies: - callsites "^3.0.0" - -parse-duration@^1.0.0: - version "1.0.3" - resolved "https://registry.yarnpkg.com/parse-duration/-/parse-duration-1.0.3.tgz#b6681f5edcc2689643b34c09ea63f86f58a35814" - integrity sha512-o6NAh12na5VvR6nFejkU0gpQ8jmOY9Y9sTU2ke3L3G/d/3z8jqmbBbeyBGHU73P4JLXfc7tJARygIK3WGIkloA== - -parse-duration@^1.0.2: - version "1.1.0" - resolved "https://registry.yarnpkg.com/parse-duration/-/parse-duration-1.1.0.tgz#5192084c5d8f2a3fd676d04a451dbd2e05a1819c" - integrity sha512-z6t9dvSJYaPoQq7quMzdEagSFtpGu+utzHqqxmpVWNNZRIXnvqyCvn9XsTdh7c/w0Bqmdz3RB3YnRaKtpRtEXQ== - path-exists@^4.0.0: version "4.0.0" - resolved "https://registry.npmjs.org/path-exists/-/path-exists-4.0.0.tgz" + resolved "https://registry.npmjs.org/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 sha1-F0uSaHNVNP+8es5r9TpanhtcX18= - path-key@^3.1.0: version "3.1.1" - resolved "https://registry.npmjs.org/path-key/-/path-key-3.1.1.tgz" + resolved "https://registry.npmjs.org/path-key/-/path-key-3.1.1.tgz#581f6ade658cbba65a0d3380de7753295054f375" integrity sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q== +path-scurry@^3.0.0: + version "3.0.0" + resolved "https://registry.npmjs.org/path-scurry/-/path-scurry-3.0.0.tgz#384894267bb8d1889242d176433f91ae1eec5cbb" + integrity sha512-1pTbQqH1wIwMi/eleQ5leFTTCkzFsPcgXNjwOA8YGGW/W4/kHT3dssE7Z6NH+zuqNLOzOB0uaD61yl7cAcVhgg== + dependencies: + lru-cache "^11.0.0" + minipass "^7.1.2" + pathval@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/pathval/-/pathval-2.0.0.tgz#7e2550b422601d4f6b8e26f1301bc8f15a741a25" - integrity sha512-vE7JKRyES09KiunauX7nd2Q9/L7lhok4smP9RZTDeD4MVs72Dp2qNFVz39Nz5a0FVEW0BJR6C0DYrq6unoziZA== + version "2.0.1" + resolved "https://registry.npmjs.org/pathval/-/pathval-2.0.1.tgz#8855c5a2899af072d6ac05d11e46045ad0dc605d" + integrity sha512-//nshmD55c46FuFw26xV/xFAaB5HF9Xdap7HJBBnrKdAd6/GxDBaNA1870O79+9ueg61cZLSVc+OaFlfmObYVQ== -performance-now@^2.1.0: - version "2.1.0" - resolved "https://registry.npmjs.org/performance-now/-/performance-now-2.1.0.tgz" - integrity sha1-Ywn04OX6kT7BxpMHrjZLSzd8nns= +picocolors@^1.1.1: + version "1.1.1" + resolved "https://registry.npmjs.org/picocolors/-/picocolors-1.1.1.tgz#3d321af3eab939b083c8f929a1d12cda81c26b6b" + integrity sha512-xceH2snhtb5M9liqDsmEw56le376mTZkEX/jEb/RxNFyegNul7eNslCXP9FDj/Lcu0X8KEyMceP2ntpaHrDEVA== -picomatch@^2.0.4, picomatch@^2.2.1: - version "2.3.1" - resolved "https://registry.npmjs.org/picomatch/-/picomatch-2.3.1.tgz" - integrity sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA== +picomatch@^4.0.4: + version "4.0.7" + resolved "https://registry.npmjs.org/picomatch/-/picomatch-4.0.7.tgz#6313360034ccb36b3dc61ecbdff78121f90fe21f" + integrity sha512-qcJu88Q2IWqJsDD529JKMdwGm/dvInW4HvQnRwiH9JtihJvzGOscDtHE3x1pBKeUOTysQ8kVmLnJ2kJu7yhcGA== prelude-ls@^1.2.1: version "1.2.1" - resolved "https://registry.npmjs.org/prelude-ls/-/prelude-ls-1.2.1.tgz" + resolved "https://registry.npmjs.org/prelude-ls/-/prelude-ls-1.2.1.tgz#debc6489d7a6e6b0e7611888cec880337d316396" integrity sha512-vkcDPrRZo1QZLbn5RLGPpg/WmIQ65qoWWhcGKf/b5eplkkarX0m9z8ppCat4mlOqUsWpyNuYgO3VRyrYHSzX5g== prettier@^2.1.2: - version "2.1.2" - resolved "https://registry.npmjs.org/prettier/-/prettier-2.1.2.tgz" - integrity sha512-16c7K+x4qVlJg9rEbXl7HEGmQyZlG4R9AgP+oHKRMsMsuk8s+ATStlf1NpDqyBI1HpVyfjLOeMhH2LvuNvV5Vg== - -progress-events@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/progress-events/-/progress-events-1.0.0.tgz#34f5e8fdb5dae3561837b22672d1e02277bb2109" - integrity sha512-zIB6QDrSbPfRg+33FZalluFIowkbV5Xh1xSuetjG+rlC5he6u2dc6VQJ0TbMdlN3R1RHdpOqxEFMKTnQ+itUwA== - -progress@^2.0.0: - version "2.0.3" - resolved "https://registry.npmjs.org/progress/-/progress-2.0.3.tgz" - integrity sha512-7PiHtLll5LdnKIMw100I+8xJXR5gW2QwWYkT6iJva0bXitZKa/XMrSbdmg3r2Xnaidz9Qumd0VPaMrZlF9V9sA== - -protobufjs@^7.0.0: - version "7.2.3" - resolved "https://registry.yarnpkg.com/protobufjs/-/protobufjs-7.2.3.tgz#01af019e40d9c6133c49acbb3ff9e30f4f0f70b2" - integrity sha512-TtpvOqwB5Gdz/PQmOjgsrGH1nHjAQVCN7JG4A6r1sXRWESL5rNMAiRcBQlCAdKxZcAbstExQePYG8xof/JVRgg== - dependencies: - "@protobufjs/aspromise" "^1.1.2" - "@protobufjs/base64" "^1.1.2" - "@protobufjs/codegen" "^2.0.4" - "@protobufjs/eventemitter" "^1.1.0" - "@protobufjs/fetch" "^1.1.0" - "@protobufjs/float" "^1.0.2" - "@protobufjs/inquire" "^1.1.0" - "@protobufjs/path" "^1.1.2" - "@protobufjs/pool" "^1.1.0" - "@protobufjs/utf8" "^1.1.0" - "@types/node" ">=13.7.0" - long "^5.0.0" - -protons-runtime@^5.0.0: - version "5.0.0" - resolved "https://registry.yarnpkg.com/protons-runtime/-/protons-runtime-5.0.0.tgz#1eb3c78637ff02cc90bb030e3bff6f0402109c25" - integrity sha512-QqjGnPGkpvbzq0dITzhG9DVK10rRIHf7nePcU2QQVVpFGuYbwrOWnvGSvei1GcceAzB9syTz6vHzvTPmGRR0PA== - dependencies: - protobufjs "^7.0.0" - uint8arraylist "^2.4.3" - -psl@^1.1.28: - version "1.8.0" - resolved "https://registry.npmjs.org/psl/-/psl-1.8.0.tgz" - integrity sha512-RIdOzyoavK+hA18OGGWDqUTsCLhtA7IcZ/6NCs4fFJaHBDab+pDDmDIByWFRQJq2Cd7r1OoQxBGKOaztq+hjIQ== + version "2.8.8" + resolved "https://registry.npmjs.org/prettier/-/prettier-2.8.8.tgz#e8c5d7e98a4305ffe3de2e1fc4aca1a71c28b1da" + integrity sha512-tdN8qQGvNjw4CHbY+XXk0JgCXn9QiF21a55rBe5LJAU+kDyC4WQn4+awm2Xfk2lQMk5fKup9XgzTZtGkjBdP9Q== pump@^3.0.0: - version "3.0.0" - resolved "https://registry.npmjs.org/pump/-/pump-3.0.0.tgz" - integrity sha512-LwZy+p3SFs1Pytd/jYct4wpv49HiYCqd9Rlc5ZVdk0V+8Yzv6jR5Blk3TRmPL1ft69TxP0IMZGJ+WPFU2BFhww== + version "3.0.4" + resolved "https://registry.npmjs.org/pump/-/pump-3.0.4.tgz#1f313430527fa8b905622ebd22fe1444e757ab3c" + integrity sha512-VS7sjc6KR7e1ukRFhQSY5LM2uBWAUPiOPa/A3mkKmiMwSmRFUITt0xuj+/lesgnCv+dPIEYlkzrcyXgquIHMcA== dependencies: end-of-stream "^1.1.0" once "^1.3.1" -punycode@^2.1.0, punycode@^2.1.1: - version "2.1.1" - resolved "https://registry.npmjs.org/punycode/-/punycode-2.1.1.tgz" - integrity sha512-XRsRjdf+j5ml+y/6GKHPZbrF/8p2Yga0JPtdqTIY2Xe5ohJPD9saDJJLPvp9+NSBprVvevdXZybnj2cv8OEd0A== - -qs@~6.5.2: - version "6.5.3" - resolved "https://registry.npmjs.org/qs/-/qs-6.5.3.tgz" - integrity sha512-qxXIEh4pCGfHICj1mAJQ2/2XVZkjCDTcEgfoSQxc/fYivUZxTkk7L3bDBJSoNrEzXI17oUO5Dp07ktqE5KzczA== +punycode@^2.1.0: + version "2.3.1" + resolved "https://registry.npmjs.org/punycode/-/punycode-2.3.1.tgz#027422e2faec0b25e1549c3e1bd8309b9133b6e5" + integrity sha512-vYt7UD1U9Wg6138shLtLOvdAu+8DsC/ilFtEVHcH+wydcSpNE20AfSOduf6MkRFahL5FY7X1oU7nKVZFtfq8Fg== -queue@6.0.1: - version "6.0.1" - resolved "https://registry.npmjs.org/queue/-/queue-6.0.1.tgz" - integrity sha512-AJBQabRCCNr9ANq8v77RJEv73DPbn55cdTb+Giq4X0AVnNVZvMHlYp7XlQiN+1npCZj1DuSmaA2hYVUUDgxFDg== +qified@^0.10.1: + version "0.10.1" + resolved "https://registry.npmjs.org/qified/-/qified-0.10.1.tgz#0640bf21bbe6ca540db290ad8f5fde4d870b8bda" + integrity sha512-+Owyggi9IxT1ePKGafcI87ubSmxol6smwJ+RAHDQlx9+9cPwFWDiKFFCPuWhr9ignlGpZ9vDQLw67N4dcTVFEA== dependencies: - inherits "~2.0.3" + hookified "^2.1.1" quick-lru@^5.1.1: version "5.1.1" - resolved "https://registry.yarnpkg.com/quick-lru/-/quick-lru-5.1.1.tgz#366493e6b3e42a3a6885e2e99d18f80fb7a8c932" + resolved "https://registry.npmjs.org/quick-lru/-/quick-lru-5.1.1.tgz#366493e6b3e42a3a6885e2e99d18f80fb7a8c932" integrity sha512-WuyALRjWPDGtt/wzJiadO5AXY+8hZ80hVpe6MyivgraREW751X3SbhRvG3eLKOYN+8VEvqLcf3wdnt44Z4S4SA== -randombytes@^2.1.0: - version "2.1.0" - resolved "https://registry.npmjs.org/randombytes/-/randombytes-2.1.0.tgz" - integrity sha512-vYl3iOX+4CKUWuxGi9Ukhie6fsqXqS9FE2Zaic4tNFD2N2QQaXOMFbuKK4QmDHC0JO6B1Zp41J0LpT0oR68amQ== - dependencies: - safe-buffer "^5.1.0" - -react-native-fetch-api@^3.0.0: - version "3.0.0" - resolved "https://registry.yarnpkg.com/react-native-fetch-api/-/react-native-fetch-api-3.0.0.tgz#81e1bb6562c292521bc4eca52fe1097f4c1ebab5" - integrity sha512-g2rtqPjdroaboDKTsJCTlcmtw54E25OjyaunUP0anOZn4Fuo2IKs8BVfe02zVggA/UysbmfSnRJIqtNkAgggNA== - dependencies: - p-defer "^3.0.0" - -readable-stream@^3.1.1, readable-stream@^3.4.0: - version "3.6.0" - resolved "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.0.tgz" - integrity sha512-BViHy7LKeTz4oNnkcLJ+lVSL6vpiFeX6/d3oSH8zCW7UxP2onchk+vTGB143xuFjHS3deTgkKoXXymXqymiIdA== - dependencies: - inherits "^2.0.3" - string_decoder "^1.1.1" - util-deprecate "^1.0.1" - -readable-stream@^3.5.0, readable-stream@^3.6.0: - version "3.6.2" - resolved "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.2.tgz" - integrity sha512-9u/sniCrY3D5WdsERHzHE4G2YCXqoG5FTHUiCC4SIbr6XcLZBY05ya9EKjYek9O5xOAwjGq+1JdGBAS7Q9ScoA== - dependencies: - inherits "^2.0.3" - string_decoder "^1.1.1" - util-deprecate "^1.0.1" - -readdirp@~3.6.0: - version "3.6.0" - resolved "https://registry.npmjs.org/readdirp/-/readdirp-3.6.0.tgz" - integrity sha512-hOS089on8RduqdbhvQ5Z37A0ESjsqz6qnRcffsMU3495FuTdqSm+7bhJ29JvIOsBDEEnan5DPu9t3To9VRlMzA== - dependencies: - picomatch "^2.2.1" - -receptacle@^1.3.2: - version "1.3.2" - resolved "https://registry.yarnpkg.com/receptacle/-/receptacle-1.3.2.tgz#a7994c7efafc7a01d0e2041839dab6c4951360d2" - integrity sha512-HrsFvqZZheusncQRiEE7GatOAETrARKV/lnfYicIm8lbvp/JQOdADOfhjBd2DajvoszEyxSM6RlAAIZgEoeu/A== - dependencies: - ms "^2.1.1" - -regexpp@^3.0.0, regexpp@^3.1.0: - version "3.1.0" - resolved "https://registry.npmjs.org/regexpp/-/regexpp-3.1.0.tgz" - integrity sha512-ZOIzd8yVsQQA7j8GCSlPGXwg5PfmA1mrq0JP4nGhh54LaKN3xdai/vHUDu74pKwV8OxseMS65u2NImosQcSD0Q== - -request@^2.88.2: - version "2.88.2" - resolved "https://registry.npmjs.org/request/-/request-2.88.2.tgz" - integrity sha512-MsvtOrfG9ZcrOwAW+Qi+F6HbD0CWXEh9ou77uOb7FM2WPhwT7smM833PzanhJLsgXjN89Ir6V2PczXNnMpwKhw== - dependencies: - aws-sign2 "~0.7.0" - aws4 "^1.8.0" - caseless "~0.12.0" - combined-stream "~1.0.6" - extend "~3.0.2" - forever-agent "~0.6.1" - form-data "~2.3.2" - har-validator "~5.1.3" - http-signature "~1.2.0" - is-typedarray "~1.0.0" - isstream "~0.1.2" - json-stringify-safe "~5.0.1" - mime-types "~2.1.19" - oauth-sign "~0.9.0" - performance-now "^2.1.0" - qs "~6.5.2" - safe-buffer "^5.1.2" - tough-cookie "~2.5.0" - tunnel-agent "^0.6.0" - uuid "^3.3.2" +readdirp@^5.0.0: + version "5.1.1" + resolved "https://registry.npmjs.org/readdirp/-/readdirp-5.1.1.tgz#520bca06f9d1ae1b96cc0800dbe84b983d19422c" + integrity sha512-Kko+Y5XQ6fM+Ce3dq3m9YGxnacYZYl9cA1wZjaF3Vbry2L3i1qVg8+CAgNPsXRArPMUMCaOR7oa9Nqntc43JKA== require-directory@^2.1.1: version "2.1.1" - resolved "https://registry.npmjs.org/require-directory/-/require-directory-2.1.1.tgz" - integrity sha1-jGStX9MNqxyXbiNE/+f3kqam30I= + resolved "https://registry.npmjs.org/require-directory/-/require-directory-2.1.1.tgz#8c64ad5fd30dab1c976e2344ffe7f792a6a6df42" + integrity sha512-fGxEI7+wsG9xrvdjsrlmL22OMTTiHRwAMroiEeMgq8gzoLC/PQr7RsRDSTLUg/bZAZtF+TVIkHc6/4RIKrui+Q== require-from-string@^2.0.2: version "2.0.2" - resolved "https://registry.npmjs.org/require-from-string/-/require-from-string-2.0.2.tgz" + resolved "https://registry.npmjs.org/require-from-string/-/require-from-string-2.0.2.tgz#89a7fdd938261267318eafe14f9c32e598c36909" integrity sha512-Xf0nWe6RseziFMu+Ap9biiUbmplq6S9/p+7w7YXP/JBHhrUDDUhwa+vANyubuqfZWTveU//DYVGsDG7RKL/vEw== resolve-alpn@^1.2.0: version "1.2.1" - resolved "https://registry.yarnpkg.com/resolve-alpn/-/resolve-alpn-1.2.1.tgz#b7adbdac3546aaaec20b45e7d8265927072726f9" + resolved "https://registry.npmjs.org/resolve-alpn/-/resolve-alpn-1.2.1.tgz#b7adbdac3546aaaec20b45e7d8265927072726f9" integrity sha512-0a1F4l73/ZFZOakJnQ3FvkJ2+gSTQWz/r2KE5OdDY0TxPm5h4GkqkWWfM47T7HsbnOtcJVEF4epCVy6u7Q3K+g== -resolve-from@^4.0.0: - version "4.0.0" - resolved "https://registry.npmjs.org/resolve-from/-/resolve-from-4.0.0.tgz" - integrity sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g== - -responselike@^3.0.0: - version "3.0.0" - resolved "https://registry.yarnpkg.com/responselike/-/responselike-3.0.0.tgz#20decb6c298aff0dbee1c355ca95461d42823626" - integrity sha512-40yHxbNcl2+rzXvZuVkrYohathsSJlMTXKryG5y8uciHv1+xDLHQpgjG64JUO9nrEq2jGLH6IZ8BcZyw3wrweg== +responselike@^4.0.2: + version "4.0.2" + resolved "https://registry.npmjs.org/responselike/-/responselike-4.0.2.tgz#d99a1105aeca5909c1e93156a839c7f3173e26c2" + integrity sha512-cGk8IbWEAnaCpdAt1BHzJ3Ahz5ewDJa0KseTsE3qIRMJ3C698W8psM7byCeWVpd/Ha7FUYzuRVzXoKoM6nRUbA== dependencies: lowercase-keys "^3.0.0" restore-cursor@^2.0.0: version "2.0.0" - resolved "https://registry.npmjs.org/restore-cursor/-/restore-cursor-2.0.0.tgz" - integrity sha1-n37ih/gv0ybU/RYpI9YhKe7g368= + resolved "https://registry.npmjs.org/restore-cursor/-/restore-cursor-2.0.0.tgz#9f7ee287f82fd326d4fd162923d62129eee0dfaf" + integrity sha512-6IzJLuGi4+R14vwagDHX+JrXmPVtPpn4mffDJ1UdR7/Edm87fl6yi8mMBIVvFtJaNTUvjughmW4hwLhRG7gC1Q== dependencies: onetime "^2.0.0" signal-exit "^3.0.2" -retimer@^3.0.0: - version "3.0.0" - resolved "https://registry.yarnpkg.com/retimer/-/retimer-3.0.0.tgz#98b751b1feaf1af13eb0228f8ea68b8f9da530df" - integrity sha512-WKE0j11Pa0ZJI5YIk0nflGI7SQsfl2ljihVy7ogh7DeQSeYAUi0ubZ/yEueGtDfUPk6GH5LRw1hBdLq4IwUBWA== - -retry@0.12.0: - version "0.12.0" - resolved "https://registry.npmjs.org/retry/-/retry-0.12.0.tgz" - integrity sha1-G0KmJmoh8HQh0bC1S33BZ7AcATs= - -rimraf@2.6.3: - version "2.6.3" - resolved "https://registry.npmjs.org/rimraf/-/rimraf-2.6.3.tgz" - integrity sha512-mwqeW5XsA2qAejG46gYdENaxXjx9onRNCfn7L0duuP4hCuTIi/QO7PDK07KJfp1d+izWPrzEJDcSqBa0OZQriA== +restore-cursor@^5.0.0: + version "5.1.0" + resolved "https://registry.npmjs.org/restore-cursor/-/restore-cursor-5.1.0.tgz#0766d95699efacb14150993f55baf0953ea1ebe7" + integrity sha512-oMA2dcrw6u0YfxJQXm342bFKX/E4sG9rbTzO9ptUcR/e8A33cHuvStiYOwH7fszkZlZ1z/ta9AAoPk2F4qIOHA== dependencies: - glob "^7.1.3" + onetime "^7.0.0" + signal-exit "^4.1.0" -rimraf@^3.0.2: - version "3.0.2" - resolved "https://registry.npmjs.org/rimraf/-/rimraf-3.0.2.tgz" - integrity sha512-JZkJMZkAGFFPP2YqXZXPbMlMBgsxzE8ILs4lMIX/2o0L9UBw9O/Y3o6wFw/i9YLapcUJWwqbi3kdxIPdC62TIA== - dependencies: - glob "^7.1.3" +retry@0.13.1: + version "0.13.1" + resolved "https://registry.npmjs.org/retry/-/retry-0.13.1.tgz#185b1587acf67919d63b357349e03537b2484658" + integrity sha512-XQBQ3I8W1Cge0Seh+6gjj03LbmRFWuoszgK9ooCpwYIrhhoO80pfq4cUkU5DkknwfOfFteRwlZ56PYOGYyFWdg== -run-async@^2.2.0: - version "2.4.1" - resolved "https://registry.npmjs.org/run-async/-/run-async-2.4.1.tgz" - integrity sha512-tvVnVv01b8c1RrA6Ep7JkStj85Guv/YrMcwqYQnwjsAS2cTmmPGBBjAjpCW7RrSodNSoE2/qg9O4bceNvUuDgQ== +run-async@^4.0.6: + version "4.0.6" + resolved "https://registry.npmjs.org/run-async/-/run-async-4.0.6.tgz#d53b86acb71f42650fe23de2b3c1b6b6b34b9294" + integrity sha512-IoDlSLTs3Yq593mb3ZoKWKXMNu3UpObxhgA/Xuid5p4bbfi2jdY1Hj0m1K+0/tEuQTxIGMhQDqGjKb7RuxGpAQ== -rxjs@^6.3.3, rxjs@^6.4.0, rxjs@^6.5.1: - version "6.5.5" - resolved "https://registry.npmjs.org/rxjs/-/rxjs-6.5.5.tgz" - integrity sha512-WfQI+1gohdf0Dai/Bbmk5L5ItH5tYqm3ki2c5GdWhKjalzjg93N3avFjVStyZZz+A2Em+ZxKH5bNghw9UeylGQ== +rxjs@^6.3.3, rxjs@^6.5.1: + version "6.6.7" + resolved "https://registry.npmjs.org/rxjs/-/rxjs-6.6.7.tgz#90ac018acabf491bf65044235d5863c4dab804c9" + integrity sha512-hTdwr+7yYNIT5n4AMYp85KA6yw2Va0FLa3Rguvbpa4W3I5xynaBZo41cM3XM+4Q6fRMj3sBYIR1VAmZMXYJvRQ== dependencies: tslib "^1.9.0" -safe-buffer@^5.0.1, safe-buffer@^5.1.0, safe-buffer@^5.1.2, safe-buffer@~5.2.0: - version "5.2.1" - resolved "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz" - integrity sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ== +rxjs@^7.8.2: + version "7.8.2" + resolved "https://registry.npmjs.org/rxjs/-/rxjs-7.8.2.tgz#955bc473ed8af11a002a2be52071bf475638607b" + integrity sha512-dhKf903U/PQZY6boNNtAGdWbG85WAbjT/1xYoZIC7FAY0yWapOBQVsVrDl58W86//e1VpMNBtRV4MaXfdMySFA== + dependencies: + tslib "^2.1.0" -"safer-buffer@>= 2.1.2 < 3", "safer-buffer@>= 2.1.2 < 3.0.0", safer-buffer@^2.0.2, safer-buffer@^2.1.0, safer-buffer@~2.1.0: +"safer-buffer@>= 2.1.2 < 3.0.0": version "2.1.2" - resolved "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz" + resolved "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz#44fa161b0187b9549dd84bb91802f9bd8385cd6a" integrity sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg== -semver@^7.2.1, semver@^7.3.2: - version "7.3.2" - resolved "https://registry.npmjs.org/semver/-/semver-7.3.2.tgz" - integrity sha512-OrOb32TeeambH6UrhtShmF7CRDqhL6/5XpPNp2DuRH6+9QLw/orhp72j87v8Qa1ScDkvrrBNpZcDejAirJmfXQ== - -semver@^7.5.0: - version "7.5.0" - resolved "https://registry.yarnpkg.com/semver/-/semver-7.5.0.tgz#ed8c5dc8efb6c629c88b23d41dc9bf40c1d96cd0" - integrity sha512-+XC0AD/R7Q2mPSRuy2Id0+CGTZ98+8f+KvwirxOKIEyid+XSx6HbC63p+O4IndTHuX5Z+JxQ0TghCkO5Cg/2HA== - dependencies: - lru-cache "^6.0.0" - -semver@^7.6.0: - version "7.6.0" - resolved "https://registry.yarnpkg.com/semver/-/semver-7.6.0.tgz#1a46a4db4bffcccd97b743b5005c8325f23d4e2d" - integrity sha512-EnwXhrlwXMk9gKu5/flx5sv/an57AkRplG3hTK68W7FRDN+k+OWBj65M7719OkA82XLBxrcX0KSHj+X5COhOVg== - dependencies: - lru-cache "^6.0.0" +semver@^7.5.0, semver@^7.6.0, semver@^7.7.3: + version "7.8.6" + resolved "https://registry.npmjs.org/semver/-/semver-7.8.6.tgz#67c0cda133a3ceb6f70b803e67625bf969000424" + integrity sha512-9lpSSU4Mly3mrtruwLs1eLK6+gzbzqeBFwRNjIjE+9LuDpWdYctrQlQ3ej1Ilgi7gknpsTRnPoLP8DpCHqHIJw== -serialize-javascript@6.0.0: - version "6.0.0" - resolved "https://registry.npmjs.org/serialize-javascript/-/serialize-javascript-6.0.0.tgz" - integrity sha512-Qr3TosvguFt8ePWqsvRfrKyQXIiW+nGbYpy8XK24NQHE83caxWt+mIymTT19DGFbNWNLfEwsrkSmN64lVWB9ag== - dependencies: - randombytes "^2.1.0" +serialize-javascript@^7.1.1: + version "7.1.4" + resolved "https://registry.npmjs.org/serialize-javascript/-/serialize-javascript-7.1.4.tgz#477af55bdec0d831fa3b209245f673217fd27380" + integrity sha512-FqlEuoTq/zRmA4Lg6aOqyH3lCHbUtCB0bmHCeFniX2GBdDqMJM3FwdvEhlE5Pim1dlt2FfBdVPmUNNiGhhKqpw== shebang-command@^2.0.0: version "2.0.0" - resolved "https://registry.npmjs.org/shebang-command/-/shebang-command-2.0.0.tgz" + resolved "https://registry.npmjs.org/shebang-command/-/shebang-command-2.0.0.tgz#ccd0af4f8835fbdc265b82461aaf0c36663f34ea" integrity sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA== dependencies: shebang-regex "^3.0.0" shebang-regex@^3.0.0: version "3.0.0" - resolved "https://registry.npmjs.org/shebang-regex/-/shebang-regex-3.0.0.tgz" + resolved "https://registry.npmjs.org/shebang-regex/-/shebang-regex-3.0.0.tgz#ae16f1644d873ecad843b0307b143362d4c42172" integrity sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A== signal-exit@^3.0.2: - version "3.0.3" - resolved "https://registry.npmjs.org/signal-exit/-/signal-exit-3.0.3.tgz" - integrity sha512-VUJ49FC8U1OxwZLxIbTTrDvLnf/6TDgxZcK8wxR8zs13xpx7xbG60ndBlhNrFi2EMuFRoeDoJO7wthSLq42EjA== + version "3.0.7" + resolved "https://registry.npmjs.org/signal-exit/-/signal-exit-3.0.7.tgz#a9a1767f8af84155114eaabd73f99273c8f59ad9" + integrity sha512-wnD2ZE+l+SPC/uoS0vXeE9L1+0wuaMqKlfz9AMUo38JsyLSBWSFcHR1Rri62LZc12vLr1gb3jl7iwQhgwpAbGQ== + +signal-exit@^4.1.0: + version "4.1.0" + resolved "https://registry.npmjs.org/signal-exit/-/signal-exit-4.1.0.tgz#952188c1cbd546070e2dd20d0f41c0ae0530cb04" + integrity sha512-bzyZ1e88w9O1iNJbKnOlvYTrWPDl46O1bG0D3XInv+9tkPrxrN8jUUTiFlDkkmKWgn1M6CfIA13SuGqOa9Korw== slice-ansi@0.0.4: version "0.0.4" - resolved "https://registry.npmjs.org/slice-ansi/-/slice-ansi-0.0.4.tgz" - integrity sha1-7b+JA/ZvfOL46v1s7tZeJkyDGzU= + resolved "https://registry.npmjs.org/slice-ansi/-/slice-ansi-0.0.4.tgz#edbf8903f66f7ce2f8eafd6ceed65e264c831b35" + integrity sha512-up04hB2hR92PgjpyU3y/eg91yIBILyjVY26NvvciY3EVVPjybkMszMpXQ9QAkcS3I5rtJBDLoTxxg+qvW8c7rw== -slice-ansi@^2.1.0: - version "2.1.0" - resolved "https://registry.npmjs.org/slice-ansi/-/slice-ansi-2.1.0.tgz" - integrity sha512-Qu+VC3EwYLldKa1fCxuuvULvSJOKEgk9pi8dZeCVK7TqBfUNTH4sFkk4joj8afVSfAYgJoSOetjx9QWOJ5mYoQ== +slice-ansi@^7.1.0: + version "7.1.2" + resolved "https://registry.npmjs.org/slice-ansi/-/slice-ansi-7.1.2.tgz#adf7be70aa6d72162d907cd0e6d5c11f507b5403" + integrity sha512-iOBWFgUX7caIZiuutICxVgX1SdxwAVFFKwt1EvMYYec/NWO5meOJ6K5uQxhrYBdQJne4KxiqZc+KptFOWFSI9w== dependencies: - ansi-styles "^3.2.0" - astral-regex "^1.0.0" - is-fullwidth-code-point "^2.0.0" + ansi-styles "^6.2.1" + is-fullwidth-code-point "^5.0.0" source-map-support@^0.5.19: - version "0.5.19" - resolved "https://registry.npmjs.org/source-map-support/-/source-map-support-0.5.19.tgz" - integrity sha512-Wonm7zOCIJzBGQdB+thsPar0kYuCIzYvxZwlBa87yi/Mdjv7Tip2cyVbLj5o0cFPN4EVkuTwb3GDDyUx2DGnGw== + version "0.5.21" + resolved "https://registry.npmjs.org/source-map-support/-/source-map-support-0.5.21.tgz#04fe7c7f9e1ed2d662233c28cb2b35b9f63f6e4f" + integrity sha512-uBHU3L3czsIyYXKX88fdrGovxdSCoTGDRZ6SYXtSRxLZUzHg5P/66Ht6uoUlHu9EZod+inXhKo3qQgwXUT/y1w== dependencies: buffer-from "^1.0.0" source-map "^0.6.0" source-map@^0.6.0: version "0.6.1" - resolved "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz" + resolved "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz#74722af32e9614e9c287a8d0bbde48b5e2f1a263" integrity sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g== -sparse-array@^1.3.1: - version "1.3.2" - resolved "https://registry.yarnpkg.com/sparse-array/-/sparse-array-1.3.2.tgz#0e1a8b71706d356bc916fe754ff496d450ec20b0" - integrity sha512-ZT711fePGn3+kQyLuv1fpd3rNSkNF8vd5Kv2D+qnOANeyKs3fx6bUMGWRPvgTTcYV64QMqZKZwcuaQSP3AZ0tg== - -split-ca@^1.0.1: - version "1.0.1" - resolved "https://registry.npmjs.org/split-ca/-/split-ca-1.0.1.tgz" - integrity sha512-Q5thBSxp5t8WPTTJQS59LrGqOZqOsrhDGDVm8azCqIBjSBd7nd9o2PM+mDulQQkh8h//4U6hFZnc/mul8t5pWQ== - -sprintf-js@~1.0.2: - version "1.0.3" - resolved "https://registry.npmjs.org/sprintf-js/-/sprintf-js-1.0.3.tgz" - integrity sha1-BOaSb2YolTVPPdAVIDYzuFcpfiw= - -ssh2@^1.11.0: - version "1.11.0" - resolved "https://registry.npmjs.org/ssh2/-/ssh2-1.11.0.tgz" - integrity sha512-nfg0wZWGSsfUe/IBJkXVll3PEZ//YH2guww+mP88gTpuSU4FtZN7zu9JoeTGOyCNx2dTDtT9fOpWwlzyj4uOOw== +streamx@^2.12.5, streamx@^2.25.0, streamx@^2.28.1: + version "2.28.1" + resolved "https://registry.npmjs.org/streamx/-/streamx-2.28.1.tgz#376cd42a089505a69bec0efdb5189aa45586141f" + integrity sha512-zEzXb0s5Cds7tqMH6rhZ05lcJydCWiQPEwiNngVqzsxCc962vLY4Uw+mW7od8kDH258k2Uz/JrOkdIAAhSh9VA== dependencies: - asn1 "^0.2.4" - bcrypt-pbkdf "^1.0.2" - optionalDependencies: - cpu-features "~0.0.4" - nan "^2.16.0" - -sshpk@^1.7.0: - version "1.16.1" - resolved "https://registry.npmjs.org/sshpk/-/sshpk-1.16.1.tgz" - integrity sha512-HXXqVUq7+pcKeLqqZj6mHFUMvXtOJt1uoUx09pFW6011inTMxqI8BA8PM95myrIyyKwdnzjdFjLiE6KBPVtJIg== - dependencies: - asn1 "~0.2.3" - assert-plus "^1.0.0" - bcrypt-pbkdf "^1.0.0" - dashdash "^1.12.0" - ecc-jsbn "~0.1.1" - getpass "^0.1.1" - jsbn "~0.1.0" - safer-buffer "^2.0.2" - tweetnacl "~0.14.0" - -stream-to-it@^0.2.2, stream-to-it@^0.2.4: - version "0.2.4" - resolved "https://registry.yarnpkg.com/stream-to-it/-/stream-to-it-0.2.4.tgz#d2fd7bfbd4a899b4c0d6a7e6a533723af5749bd0" - integrity sha512-4vEbkSs83OahpmBybNJXlJd7d6/RxzkkSdT3I0mnGt79Xd2Kk+e1JqbvAvsQfCeKj3aKb0QIWkyK3/n0j506vQ== - dependencies: - get-iterator "^1.0.2" - -streamsearch@^1.1.0: - version "1.1.0" - resolved "https://registry.yarnpkg.com/streamsearch/-/streamsearch-1.1.0.tgz#404dd1e2247ca94af554e841a8ef0eaa238da764" - integrity sha512-Mcc5wHehp9aXz1ax6bZUyY5afg9u2rv5cqQI3mRrYkGC8rW2hM02jWuwjtL++LS5qinSyhj2QfLyNsuc+VsExg== + events-universal "^1.0.0" + fast-fifo "^1.3.2" + text-decoder "^1.1.0" string-width@^1.0.1: version "1.0.2" - resolved "https://registry.npmjs.org/string-width/-/string-width-1.0.2.tgz" - integrity sha1-EYvfW4zcUaKn5w0hHgfisLmxB9M= + resolved "https://registry.npmjs.org/string-width/-/string-width-1.0.2.tgz#118bdf5b8cdc51a2a7e70d211e07e2b0b9b107d3" + integrity sha512-0XsVpQLnVCXHJfyEs8tC0zpTVIr5PKKsQtkT29IwupnPTjtPmQ3xT/4yCREF9hYkV/3M3kzcUTSAZT6a6h81tw== dependencies: code-point-at "^1.0.0" is-fullwidth-code-point "^1.0.0" strip-ansi "^3.0.0" -string-width@^2.1.0, string-width@^2.1.1: +string-width@^2.1.1: version "2.1.1" - resolved "https://registry.npmjs.org/string-width/-/string-width-2.1.1.tgz" + resolved "https://registry.npmjs.org/string-width/-/string-width-2.1.1.tgz#ab93f27a8dc13d28cac815c462143a6d9012ae9e" integrity sha512-nOqH59deCq9SRHlxq1Aw85Jnt4w6KvLKqWVik6oA9ZklXLNIOlqg4F2yrT1MVaTjAqvVwdfeZ7w7aCvJD7ugkw== dependencies: is-fullwidth-code-point "^2.0.0" strip-ansi "^4.0.0" -string-width@^3.0.0: - version "3.1.0" - resolved "https://registry.npmjs.org/string-width/-/string-width-3.1.0.tgz" - integrity sha512-vafcv6KjVZKSgz06oM/H6GDBrAtz8vdhQakGjFIvNrHA6y3HCF1CInLy+QLq8dTJPQ1b+KDUqDFctkdRW44e1w== - dependencies: - emoji-regex "^7.0.1" - is-fullwidth-code-point "^2.0.0" - strip-ansi "^5.1.0" - -string-width@^4.1.0, string-width@^4.2.3: +string-width@^4.1.0, string-width@^4.2.0, string-width@^4.2.3: version "4.2.3" - resolved "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz" + resolved "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz#269c7117d27b05ad2e536830a8ec895ef9c6d010" integrity sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g== dependencies: emoji-regex "^8.0.0" is-fullwidth-code-point "^3.0.0" strip-ansi "^6.0.1" -string-width@^4.2.0: - version "4.2.0" - resolved "https://registry.npmjs.org/string-width/-/string-width-4.2.0.tgz" - integrity sha512-zUz5JD+tgqtuDjMhwIg5uFVV3dtqZ9yQJlZVfq4I01/K5Paj5UHj7VyrQOJvzawSVlKpObApbfD0Ed6yJc+1eg== - dependencies: - emoji-regex "^8.0.0" - is-fullwidth-code-point "^3.0.0" - strip-ansi "^6.0.0" - -string_decoder@^1.1.1: - version "1.3.0" - resolved "https://registry.npmjs.org/string_decoder/-/string_decoder-1.3.0.tgz" - integrity sha512-hkRX8U1WjJFd8LsDJ2yQ/wWWxaopEsABU1XfkM8A+j0+85JAGppt16cr1Whg6KIbb4okU6Mql6BOj+uup/wKeA== +string-width@^7.0.0: + version "7.2.0" + resolved "https://registry.npmjs.org/string-width/-/string-width-7.2.0.tgz#b5bb8e2165ce275d4d43476dd2700ad9091db6dc" + integrity sha512-tsaTIkKW9b4N+AEj+SVA+WhJzV7/zMhcSu78mLKWSk7cXMOSHsBKFWUs0fWwq8QyK3MgJBQRX6Gbi4kYbdvGkQ== dependencies: - safe-buffer "~5.2.0" + emoji-regex "^10.3.0" + get-east-asian-width "^1.0.0" + strip-ansi "^7.1.0" strip-ansi@^3.0.0, strip-ansi@^3.0.1: version "3.0.1" - resolved "https://registry.npmjs.org/strip-ansi/-/strip-ansi-3.0.1.tgz" - integrity sha1-ajhfuIU9lS1f8F0Oiq+UJ43GPc8= + resolved "https://registry.npmjs.org/strip-ansi/-/strip-ansi-3.0.1.tgz#6a385fb8853d952d5ff05d0e8aaf94278dc63dcf" + integrity sha512-VhumSSbBqDTP8p2ZLKj40UjBCV4+v8bUSEpUb4KjRgWk9pbqGF4REFj6KEagidb2f/M6AzC0EmFyDNGaw9OCzg== dependencies: ansi-regex "^2.0.0" strip-ansi@^4.0.0: version "4.0.0" - resolved "https://registry.npmjs.org/strip-ansi/-/strip-ansi-4.0.0.tgz" - integrity sha1-qEeQIusaw2iocTibY1JixQXuNo8= + resolved "https://registry.npmjs.org/strip-ansi/-/strip-ansi-4.0.0.tgz#a8479022eb1ac368a871389b635262c505ee368f" + integrity sha512-4XaJ2zQdCzROZDivEVIDPkcQn8LMFSa8kj8Gxb/Lnwzv9A8VctNZ+lfivC/sV3ivW8ElJTERXZoPBRrZKkNKow== dependencies: ansi-regex "^3.0.0" -strip-ansi@^5.1.0: - version "5.2.0" - resolved "https://registry.npmjs.org/strip-ansi/-/strip-ansi-5.2.0.tgz" - integrity sha512-DuRs1gKbBqsMKIZlrffwlug8MHkcnpjs5VPmL1PAh+mA30U0DTotfDZ0d2UUsXpPmPmMMJ6W773MaA3J+lbiWA== - dependencies: - ansi-regex "^4.1.0" - -strip-ansi@^6.0.0: - version "6.0.0" - resolved "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.0.tgz" - integrity sha512-AuvKTrTfQNYNIctbR1K/YGTR1756GycPsg7b9bdV9Duqur4gv6aKqHXah67Z8ImS7WEz5QVcOtlfW2rZEugt6w== - dependencies: - ansi-regex "^5.0.0" - -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" + resolved "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz#9e26c63d30f53443e9489495b2105d37b67a85d9" integrity sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A== dependencies: ansi-regex "^5.0.1" -strip-json-comments@3.1.1, strip-json-comments@^3.1.0: - version "3.1.1" - resolved "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-3.1.1.tgz" - integrity sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig== - -supports-color@8.1.1: - version "8.1.1" - resolved "https://registry.npmjs.org/supports-color/-/supports-color-8.1.1.tgz" - integrity sha512-MpUEN2OodtUzxvKQl72cUF7RQ5EiHsGvSsVG0ia9c5RbWGL2CI4C7EpPS8UTBIplnlzZiNuV56w+FuNxy3ty2Q== +strip-ansi@^7.1.0: + version "7.2.0" + resolved "https://registry.npmjs.org/strip-ansi/-/strip-ansi-7.2.0.tgz#d22a269522836a627af8d04b5c3fd2c7fa3e32e3" + integrity sha512-yDPMNjp4WyfYBkHnjIRLfca1i6KMyGCtsVgoKe/z1+6vukgaENdgGBZt+ZmKPc4gavvEZ5OgHfHdrazhgNyG7w== dependencies: - has-flag "^4.0.0" + ansi-regex "^6.2.2" + +strip-json-comments@^5.0.3: + version "5.0.3" + resolved "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-5.0.3.tgz#b7304249dd402ee67fd518ada993ab3593458bcf" + integrity sha512-1tB5mhVo7U+ETBKNf92xT4hrQa3pm0MZ0PQvuDnWgAAGHDsfp4lPSpiS6psrSiet87wyGPh9ft6wmhOMQ0hDiw== supports-color@^2.0.0: version "2.0.0" - resolved "https://registry.npmjs.org/supports-color/-/supports-color-2.0.0.tgz" - integrity sha1-U10EXOa2Nj+kARcIRimZXp3zJMc= + resolved "https://registry.npmjs.org/supports-color/-/supports-color-2.0.0.tgz#535d045ce6b6363fa40117084629995e9df324c7" + integrity sha512-KKNVtd6pCYgPIKU4cp2733HWYCpplQhddZLBUryaAHou723x+FRzQ5Df824Fj+IyyuiQTRoub4SnIFfIcrp70g== supports-color@^5.3.0: version "5.5.0" - resolved "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz" + resolved "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz#e2e69a44ac8772f78a1ec0b35b689df6530efc8f" integrity sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow== dependencies: has-flag "^3.0.0" -supports-color@^7.1.0: - version "7.1.0" - resolved "https://registry.npmjs.org/supports-color/-/supports-color-7.1.0.tgz" - integrity sha512-oRSIpR8pxT1Wr2FquTNnGet79b3BWljqOuoW/h4oBhxJ/HUbX5nX6JSruTkvXDCFMwDPvsaTTbvMLKZWSy0R5g== +supports-color@^8.1.1: + version "8.1.1" + resolved "https://registry.npmjs.org/supports-color/-/supports-color-8.1.1.tgz#cd6fc17e28500cff56c1b86c0a7fd4a54a73005c" + integrity sha512-MpUEN2OodtUzxvKQl72cUF7RQ5EiHsGvSsVG0ia9c5RbWGL2CI4C7EpPS8UTBIplnlzZiNuV56w+FuNxy3ty2Q== dependencies: has-flag "^4.0.0" symbol-observable@^1.1.0: version "1.2.0" - resolved "https://registry.npmjs.org/symbol-observable/-/symbol-observable-1.2.0.tgz" + resolved "https://registry.npmjs.org/symbol-observable/-/symbol-observable-1.2.0.tgz#c22688aed4eab3cdc2dfeacbb561660560a00804" integrity sha512-e900nM8RRtGhlV36KGEU9k65K3mPb1WV70OdjfxlG2EAuM1noi/E/BaW/uMhL7bPEssK8QV57vN3esixjUvcXQ== -table@^5.2.3: - version "5.4.6" - resolved "https://registry.npmjs.org/table/-/table-5.4.6.tgz" - integrity sha512-wmEc8m4fjnob4gt5riFRtTu/6+4rSe12TpAELNSqHMfF3IqnA+CH37USM6/YR3qRZv7e56kAEAtd6nKZaxe0Ug== +tar-fs@^3.1.3: + version "3.1.3" + resolved "https://registry.npmjs.org/tar-fs/-/tar-fs-3.1.3.tgz#05668cc68a30741c3813f9c16593b8dec7dcbcd1" + integrity sha512-/hU4AXnIdZu+Gvl1pk0oI5f5HxWsCJRtY2aFaJdk9VvyL48DWU6iU5WAIPG+wIi1YvWA6eTJvIviP/tMAZZNwQ== dependencies: - ajv "^6.10.2" - lodash "^4.17.14" - slice-ansi "^2.1.0" - string-width "^3.0.0" + pump "^3.0.0" + tar-stream "^3.1.5" + optionalDependencies: + bare-fs "^4.0.1" + bare-path "^3.0.0" -tar-fs@^2.0.0: - version "2.1.0" - resolved "https://registry.npmjs.org/tar-fs/-/tar-fs-2.1.0.tgz" - integrity sha512-9uW5iDvrIMCVpvasdFHW0wJPez0K4JnMZtsuIeDI7HyMGJNxmDZDOCQROr7lXyS+iL/QMpj07qcjGYTSdRFXUg== +tar-stream@^3.1.5: + version "3.2.2" + resolved "https://registry.npmjs.org/tar-stream/-/tar-stream-3.2.2.tgz#aec7f257e712192a177a93aa0450c2e76855c8be" + integrity sha512-+8NeqHRjQWH9nYlwo2gamAMImZCVzI4UoEgDpWorBt9OEfppiZn+uSkskzQKPWIZyji/C8fpWO7u69G0DX0tbg== dependencies: - chownr "^1.1.1" - mkdirp-classic "^0.5.2" - pump "^3.0.0" - tar-stream "^2.0.0" + b4a "^1.9.0" + bare-fs "^4.8.2" + fast-fifo "^1.3.2" + streamx "^2.28.1" -tar-fs@~2.0.1: - version "2.0.1" - resolved "https://registry.npmjs.org/tar-fs/-/tar-fs-2.0.1.tgz" - integrity sha512-6tzWDMeroL87uF/+lin46k+Q+46rAJ0SyPGz7OW7wTgblI273hsBqk2C1j0/xNadNLKDTUL9BukSjB7cwgmlPA== +teex@^1.0.1: + version "1.0.1" + resolved "https://registry.npmjs.org/teex/-/teex-1.0.1.tgz#b8fa7245ef8e8effa8078281946c85ab780a0b12" + integrity sha512-eYE6iEI62Ni1H8oIa7KlDU6uQBtqr4Eajni3wX7rpfXD8ysFx8z0+dri+KWEPWpBsxXfxu58x/0jvTVT1ekOSg== dependencies: - chownr "^1.1.1" - mkdirp-classic "^0.5.2" - pump "^3.0.0" - tar-stream "^2.0.0" + streamx "^2.12.5" -tar-stream@^2.0.0: - version "2.1.2" - resolved "https://registry.npmjs.org/tar-stream/-/tar-stream-2.1.2.tgz" - integrity sha512-UaF6FoJ32WqALZGOIAApXx+OdxhekNMChu6axLJR85zMMjXKWFGjbIRe+J6P4UnRGg9rAwWvbTT0oI7hD/Un7Q== - dependencies: - bl "^4.0.1" - end-of-stream "^1.4.1" - fs-constants "^1.0.0" - inherits "^2.0.3" - readable-stream "^3.1.1" - -text-table@^0.2.0: - version "0.2.0" - resolved "https://registry.npmjs.org/text-table/-/text-table-0.2.0.tgz" - integrity sha1-f17oI66AUgfACvLfSoTsP8+lcLQ= - -through@^2.3.6: - version "2.3.8" - resolved "https://registry.npmjs.org/through/-/through-2.3.8.tgz" - integrity sha1-DdTJ/6q8NXlgsbckEV1+Doai4fU= - -timeout-abort-controller@^3.0.0: - version "3.0.0" - resolved "https://registry.yarnpkg.com/timeout-abort-controller/-/timeout-abort-controller-3.0.0.tgz#dd57ffca041652c03769904f8d95afd93fb95595" - integrity sha512-O3e+2B8BKrQxU2YRyEjC/2yFdb33slI22WRdUaDx6rvysfi9anloNZyR2q0l6LnePo5qH7gSM7uZtvvwZbc2yA== +text-decoder@^1.1.0: + version "1.2.7" + resolved "https://registry.npmjs.org/text-decoder/-/text-decoder-1.2.7.tgz#5d073a9a74b9c0a9d28dfadcab96b604af57d8ba" + integrity sha512-vlLytXkeP4xvEq2otHeJfSQIRyWxo/oZGEbXrtEEF9Hnmrdly59sUbzZ/QgyWuLYHctCHxFF4tRQZNQ9k60ExQ== dependencies: - retimer "^3.0.0" + b4a "^1.6.4" timestring@^5.0.1: version "5.0.1" - resolved "https://registry.npmjs.org/timestring/-/timestring-5.0.1.tgz" + resolved "https://registry.npmjs.org/timestring/-/timestring-5.0.1.tgz#065bd9dda1bcaf7c08ec9a4841569d3bbbb6cf87" integrity sha512-0VfOVpaTYqBMTEpjwcY5mB+72YYjFI44Z5F2q80ZiIyDn5pRJm+rEV1OEM8xfnf5/FdtckcrTERTp9TbrlMMHw== -tmp@^0.0.33: - version "0.0.33" - resolved "https://registry.npmjs.org/tmp/-/tmp-0.0.33.tgz" - integrity sha512-jRCJlojKnZ3addtTOjdIqoRuPEKBvNXcGYqzO6zWZX8KfKEpnGY5jfggJQ3EjKuu8D4bJRr0y+cYJFmYbImXGw== - dependencies: - os-tmpdir "~1.0.2" - -to-regex-range@^5.0.1: - version "5.0.1" - resolved "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz" - integrity sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ== +tinyglobby@^0.2.15: + version "0.2.17" + resolved "https://registry.npmjs.org/tinyglobby/-/tinyglobby-0.2.17.tgz#562a9a6c9eb2b3b123d39719f9af5bb44fcd7631" + integrity sha512-wXR/dYpcqKmfWpEdZjiKJOwCNFndD0DMnrW/cYjVGttEkBfVgcLFHoNrlj47mjOVic9yyNu65alsgF4NQyTa2g== dependencies: - is-number "^7.0.0" + fdir "^6.5.0" + picomatch "^4.0.4" -tough-cookie@~2.5.0: +ts-api-utils@^2.5.0: version "2.5.0" - resolved "https://registry.npmjs.org/tough-cookie/-/tough-cookie-2.5.0.tgz" - integrity sha512-nlLsUzgm1kfLXSXfRZMc1KLAugd4hqJHDTvc2hDIwS3mZAfMEuMbc03SujMF+GEcpaX/qboeycw6iO8JwVv2+g== - dependencies: - psl "^1.1.28" - punycode "^2.1.1" - -tr46@~0.0.3: - version "0.0.3" - resolved "https://registry.npmjs.org/tr46/-/tr46-0.0.3.tgz" - integrity sha512-N3WMsuqV66lT30CrXNbEjx4GEwlow3v6rr4mCcv6prnfwhS01rkgyFdjPNBYd9br7LpXV1+Emh01fHnq2Gdgrw== - -ts-node@^10.9.1: - version "10.9.1" - resolved "https://registry.npmjs.org/ts-node/-/ts-node-10.9.1.tgz" - integrity sha512-NtVysVPkxxrwFGUUxGYhfux8k78pQB3JqYBXlLRZgdGUqTO5wU/UyHop5p70iEbGhB7q5KmiZiU0Y3KlJrScEw== - dependencies: - "@cspotcode/source-map-support" "^0.8.0" - "@tsconfig/node10" "^1.0.7" - "@tsconfig/node12" "^1.0.7" - "@tsconfig/node14" "^1.0.0" - "@tsconfig/node16" "^1.0.2" - acorn "^8.4.1" - acorn-walk "^8.1.1" - arg "^4.1.0" - create-require "^1.1.0" - diff "^4.0.1" - make-error "^1.1.1" - v8-compile-cache-lib "^3.0.1" - yn "3.1.1" - -tslib@2.4.0: - version "2.4.0" - resolved "https://registry.yarnpkg.com/tslib/-/tslib-2.4.0.tgz#7cecaa7f073ce680a05847aa77be941098f36dc3" - integrity sha512-d6xOpEDfsi2CZVlPQzGeux8XMwLT9hssAsaPYExaQMuYskwb+x1x7J371tWlbBdWHroy99KnVB6qIkUbs5X3UQ== - -tslib@^1.8.1, tslib@^1.9.0: - version "1.13.0" - resolved "https://registry.npmjs.org/tslib/-/tslib-1.13.0.tgz" - integrity sha512-i/6DQjL8Xf3be4K/E6Wgpekn5Qasl1usyw++dAA35Ue5orEn65VIxOA+YvNNl9HV3qv70T7CNwjODHZrLwvd1Q== - -tsutils@^3.17.1: - version "3.17.1" - resolved "https://registry.npmjs.org/tsutils/-/tsutils-3.17.1.tgz" - integrity sha512-kzeQ5B8H3w60nFY2g8cJIuH7JDpsALXySGtwGJ0p2LSjLgay3NdIpqq5SoOBe46bKDW2iq25irHCr8wjomUS2g== - dependencies: - tslib "^1.8.1" - -tunnel-agent@^0.6.0: - version "0.6.0" - resolved "https://registry.npmjs.org/tunnel-agent/-/tunnel-agent-0.6.0.tgz" - integrity sha1-J6XeoGs2sEoKmWZ3SykIaPD8QP0= - dependencies: - safe-buffer "^5.0.1" - -tweetnacl@^0.14.3, tweetnacl@~0.14.0: - version "0.14.5" - resolved "https://registry.npmjs.org/tweetnacl/-/tweetnacl-0.14.5.tgz" - integrity sha1-WuaBd/GS1EViadEIr6k/+HQ/T2Q= + resolved "https://registry.npmjs.org/ts-api-utils/-/ts-api-utils-2.5.0.tgz#4acd4a155e22734990a5ed1fe9e97f113bcb37c1" + integrity sha512-OJ/ibxhPlqrMM0UiNHJ/0CKQkoKF243/AEmplt3qpRgkW8VG7IfOS41h7V8TjITqdByHzrjcS/2si+y4lIh8NA== + +tslib@2.7.0: + version "2.7.0" + resolved "https://registry.npmjs.org/tslib/-/tslib-2.7.0.tgz#d9b40c5c40ab59e8738f297df3087bf1a2690c01" + integrity sha512-gLXCKdN1/j47AiHiOkJN69hJmcbGTHI0ImLmbYLHykhgeN0jVGola9yVjFgzCUklsZQMW55o+dW7IXv3RCXDzA== + +tslib@^1.9.0: + version "1.14.1" + resolved "https://registry.npmjs.org/tslib/-/tslib-1.14.1.tgz#cf2d38bdc34a134bcaf1091c41f6619e2f672d00" + integrity sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg== + +tslib@^2.1.0: + version "2.9.1" + resolved "https://registry.npmjs.org/tslib/-/tslib-2.9.1.tgz#8986213ba2f17f38ba39a7c43d0e565a9134ff5f" + integrity sha512-a4Ux9VKuIMHsOS7ENbEq6hK2ZGYIT27Rtl0E4eD9KqwxhKiQeMZE/9xb3IdYwWaSOyIBQLExhQgXDTYoiCxnWA== + +tsx@^4.23.15: + version "4.23.15" + resolved "https://registry.npmjs.org/tsx/-/tsx-4.23.15.tgz#f53901695685ad567fed0f08532f7782e631c251" + integrity sha512-Yiex1Ovn8z2xPpOWckIiysV1SSyRMY9BkLF++q0yKiDxCqRhosKfMg3janKkiLBwZ5c/YryloKwGZcrEmtwxKw== + dependencies: + esbuild "~0.28.0" + optionalDependencies: + fsevents "~2.3.3" type-check@^0.4.0, type-check@~0.4.0: version "0.4.0" - resolved "https://registry.npmjs.org/type-check/-/type-check-0.4.0.tgz" + resolved "https://registry.npmjs.org/type-check/-/type-check-0.4.0.tgz#07b8203bfa7056c0657050e3ccd2c37730bab8f1" integrity sha512-XleUoc9uwGXqjWwXaUTZAmzMcFZ5858QA2vvx1Ur5xIcixXIP+8LnFDgRplU30us6teqdlskFfu+ae4K79Ooew== dependencies: prelude-ls "^1.2.1" -type-fest@^0.8.1: - version "0.8.1" - resolved "https://registry.npmjs.org/type-fest/-/type-fest-0.8.1.tgz" - integrity sha512-4dbzIzqvjtgiM5rw1k5rEHtBANKmdudhGyBEajN01fEyhaAIhsoKNy6y7+IN93IfpFtwY9iqi7kD+xwKhQsNJA== +type-fest@^4.26.1: + version "4.41.0" + resolved "https://registry.npmjs.org/type-fest/-/type-fest-4.41.0.tgz#6ae1c8e5731273c2bf1f58ad39cbae2c91a46c58" + integrity sha512-TeTSQ6H5YHvpqVwBRcnLDCBnDOHWYu7IvGbHT6N8AOymcr9PJGjc1GTtiWZTYg0NCgYwvnYWEkVChQAr9bjfwA== -typescript@^5.6.3: - version "5.6.3" - resolved "https://registry.yarnpkg.com/typescript/-/typescript-5.6.3.tgz#5f3449e31c9d94febb17de03cc081dd56d81db5b" - integrity sha512-hjcS1mhfuyi4WW8IWtjP7brDrG2cuDZukyrYrSauoXGNgx0S7zceP07adYkJycEr56BOUTNPzbInooiN3fn1qw== - -uint8arraylist@^2.1.2, uint8arraylist@^2.4.3: - version "2.4.3" - resolved "https://registry.yarnpkg.com/uint8arraylist/-/uint8arraylist-2.4.3.tgz#1148aa979b407d382e4eb8d9c8f2b4bf3f5910d5" - integrity sha512-oEVZr4/GrH87K0kjNce6z8pSCzLEPqHNLNR5sj8cJOySrTP8Vb/pMIbZKLJGhQKxm1TiZ31atNrpn820Pyqpow== - dependencies: - uint8arrays "^4.0.2" - -uint8arrays@^4.0.2: - version "4.0.3" - resolved "https://registry.yarnpkg.com/uint8arrays/-/uint8arrays-4.0.3.tgz#43109c03c4c10d312e7f2e9f4d53e5cd2398c7fd" - integrity sha512-b+aKlI2oTnxnfeSQWV1sMacqSNxqhtXySaH6bflvONGxF8V/fT3ZlYH7z2qgGfydsvpVo4JUgM/Ylyfl2YouCg== +typescript-eslint@^8.72.1: + version "8.72.1" + resolved "https://registry.npmjs.org/typescript-eslint/-/typescript-eslint-8.72.1.tgz#46324b99d4809e986aeb01285cfce28f74b45d14" + integrity sha512-3Li9FfPmQp45nxEtFD1ZCrYFI3cYK5kpyNtmm1H7lMagm8u9sy6PTjy3ytwQZs7KNukOyKFHAZ6z6GjYFeaeXw== dependencies: - multiformats "^11.0.0" + "@typescript-eslint/eslint-plugin" "8.72.1" + "@typescript-eslint/parser" "8.72.1" + "@typescript-eslint/typescript-estree" "8.72.1" + "@typescript-eslint/utils" "8.72.1" -uint8arrays@^4.0.3: - version "4.0.4" - resolved "https://registry.yarnpkg.com/uint8arrays/-/uint8arrays-4.0.4.tgz#3254e01aeb166a3f35e66e60e4e37002f4ea13fd" - integrity sha512-AOoA66e/A7zoXm1mgzQjGmkWDTvCrS3ttWXLHFtlVAwMobLcaOA7G7WRNNAcyfjjYdFDtkEK6njRDX7hZLIO9Q== - dependencies: - multiformats "^11.0.0" +typescript@~5.9.3: + version "5.9.3" + resolved "https://registry.npmjs.org/typescript/-/typescript-5.9.3.tgz#5b4f59e15310ab17a216f5d6cf53ee476ede670f" + integrity sha512-jl1vZzPDinLr9eUt3J/t7V6FgNEw9QjvBPdysz9KfQDD41fQrC2Y4vKQdiaUpFT4bXlb1RHhLpp8wtm6M5TgSw== undici-types@~6.19.2: version "6.19.8" - resolved "https://registry.yarnpkg.com/undici-types/-/undici-types-6.19.8.tgz#35111c9d1437ab83a7cdc0abae2f26d88eda0a02" + resolved "https://registry.npmjs.org/undici-types/-/undici-types-6.19.8.tgz#35111c9d1437ab83a7cdc0abae2f26d88eda0a02" integrity sha512-ve2KP6f/JnbPBFyobGHuerC9g1FYGn/F8n1LWTwNxCEzd6IfqTwUQcNXgEtmmQ6DlRrC1hrSrBnCZPokRrDHjw== -undici@^5.12.0: - version "5.22.1" - resolved "https://registry.yarnpkg.com/undici/-/undici-5.22.1.tgz#877d512effef2ac8be65e695f3586922e1a57d7b" - integrity sha512-Ji2IJhFXZY0x/0tVBXeQwgPlLWw13GVzpsWPQ3rV50IFMMof2I55PZZxtm4P6iNq+L5znYN9nSTAq0ZyE6lSJw== - dependencies: - busboy "^1.6.0" +undici-types@~6.21.0: + version "6.21.0" + resolved "https://registry.npmjs.org/undici-types/-/undici-types-6.21.0.tgz#691d00af3909be93a7faa13be61b3a5b50ef12cb" + integrity sha512-iwDZqg0QAGrg9Rav5H4n0M64c3mkR59cJ6wQp+7C4nI0gsmExaedaYLNO44eT4AtBBwjbTiGPMlt2Md0T9H9JQ== -universal-user-agent@^6.0.0: - version "6.0.0" - resolved "https://registry.npmjs.org/universal-user-agent/-/universal-user-agent-6.0.0.tgz" - integrity sha512-isyNax3wXoKaulPDZWHQqbmIx1k2tb9fb3GGDBRxCscfYV2Ch7WxPArBsFEG8s/safwXTT7H4QGhaIkTp9447w== +undici-types@~8.9.0: + version "8.9.0" + resolved "https://registry.npmjs.org/undici-types/-/undici-types-8.9.0.tgz#e240d97c8b5d85e5347ce73d25865c7906c1ec9f" + integrity sha512-KTDyRTYX8sWmKXAikPHHSyc63CRPETMctyjKFupcC6OBLXT3xsN0e9aF7m+mIXutFWpUXuedtowG7iLOzp0kQg== + +universal-user-agent@^7.0.0, universal-user-agent@^7.0.2: + version "7.0.3" + resolved "https://registry.npmjs.org/universal-user-agent/-/universal-user-agent-7.0.3.tgz#c05870a58125a2dc00431f2df815a77fe69736be" + integrity sha512-TmnEAEAsBJVZM/AADELsK76llnwcf9vMKuPz8JflO1frO8Lchitr0fNaN9d+Ap0BjKtqWqd/J17qeDnXh8CL2A== uri-js@^4.2.2: - version "4.2.2" - resolved "https://registry.npmjs.org/uri-js/-/uri-js-4.2.2.tgz" - integrity sha512-KY9Frmirql91X2Qgjry0Wd4Y+YTdrdZheS8TFwvkbLWf/G5KNJDCh6pKL5OZctEW4+0Baa5idK2ZQuELRwPznQ== + version "4.4.1" + resolved "https://registry.npmjs.org/uri-js/-/uri-js-4.4.1.tgz#9b1a52595225859e55f669d928f88c6c57f2a77e" + integrity sha512-7rKUyy33Q1yc98pQ1DAmLtwX109F7TIfWlW1Ydo8Wl1ii1SeHieeh0HHfPeL2fMXK6z0s8ecKs9frCuLJvndBg== dependencies: punycode "^2.1.0" -util-deprecate@^1.0.1: - version "1.0.2" - resolved "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz" - integrity sha1-RQ1Nyfpw3nMnYvvS1KKJgUGaDM8= - -uuid@^3.3.2: - version "3.4.0" - resolved "https://registry.npmjs.org/uuid/-/uuid-3.4.0.tgz" - integrity sha512-HjSDRw6gZE5JMggctHBcjVak08+KEVhSIiDzFnT9S9aegmp85S/bReBVTb4QTFaRNptJ9kuYaNhnbNEOkbKb/A== - -v8-compile-cache-lib@^3.0.1: - version "3.0.1" - resolved "https://registry.npmjs.org/v8-compile-cache-lib/-/v8-compile-cache-lib-3.0.1.tgz" - integrity sha512-wa7YjyUGfNZngI/vtK0UHAN+lgDCxBPCylVXGp0zu59Fz5aiGtNXaq3DhIov063MorB+VfufLh3JlF2KdTK3xg== - -v8-compile-cache@^2.0.3: - version "2.1.1" - resolved "https://registry.npmjs.org/v8-compile-cache/-/v8-compile-cache-2.1.1.tgz" - integrity sha512-8OQ9CL+VWyt3JStj7HX7/ciTL2V3Rl1Wf5OL+SNTm0yK1KvtReVulksyeRnCANHHuUxHlQig+JJDlUhBt1NQDQ== - -varint@^6.0.0: - version "6.0.0" - resolved "https://registry.yarnpkg.com/varint/-/varint-6.0.0.tgz#9881eb0ce8feaea6512439d19ddf84bf551661d0" - integrity sha512-cXEIW6cfr15lFv563k4GuVuW/fiwjknytD37jIOLSdSWuOI6WnO/oKwmP2FQTU2l01LP8/M5TSAJpzUaGe3uWg== - -verror@1.10.0: - version "1.10.0" - resolved "https://registry.npmjs.org/verror/-/verror-1.10.0.tgz" - integrity sha1-OhBcoXBTr1XW4nDB+CiGguGNpAA= - dependencies: - assert-plus "^1.0.0" - core-util-is "1.0.2" - extsprintf "^1.2.0" - -webidl-conversions@^3.0.0: - version "3.0.1" - resolved "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-3.0.1.tgz" - integrity sha512-2JAn3z8AR6rjK8Sm8orRC0h/bcl/DqL7tRPdGZ4I1CjdF+EaMLmYxBHyXuKL849eucPFhvBoxMsflfOb8kxaeQ== - -whatwg-url@^5.0.0: - version "5.0.0" - resolved "https://registry.npmjs.org/whatwg-url/-/whatwg-url-5.0.0.tgz" - integrity sha512-saE57nupxk6v3HY35+jzBwYa0rKSy0XR8JSxZPwgLr7ys0IBzhGviA1/TUGJLmSVqs8pb9AnvICXEuOHLprYTw== - dependencies: - tr46 "~0.0.3" - webidl-conversions "^3.0.0" - which@^2.0.1: version "2.0.2" - resolved "https://registry.npmjs.org/which/-/which-2.0.2.tgz" + resolved "https://registry.npmjs.org/which/-/which-2.0.2.tgz#7c6a8dd0a636a0327e10b59c9286eee93f3f51b1" integrity sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA== dependencies: isexe "^2.0.0" -word-wrap@^1.2.3: - version "1.2.3" - resolved "https://registry.npmjs.org/word-wrap/-/word-wrap-1.2.3.tgz" - integrity sha512-Hz/mrNwitNRh/HUAtM/VT/5VH+ygD6DV7mYKZAtHOrbs8U7lvPS6xf7EJKMF0uW1KJCl0H701g3ZGus+muE5vQ== +word-wrap@^1.2.5: + version "1.2.5" + resolved "https://registry.npmjs.org/word-wrap/-/word-wrap-1.2.5.tgz#d2c45c6dd4fbce621a66f136cbe328afd0410b34" + integrity sha512-BN22B5eaMMI9UMtjrGd5g5eCYPpCPDUy0FJXbYsaT5zYxjFOckS53SQDE3pWkVoWpHXVb3BrYcEN4Twa55B5cA== -workerpool@6.2.1: - version "6.2.1" - resolved "https://registry.npmjs.org/workerpool/-/workerpool-6.2.1.tgz" - integrity sha512-ILEIE97kDZvF9Wb9f6h5aXK4swSlKGUcOEGiIYb2OOu/IrDU9iwj0fD//SsA6E5ibwJxpEvhullJY4Sl4GcpAw== +workerpool@^10.0.0: + version "10.0.3" + resolved "https://registry.npmjs.org/workerpool/-/workerpool-10.0.3.tgz#e9914112d0169a974fc1b4c2fda00388bbd70b61" + integrity sha512-6z2Iis68Wqth93/G/wJP9u+R3O+d2XTlgWChGCwuT1qLbBsOYueGRZuJ++v3mtDP5KjYdy+WzvWC+VWETSVXJA== wrap-ansi@^3.0.1: version "3.0.1" - resolved "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-3.0.1.tgz" - integrity sha1-KIoE2H7aXChuBg3+jxNc6NAH+Lo= + resolved "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-3.0.1.tgz#288a04d87eda5c286e060dfe8f135ce8d007f8ba" + integrity sha512-iXR3tDXpbnTpzjKSylUJRkLuOrEC7hwEB221cgn6wtF8wpmz28puFXAEfPT5zrjM3wahygB//VuWEr1vTkDcNQ== dependencies: string-width "^2.1.1" strip-ansi "^4.0.0" +wrap-ansi@^6.2.0: + version "6.2.0" + resolved "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-6.2.0.tgz#e9393ba07102e6c91a3b221478f0257cd2856e53" + integrity sha512-r6lPcBGxZXlIcymEu7InxDMhdW0KDxpLgoFLcguasxCaJ/SOIZwINatK9KY/tf+ZrlywOKU0UDj3ATXUBfxJXA== + dependencies: + ansi-styles "^4.0.0" + string-width "^4.1.0" + strip-ansi "^6.0.0" + wrap-ansi@^7.0.0: version "7.0.0" - resolved "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-7.0.0.tgz" + resolved "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-7.0.0.tgz#67e145cff510a6a6984bdf1152911d69d2eb9e43" integrity sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q== dependencies: ansi-styles "^4.0.0" string-width "^4.1.0" strip-ansi "^6.0.0" +wrap-ansi@^9.0.0, wrap-ansi@^9.0.2: + version "9.0.2" + resolved "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-9.0.2.tgz#956832dea9494306e6d209eb871643bb873d7c98" + integrity sha512-42AtmgqjV+X1VpdOfyTGOYRi0/zsoLqtXQckTmqTeybT+BDIbM/Guxo7x3pE2vtpr1ok6xRqM9OpBe+Jyoqyww== + dependencies: + ansi-styles "^6.2.1" + string-width "^7.0.0" + strip-ansi "^7.1.0" + wrappy@1: version "1.0.2" - resolved "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz" - integrity sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8= - -write@1.0.3: - version "1.0.3" - resolved "https://registry.npmjs.org/write/-/write-1.0.3.tgz" - integrity sha512-/lg70HAjtkUgWPVZhZcm+T4hkL8Zbtp1nFNOn3lRrxnlv50SRBv7cR7RqR+GMsd3hUXy9hWBo4CHTbFTcOYwig== - dependencies: - mkdirp "^0.5.1" + resolved "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz#b5243d8f3ec1aa35f1364605bc0d1036e30ab69f" + integrity sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ== -ws@8.5.0: - version "8.5.0" - resolved "https://registry.yarnpkg.com/ws/-/ws-8.5.0.tgz#bfb4be96600757fe5382de12c670dab984a1ed4f" - integrity sha512-BWX0SWVgLPzYwF8lTzEy1egjhS4S4OEAHfsO8o65WOVsrnSRGaSiUaa9e0ggGlkMTtBlmOpEXiie9RUcBO86qg== +ws@8.21.0: + version "8.21.0" + resolved "https://registry.npmjs.org/ws/-/ws-8.21.0.tgz#012e413fc07429945121b0c153158c4343086951" + integrity sha512-Vsp28b7DRcimFQvrqu2Wek3z1iYxDCWqHYB8Qsnk/S4RfaCQzPGPyBNuVjJV3cd6UiKtUtp6sNM77gWvzcCH+g== y18n@^5.0.5: version "5.0.8" - resolved "https://registry.npmjs.org/y18n/-/y18n-5.0.8.tgz" + resolved "https://registry.npmjs.org/y18n/-/y18n-5.0.8.tgz#7f4934d0f7ca8c56f95314939ddcd2dd91ce1d55" integrity sha512-0pfFzegeDWJHJIAmTLRP2DwHjdF5s7jo9tuztdQxAhINCdvS+3nGINqPd00AphqJR/0LhANUS6/+7SCb98YOfA== -yallist@^4.0.0: - version "4.0.0" - resolved "https://registry.yarnpkg.com/yallist/-/yallist-4.0.0.tgz#9bb92790d9c0effec63be73519e11a35019a3a72" - integrity sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A== - -yaml@^2.2.2: - version "2.3.0" - resolved "https://registry.yarnpkg.com/yaml/-/yaml-2.3.0.tgz#47ebe58ee718f772ce65862beb1db816210589a0" - integrity sha512-8/1wgzdKc7bc9E6my5wZjmdavHLvO/QOmLG1FBugblEvY4IXrLjlViIOmL24HthU042lWTDRO90Fz1Yp66UnMw== - -yargs-parser@20.2.4: - version "20.2.4" - resolved "https://registry.npmjs.org/yargs-parser/-/yargs-parser-20.2.4.tgz" - integrity sha512-WOkpgNhPTlE73h4VFAFsOnomJVaovO8VqLDzy5saChRBFQFBoMYirowyW+Q9HB4HFF4Z7VZTiG3iSzJJA29yRA== - -yargs-parser@^20.2.2: - version "20.2.9" - resolved "https://registry.npmjs.org/yargs-parser/-/yargs-parser-20.2.9.tgz" - 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" + resolved "https://registry.npmjs.org/yargs-parser/-/yargs-parser-21.1.1.tgz#9096bceebf990d21bb31fa9516e0ede294a77d35" integrity sha512-tVpsJW7DdjecAiFpbIB1e3qxIQsE6NoPc5/eTdrbbIC4h0LVsWhnoa3g+m2HclBIujHzsxZ4VJVA+GUuc2/LBw== -yargs-unparser@2.0.0: - version "2.0.0" - resolved "https://registry.npmjs.org/yargs-unparser/-/yargs-unparser-2.0.0.tgz" - 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.npmjs.org/yargs/-/yargs-16.2.0.tgz" - 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.7.1: - version "17.7.1" - resolved "https://registry.npmjs.org/yargs/-/yargs-17.7.1.tgz" - integrity sha512-cwiTb08Xuv5fqF4AovYacTFNxk62th7LKJ6BL9IGUpTJrWoU7/7WdQGTP2SjKf1dUNBGzDd28p/Yfs/GI6JrLw== + version "17.7.3" + resolved "https://registry.npmjs.org/yargs/-/yargs-17.7.3.tgz#779dffe6bcafec596a7172e983289a588647faaa" + integrity sha512-GZtjxm/J/4TSxuL3FNYjCmLktBTnIw/rVmKSIyKeYAZpmJB2ig9VauCC5xsa82GNKVKDAqpOn3KVzNt0zmrU0g== dependencies: cliui "^8.0.1" escalade "^3.1.1" @@ -3883,12 +2639,12 @@ yargs@^17.7.1: y18n "^5.0.5" yargs-parser "^21.1.1" -yn@3.1.1: - version "3.1.1" - resolved "https://registry.npmjs.org/yn/-/yn-3.1.1.tgz" - integrity sha512-Ux4ygGWsu2c7isFWe8Yu1YluJmqVhxqK2cLXNQA5AcC3QfbGNpM7fu0Y8b/z16pXLnFxZYvWhd3fhBY9DLmC6Q== - yocto-queue@^0.1.0: version "0.1.0" - resolved "https://registry.npmjs.org/yocto-queue/-/yocto-queue-0.1.0.tgz" + resolved "https://registry.npmjs.org/yocto-queue/-/yocto-queue-0.1.0.tgz#0294eb3dee05028d31ee1a5fa2c556a6aaf10a1b" integrity sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q== + +yoctocolors-cjs@^2.1.3: + version "2.1.3" + resolved "https://registry.npmjs.org/yoctocolors-cjs/-/yoctocolors-cjs-2.1.3.tgz#7e4964ea8ec422b7a40ac917d3a344cfd2304baa" + integrity sha512-U/PBtDf35ff0D8X8D0jfdzHYEPFxAI7jJlxZXwCSez5M3190m+QobIfh+sWDWSHMCWWJN2AWamkegn6vr6YBTw== From aeaf2e9df8a139d463ce1c019a8e50ac52dd822c Mon Sep 17 00:00:00 2001 From: 3alpha <15694175+3alpha@users.noreply.github.com> Date: Wed, 4 Nov 2026 22:19:36 +0100 Subject: [PATCH 02/15] Parse --timeout predictably Accept human-readable durations and bare integer strings as seconds (the documented --timeout 5000), pass numeric milliseconds through with 0 meaning no timeout, and reject invalid values instead of returning NaN. --- src/utils/timeout.ts | 36 ++++++++++++++++-------------------- test/utils/timeout.test.ts | 26 ++++++++++++++++++++++++++ 2 files changed, 42 insertions(+), 20 deletions(-) create mode 100644 test/utils/timeout.test.ts diff --git a/src/utils/timeout.ts b/src/utils/timeout.ts index a7ee0345..13734fb0 100644 --- a/src/utils/timeout.ts +++ b/src/utils/timeout.ts @@ -1,28 +1,24 @@ -// timestring does not have a @types package -// eslint-disable-next-line @typescript-eslint/ban-ts-comment -// @ts-ignore import timestring from "timestring/index.js"; -// Define build timeout (60 min) const defaultBuildTimeout = 60 * 60 * 1000; /** - * Parses a timeout string and returns a number in miliseconds - * @param timeout "20min", "5000", undefined + * Parses a timeout and returns milliseconds. + * - Strings are human-readable durations ("20min", "1h"); a bare integer string ("5000") is seconds. + * - Numbers are already milliseconds; 0 disables the timeout, as before. */ -export function parseTimeout(timeout: string | undefined): number { - switch (typeof timeout) { - case "number": { - return timeout; - } - case "string": { - if (!timeout) defaultBuildTimeout; - // Timestring returns in seconds - const parsedString = timestring(timeout) || parseInt(timeout); - if (!parsedString) throw Error(`Error parsing timeout: ${timeout}`); - return parsedString * 1000; - } - default: - return defaultBuildTimeout; +export function parseTimeout(timeout: string | number | undefined): number { + if (timeout === undefined || timeout === "") return defaultBuildTimeout; + if (typeof timeout === "number") { + if (!Number.isFinite(timeout) || timeout < 0) + throw new Error(`Invalid timeout: ${timeout}`); + return timeout; } + const trimmed = timeout.trim(); + const parsed = /^\d+$/.test(trimmed) + ? Number(trimmed) * 1000 + : timestring(trimmed) * 1000; + if (!Number.isFinite(parsed) || parsed <= 0) + throw new Error(`Invalid timeout: ${timeout}`); + return parsed; } diff --git a/test/utils/timeout.test.ts b/test/utils/timeout.test.ts new file mode 100644 index 00000000..d8a215d1 --- /dev/null +++ b/test/utils/timeout.test.ts @@ -0,0 +1,26 @@ +import { expect } from "chai"; +import { parseTimeout } from "../../src/utils/timeout.js"; + +describe("parseTimeout", () => { + it("parses human-readable durations", () => { + expect(parseTimeout("20min")).to.equal(20 * 60 * 1000); + expect(parseTimeout("1h")).to.equal(60 * 60 * 1000); + }); + + it("treats a bare integer string as seconds, as documented by `--timeout 5000`", () => { + expect(parseTimeout("5000")).to.equal(5000 * 1000); + }); + + it("passes numeric milliseconds through, with 0 meaning no timeout", () => { + expect(parseTimeout(5000)).to.equal(5000); + expect(parseTimeout(0)).to.equal(0); + }); + + it("defaults when unset and rejects nonsense", () => { + expect(parseTimeout(undefined)).to.equal(60 * 60 * 1000); + expect(parseTimeout("")).to.equal(60 * 60 * 1000); + expect(() => parseTimeout("0")).to.throw("Invalid timeout"); + expect(() => parseTimeout(-1)).to.throw("Invalid timeout"); + expect(() => parseTimeout("abc")).to.throw(); + }); +}); From e9b4efca4c89e21cb82b3ec3c95012900691d942 Mon Sep 17 00:00:00 2001 From: 3alpha <15694175+3alpha@users.noreply.github.com> Date: Wed, 4 Nov 2026 22:19:36 +0100 Subject: [PATCH 03/15] Run git and docker commands without a shell Argument arrays now go through execFile, so upstream tags, branch names and image tags are passed literally instead of being interpolated into shell source. Commands accept a cwd, and streamed output is delivered as complete lines. The upstream tag allowlist keeps "@" (e.g. n8n@2.46.6). --- .../bumpUpstream/github/closeOldPrs.ts | 2 +- .../bumpUpstream/github/isBranchNew.ts | 6 +- .../bumpUpstream/github/isValidRelease.ts | 6 +- .../githubActions/bumpUpstream/index.ts | 57 +++++++++++----- src/utils/getImageId.ts | 9 ++- src/utils/git.ts | 23 +++++-- src/utils/shell.ts | 67 ++++++++++++++----- test/commands/gaBumpUpstream/format.test.ts | 5 ++ test/utils/process.test.ts | 55 +++++++++++++++ 9 files changed, 184 insertions(+), 46 deletions(-) create mode 100644 test/utils/process.test.ts diff --git a/src/commands/githubActions/bumpUpstream/github/closeOldPrs.ts b/src/commands/githubActions/bumpUpstream/github/closeOldPrs.ts index c3b6c661..80a7970c 100644 --- a/src/commands/githubActions/bumpUpstream/github/closeOldPrs.ts +++ b/src/commands/githubActions/bumpUpstream/github/closeOldPrs.ts @@ -80,7 +80,7 @@ async function closePr( */ async function deleteBranch(branchName: string) { try { - await shell(`git push origin --delete ${branchName}`); + await shell(["git", "push", "origin", "--delete", branchName]); console.log(`Deleted branch: ${branchName}`); } catch (error) { console.error(`Error deleting branch ${branchName}`, error); diff --git a/src/commands/githubActions/bumpUpstream/github/isBranchNew.ts b/src/commands/githubActions/bumpUpstream/github/isBranchNew.ts index 734f2201..b2aa14bb 100644 --- a/src/commands/githubActions/bumpUpstream/github/isBranchNew.ts +++ b/src/commands/githubActions/bumpUpstream/github/isBranchNew.ts @@ -3,14 +3,16 @@ import { getLocalBranchExists } from "../../../../utils/git.js"; export async function isBranchNew({ branchName, - repo + repo, + dir }: { branchName: string; repo: Github; + dir?: string; }): Promise { const [remoteBranchExists, localBranchExists] = await Promise.all([ repo.branchExists(branchName), - getLocalBranchExists(branchName) + getLocalBranchExists(branchName, dir) ]); return !remoteBranchExists && !localBranchExists; diff --git a/src/commands/githubActions/bumpUpstream/github/isValidRelease.ts b/src/commands/githubActions/bumpUpstream/github/isValidRelease.ts index 3337c633..7d5d84b4 100644 --- a/src/commands/githubActions/bumpUpstream/github/isValidRelease.ts +++ b/src/commands/githubActions/bumpUpstream/github/isValidRelease.ts @@ -1,8 +1,12 @@ import semver from "semver"; export function isValidRelease(version: string): boolean { + // Commands receive tags as arguments, not shell source; this only rejects + // characters that can never form a branch name. `@` is used by real + // upstreams (e.g. n8n@2.46.6). + if (!/^[a-zA-Z0-9][a-zA-Z0-9._+/@-]*$/.test(version)) return false; // Nightly builds are not considered valid releases (not taken into account by semver) - if (version.includes("nightly")) return false; + if (version.toLowerCase().includes("nightly")) return false; if (semver.valid(version)) { const preReleases = semver.prerelease(version); diff --git a/src/commands/githubActions/bumpUpstream/index.ts b/src/commands/githubActions/bumpUpstream/index.ts index 8de15d1d..f43fab3f 100644 --- a/src/commands/githubActions/bumpUpstream/index.ts +++ b/src/commands/githubActions/bumpUpstream/index.ts @@ -106,7 +106,7 @@ async function gaBumpUpstreamHandler({ const githubSettings = await getGithubSettings(dir, upstreamSettings); const { branchName, repo } = githubSettings; - if (!(await isBranchNew({ branchName, repo }))) { + if (!(await isBranchNew({ branchName, repo, dir }))) { // We assume the PR was already opened console.log(`Branch ${branchName} already exists`); return; @@ -129,6 +129,7 @@ async function gaBumpUpstreamHandler({ }); await prepareAndCommitChanges({ + dir, gitSettings, upstreamSettings, githubSettings @@ -145,8 +146,13 @@ async function gaBumpUpstreamHandler({ return; } - const gitHead = await getGitHead(); - await buildAndComment({ dir, commitSha: gitHead.commit, branch: branchName, all_variants: useVariants }); + const gitHead = await getGitHead(dir); + await buildAndComment({ + dir, + commitSha: gitHead.commit, + branch: branchName, + all_variants: useVariants + }); } /** @@ -217,7 +223,7 @@ function updateManifestUpstreamVersion({ try { writeManifest(manifest, manifestFormat, { dir }); } catch (e) { - throw new Error(`Error writing manifest: ${e.message}`); + throw new Error(`Error writing manifest: ${e.message}`, { cause: e }); } } @@ -232,10 +238,11 @@ async function updateManifestPkgVersion({ allVariants?: boolean; variantsDir: string; }): Promise { + const variantsPath = path.resolve(dir, variantsDir); const manifestDirs = allVariants - ? getAllVariantsInPath(variantsDir).map(variant => - path.join(variantsDir, variant) - ) + ? getAllVariantsInPath(variantsPath).map(variant => + path.join(variantsPath, variant) + ) : [dir]; for (const dir of manifestDirs) { @@ -285,10 +292,12 @@ async function getNewManifestVersion({ } async function prepareAndCommitChanges({ + dir, gitSettings, upstreamSettings, githubSettings }: { + dir: string; gitSettings: GitSettings; upstreamSettings: UpstreamSettings[]; githubSettings: GithubSettings; @@ -303,9 +312,9 @@ async function prepareAndCommitChanges({ return; } - await configureGitUser(gitSettings); - await checkoutNewBranch(branchName); - await commitAndPushChanges({ commitMsg, branchRef }); + await configureGitUser(gitSettings, dir); + await checkoutNewBranch(branchName, dir); + await commitAndPushChanges({ commitMsg, branchRef, dir }); await attemptToOpenPR({ commitMsg, upstreamSettings, githubSettings }); } @@ -315,24 +324,38 @@ function createCommitMessage(upstreamSettings: UpstreamSettings[]): string { .join(", ")}`; } -async function configureGitUser({ userName, userEmail }: GitSettings) { - await shell(`git config user.name ${userName}`); - await shell(`git config user.email ${userEmail}`); +async function configureGitUser( + { userName, userEmail }: GitSettings, + dir: string +) { + await shell(["git", "config", "user.name", userName], { cwd: dir }); + await shell(["git", "config", "user.email", userEmail], { cwd: dir }); } -async function checkoutNewBranch(branchName: string) { - await shell(`git checkout -b ${branchName}`); +async function checkoutNewBranch(branchName: string, dir: string) { + await shell(["git", "check-ref-format", "--branch", branchName], { + cwd: dir + }); + await shell(["git", "checkout", "-b", branchName], { cwd: dir }); } async function commitAndPushChanges({ + dir, commitMsg, branchRef }: { + dir: string; commitMsg: string; branchRef: string; }) { - await shell(`git commit -a -m "${commitMsg}"`, { pipeToMain: true }); - await shell(`git push -u origin ${branchRef}`, { pipeToMain: true }); + await shell(["git", "commit", "-a", "-m", commitMsg], { + pipeToMain: true, + cwd: dir + }); + await shell(["git", "push", "-u", "origin", branchRef], { + pipeToMain: true, + cwd: dir + }); } async function attemptToOpenPR({ diff --git a/src/utils/getImageId.ts b/src/utils/getImageId.ts index 113f435b..670d8e5c 100644 --- a/src/utils/getImageId.ts +++ b/src/utils/getImageId.ts @@ -8,7 +8,12 @@ import { shell } from "./shell.js"; * @return formated ID: sha256:0d31e5521ef6e92a0efb6110024da8a3517daac4b1e4bbbccaf063ce96641b1b */ export async function getImageId(imageTag: string): Promise { - const id = await shell(`docker inspect --format='{{json .Id}}' ${imageTag}`); + const id = await shell([ + "docker", + "inspect", + "--format={{json .Id}}", + imageTag + ]); return id.replace(/['"]+/g, ""); } @@ -23,6 +28,6 @@ export async function getImageId(imageTag: string): Promise { * ] */ export async function getImageIds(): Promise { - const res = await shell(`docker images -q`); + const res = await shell(["docker", "images", "-q"]); return res.trim().split(/\r?\n/); } diff --git a/src/utils/git.ts b/src/utils/git.ts index 4449b34c..ac1bf6da 100644 --- a/src/utils/git.ts +++ b/src/utils/git.ts @@ -20,9 +20,15 @@ export interface GitHead { * branch: "dapplion/prepare-build-action" * ``` */ -export async function getGitHead(): Promise { - const commit = await shell("git rev-parse --verify HEAD"); - const branch = await shell("git rev-parse --abbrev-ref HEAD"); +export async function getGitHead(dir?: string): Promise { + const commit = await shell(["git", "rev-parse", "--verify", "HEAD"], { + cwd: dir + }); + let branch = await shell(["git", "rev-parse", "--abbrev-ref", "HEAD"], { + cwd: dir + }); + if (branch === "HEAD" && process.env.GITHUB_REF?.startsWith("refs/heads/")) + branch = process.env.GITHUB_REF.slice("refs/heads/".length); return { commit, branch }; } @@ -32,9 +38,10 @@ export async function getGitHead(): Promise { */ export async function getGitHeadIfAvailable(options?: { requireGitData?: boolean; + dir?: string; }): Promise { try { - return await getGitHead(); + return await getGitHead(options?.dir); } catch (e) { if (options?.requireGitData) { e.message = `Error on getGitHead: ${e.message}`; @@ -48,10 +55,14 @@ export async function getGitHeadIfAvailable(options?: { /** * @param branch dappnodebot/bump-upstream/go-ipfs@v0.7.0 */ -export async function getLocalBranchExists(branch: string): Promise { +export async function getLocalBranchExists( + branch: string, + dir?: string +): Promise { try { const branchSha = await shell( - `git show-ref --verify -s refs/heads/${branch}` + ["git", "show-ref", "--verify", "-s", `refs/heads/${branch}`], + { cwd: dir } ); return Boolean(branchSha); } catch (e) { diff --git a/src/utils/shell.ts b/src/utils/shell.ts index 9772fb5f..aab42914 100644 --- a/src/utils/shell.ts +++ b/src/utils/shell.ts @@ -1,4 +1,10 @@ -import { exec, ExecException } from "child_process"; +import { + exec, + execFile, + ExecException, + ExecFileException +} from "child_process"; +import { StringDecoder } from "string_decoder"; /** * If timeout is greater than 0, the parent will send the signal @@ -10,13 +16,8 @@ const defaultTimeout = 3 * 60 * 1000; // ms const defaultMaxBuffer = 1e7; // bytes /** - * Run arbitrary commands in a shell - * If the child process exits with code > 0, rejects - * Note: using exec instead of spawn since it's not as safe to run - * complex arbirary commands. For example: - * - The executable docker-compose may not be detected, causing ENOENT - * - Doing cmd > cmd2 may fail - * - Flags may not be passed properly + * Execute an argument array directly, or an intentional shell script as a string. + * Stream complete output lines while retaining stdout/stderr for failure diagnostics. */ export async function shell( cmd: string | string[], @@ -25,34 +26,66 @@ export async function shell( maxBuffer?: number; pipeToMain?: boolean; onData?: (data: string) => void; + cwd?: string; } ): Promise { const { timeout = defaultTimeout, maxBuffer = defaultMaxBuffer, pipeToMain = false, - onData + onData, + cwd } = options || {}; return new Promise((resolve, reject): void => { const cmdStr = Array.isArray(cmd) ? cmd.join(" ") : cmd; - const proc = exec(cmdStr, { timeout, maxBuffer }, (err, stdout, stderr) => { + const callback = ( + err: ExecException | ExecFileException | null, + stdout: string, + stderr: string + ): void => { if (err) { // Rethrow a typed error, and ignore the internal NodeJS stack trace reject(new ShellError(err, { stdout, stderr, cmd: cmdStr })); } else { resolve(stdout.trim() || stderr); } - }); + }; + // Arrays are arguments, never shell source. Use strings only for intentional scripts. + const proc = Array.isArray(cmd) + ? execFile( + cmd[0], + cmd.slice(1), + { timeout, maxBuffer, cwd, encoding: "utf8" }, + callback + ) + : exec(cmd, { timeout, maxBuffer, cwd, encoding: "utf8" }, callback); if (pipeToMain) { if (proc.stdout) proc.stdout.pipe(process.stdout); if (proc.stderr) proc.stderr.pipe(process.stderr); } if (onData) { - const onChunkData = (chunk: Buffer): void => - onData(chunk.toString().trim()); - if (proc.stdout) proc.stdout.on("data", onChunkData); - if (proc.stderr) proc.stderr.on("data", onChunkData); + for (const stream of [proc.stdout, proc.stderr]) { + if (!stream) continue; + const decoder = new StringDecoder("utf8"); + let pending = ""; + const flush = (text: string): void => { + pending += text; + const lines = pending.split(/\r\n|[\r\n]/); + pending = lines.pop() || ""; + for (const line of lines) if (line.trim()) onData(line); + // Keep malformed/no-newline process output bounded as well. + if (pending.length > 65536) { + onData(pending.slice(0, 65536)); + pending = pending.slice(65536); + } + }; + stream.on("data", (chunk: Buffer) => flush(decoder.write(chunk))); + stream.on("end", () => { + flush(decoder.end()); + if (pending.trim()) onData(pending); + }); + } } }); } @@ -64,12 +97,12 @@ export async function shell( export class ShellError extends Error { cmd?: string; killed?: boolean; - code?: number; + code?: string | number | null; signal?: NodeJS.Signals; stdout: string; stderr: string; constructor( - e: ExecException, + e: ExecException | ExecFileException, { cmd, stdout, stderr }: { cmd: string; stdout: string; stderr: string } ) { const msg = [ diff --git a/test/commands/gaBumpUpstream/format.test.ts b/test/commands/gaBumpUpstream/format.test.ts index c7e0f3f4..deeb2071 100644 --- a/test/commands/gaBumpUpstream/format.test.ts +++ b/test/commands/gaBumpUpstream/format.test.ts @@ -57,6 +57,11 @@ describe("command / gaBumpUpstream / format", () => { "sigp/lighthouse": { newVersion: "v0.1.5", currentVersion: "v0.1.2" + }, + // DAppNodePackage-n8n tracks tags such as n8n@2.46.6 + "n8n-io/n8n": { + newVersion: "n8n@2.46.6", + currentVersion: "n8n@2.46.5" } }; diff --git a/test/utils/process.test.ts b/test/utils/process.test.ts new file mode 100644 index 00000000..aa106799 --- /dev/null +++ b/test/utils/process.test.ts @@ -0,0 +1,55 @@ +import fs from "fs"; +import path from "path"; +import { expect } from "chai"; +import { shell } from "../../src/utils/shell.js"; +import { getLocalBranchExists } from "../../src/utils/git.js"; +import { isValidRelease } from "../../src/commands/githubActions/bumpUpstream/github/isValidRelease.js"; +import { + executable, + temporaryDirectory, + useExecutables +} from "../helpers/fixtures.js"; + +describe("safe commands and line buffering", () => { + it("passes metacharacters literally instead of executing them", async () => { + const value = '$(touch SHOULD_NOT_EXIST);echo unsafe "quoted"'; + const result = await shell([ + process.execPath, + "-e", + "process.stdout.write(process.argv[1])", + value + ]); + expect(result).to.equal(value); + expect(isValidRelease("v1.2.3$(touch${IFS}marker)")).to.equal(false); + }); + + it("never evaluates a branch name while checking whether it exists", async () => { + const dir = temporaryDirectory(); + const marker = path.join(dir, "marker"); + executable(dir, "git", "process.exit(1);"); + const restore = useExecutables(dir); + try { + expect( + await getLocalBranchExists(`demo$(touch\u0024{IFS}${marker})`) + ).to.equal(false); + expect(fs.existsSync(marker)).to.equal(false); + } finally { + restore(); + fs.rmSync(dir, { recursive: true, force: true }); + } + }); + + it("assembles partial UTF-8 lines independently on stdout and stderr", async () => { + const lines: string[] = []; + await shell( + [ + process.execPath, + "-e", + 'process.stdout.write("hel"); process.stderr.write("warn\\n"); setTimeout(() => { process.stdout.write("lo\\nlast"); }, 30);' + ], + { onData: line => lines.push(line) } + ); + expect(lines).to.include("hello").and.include("warn").and.include("last"); + expect(lines).not.to.include("hel"); + }); +}); From 004b232ffea6b4bc2175175e454fc7e911ab4b87 Mon Sep 17 00:00:00 2001 From: 3alpha <15694175+3alpha@users.noreply.github.com> Date: Wed, 4 Nov 2026 22:19:36 +0100 Subject: [PATCH 04/15] Render build progress with one bounded terminal preview A single renderer owns the terminal and shows numbered package/architecture stages with the last complete log lines. --skip_save no longer reports a successful build as an error, --all_variants prints the resolved variant names, and the build and publish handlers forward delete_old_pins. --- src/commands/build/handler.ts | 4 +- src/commands/build/index.ts | 10 +- src/commands/build/types.ts | 3 +- src/commands/build/variants.ts | 3 +- src/commands/publish/handler.ts | 10 +- src/tasks/buildAndUpload/getBuildTasks.ts | 30 +++--- .../publish/subtasks/getBuildAndUploadTask.ts | 13 +-- src/utils/progress.ts | 97 +++++++++++++++++++ test/utils/progress.test.ts | 42 ++++++++ 9 files changed, 176 insertions(+), 36 deletions(-) create mode 100644 src/utils/progress.ts create mode 100644 test/utils/progress.test.ts diff --git a/src/commands/build/handler.ts b/src/commands/build/handler.ts index 137443cd..880e538a 100644 --- a/src/commands/build/handler.ts +++ b/src/commands/build/handler.ts @@ -1,3 +1,4 @@ +import { ProgressRenderer } from "../../utils/progress.js"; import Listr from "listr"; import { Architecture, architectures } from "@dappnode/types"; import { buildAndUpload } from "../../tasks/buildAndUpload/index.js"; @@ -66,6 +67,7 @@ export async function buildHandler({ skipUpload, composeFileName, requireGitData, + deleteOldPins, variantsDirPath, skipComposeValidation, stripComposeVersion, @@ -73,7 +75,7 @@ export async function buildHandler({ }; const verbosityOptions: VerbosityOptions = { - renderer: verbose ? "verbose" : silent ? "silent" : "default" + renderer: verbose ? "verbose" : silent ? "silent" : ProgressRenderer }; const buildTasks = new Listr(buildAndUpload(buildOptions), verbosityOptions); diff --git a/src/commands/build/index.ts b/src/commands/build/index.ts index c17bc639..5e3b0565 100644 --- a/src/commands/build/index.ts +++ b/src/commands/build/index.ts @@ -74,7 +74,10 @@ export const build: CommandModule = { handler: async (args): Promise => { const buildResults = await buildHandler(args); - printBuildResults(buildResults, Boolean(args.skipUpload)); + printBuildResults( + buildResults, + Boolean(args.skip_upload || args.skip_save) + ); } }; @@ -89,8 +92,9 @@ function printBuildResults( for (const [dnpName, { releaseMultiHash }] of Object.entries(buildResults)) { if (!releaseMultiHash) { - console.log(chalk.red(`Error building Dappnode Package (${dnpName})\n`)); - return; + throw new Error( + `No uploaded release hash for Dappnode Package (${dnpName})` + ); } console.log(` diff --git a/src/commands/build/types.ts b/src/commands/build/types.ts index 587da620..f42a5b94 100644 --- a/src/commands/build/types.ts +++ b/src/commands/build/types.ts @@ -1,3 +1,4 @@ +import type { ProgressRenderer } from "../../utils/progress.js"; import { UploadTo } from "../../releaseUploader/index.js"; import { CliGlobalOptions } from "../../types.js"; @@ -18,5 +19,5 @@ export interface BuildCommandOptions extends CliGlobalOptions { } export interface VerbosityOptions { - renderer: "verbose" | "silent" | "default"; + renderer: "verbose" | "silent" | "default" | typeof ProgressRenderer; } diff --git a/src/commands/build/variants.ts b/src/commands/build/variants.ts index f96799d3..853e029b 100644 --- a/src/commands/build/variants.ts +++ b/src/commands/build/variants.ts @@ -16,7 +16,6 @@ export function getPackagesToBuildProps({ variantsDirPath: string; composeFileName: string; }): PackageToBuildProps[] { - const buildVariantMapArgs = { rootDir, variantsDirPath, composeFileName }; if (!allVariants && !commaSeparatedVariants) @@ -34,7 +33,7 @@ export function getPackagesToBuildProps({ console.log( `${chalk.dim( - `Building package from template for variant(s) ${commaSeparatedVariants}...` + `Building package from template for variant(s) ${validVariantNames.join(", ")}...` )}` ); diff --git a/src/commands/publish/handler.ts b/src/commands/publish/handler.ts index 27bd37d4..1eea4386 100644 --- a/src/commands/publish/handler.ts +++ b/src/commands/publish/handler.ts @@ -1,3 +1,4 @@ +import { ProgressRenderer } from "../../utils/progress.js"; import Listr from "listr"; import path from "path"; import { @@ -43,10 +44,6 @@ export async function publishHandler({ const isCi = process.env.CI; - const verbosityOptions: VerbosityOptions = { - renderer: verbose ? "verbose" : silent ? "silent" : "default" - }; - /** * Specific set of options used for internal DAppNode releases. * Caution: options may change without notice. @@ -61,6 +58,10 @@ export async function publishHandler({ githubRelease = true; } + const verbosityOptions: VerbosityOptions = { + renderer: verbose ? "verbose" : silent ? "silent" : ProgressRenderer + }; + const releaseType = parseReleaseType({ type }); const variantsDirPath = path.join(dir, variantsDirName); @@ -77,6 +78,7 @@ export async function publishHandler({ uploadTo, userTimeout, requireGitData, + deleteOldPins, developerAddress, githubRelease, verbosityOptions, diff --git a/src/tasks/buildAndUpload/getBuildTasks.ts b/src/tasks/buildAndUpload/getBuildTasks.ts index e0005e91..d1964d7a 100644 --- a/src/tasks/buildAndUpload/getBuildTasks.ts +++ b/src/tasks/buildAndUpload/getBuildTasks.ts @@ -25,19 +25,23 @@ export function getBuildTasks({ skipSave?: boolean; rootDir: string; }): ListrTask[] { - const buildTasks: ListrTask[] = packagesToBuildProps.flatMap((pkgProps) => { - return pkgProps.architectures.map(architecture => - createBuildTask({ - pkgProps, - architecture, - buildTimeout, - skipSave, - rootDir - }) - ); - }); + const buildTasks: ListrTask[] = + packagesToBuildProps.flatMap(pkgProps => { + return pkgProps.architectures.map(architecture => + createBuildTask({ + pkgProps, + architecture, + buildTimeout, + skipSave, + rootDir + }) + ); + }); - return buildTasks; + return buildTasks.map((task, index) => ({ + ...task, + title: `[${index + 1}/${buildTasks.length}] ${task.title}` + })); } function createBuildTask({ @@ -66,7 +70,7 @@ function createBuildTask({ }); return { - title: `Build ${name} (version ${version}) for arch ${architecture}`, + title: `Build ${pkgProps.variant || name.split(".")[0]} ${version} · ${architecture}`, task: () => new Listr( buildFn({ diff --git a/src/tasks/publish/subtasks/getBuildAndUploadTask.ts b/src/tasks/publish/subtasks/getBuildAndUploadTask.ts index 070d09da..cd1d036e 100644 --- a/src/tasks/publish/subtasks/getBuildAndUploadTask.ts +++ b/src/tasks/publish/subtasks/getBuildAndUploadTask.ts @@ -3,7 +3,6 @@ import { BuildAndUploadOptions } from "../../buildAndUpload/types.js"; import { ListrContextPublish } from "../../../types.js"; import { buildAndUpload } from "../../buildAndUpload/index.js"; import { VerbosityOptions } from "../../../commands/build/types.js"; -import { merge } from "lodash-es"; export function getBuildAndUploadTask({ buildOptions, @@ -14,16 +13,6 @@ export function getBuildAndUploadTask({ }): ListrTask { return { title: "Building and uploading", - task: async ctx => { - const buildTasks = new Listr( - buildAndUpload(buildOptions), - verbosityOptions - ); - - const buildResults = await buildTasks.run(); - - // Add build results to publish context - ctx = merge(ctx, buildResults); - } + task: () => new Listr(buildAndUpload(buildOptions), verbosityOptions) }; } diff --git a/src/utils/progress.ts b/src/utils/progress.ts new file mode 100644 index 00000000..da0304fd --- /dev/null +++ b/src/utils/progress.ts @@ -0,0 +1,97 @@ +import { createLogUpdate } from "log-update"; +import wrapAnsi from "wrap-ansi"; +import { stripVTControlCharacters } from "util"; +import type Listr from "listr"; + +export interface ProgressTask { + title: string; + output?: string; + subtasks: readonly ProgressTask[]; + isEnabled(): boolean; + isPending(): boolean; + isCompleted(): boolean; + isSkipped(): boolean; + hasFailed(): boolean; +} + +/** Keep a useful preview while verbose renderers still receive every complete line. */ +export function taskLog(task: { output: string }): (line: string) => void { + const lines: string[] = []; + return line => { + lines.push(stripVTControlCharacters(line)); + if (lines.length > 4) lines.shift(); + task.output = lines.join("\n"); + }; +} + +export function renderProgress( + tasks: readonly ProgressTask[], + frame = "⠋", + depth = 0 +): string[] { + const lines: string[] = []; + for (const task of tasks) { + if (!task.isEnabled()) continue; + const failed = task.hasFailed(); + const pending = task.isPending(); + if (!pending && !failed && !task.isCompleted() && !task.isSkipped()) + continue; + const symbol = failed + ? "✖" + : pending + ? frame + : task.isSkipped() + ? "↓" + : "✔"; + const indent = " ".repeat(depth); + lines.push(`${indent}${symbol} ${stripVTControlCharacters(task.title)}`); + if ((pending || failed) && task.output) + for (const line of stripVTControlCharacters(task.output) + .split(/\r?\n/) + .slice(-4)) + if (line.trim()) lines.push(`${indent} │ ${line}`); + if (pending || failed) + lines.push(...renderProgress(task.subtasks, frame, depth + 1)); + } + return lines; +} + +/** One renderer owns the terminal; nested task lists share its bounded preview. */ +export class ProgressRenderer { + static nonTTY = false; + private readonly update = createLogUpdate(process.stdout); + private interval?: ReturnType; + private frame = 0; + constructor( + private readonly tasks: ReadonlyArray> + ) {} + + private draw(): void { + const frames = ["⠋", "⠙", "⠹", "⠸", "⠼", "⠴", "⠦", "⠧", "⠇", "⠏"]; + const lines = renderProgress( + this.tasks as unknown as readonly ProgressTask[], + frames[this.frame++ % frames.length] + ); + const rows = lines.flatMap(line => + wrapAnsi(line, Math.max(10, process.stdout.columns || 80), { + hard: true, + trim: false, + wordWrap: false + }).split("\n") + ); + this.update( + rows.slice(-Math.max(1, (process.stdout.rows || 24) - 2)).join("\n") + ); + } + + render(): void { + this.draw(); + this.interval = setInterval(() => this.draw(), 100); + } + + end(): void { + if (this.interval) clearInterval(this.interval); + this.draw(); + this.update.done(); + } +} diff --git a/test/utils/progress.test.ts b/test/utils/progress.test.ts new file mode 100644 index 00000000..6b9e30ef --- /dev/null +++ b/test/utils/progress.test.ts @@ -0,0 +1,42 @@ +import { expect } from "chai"; +import { + renderProgress, + taskLog, + type ProgressTask +} from "../../src/utils/progress.js"; + +function pending(title: string, output: string): ProgressTask { + return { + title, + output, + subtasks: [], + isEnabled: () => true, + isPending: () => true, + isCompleted: () => false, + isSkipped: () => false, + hasFailed: () => false + }; +} + +describe("build progress preview", () => { + it("retains complete recent log lines and renders them together", () => { + const task = pending("Build mainnet · linux/arm64", ""); + const write = taskLog(task as { output: string }); + for (let index = 0; index < 6; index++) write(`layer ${index}`); + const lines = renderProgress([task]); + expect(lines.join("\n")).to.include("layer 2").and.include("layer 5"); + expect(lines.join("\n")).not.to.include("layer 1"); + expect(lines[0]).to.include("mainnet").and.include("arm64"); + }); + + it("keeps the active upload/pinning stage visible without future task clutter", () => { + const task = pending( + "Upload mainnet", + "Upload sent · waiting for pinning confirmation..." + ); + const future = { ...pending("Future stage", ""), isPending: () => false }; + const lines = renderProgress([task, future]); + expect(lines.join("\n")).to.include("waiting for pinning confirmation"); + expect(lines.join("\n")).not.to.include("Future stage"); + }); +}); From e996d394b7d2ef6922c0c69037ffabe27d8acd74 Mon Sep 17 00:00:00 2001 From: 3alpha <15694175+3alpha@users.noreply.github.com> Date: Wed, 4 Nov 2026 22:19:36 +0100 Subject: [PATCH 05/15] Export images atomically and for the requested platform Reject failed or signalled docker save/xz processes, bound export time and replace the archive atomically, so a broken export is never cached or uploaded. The compose path now pulls external images for the requested architecture, and the architecture check inspects that platform (--platform, with a fallback for Docker CLI < 28.1). --- src/tasks/buildAndUpload/buildWithBuildx.ts | 69 ++++++--- src/tasks/buildAndUpload/buildWithCompose.ts | 30 +++- src/tasks/saveAndCompressImages.ts | 143 +++++++++++++------ test/tasks/inspectImageForPlatform.test.ts | 62 ++++++++ test/tasks/saveAndCompressImages.test.ts | 102 +++++++++++++ 5 files changed, 332 insertions(+), 74 deletions(-) create mode 100644 test/tasks/inspectImageForPlatform.test.ts create mode 100644 test/tasks/saveAndCompressImages.test.ts diff --git a/src/tasks/buildAndUpload/buildWithBuildx.ts b/src/tasks/buildAndUpload/buildWithBuildx.ts index f6c4d807..1e45c563 100644 --- a/src/tasks/buildAndUpload/buildWithBuildx.ts +++ b/src/tasks/buildAndUpload/buildWithBuildx.ts @@ -1,3 +1,5 @@ +import fs from "fs"; +import { taskLog } from "../../utils/progress.js"; import { ListrTask } from "listr"; import semver from "semver"; import { shell } from "../../utils/shell.js"; @@ -67,40 +69,61 @@ export function buildWithBuildx({ switch (architecture) { case "linux/arm64": - await shell( - `docker run --privileged --rm tonistiigi/binfmt --uninstall qemu-*` - ); - await shell( - `docker run --privileged --rm tonistiigi/binfmt --install all` - ); + await shell([ + "docker", + "run", + "--privileged", + "--rm", + "tonistiigi/binfmt", + "--uninstall", + "qemu-*" + ]); + await shell([ + "docker", + "run", + "--privileged", + "--rm", + "tonistiigi/binfmt", + "--install", + "all" + ]); // Make sure QEMU is enabled // `cat /proc/sys/fs/binfmt_misc/qemu-aarch64` break; } - const currentInstances = await shell(`docker buildx ls`); + const currentInstances = await shell(["docker", "buildx", "ls"]); if (currentInstances.includes(buildxInstanceName)) { - await shell(`docker buildx use ${buildxInstanceName}`); + await shell(["docker", "buildx", "use", buildxInstanceName]); } else { - await shell( - `docker buildx create --name ${buildxInstanceName} --use` - ); + await shell([ + "docker", + "buildx", + "create", + "--name", + buildxInstanceName, + "--use" + ]); } // Will build all services defined in the compose in paralel // The resulting images will be imported to docker with the tag declared in the service await shell( [ - "docker buildx bake", - "--progress plain", + "docker", + "buildx", + "bake", + "--progress", + "plain", "--load", - `--file ${tmpComposePath}`, + "--file", + tmpComposePath, `--set=*.platform=${architecture}` - ].join(" "), + ], { timeout: buildTimeout, maxBuffer: 100 * 1e6, - onData: data => (task.output = data) + onData: taskLog(task) } ); @@ -110,9 +133,15 @@ export function buildWithBuildx({ // Make sure the built was done for the correct architecture switch (architecture) { case "linux/arm64": { - const res = await shell( - `docker run --rm --entrypoint="" ${firstImageTag} uname -m` - ).catch(() => { + const res = await shell([ + "docker", + "run", + "--rm", + "--entrypoint=", + firstImageTag, + "uname", + "-m" + ]).catch(() => { // Ignore all errors }); if (res && res !== "aarch64") @@ -134,7 +163,7 @@ export function buildWithBuildx({ }), { title: "Cleanup temporary files", - task: async () => shell(`rm ${tmpComposePath}`) + task: async () => fs.promises.rm(tmpComposePath, { force: true }) } ]; } diff --git a/src/tasks/buildAndUpload/buildWithCompose.ts b/src/tasks/buildAndUpload/buildWithCompose.ts index d3a63054..4aff5894 100644 --- a/src/tasks/buildAndUpload/buildWithCompose.ts +++ b/src/tasks/buildAndUpload/buildWithCompose.ts @@ -1,3 +1,4 @@ +import { taskLog } from "../../utils/progress.js"; import { ListrTask } from "listr"; import { PackageImage } from "../../types.js"; import { shell } from "../../utils/shell.js"; @@ -5,6 +6,7 @@ import { saveAndCompressImagesCached } from "../saveAndCompressImages.js"; import { Compose, Manifest, defaultArch } from "@dappnode/types"; import { tmpComposeFileName } from "../../params.js"; import path from "path"; +import fs from "fs"; import { writeTmpCompose } from "./writeTmpCompose.js"; /** @@ -13,6 +15,7 @@ import { writeTmpCompose } from "./writeTmpCompose.js"; * A local cache file will prevent unnecessary compressions if the image hasn't changed */ export function buildWithCompose({ + architecture = defaultArch, images, compose, manifest, @@ -21,6 +24,7 @@ export function buildWithCompose({ skipSave, rootDir }: { + architecture?: import("@dappnode/types").Architecture; images: PackageImage[]; compose: Compose; manifest: Manifest; @@ -42,26 +46,38 @@ export function buildWithCompose({ return [ { title: "Build docker image", + enabled: () => images.some(image => image.type === "local"), task: async (_, task) => { // Prior to this task, the compose should had been updated with the proper tag - await shell(`docker compose --file ${tmpComposePath} build`, { - timeout: buildTimeout, - maxBuffer: 100 * 1e6, - onData: data => (task.output = data) - }); + await shell( + [ + "docker", + "compose", + "--progress", + "plain", + "--file", + tmpComposePath, + "build" + ], + { + timeout: buildTimeout, + maxBuffer: 100 * 1e6, + onData: taskLog(task) + } + ); } }, ...saveAndCompressImagesCached({ images, - architecture: defaultArch, + architecture, destPath, buildTimeout, skipSave }), { title: "Cleanup temporary files", - task: async () => shell(`rm ${tmpComposePath}`) + task: async () => fs.promises.rm(tmpComposePath, { force: true }) } ]; } diff --git a/src/tasks/saveAndCompressImages.ts b/src/tasks/saveAndCompressImages.ts index 79cdb5ae..b56cf64a 100644 --- a/src/tasks/saveAndCompressImages.ts +++ b/src/tasks/saveAndCompressImages.ts @@ -1,6 +1,7 @@ import fs from "fs"; import path from "path"; -import { spawn } from "child_process"; +import { spawn, ChildProcess } from "child_process"; +import { pipeline } from "stream/promises"; import { ListrTask } from "listr"; import { getFileHash } from "../utils/getFileHash.js"; import { loadCache, writeToCache, getCacheKey } from "../utils/cache.js"; @@ -42,14 +43,17 @@ export function saveAndCompressImagesCached({ task: async (_, task) => { for (const { imageTag, originalImageTag } of externalImages) { await shell( - `docker pull ${originalImageTag} --platform=${architecture}`, + ["docker", "pull", `--platform=${architecture}`, originalImageTag], { onData: data => (task.output = data) } ); task.output = `Tagging ${originalImageTag} > ${imageTag}`; - await shell(`docker tag ${originalImageTag} ${imageTag}`); + await shell(["docker", "tag", originalImageTag, imageTag]); // Validate the resulting image architecture - const imageDataRaw = await shell(`docker image inspect --platform=${architecture} ${imageTag}`); + const imageDataRaw = await inspectImageForPlatform( + imageTag, + architecture + ); const imageData = JSON.parse(imageDataRaw); const imageArch = `${imageData[0]["Os"]}/${imageData[0]["Architecture"]}`; if (imageArch !== architecture) @@ -91,7 +95,32 @@ export function saveAndCompressImagesCached({ ]; } -async function saveAndCompressImages({ +/** + * With the containerd image store a tag can hold several platforms, and a plain + * inspect reports the host platform (or none). `--platform` selects the pulled one. + * Docker CLI < 28.1 lacks the flag; there a tag holds one platform, so a plain inspect is exact. + */ +export async function inspectImageForPlatform( + imageTag: string, + architecture: Architecture +): Promise { + try { + return await shell([ + "docker", + "image", + "inspect", + `--platform=${architecture}`, + imageTag + ]); + } catch (e) { + const output = `${e.message || ""}\n${e.stderr || ""}`; + if (!/unknown flag: --platform/i.test(output)) throw e; + return await shell(["docker", "image", "inspect", imageTag]); + } +} + +/** Export atomically only after both processes and both pipes have succeeded. */ +export async function saveAndCompressImages({ imageTags, destPath, onData, @@ -102,50 +131,70 @@ async function saveAndCompressImages({ onData?: (data: string) => void; timeout?: number; }): Promise { - return new Promise((resolve, reject) => { - const dockerSave = spawn("docker", ["save", ...imageTags]); - - // -e9T0: Compression settings (extreme and paralelized) - // -vv: Very verbose log to provide progress - // -c: Outputs the compressed result to stdout - // -f: Overwrite the destination path if necessary - const xz = spawn("xz", ["-e9T0", "-vv", "-c", "-f"], { timeout }); - - dockerSave.stdout.pipe(xz.stdin); - - let lastStderr = ""; - xz.stderr.on("data", chunk => { - const data = chunk.toString().trim(); - lastStderr = data; - if (onData) onData(data); - }); - - xz.stdout.pipe(fs.createWriteStream(destPath)); - - // In order for xz to output update logs to stderr, - // a SIGALRM must be sent to the xz process every interval - // https://stackoverflow.com/questions/48452726/how-to-redirect-xzs-normal-stdout-when-do-tar-xz - const interval = setInterval(() => xz.kill("SIGALRM"), 1000); - - xz.on("error", err => { - clearInterval(interval); - reject(Error(`Error compressing image: ${err.message} \n${lastStderr}`)); - }); + await fs.promises.mkdir(path.dirname(destPath), { recursive: true }); + const temporaryDir = await fs.promises.mkdtemp( + path.join(path.dirname(destPath), ".dappnodesdk-") + ); + const temporaryPath = path.join(temporaryDir, "image.txz"); + const dockerSave = spawn("docker", ["save", ...imageTags]); + const xz = spawn("xz", ["-e9T0", "-vv", "-c"]); + let dockerStderr = ""; + let compressionStderr = ""; + dockerSave.stderr.on("data", (chunk: Buffer) => { + dockerStderr = (dockerStderr + chunk.toString()).slice(-65536); + }); + xz.stderr.on("data", (chunk: Buffer) => { + const message = chunk.toString().trim(); + compressionStderr = (compressionStderr + message).slice(-65536); + if (message && onData) onData(message); + }); - xz.on("exit", code => { - clearInterval(interval); - if (code) { - reject( - Error(`Error compressing image: xz exit ${code} \n${lastStderr}`) - ); - } else { - resolve(`Compressed image saved to ${destPath}`); - } + const completed = ( + child: ChildProcess, + label: string, + stderr: () => string + ): Promise => + new Promise((resolve, reject) => { + child.once("error", reject); + child.once("close", (code, signal) => { + if (code === 0 && !signal) resolve(); + else + reject( + new Error( + `${label} failed (${signal || `exit ${code}`}): ${stderr()}` + ) + ); + }); }); - dockerSave.on("error", err => { - clearInterval(interval); - reject(Error(`Error saving image: ${err.message}`)); - }); + let timer: ReturnType | undefined; + const timeoutPromise = new Promise((resolve, reject) => { + if (timeout && timeout > 0) + timer = setTimeout( + () => reject(new Error(`Image export timed out after ${timeout} ms`)), + timeout + ); }); + const interval = setInterval(() => xz.kill("SIGALRM"), 1000); + try { + await Promise.race([ + Promise.all([ + completed(dockerSave, "docker save", () => dockerStderr), + completed(xz, "xz", () => compressionStderr), + pipeline(dockerSave.stdout, xz.stdin), + pipeline(xz.stdout, fs.createWriteStream(temporaryPath)) + ]), + timeoutPromise + ]); + await fs.promises.rename(temporaryPath, destPath); + return `Compressed image saved to ${destPath}`; + } catch (error) { + dockerSave.kill("SIGKILL"); + xz.kill("SIGKILL"); + throw error; + } finally { + clearInterval(interval); + if (timer) clearTimeout(timer); + await fs.promises.rm(temporaryDir, { recursive: true, force: true }); + } } diff --git a/test/tasks/inspectImageForPlatform.test.ts b/test/tasks/inspectImageForPlatform.test.ts new file mode 100644 index 00000000..f09ec6c6 --- /dev/null +++ b/test/tasks/inspectImageForPlatform.test.ts @@ -0,0 +1,62 @@ +import fs from "fs"; +import { expect } from "chai"; +import { inspectImageForPlatform } from "../../src/tasks/saveAndCompressImages.js"; +import { + executable, + temporaryDirectory, + useExecutables +} from "../helpers/fixtures.js"; + +describe("platform-specific image inspection", () => { + let dir: string; + let restorePath: () => void; + beforeEach(() => { + dir = temporaryDirectory(); + restorePath = useExecutables(dir); + }); + afterEach(() => { + restorePath(); + fs.rmSync(dir, { recursive: true, force: true }); + }); + + it("selects the requested platform (containerd store holds several per tag)", async () => { + executable( + dir, + "docker", + `const p = process.argv.find(a => a.startsWith("--platform=")); + console.log(JSON.stringify([{ Os: "linux", Architecture: p ? p.split("/")[1] : "arm64" }]));` + ); + const data = JSON.parse( + await inspectImageForPlatform("demo:1", "linux/amd64") + ); + expect(data[0].Architecture).to.equal("amd64"); + }); + + it("falls back to a plain inspect on Docker CLI versions without --platform", async () => { + executable( + dir, + "docker", + `if (process.argv.some(a => a.startsWith("--platform"))) { + process.stderr.write("unknown flag: --platform\\nSee 'docker image inspect --help'."); + process.exit(125); + } + console.log(JSON.stringify([{ Os: "linux", Architecture: "amd64" }]));` + ); + const data = JSON.parse( + await inspectImageForPlatform("demo:1", "linux/amd64") + ); + expect(data[0].Architecture).to.equal("amd64"); + }); + + it("does not hide other inspect failures", async () => { + executable( + dir, + "docker", + `process.stderr.write("No such image: demo:1"); process.exit(1);` + ); + const error = await inspectImageForPlatform("demo:1", "linux/amd64").catch( + error => error + ); + expect(error.message).to.include("No such image"); + }); +}); diff --git a/test/tasks/saveAndCompressImages.test.ts b/test/tasks/saveAndCompressImages.test.ts new file mode 100644 index 00000000..987d380c --- /dev/null +++ b/test/tasks/saveAndCompressImages.test.ts @@ -0,0 +1,102 @@ +import fs from "fs"; +import path from "path"; +import { expect } from "chai"; +import { saveAndCompressImages } from "../../src/tasks/saveAndCompressImages.js"; +import { + executable, + temporaryDirectory, + useExecutables +} from "../helpers/fixtures.js"; + +describe("atomic image export", function () { + this.timeout(10000); + let dir: string; + let restorePath: () => void; + let destPath: string; + + beforeEach(() => { + dir = temporaryDirectory(); + destPath = path.join(dir, "image.txz"); + fs.writeFileSync(destPath, "previous verified archive"); + executable( + dir, + "xz", + 'process.on("SIGALRM", () => {}); process.stdin.pipe(process.stdout);' + ); + restorePath = useExecutables(dir); + }); + afterEach(() => { + restorePath(); + fs.rmSync(dir, { recursive: true, force: true }); + }); + + it("rejects a failed docker save and preserves the previous archive", async () => { + executable( + dir, + "docker", + 'process.stderr.write("daemon export failed"); process.exit(42);' + ); + const error = await saveAndCompressImages({ + imageTags: ["demo:1"], + destPath, + timeout: 3000 + }).catch(error => error); + expect(error).to.be.instanceOf(Error); + expect(error.message) + .to.include("docker save failed") + .and.include("daemon export failed"); + expect(fs.readFileSync(destPath, "utf8")).to.equal( + "previous verified archive" + ); + expect( + fs.readdirSync(dir).some(file => file.startsWith(".dappnodesdk-")) + ).to.equal(false); + }); + + it("rejects signal termination of the compressor", async () => { + executable(dir, "docker", 'process.stdout.write("tar payload");'); + executable( + dir, + "xz", + 'process.stdin.resume(); process.kill(process.pid, "SIGTERM");' + ); + const error = await saveAndCompressImages({ + imageTags: ["demo:1"], + destPath, + timeout: 3000 + }).catch(error => error); + expect(error).to.be.instanceOf(Error); + expect(fs.readFileSync(destPath, "utf8")).to.equal( + "previous verified archive" + ); + }); + + it("times out and cancels both child processes", async () => { + executable(dir, "docker", "setInterval(() => {}, 1000);"); + const error = await saveAndCompressImages({ + imageTags: ["demo:1"], + destPath, + timeout: 100 + }).catch(error => error); + expect(error.message).to.include("timed out"); + expect(fs.readFileSync(destPath, "utf8")).to.equal( + "previous verified archive" + ); + }); + + it("waits for all output before replacing the archive", async () => { + executable( + dir, + "docker", + "process.stdout.write(Buffer.alloc(2 * 1024 * 1024, 7));" + ); + await saveAndCompressImages({ + imageTags: ["demo:1"], + destPath, + timeout: 3000 + }); + const data = fs.readFileSync(destPath); + expect(data.length).to.equal(2 * 1024 * 1024); + expect(data.every(byte => byte === 7)).to.equal(true); + }); +}); From 964e481aaf6d65db18e6594912dced691a2c7e5b Mon Sep 17 00:00:00 2001 From: 3alpha <15694175+3alpha@users.noreply.github.com> Date: Wed, 4 Nov 2026 22:19:36 +0100 Subject: [PATCH 06/15] Confirm before init overwrites package files Wait for the overwrite prompt before writing anything, keep an existing Dockerfile unless --force is given, and derive the default package name from --dir. --- src/commands/init/fileOperations.ts | 16 ++++--- src/commands/init/handler.ts | 6 +-- src/commands/init/naming.ts | 5 +- test/commands/initSafety.test.ts | 71 +++++++++++++++++++++++++++++ 4 files changed, 87 insertions(+), 11 deletions(-) create mode 100644 test/commands/initSafety.test.ts diff --git a/src/commands/init/fileOperations.ts b/src/commands/init/fileOperations.ts index 31cf4d4e..a5671796 100644 --- a/src/commands/init/fileOperations.ts +++ b/src/commands/init/fileOperations.ts @@ -47,7 +47,7 @@ export function createPackageDirectories( } } -export function writePackageFiles({ +export async function writePackageFiles({ dir, answers, useVariants, @@ -65,9 +65,9 @@ export function writePackageFiles({ rootCompose: Compose; composeFileName: string; serviceName: string; -}): void { +}): Promise { const rootManifestPath = getManifestPath(defaultManifestFormat, { dir }); - confirmManifestOverwrite(rootManifestPath, force); + await confirmManifestOverwrite(rootManifestPath, force); if (useVariants) writeMultiVariantPackageFiles({ @@ -88,7 +88,7 @@ export function writePackageFiles({ addDefaultAvatar(dir); - addDockerfile(dir); + addDockerfile(dir, force); addGitignore(dir); } @@ -107,7 +107,7 @@ function writeSinglePackageFiles({ writeManifest(rootManifest, defaultManifestFormat, { dir }); // Only write a compose if it doesn't exist - if (!fs.existsSync(getComposePath({ dir }))) { + if (!fs.existsSync(getComposePath({ dir, composeFileName }))) { writeCompose(rootCompose, { dir, composeFileName }); } } @@ -197,8 +197,10 @@ function addDefaultAvatar(dir: string) { } } -function addDockerfile(dir: string) { - fs.writeFileSync(path.join(dir, dockerfileName), dockerfileData); +function addDockerfile(dir: string, force: boolean) { + const dockerfilePath = path.join(dir, dockerfileName); + if (force || !fs.existsSync(dockerfilePath)) + fs.writeFileSync(dockerfilePath, dockerfileData); } /** diff --git a/src/commands/init/handler.ts b/src/commands/init/handler.ts index 3f22631b..b5814aaa 100644 --- a/src/commands/init/handler.ts +++ b/src/commands/init/handler.ts @@ -1,6 +1,6 @@ import { Manifest, Compose, getImageTag } from "@dappnode/types"; import { defaultDir, defaultComposeFileName } from "../../params.js"; -import { shell } from "../../utils/shell.js"; +import path from "path"; import { defaultVersion } from "./params.js"; import { InitCommandOptions, UserAnswers } from "./types.js"; import { getDnpName, getShortDnpName } from "./naming.js"; @@ -21,7 +21,7 @@ export async function initHandler({ const useDefaults = !!yes; // shell outputs tend to include trailing spaces and new lines - const directoryName = await shell('echo "${PWD##*/}"'); + const directoryName = path.basename(path.resolve(dir)); const defaultName = getDnpName(directoryName); const answers = await getUserAnswers({ @@ -43,7 +43,7 @@ export async function initHandler({ }); createPackageDirectories(dir, answers, useVariants); - writePackageFiles({ + await writePackageFiles({ dir, answers, useVariants, diff --git a/src/commands/init/naming.ts b/src/commands/init/naming.ts index 4e92cb90..fcf61c7f 100644 --- a/src/commands/init/naming.ts +++ b/src/commands/init/naming.ts @@ -54,5 +54,8 @@ export function getDnpName(name: string): string { name = name.toLowerCase(); // Append public domain - return name.endsWith(".eth") ? name : name + publicRepoDomain; + return name.endsWith(".eth") + ? name + : name.replace(/[^a-z0-9-]+/g, "-").replace(/^-+|-+$/g, "") + + publicRepoDomain; } diff --git a/test/commands/initSafety.test.ts b/test/commands/initSafety.test.ts new file mode 100644 index 00000000..f42e9365 --- /dev/null +++ b/test/commands/initSafety.test.ts @@ -0,0 +1,71 @@ +import fs from "fs"; +import path from "path"; +import { mock } from "node:test"; +import inquirer from "inquirer"; +import { expect } from "chai"; +import { writePackageFiles } from "../../src/commands/init/fileOperations.js"; +import { temporaryDirectory } from "../helpers/fixtures.js"; + +describe("initialization overwrite safety", () => { + let dir: string; + beforeEach(() => { + dir = temporaryDirectory(); + fs.writeFileSync( + path.join(dir, "dappnode_package.json"), + '{"original":true}' + ); + fs.writeFileSync(path.join(dir, "Dockerfile"), "ORIGINAL DOCKERFILE"); + }); + afterEach(() => { + mock.restoreAll(); + fs.rmSync(dir, { recursive: true, force: true }); + }); + + function write(force = false) { + return writePackageFiles({ + dir, + force, + useVariants: false, + answers: { name: "demo.public.dappnode.eth", version: "0.1.0" }, + rootManifest: { name: "demo.public.dappnode.eth", version: "0.1.0" }, + rootCompose: { version: "3.5", services: { app: { build: "." } } }, + composeFileName: "docker-compose.yml", + serviceName: "app" + }); + } + + it("makes no writes while confirmation is pending or after it is declined", async () => { + let answer: (value: { continue: boolean }) => void = () => {}; + mock.method( + inquirer, + "prompt", + () => + new Promise(resolve => { + answer = resolve; + }) + ); + const pending = write(); + expect( + fs.readFileSync(path.join(dir, "dappnode_package.json"), "utf8") + ).to.equal('{"original":true}'); + answer({ continue: false }); + const error = await pending.catch(error => error); + expect(error.message).to.equal("Stopping"); + expect(fs.readFileSync(path.join(dir, "Dockerfile"), "utf8")).to.equal( + "ORIGINAL DOCKERFILE" + ); + }); + + it("preserves an existing Dockerfile when only manifest overwrite is confirmed", async () => { + mock.method(inquirer, "prompt", async () => ({ continue: true })); + await write(); + expect(fs.readFileSync(path.join(dir, "Dockerfile"), "utf8")).to.equal( + "ORIGINAL DOCKERFILE" + ); + expect( + JSON.parse( + fs.readFileSync(path.join(dir, "dappnode_package.json"), "utf8") + ).name + ).to.equal("demo.public.dappnode.eth"); + }); +}); From a326eb4f3b18893b87619802fb2f5651c3522038 Mon Sep 17 00:00:00 2001 From: 3alpha <15694175+3alpha@users.noreply.github.com> Date: Wed, 4 Nov 2026 22:19:36 +0100 Subject: [PATCH 07/15] Package exactly what was validated for templates Release files are now assembled from the same merged root and variant configuration that passed validation. - Setup wizards are read from JSON or YAML, merged by field id, validated against the schema and emitted as JSON. - Notifications are merged by correlationId. Within a matched wizard field or endpoint, a variant array replaces the root array instead of being merged by index. - Single release files (avatar, disclaimer, Prometheus targets, ...) come from the variant directory when present, otherwise from the root. Grafana dashboards are collected from both. - Values coerced by schema validation are listed in the "Validate files" step so source files can be fixed. - A single YAML manifest no longer hits the JSON-only template restriction. - Publishing keeps external upstream image references and recomputes the release directory for the new version. - Compose validation errors keep the "Invalid compose:" prefix. - The README documents the root and variant file rules. --- README.md | 11 + src/files/manifest/readManifest.ts | 3 +- .../readNotificationsIfExists.ts | 19 +- .../setupWizard/readSetupWizardIfExists.ts | 26 +- .../buildAndUpload/generatePackagesProps.ts | 2 +- src/tasks/buildAndUpload/getFileCopyTask.ts | 104 +++++--- .../buildAndUpload/getFileValidationTask.ts | 146 ++++++++--- .../publish/subtasks/getUpdateFilesTask.ts | 24 +- src/utils/copyReleaseFile.ts | 7 +- src/utils/merge.ts | 12 + test/files/variantMerge.test.ts | 87 +++++++ .../buildAndUpload/packageArtifacts.test.ts | 235 ++++++++++++++++++ .../buildAndUpload/validationCoercion.test.ts | 53 ++++ .../utils/versions/updateVariantFiles.test.ts | 106 ++++---- 14 files changed, 704 insertions(+), 131 deletions(-) create mode 100644 src/utils/merge.ts create mode 100644 test/files/variantMerge.test.ts create mode 100644 test/tasks/buildAndUpload/packageArtifacts.test.ts create mode 100644 test/tasks/buildAndUpload/validationCoercion.test.ts diff --git a/README.md b/README.md index 2ac37d7a..b213c812 100644 --- a/README.md +++ b/README.md @@ -30,6 +30,17 @@ Only generates the IPFS Hash to be able to install it without needing to create $ dappnodesdk build ``` +### Root and variant files + +In a multi-variant package (`--all_variants` or `--variants`), each release is assembled from the package root and the variant directory (`package_variants/` by default): + +- `dappnode_package.json` and `docker-compose.yml` are deep-merged, with the variant overriding the root. +- `setup-wizard.*` fields are merged by `id`, and `notifications.yaml` endpoints by `correlationId`. Within a matched entry, the variant's values override the root's, and an array from the variant (for example `enum`, `conditions` or `alerts`) replaces the root's array. The release contains exactly what was validated. +- Single files (avatar, `prometheus-targets.*`, `disclaimer.md`, `getting-started.md`, `setup.schema.json`, `setup-target.json`, `setup-ui.json`, `signature.json`) are taken from the variant directory when it has one, and otherwise from the root. +- Grafana dashboards (`*grafana-dashboard.json`) are collected from both the root and the variant. + +Schema validation coerces some values (for example `isBanner: "false"` becomes `false`). The release ships the coerced value, and the build prints a warning in the "Validate files" step so the source file can be fixed. + ## Publish It does the build of the image and shows the necessary transaction to be able to publish the package. The first time will create the repository but the rest will be updates of it. diff --git a/src/files/manifest/readManifest.ts b/src/files/manifest/readManifest.ts index 0b18754a..71e51f48 100644 --- a/src/files/manifest/readManifest.ts +++ b/src/files/manifest/readManifest.ts @@ -24,7 +24,8 @@ export function readManifest(paths?: ManifestPaths[]): { format: ManifestFormat; } { try { - if (!paths) return loadManifest(); // Load default manifest + if (!paths || paths.length === 0) return loadManifest(); + if (paths.length === 1) return loadManifest(paths[0]); // Load default manifest const manifestsSpecs = paths.map(path => loadManifest(path)); diff --git a/src/files/notifications/readNotificationsIfExists.ts b/src/files/notifications/readNotificationsIfExists.ts index 838476fb..27098978 100644 --- a/src/files/notifications/readNotificationsIfExists.ts +++ b/src/files/notifications/readNotificationsIfExists.ts @@ -4,7 +4,7 @@ import yaml from "js-yaml"; import { defaultDir } from "../../params.js"; import { readFile } from "../../utils/file.js"; import { NotificationsConfig, releaseFiles } from "@dappnode/types"; -import { merge } from "lodash-es"; +import { mergeReplacingArrays } from "../../utils/merge.js"; import { NotificationsPaths } from "./types.js"; /** @@ -45,9 +45,22 @@ export function readNotificationsIfExists( }); // Merge all configurations - return merge({}, ...configs); + const merged = mergeReplacingArrays>(...configs); + for (const key of ["endpoints", "customEndpoints"] as const) { + const endpoints = new Map< + string, + NonNullable[number] + >(); + for (const config of configs) + for (const endpoint of config[key] || []) { + const id = endpoint.correlationId || endpoint.name; + endpoints.set(id, mergeReplacingArrays(endpoints.get(id), endpoint)); + } + if (endpoints.size > 0) merged[key] = [...endpoints.values()]; + } + return merged as NotificationsConfig; } catch (e) { - throw new Error(`Error parsing notifications: ${e.message}`); + throw new Error(`Error parsing notifications: ${e.message}`, { cause: e }); } } diff --git a/src/files/setupWizard/readSetupWizardIfExists.ts b/src/files/setupWizard/readSetupWizardIfExists.ts index ae1ea4d3..d9772f15 100644 --- a/src/files/setupWizard/readSetupWizardIfExists.ts +++ b/src/files/setupWizard/readSetupWizardIfExists.ts @@ -1,17 +1,17 @@ import fs from "fs"; import path from "path"; import yaml from "js-yaml"; -import { merge } from "lodash-es"; +import { mergeReplacingArrays } from "../../utils/merge.js"; import { defaultDir } from "../../params.js"; import { readFile } from "../../utils/file.js"; import { SetupWizard, releaseFiles } from "@dappnode/types"; import { SetupWizardPaths } from "./types.js"; /** - * Reads one or multiple setup-wizard YAML files and merges them. Returns null if none exist. + * Reads one or multiple setup-wizard JSON or YAML files and merges them. Returns null if none exist. * @param {SetupWizardPaths[]} paths - Optional array of directory/file specs. * @returns {SetupWizard | null} - * @throws {Error} Throws if parsing fails or non-YAML format is encountered. + * @throws {Error} Throws if parsing fails or unsupported format is encountered. */ export function readSetupWizardIfExists( paths?: SetupWizardPaths[] @@ -33,10 +33,10 @@ export function readSetupWizardIfExists( if (filePaths.length === 0) return null; - // Load and validate YAML-only files + // JSON is also valid YAML; preserve both supported source formats. const wizards = filePaths.map(fp => { - if (!/\.(yml|yaml)$/i.test(fp)) - throw new Error("Only YAML format supported for setup-wizard: " + fp); + if (!/\.(json|yml|yaml)$/i.test(fp)) + throw new Error("Expected JSON or YAML setup-wizard: " + fp); const data = readFile(fp); const parsed = yaml.load(data); if (!parsed || typeof parsed === "string") @@ -45,9 +45,19 @@ export function readSetupWizardIfExists( }); // Merge all specs - return merge({}, ...wizards); + const fields = new Map(); + for (const wizard of wizards) { + if (wizard.fields !== undefined && !Array.isArray(wizard.fields)) + throw new Error("setup-wizard.fields must be an array"); + for (const field of wizard.fields || []) + fields.set(field.id, mergeReplacingArrays(fields.get(field.id), field)); + } + return { + ...mergeReplacingArrays(...wizards), + fields: [...fields.values()] + }; } catch (e) { - throw new Error(`Error parsing setup-wizard: ${e.message}`); + throw new Error(`Error parsing setup-wizard: ${e.message}`, { cause: e }); } } diff --git a/src/tasks/buildAndUpload/generatePackagesProps.ts b/src/tasks/buildAndUpload/generatePackagesProps.ts index 8a44b115..9a1fbc8e 100644 --- a/src/tasks/buildAndUpload/generatePackagesProps.ts +++ b/src/tasks/buildAndUpload/generatePackagesProps.ts @@ -112,7 +112,7 @@ function getUpstreamVersion({ ); } -function getReleaseDirPath({ +export function getReleaseDirPath({ rootDir, dnpName, version diff --git a/src/tasks/buildAndUpload/getFileCopyTask.ts b/src/tasks/buildAndUpload/getFileCopyTask.ts index 485a065e..040bd5f9 100644 --- a/src/tasks/buildAndUpload/getFileCopyTask.ts +++ b/src/tasks/buildAndUpload/getFileCopyTask.ts @@ -1,4 +1,5 @@ import fs from "fs"; +import yaml from "js-yaml"; import path from "path"; import { ListrTask } from "listr/index.js"; import { verifyAvatar } from "../../utils/verifyAvatar.js"; @@ -56,8 +57,12 @@ async function copyFilesToReleaseDir({ requireGitData?: boolean; }): Promise { for (const variantProps of packagesToBuildProps) { - - await copyVariantFilesToReleaseDir({ variantProps, rootDir, variantsDirPath, composeFileName }); + await copyVariantFilesToReleaseDir({ + variantProps, + rootDir, + variantsDirPath, + composeFileName + }); // Verify avatar (throws) const avatarPath = path.join( @@ -67,7 +72,7 @@ async function copyFilesToReleaseDir({ verifyAvatar(avatarPath); // Make sure git data is available before doing a long build - await getGitHeadIfAvailable({ requireGitData }); + await getGitHeadIfAvailable({ requireGitData, dir: rootDir }); } } @@ -82,14 +87,26 @@ async function copyVariantFilesToReleaseDir({ variantsDirPath: string; composeFileName: string; }): Promise { - const { manifest, manifestFormat, releaseDir, compose, variant } = variantProps; + const { + manifest, + manifestFormat, + releaseDir, + compose, + variant, + notifications, + setupWizard + } = variantProps; // In case of single variant packages, the targets are in the root dir - const variantDirPath = variant ? path.join(variantsDirPath, variant) : rootDir; + const variantDirPath = variant + ? path.join(variantsDirPath, variant) + : rootDir; for (const [fileId, fileConfig] of Object.entries(releaseFiles)) { // For single variant packages, the targets are in the root dir - const dirsToCopy = fs.existsSync(variantDirPath) ? [rootDir, variantDirPath] : [rootDir]; + const dirsToCopy = fs.existsSync(variantDirPath) + ? [rootDir, variantDirPath] + : [rootDir]; switch (fileId as keyof typeof releaseFiles) { case "manifest": @@ -100,35 +117,66 @@ async function copyVariantFilesToReleaseDir({ writeReleaseCompose({ compose, composeFileName, manifest, releaseDir }); break; - case "prometheusTargets": - // Copy the targets in root and in the variant dir - for (const dir of dirsToCopy) { - copyReleaseFile({ - fileConfig: { ...fileConfig, id: fileId }, - fromDir: dir, - toDir: releaseDir - }); - } + case "notifications": + if (notifications) + fs.writeFileSync( + path.join(releaseDir, releaseFilesDefaultNames.notifications), + yaml.dump(notifications) + ); break; - case "notifications": - // Copy the notifications in root and in the variant dir - for (const dir of dirsToCopy) { + case "setupWizard": + if (setupWizard) + fs.writeFileSync( + path.join(releaseDir, releaseFilesDefaultNames.setupWizard), + JSON.stringify(setupWizard, null, 2) + "\n" + ); + break; + + case "prometheusTargets": { + // Only one targets file per release: the variant's replaces the root's, + // because scrape targets differ per variant (docs/dev/metrics.md). + const sourceDir = [...new Set(dirsToCopy)] + .filter(dir => + fs.readdirSync(dir).some(file => fileConfig.regex.test(file)) + ) + .pop(); + if (!sourceDir) break; + const files = fs + .readdirSync(sourceDir) + .filter(file => fileConfig.regex.test(file)); + if (files.length > 1) + throw new Error( + `More than one prometheusTargets file found in ${sourceDir}: ${files.join( + ", " + )}. Only one file can match ${fileConfig.regex}` + ); + // Normalise YAML sources so the released .json file is valid JSON. + const targets = yaml.load( + fs.readFileSync(path.join(sourceDir, files[0]), "utf8") + ); + fs.writeFileSync( + path.join(releaseDir, releaseFilesDefaultNames.prometheusTargets), + JSON.stringify(targets, null, 2) + "\n" + ); + break; + } + + default: { + const candidates = [...new Set(dirsToCopy)].filter(dir => + fs.readdirSync(dir).some(file => fileConfig.regex.test(file)) + ); + const sources = fileConfig.multiple + ? candidates + : [candidates.pop() || rootDir]; + for (const fromDir of sources) copyReleaseFile({ fileConfig: { ...fileConfig, id: fileId }, - fromDir: dir, + fromDir, toDir: releaseDir }); - } - break; - - default: - copyReleaseFile({ - fileConfig: { ...fileConfig, id: fileId }, - fromDir: rootDir, - toDir: releaseDir - }); break; + } } } } diff --git a/src/tasks/buildAndUpload/getFileValidationTask.ts b/src/tasks/buildAndUpload/getFileValidationTask.ts index e431c11b..7672e14f 100644 --- a/src/tasks/buildAndUpload/getFileValidationTask.ts +++ b/src/tasks/buildAndUpload/getFileValidationTask.ts @@ -1,7 +1,6 @@ import { ListrTask } from "listr/index.js"; import { PackageToBuildProps, ListrContextBuild } from "../../types.js"; import { - validateComposeSchema, validateManifestSchema, validateSetupWizardSchema, validateDappnodeCompose, @@ -11,7 +10,9 @@ import { getComposePath, stripComposeVersion as removeComposeVersion } from "../../files/index.js"; +import { cloneDeep } from "lodash-es"; import { CliError } from "../../params.js"; +import { shell, ShellError } from "../../utils/shell.js"; export function getFileValidationTask({ packagesToBuildProps, @@ -24,73 +25,154 @@ export function getFileValidationTask({ }): ListrTask { return { title: `Validate files`, - task: async () => - await validatePackageFiles({ + task: async (ctx, task) => { + const coercions = await validatePackageFiles({ packagesToBuildProps, skipComposeValidation, - stripComposeVersion - }) + stripComposeVersion, + onStatus: message => { + task.output = message; + } + }); + // Release files are written from the validated objects, so coerced values are + // what ships. Keep the warning in the title so it stays visible after completion. + if (coercions.length > 0) + task.title = `Validate files (warning: schema validation changed ${ + coercions.length + } value(s), fix the source files: ${coercions.slice(0, 5).join("; ")}${ + coercions.length > 5 ? "; ..." : "" + })`; + } }; } async function validatePackageFiles({ packagesToBuildProps, skipComposeValidation, - stripComposeVersion + stripComposeVersion, + onStatus }: { packagesToBuildProps: PackageToBuildProps[]; skipComposeValidation?: boolean; stripComposeVersion?: boolean; -}): Promise { - for (const pkgProps of packagesToBuildProps) - await validateVariantFiles( - pkgProps, - skipComposeValidation, - stripComposeVersion + onStatus: (message: string) => void; +}): Promise { + const coercions: string[] = []; + for (const pkgProps of packagesToBuildProps) { + onStatus(`Validating ${pkgProps.manifest.name}`); + coercions.push( + ...(await validateVariantFiles( + pkgProps, + skipComposeValidation, + stripComposeVersion + )) ); + } + return coercions; } async function validateVariantFiles( pkgProps: PackageToBuildProps, skipComposeValidation?: boolean, stripComposeVersion?: boolean -): Promise { - const { - manifest, - compose, - composePaths, - notifications, - setupWizard - } = pkgProps; - - console.log( - `Validating files for ${manifest.name} (version ${manifest.version})` - ); +): Promise { + const { manifest, compose, composePaths, notifications, setupWizard } = + pkgProps; + const coercions: string[] = []; + const label = (file: string) => `${manifest.name} ${file}`; // Validate manifest schema - validateManifestSchema(manifest); + coercions.push( + ...validateReportingCoercions( + label("manifest"), + manifest, + validateManifestSchema + ) + ); validatePackageName(manifest.name); validatePackageVersion(manifest.version); // Validate compose file using docker compose - await validateComposeSchema( - composePaths.map(pathObj => getComposePath(pathObj)) - ); + try { + await shell([ + "docker", + "compose", + ...composePaths.flatMap(spec => ["-f", getComposePath(spec)]), + "config", + "--quiet" + ]); + } catch (e) { + if (!(e instanceof ShellError)) throw e; + throw new CliError(`Invalid compose:\n${e.stderr.trim() || e.message}`); + } // Validate compose file specifically for Dappnode requirements - if (skipComposeValidation) { - console.log(`Skipping Dappnode compose validation for ${manifest.name}`); - } else { + if (!skipComposeValidation) { validateDappnodeCompose(compose, manifest); } // Validate notifications schema - if (notifications) validateNotificationsSchema(notifications); + if (notifications) + coercions.push( + ...validateReportingCoercions( + label("notifications"), + notifications, + validateNotificationsSchema + ) + ); + if (setupWizard) + coercions.push( + ...validateReportingCoercions( + label("setup-wizard"), + setupWizard, + validateSetupWizardSchema + ) + ); // Keep version available for the Dappnode validation above. Stripping is // opt-in while support for versionless Compose files is being tested. if (stripComposeVersion) removeComposeVersion(compose); + return coercions; +} + +/** + * The schemas validate with type coercion, which mutates the object in place. + * Returns a description of every value the validator changed. + */ +export function validateReportingCoercions( + label: string, + value: T, + validate: (value: T) => unknown +): string[] { + const before = cloneDeep(value); + validate(value); + return changedPaths(before, value).map(change => `${label} ${change}`); +} + +function changedPaths(before: unknown, after: unknown, at = ""): string[] { + if ( + before !== null && + after !== null && + typeof before === "object" && + typeof after === "object" + ) { + const keys = new Set([...Object.keys(before), ...Object.keys(after)]); + return [...keys].flatMap(key => + changedPaths( + (before as Record)[key], + (after as Record)[key], + at ? `${at}.${key}` : key + ) + ); + } + return Object.is(before, after) + ? [] + : [ + `${at || "(root)"}: ${JSON.stringify(before)} -> ${JSON.stringify( + after + )}` + ]; } function validatePackageName(name: string): void { diff --git a/src/tasks/publish/subtasks/getUpdateFilesTask.ts b/src/tasks/publish/subtasks/getUpdateFilesTask.ts index 7b72d19e..220aa36f 100644 --- a/src/tasks/publish/subtasks/getUpdateFilesTask.ts +++ b/src/tasks/publish/subtasks/getUpdateFilesTask.ts @@ -1,4 +1,5 @@ import path from "path"; +import { getReleaseDirPath } from "../../buildAndUpload/generatePackagesProps.js"; import { ListrTask } from "listr"; import { PackageToBuildProps, ListrContextPublish } from "../../../types.js"; import { @@ -14,7 +15,7 @@ export function getUpdateFilesTask({ rootDir, variantsDirPath, composeFileName, - packagesToBuildProps, + packagesToBuildProps }: { rootDir: string; variantsDirPath: string; @@ -25,7 +26,12 @@ export function getUpdateFilesTask({ title: "Update compose and manifest files", task: async ctx => { for (const pkgProps of packagesToBuildProps) { - const { variant, manifest: { name }, composePaths, manifestPaths } = pkgProps; + const { + variant, + manifest: { name }, + composePaths, + manifestPaths + } = pkgProps; const nextVersion = ctx[name].nextVersion; if (!nextVersion) { @@ -40,7 +46,7 @@ export function getUpdateFilesTask({ variant, variantsDirPath, dnpName: name, - nextVersion, + nextVersion }); const newCompose = readCompose(composePaths); @@ -49,6 +55,12 @@ export function getUpdateFilesTask({ // Update variantsMap entry pkgProps.compose = newCompose; pkgProps.manifest = newManifest; + pkgProps.releaseDir = getReleaseDirPath({ + rootDir, + dnpName: name, + version: nextVersion + }); + ctx[name].releaseDir = pkgProps.releaseDir; pkgProps.images = getComposePackageImages(newCompose, newManifest); } } @@ -62,7 +74,7 @@ export function updateVariantFiles({ variant, variantsDirPath, dnpName, - nextVersion, + nextVersion }: { rootDir: string; composeFileName: string; @@ -120,10 +132,10 @@ function updateComposeFileImages({ const newCompose = updateComposeImageTags(compose, { name: dnpName, version: nextVersion - }, { editExternalImages: true }); + }); writeCompose(newCompose, { dir: composeDir, composeFileName }); -} \ No newline at end of file +} diff --git a/src/utils/copyReleaseFile.ts b/src/utils/copyReleaseFile.ts index 42f83eee..2c2c55a2 100644 --- a/src/utils/copyReleaseFile.ts +++ b/src/utils/copyReleaseFile.ts @@ -37,7 +37,12 @@ export function copyReleaseFile({ } else if (matchingFiles.length === 1) { fs.copyFileSync( path.join(fromDir, matchingFiles[0]), - path.join(toDir, getDefaultName(fileConfig.id) || matchingFiles[0]) + path.join( + toDir, + (fileConfig.multiple + ? matchingFiles[0] + : getDefaultName(fileConfig.id)) || matchingFiles[0] + ) ); } else { if (fileConfig.multiple) { diff --git a/src/utils/merge.ts b/src/utils/merge.ts new file mode 100644 index 00000000..fbcfe573 --- /dev/null +++ b/src/utils/merge.ts @@ -0,0 +1,12 @@ +import { cloneDeep, mergeWith } from "lodash-es"; + +/** + * Deep merge where an array from a later source replaces the earlier array. + * lodash `merge` combines arrays by index, so root `enum: [a, b, c]` plus a + * variant `enum: [mainnet]` would become `[mainnet, b, c]`, which neither file declares. + */ +export function mergeReplacingArrays(...sources: unknown[]): T { + return mergeWith({}, ...sources, (_base: unknown, override: unknown) => + Array.isArray(override) ? cloneDeep(override) : undefined + ); +} diff --git a/test/files/variantMerge.test.ts b/test/files/variantMerge.test.ts new file mode 100644 index 00000000..3c9dde8c --- /dev/null +++ b/test/files/variantMerge.test.ts @@ -0,0 +1,87 @@ +import fs from "fs"; +import path from "path"; +import yaml from "js-yaml"; +import { expect } from "chai"; +import { readSetupWizardIfExists } from "../../src/files/setupWizard/readSetupWizardIfExists.js"; +import { readNotificationsIfExists } from "../../src/files/notifications/readNotificationsIfExists.js"; +import { temporaryDirectory } from "../helpers/fixtures.js"; + +describe("root and variant config merging", () => { + let root: string; + let variant: string; + beforeEach(() => { + root = temporaryDirectory(); + variant = path.join(root, "package_variants", "mainnet"); + fs.mkdirSync(variant, { recursive: true }); + }); + afterEach(() => fs.rmSync(root, { recursive: true, force: true })); + + it("replaces arrays inside a setup-wizard field instead of merging them by index", () => { + fs.writeFileSync( + path.join(root, "setup-wizard.yml"), + yaml.dump({ + version: "2", + fields: [ + { + id: "network", + title: "Network", + description: "Root description", + enum: ["a", "b", "c"] + } + ] + }) + ); + fs.writeFileSync( + path.join(variant, "setup-wizard.yml"), + yaml.dump({ + version: "2", + fields: [{ id: "network", enum: ["mainnet"] }] + }) + ); + const wizard = readSetupWizardIfExists([{ dir: root }, { dir: variant }]); + expect(wizard?.fields).to.deep.equal([ + { + id: "network", + title: "Network", + description: "Root description", + enum: ["mainnet"] + } + ]); + }); + + it("replaces arrays inside a notification endpoint instead of merging them by index", () => { + const endpoint = { + name: "Health", + enabled: true, + url: "http://pkg.dappnode:8080", + method: "GET", + conditions: ["[STATUS] == 200", "[RESPONSE_TIME] < 500"], + interval: "1m", + group: "pkg", + alerts: [], + definition: { title: "Health", description: "Health check" }, + metric: { min: 0, max: 1, unit: "s" }, + correlationId: "pkg-health", + isBanner: false + }; + fs.writeFileSync( + path.join(root, "notifications.yaml"), + yaml.dump({ endpoints: [endpoint] }) + ); + fs.writeFileSync( + path.join(variant, "notifications.yaml"), + yaml.dump({ + endpoints: [ + { correlationId: "pkg-health", conditions: ["[STATUS] == 204"] } + ] + }) + ); + const notifications = readNotificationsIfExists([ + { dir: root }, + { dir: variant } + ]); + expect(notifications?.endpoints).to.deep.equal([ + { ...endpoint, conditions: ["[STATUS] == 204"] } + ]); + }); +}); diff --git a/test/tasks/buildAndUpload/packageArtifacts.test.ts b/test/tasks/buildAndUpload/packageArtifacts.test.ts new file mode 100644 index 00000000..26c1bfde --- /dev/null +++ b/test/tasks/buildAndUpload/packageArtifacts.test.ts @@ -0,0 +1,235 @@ +import fs from "fs"; +import path from "path"; +import yaml from "js-yaml"; +import { expect } from "chai"; +import Listr from "listr"; +import { initHandler } from "../../../src/commands/init/handler.js"; +import { generatePackagesProps } from "../../../src/tasks/buildAndUpload/generatePackagesProps.js"; +import { getFileCopyTask } from "../../../src/tasks/buildAndUpload/getFileCopyTask.js"; +import { getFileValidationTask } from "../../../src/tasks/buildAndUpload/getFileValidationTask.js"; +import { getUpdateFilesTask } from "../../../src/tasks/publish/subtasks/getUpdateFilesTask.js"; +import { + readManifest, + readSetupWizardIfExists +} from "../../../src/files/index.js"; +import { ManifestFormat } from "../../../src/files/manifest/types.js"; +import { + temporaryDirectory, + executable, + useExecutables +} from "../../helpers/fixtures.js"; + +describe("template and generic package artifacts", () => { + let dir: string; + let variantsDirPath: string; + beforeEach(async () => { + dir = temporaryDirectory(); + await initHandler({ dir, yes: true, force: true, use_variants: true }); + variantsDirPath = path.join(dir, "package_variants"); + }); + afterEach(() => fs.rmSync(dir, { recursive: true, force: true })); + + it("packages the merged wizard and notifications, with variant asset overrides", async () => { + const variantDir = path.join(variantsDirPath, "mainnet"); + fs.writeFileSync( + path.join(dir, "setup-wizard.json"), + JSON.stringify({ + version: "2", + fields: [ + { id: "shared", title: "Shared", description: "Shared field" }, + { id: "replace", title: "Old", description: "Preserved description" } + ] + }) + ); + fs.writeFileSync( + path.join(variantDir, "setup-wizard.yaml"), + yaml.dump({ + version: "2", + fields: [ + { id: "replace", title: "Variant" }, + { id: "new", title: "New", description: "New field" } + ] + }) + ); + fs.writeFileSync( + path.join(dir, "notifications.yaml"), + yaml.dump({ + customEndpoints: [ + { + name: "shared", + correlationId: "shared", + description: "shared", + enabled: true, + isBanner: false + } + ] + }) + ); + fs.writeFileSync( + path.join(variantDir, "notifications.yaml"), + yaml.dump({ + customEndpoints: [ + { + name: "variant", + correlationId: "variant", + description: "variant", + enabled: true, + isBanner: false + } + ] + }) + ); + fs.writeFileSync(path.join(dir, "disclaimer.md"), "shared disclaimer"); + fs.writeFileSync( + path.join(variantDir, "disclaimer.md"), + "variant disclaimer" + ); + fs.writeFileSync( + path.join(dir, "prometheus-targets.json"), + JSON.stringify([ + { targets: ["shared:9090"], labels: { network: "shared" } } + ]) + ); + fs.writeFileSync( + path.join(variantDir, "prometheus-targets.yaml"), + yaml.dump([{ targets: ["variant:9090"], labels: { network: "variant" } }]) + ); + const packages = generatePackagesProps({ + variants: ["mainnet"], + rootDir: dir, + variantsDirPath + }); + const pkg = packages[0]; + fs.mkdirSync(pkg.releaseDir, { recursive: true }); + await new Listr( + [ + getFileCopyTask({ + packagesToBuildProps: packages, + rootDir: dir, + variantsDirPath, + composeFileName: "docker-compose.yml" + }) + ], + { renderer: "silent" } + ).run(); + // The variant's targets replace the root's (e.g. a stale root template in + // erigon-generic must not be scraped); YAML sources are released as JSON. + expect( + JSON.parse( + fs.readFileSync( + path.join(pkg.releaseDir, "prometheus-targets.json"), + "utf8" + ) + ) + ).to.deep.equal([ + { targets: ["variant:9090"], labels: { network: "variant" } } + ]); + const wizard = JSON.parse( + fs.readFileSync(path.join(pkg.releaseDir, "setup-wizard.json"), "utf8") + ); + expect( + wizard.fields.map((field: { id: string }) => field.id) + ).to.deep.equal(["shared", "replace", "new"]); + expect(wizard.fields[1]).to.include({ + title: "Variant", + description: "Preserved description" + }); + expect( + yaml.load( + fs.readFileSync(path.join(pkg.releaseDir, "notifications.yaml"), "utf8") + ) + ).to.deep.equal(pkg.notifications); + expect( + fs.readFileSync(path.join(pkg.releaseDir, "disclaimer.md"), "utf8") + ).to.equal("variant disclaimer"); + }); + + it("preserves an upstream image and updates the release directory when publishing", async () => { + const packages = generatePackagesProps({ + variants: ["mainnet"], + rootDir: dir, + variantsDirPath + }); + const pkg = packages[0]; + const composePath = path.join( + variantsDirPath, + "mainnet", + "docker-compose.yml" + ); + fs.writeFileSync( + composePath, + yaml.dump({ + version: "3.5", + services: { external: { image: "alpine:3.21" } } + }) + ); + const ctx = { + [pkg.manifest.name]: { + nextVersion: "0.1.2", + releaseDir: pkg.releaseDir, + variant: pkg.variant + } + }; + await new Listr( + [ + getUpdateFilesTask({ + rootDir: dir, + variantsDirPath, + composeFileName: "docker-compose.yml", + packagesToBuildProps: packages + }) + ], + { renderer: "silent" } + ).run(ctx); + expect(pkg.images.find(image => image.type === "external")).to.include({ + originalImageTag: "alpine:3.21" + }); + expect(pkg.manifest.version).to.equal("0.1.2"); + expect(pkg.releaseDir).to.equal( + path.join(dir, `build_${pkg.manifest.name}_0.1.2`) + ); + expect(ctx[pkg.manifest.name].releaseDir).to.equal(pkg.releaseDir); + }); + + it("accepts a single YAML manifest without invoking template-only restrictions", () => { + const file = path.join(dir, "single.yaml"); + fs.writeFileSync(file, "name: demo.public.dappnode.eth\nversion: 0.1.0\n"); + expect( + readManifest([{ dir, manifestFileName: "single.yaml" }]).format + ).to.equal(ManifestFormat.yaml); + }); + + it("accepts JSON setup wizards and rejects invalid wizard schemas", async () => { + fs.writeFileSync( + path.join(dir, "setup-wizard.json"), + '{"version":"2","fields":[]}' + ); + expect(readSetupWizardIfExists([{ dir }])).to.deep.equal({ + version: "2", + fields: [] + }); + const packages = generatePackagesProps({ + variants: ["mainnet"], + rootDir: dir, + variantsDirPath + }); + packages[0].setupWizard = { + version: "2", + fields: [{ id: "missing-title" }] + } as never; + const bin = path.join(dir, "bin"); + executable(bin, "docker", "process.exit(0);"); + const restore = useExecutables(bin); + try { + const error = await new Listr( + [getFileValidationTask({ packagesToBuildProps: packages })], + { renderer: "silent" } + ) + .run() + .catch(error => error); + expect(error.message).to.include("Invalid setupWizard"); + } finally { + restore(); + } + }); +}); diff --git a/test/tasks/buildAndUpload/validationCoercion.test.ts b/test/tasks/buildAndUpload/validationCoercion.test.ts new file mode 100644 index 00000000..8187002b --- /dev/null +++ b/test/tasks/buildAndUpload/validationCoercion.test.ts @@ -0,0 +1,53 @@ +import { expect } from "chai"; +import { validateNotificationsSchema } from "@dappnode/schemas"; +import { validateReportingCoercions } from "../../../src/tasks/buildAndUpload/getFileValidationTask.js"; + +describe("schema coercion warnings", () => { + it("reports values the schema validator coerced in place", () => { + // DAppNodePackage-DMS ships `isBanner: "false"`, a truthy string for consumers. + const notifications = { + endpoints: [ + { + name: "Health", + enabled: true, + url: "http://pkg.dappnode:8080", + method: "GET", + conditions: ["[STATUS] == 200"], + interval: "1m", + group: "pkg", + priority: "medium", + alerts: [ + { + type: "custom", + enabled: true, + description: "Health failed", + "failure-threshold": 2, + "success-threshold": 1, + "send-on-resolved": true + } + ], + definition: { title: "Health", description: "Health check" }, + metric: { min: 0, max: 1, unit: "s" }, + correlationId: "pkg-health", + isBanner: "false" + } + ] + }; + const changes = validateReportingCoercions( + "pkg notifications", + notifications as never, + validateNotificationsSchema + ); + expect(notifications.endpoints[0].isBanner).to.equal(false); + expect(changes).to.deep.equal([ + 'pkg notifications endpoints.0.isBanner: "false" -> false' + ]); + }); + + it("reports nothing when the source is already well typed", () => { + const wizard = { version: "2", fields: [] }; + expect( + validateReportingCoercions("pkg wizard", wizard, () => undefined) + ).to.deep.equal([]); + }); +}); diff --git a/test/utils/versions/updateVariantFiles.test.ts b/test/utils/versions/updateVariantFiles.test.ts index 9e4e9edf..2194f5f7 100644 --- a/test/utils/versions/updateVariantFiles.test.ts +++ b/test/utils/versions/updateVariantFiles.test.ts @@ -2,61 +2,65 @@ import { expect } from "chai"; import { cleanTestDir, testDir } from "../../testUtils.js"; import { defaultComposeFileName } from "../../../src/params.js"; import { - writeManifest, - readCompose, - writeCompose, - readManifest + writeManifest, + readCompose, + writeCompose, + readManifest } from "../../../src/files/index.js"; import { Compose, Manifest } from "@dappnode/types"; import { ManifestFormat } from "../../../src/files/manifest/types.js"; -import { updateVariantFiles, } from "../../../src/tasks/publish/subtasks/getUpdateFilesTask.js"; - +import { updateVariantFiles } from "../../../src/tasks/publish/subtasks/getUpdateFilesTask.js"; describe("Update Variant Files and Entries", function () { - this.timeout(60 * 1000); - - const dnpName = "admin.dnp.dappnode.eth"; - - const manifest: Manifest = { - name: dnpName, - version: "0.1.0", - type: "dncore" - }; - - const compose: Compose = { - version: "3.8", - services: { [dnpName]: { image: "override-me" } } - }; - - const nextVersion = "0.1.1"; - - before("Clean testDir", () => cleanTestDir()); - after("Clean testDir", () => cleanTestDir()); - - it("Should update manifest and compose files correctly for a single variant package", async () => { - // Write initial manifest and compose files - writeManifest(manifest, ManifestFormat.json, { dir: testDir }); - writeCompose(compose, { dir: testDir }); - - // Update variant files - updateVariantFiles({ - rootDir: testDir, - composeFileName: defaultComposeFileName, - variant: null, - variantsDirPath: testDir, - dnpName, - nextVersion, - }); - - // Check that the manifest was updated correctly - const { manifest: newManifest } = readManifest([{ dir: testDir }]); - expect(newManifest.version).to.equal(nextVersion, "Manifest version should be updated to the next version"); - - // Check that the compose was updated correctly - const updatedCompose = readCompose([{ dir: testDir, composeFileName: defaultComposeFileName }]); - expect(updatedCompose.services[dnpName].image).to.equal( - `${dnpName}:${nextVersion}`, - "Compose image should be updated to the next version" - ); + this.timeout(60 * 1000); + + const dnpName = "admin.dnp.dappnode.eth"; + + const manifest: Manifest = { + name: dnpName, + version: "0.1.0", + type: "dncore" + }; + + const compose: Compose = { + version: "3.8", + services: { [dnpName]: { image: "override-me" } } + }; + + const nextVersion = "0.1.1"; + + before("Clean testDir", () => cleanTestDir()); + after("Clean testDir", () => cleanTestDir()); + + it("Should update manifest and compose files correctly for a single variant package", async () => { + // Write initial manifest and compose files + writeManifest(manifest, ManifestFormat.json, { dir: testDir }); + writeCompose(compose, { dir: testDir }); + + // Update variant files + updateVariantFiles({ + rootDir: testDir, + composeFileName: defaultComposeFileName, + variant: null, + variantsDirPath: testDir, + dnpName, + nextVersion }); + + // Check that the manifest was updated correctly + const { manifest: newManifest } = readManifest([{ dir: testDir }]); + expect(newManifest.version).to.equal( + nextVersion, + "Manifest version should be updated to the next version" + ); + + // Check that the compose was updated correctly + const updatedCompose = readCompose([ + { dir: testDir, composeFileName: defaultComposeFileName } + ]); + expect(updatedCompose.services[dnpName].image).to.equal( + "override-me", + "External source image must remain unchanged" + ); + }); }); From 0d83ef045a8042daea2a360153366a9646b282cf Mon Sep 17 00:00:00 2001 From: 3alpha <15694175+3alpha@users.noreply.github.com> Date: Wed, 4 Nov 2026 22:19:36 +0100 Subject: [PATCH 08/15] Only unpin releases that were actually replaced - Old pins are deleted only after the replacement upload succeeded, and only for commits that are ancestors of the current commit. - On shallow CI checkouts the missing history is fetched once before checking. Commits that are still unknown are never unpinned. - Branch cleanup paginates Pinata pins, rechecks each allegedly deleted branch before unpinning, and handles template packages per variant. --- .../build/cleanPinsFromDeletedBranches.ts | 45 +++-- src/pinStrategy/index.ts | 69 +++++++- src/pinStrategy/types.ts | 3 +- src/providers/pinata/pinManager.ts | 40 +++-- .../buildAndUpload/getDeleteOldPinsTask.ts | 20 ++- test/pinStrategySafety.test.ts | 166 ++++++++++++++++++ 6 files changed, 309 insertions(+), 34 deletions(-) create mode 100644 test/pinStrategySafety.test.ts diff --git a/src/commands/githubActions/build/cleanPinsFromDeletedBranches.ts b/src/commands/githubActions/build/cleanPinsFromDeletedBranches.ts index 95ff8592..fca63313 100644 --- a/src/commands/githubActions/build/cleanPinsFromDeletedBranches.ts +++ b/src/commands/githubActions/build/cleanPinsFromDeletedBranches.ts @@ -1,3 +1,6 @@ +import path from "path"; +import { defaultVariantsDirName } from "../../../params.js"; +import { getAllVariantsInPath } from "../../../files/variants/getAllPackageVariants.js"; import { fetchPinsGroupedByBranch } from "../../../pinStrategy/index.js"; import { cliArgsToReleaseUploaderProvider } from "../../../releaseUploader/index.js"; import { Github } from "../../../providers/github/Github.js"; @@ -8,13 +11,26 @@ import { readManifest } from "../../../files/index.js"; * Removes all pins associated with a branch that no longer exists */ export async function cleanPinsFromDeletedBranches({ - dir + dir, + variantsDirName = defaultVariantsDirName }: { dir: string; + variantsDirName?: string; }): Promise { // Read manifest from disk to get package name const { manifest } = readManifest([{ dir }]); + const variantsPath = path.join(dir, variantsDirName); + const manifests = manifest.name + ? [manifest] + : getAllVariantsInPath(variantsPath).map( + variant => + readManifest([{ dir }, { dir: path.join(variantsPath, variant) }]) + .manifest + ); + if (manifests.some(item => !item.name)) + throw new Error("Cannot clean pins without a package name"); + // Connect to Github Octokit REST API to know existing branches const github = Github.fromLocal(dir); const branches = await github.listBranches(); @@ -28,17 +44,24 @@ export async function cleanPinsFromDeletedBranches({ throw Error("Must use pinata for deletePins"); const pinata = new PinataPinManager(releaseUploaderProvider); - const pinsGroupedByBranch = await fetchPinsGroupedByBranch(pinata, manifest); - for (const { branch, pins } of pinsGroupedByBranch) { - if (branches.find(b => b.name === branch)) continue; + for (const manifest of manifests) { + const pinsGroupedByBranch = await fetchPinsGroupedByBranch( + pinata, + manifest + ); + for (const { branch, pins } of pinsGroupedByBranch) { + if (branches.find(b => b.name === branch)) continue; + // A branch may have been created after the list was fetched. Fail closed. + if (await github.branchExists(branch)) continue; - // Branch not found, delete all associated pins - for (const pin of pins) { - console.log(`Unpin ${pin.commit} ${pin.ipfsHash}`); - await pinata.unpin(pin.ipfsHash).catch(e => { - // Don't prevent unpinning other pins if one is faulty - console.error(`Error on unpin ${pin.ipfsHash}`, e); - }); + // Branch not found, delete all associated pins + for (const pin of pins) { + console.log(`Unpin ${pin.commit} ${pin.ipfsHash}`); + await pinata.unpin(pin.ipfsHash).catch(e => { + // Don't prevent unpinning other pins if one is faulty + console.error(`Error on unpin ${pin.ipfsHash}`, e); + }); + } } } } diff --git a/src/pinStrategy/index.ts b/src/pinStrategy/index.ts index 8641fe3a..0ba2f5ef 100644 --- a/src/pinStrategy/index.ts +++ b/src/pinStrategy/index.ts @@ -1,6 +1,7 @@ import { PinataMetadata } from "../releaseUploader/pinata/index.js"; import { PinataPinManager } from "../providers/pinata/pinManager.js"; import { GitHead } from "../utils/git.js"; +import { shell } from "../utils/shell.js"; import { prettyPinataPinName } from "../utils/format.js"; import { DnpPinMetadata, PinDataSummary, PinsByBranch } from "./types.js"; import { groupPinsByBranch } from "./utils.js"; @@ -79,8 +80,72 @@ export async function fetchPinsGroupedByBranch( export async function fetchPinsWithBranchToDelete( pinata: PinataPinManager, manifest: Manifest, - gitHead: GitHead + gitHead: GitHead, + dir?: string ): Promise { const pins = await fetchPinsWithBranch(pinata, manifest, gitHead); - return pins.filter(pin => pin.commit && pin.commit !== gitHead.commit); + const candidates = pins.filter( + pin => + pin.commit && + pin.commit !== gitHead.commit && + /^[a-f0-9]{7,64}$/i.test(pin.commit) + ); + const ancestorOf = (commit: string) => + isAncestorCommit(commit, gitHead.commit, dir); + + let results = await Promise.all( + candidates.map(pin => ancestorOf(pin.commit as string)) + ); + // CI checkouts are usually shallow (depth 1), so older pin commits are unknown locally. + // Fetch the missing history once and re-check only the unresolved commits. + if (results.includes("unknown") && (await deepenShallowHistory(dir))) + results = await Promise.all( + candidates.map((pin, index) => + results[index] === "unknown" + ? ancestorOf(pin.commit as string) + : results[index] + ) + ); + // A commit that is still unknown (rewritten, foreign or unfetchable) must never cause an unpin. + return candidates.filter((pin, index) => results[index] === "ancestor"); +} + +type AncestryResult = "ancestor" | "not-ancestor" | "unknown"; + +/** `git merge-base --is-ancestor` exits 0 (yes), 1 (no) or 128 (unknown object). */ +async function isAncestorCommit( + commit: string, + head: string, + dir?: string +): Promise { + try { + await shell(["git", "merge-base", "--is-ancestor", commit, head], { + cwd: dir + }); + return "ancestor"; + } catch (e) { + return e.code === 1 ? "not-ancestor" : "unknown"; + } +} + +/** Returns true if the repository was shallow and its full history was fetched. */ +async function deepenShallowHistory(dir?: string): Promise { + try { + const shallow = await shell( + ["git", "rev-parse", "--is-shallow-repository"], + { cwd: dir } + ); + if (shallow.trim() !== "true") return false; + await shell( + ["git", "fetch", "--unshallow", "--no-tags", "--quiet", "origin"], + { + cwd: dir, + timeout: 10 * 60 * 1000 + } + ); + return true; + } catch (e) { + console.warn(`Could not fetch git history to check old pins: ${e.message}`); + return false; + } } diff --git a/src/pinStrategy/types.ts b/src/pinStrategy/types.ts index aebccdac..704d34ea 100644 --- a/src/pinStrategy/types.ts +++ b/src/pinStrategy/types.ts @@ -4,7 +4,8 @@ export interface DnpPinMetadata { dnpName: string; version: string; - upstreamVersion: string | undefined | string[]; + upstreamVersion: string | undefined; + [key: string]: string | undefined; commit: string | undefined; branch: string | undefined; } diff --git a/src/providers/pinata/pinManager.ts b/src/providers/pinata/pinManager.ts index 093dfec8..63de1335 100644 --- a/src/providers/pinata/pinManager.ts +++ b/src/providers/pinata/pinManager.ts @@ -51,24 +51,32 @@ export class PinataPinManager { // Fetch only "pinned" items by default searchParams["status"] = filters?.status || "pinned"; - // Note: Results in rows will be limited to 1000, in case of needing more pagination should be implemented try { - const result: { - count: number; - rows: PinItem[]; - } = await got - .get({ - prefixUrl: this.pinataUrl, - url: "data/pinList", - headers: { - pinata_api_key: this.apiKey, - pinata_secret_api_key: this.secretApiKey - }, - searchParams - }) - .json(); + const pins: PinItem[] = []; + while (true) { + const result: { + count: number; + rows: PinItem[]; + } = await got + .get({ + prefixUrl: this.pinataUrl, + url: "data/pinList", + headers: { + pinata_api_key: this.apiKey, + pinata_secret_api_key: this.secretApiKey + }, + searchParams: { + ...searchParams, + pageLimit: "1000", + pageOffset: String(pins.length) + } + }) + .json(); - return result.rows; + pins.push(...result.rows); + if (result.rows.length === 0 || pins.length >= result.count) + return pins; + } } catch (e) { e.message = `Error on Pinata pinList: ${e.message}`; throw e; diff --git a/src/tasks/buildAndUpload/getDeleteOldPinsTask.ts b/src/tasks/buildAndUpload/getDeleteOldPinsTask.ts index 4d253cea..a59b4dda 100644 --- a/src/tasks/buildAndUpload/getDeleteOldPinsTask.ts +++ b/src/tasks/buildAndUpload/getDeleteOldPinsTask.ts @@ -17,22 +17,34 @@ export function getDeleteOldPinsTask({ return { title: "Delete old pins", enabled: () => deleteOldPins, - task: async (_, task) => { - const gitHead = await getGitHead(); + skip: ctx => + !packagesToBuildProps.some( + pkg => ctx[pkg.manifest.name]?.releaseMultiHash + ), + task: async (ctx, task) => { if (releaseUploaderProvider.type !== "pinata") throw Error("Must use pinata for deleteOldPins"); // Unpin items on the same branch but previous (ancestor) commits const pinata = new PinataPinManager(releaseUploaderProvider); - for (const { manifest } of packagesToBuildProps) { + for (const { manifest, manifestPaths } of packagesToBuildProps) { + // Never remove the previous release until its replacement was uploaded. + if (!ctx[manifest.name]?.releaseMultiHash) continue; + const gitHead = await getGitHead(manifestPaths[0]?.dir); const pinsToDelete = await fetchPinsWithBranchToDelete( pinata, manifest, - gitHead + gitHead, + manifestPaths[0]?.dir ); for (const pin of pinsToDelete) { + if ( + pin.ipfsHash === + ctx[manifest.name].releaseMultiHash?.replace(/^\/ipfs\//, "") + ) + continue; task.output = `Unpinning previous commit ${pin.commit} ${pin.ipfsHash}`; await pinata.unpin(pin.ipfsHash).catch(e => { console.error(`Error deleting old pin ${pin.ipfsHash}`, e); diff --git a/test/pinStrategySafety.test.ts b/test/pinStrategySafety.test.ts new file mode 100644 index 00000000..786fcd38 --- /dev/null +++ b/test/pinStrategySafety.test.ts @@ -0,0 +1,166 @@ +import fs from "fs"; +import { execFileSync } from "child_process"; +import path from "path"; +import { mock } from "node:test"; +import { expect } from "chai"; +import Listr from "listr"; +import { fetchPinsWithBranchToDelete } from "../src/pinStrategy/index.js"; +import { PinataPinManager } from "../src/providers/pinata/pinManager.js"; +import { Github } from "../src/providers/github/Github.js"; +import { cleanPinsFromDeletedBranches } from "../src/commands/githubActions/build/cleanPinsFromDeletedBranches.js"; +import { getDeleteOldPinsTask } from "../src/tasks/buildAndUpload/getDeleteOldPinsTask.js"; +import { + executable, + temporaryDirectory, + useExecutables +} from "./helpers/fixtures.js"; + +const manifest = { name: "demo.public.dappnode.eth", version: "0.1.0" }; +describe("safe pin cleanup", () => { + let dir: string; + let restorePath: () => void; + const originalKey = process.env.PINATA_API_KEY; + const originalSecret = process.env.PINATA_SECRET_API_KEY; + beforeEach(() => { + dir = temporaryDirectory(); + fs.writeFileSync( + path.join(dir, "dappnode_package.json"), + JSON.stringify(manifest) + ); + executable( + dir, + "git", + `const args = process.argv.slice(2); if (args[0] === 'merge-base') process.exit(args[2] === '1111111' ? 0 : 1); console.log(args.includes('--abbrev-ref') ? 'feature' : '2222222');` + ); + restorePath = useExecutables(dir); + process.env.PINATA_API_KEY = "fake"; + process.env.PINATA_SECRET_API_KEY = "fake"; + }); + afterEach(() => { + mock.restoreAll(); + restorePath(); + fs.rmSync(dir, { recursive: true, force: true }); + if (originalKey === undefined) delete process.env.PINATA_API_KEY; + else process.env.PINATA_API_KEY = originalKey; + if (originalSecret === undefined) delete process.env.PINATA_SECRET_API_KEY; + else process.env.PINATA_SECRET_API_KEY = originalSecret; + }); + + it("only deletes known ancestor commits, preserving concurrent newer builds", async () => { + const pinata = { + pinList: async () => + ["1111111", "2222222", "3333333", "invalid"].map(commit => ({ + ipfs_pin_hash: commit, + metadata: { keyvalues: { commit } } + })) + } as unknown as PinataPinManager; + const pins = await fetchPinsWithBranchToDelete( + pinata, + manifest, + { branch: "feature", commit: "2222222" }, + dir + ); + expect(pins.map(pin => pin.commit)).to.deep.equal(["1111111"]); + }); + + it("rechecks allegedly deleted branches before unpinning", async () => { + mock.method(Github, "fromLocal", () => ({ + listBranches: async () => [], + branchExists: async (branch: string) => branch === "active" + })); + mock.method(PinataPinManager.prototype, "pinList", async () => + ["active", "removed"].map(branch => ({ + ipfs_pin_hash: branch, + metadata: { keyvalues: { branch, commit: "1111111" } } + })) + ); + const removed: string[] = []; + mock.method(PinataPinManager.prototype, "unpin", async (hash: string) => { + removed.push(hash); + }); + await cleanPinsFromDeletedBranches({ dir }); + expect(removed).to.deep.equal(["removed"]); + }); + + it("does not delete old pins if no replacement was uploaded", async () => { + let lookedUp = false; + mock.method(PinataPinManager.prototype, "pinList", async () => { + lookedUp = true; + return []; + }); + await new Listr( + [ + getDeleteOldPinsTask({ + packagesToBuildProps: [ + { manifest, manifestPaths: [{ dir }] } + ] as never, + deleteOldPins: true, + releaseUploaderProvider: { + network: "ipfs", + type: "pinata", + apiKey: "fake", + secretApiKey: "fake" + } + }) + ], + { renderer: "silent" } + ).run({}); + expect(lookedUp).to.equal(false); + }); +}); + +describe("old pin cleanup on shallow CI checkouts", function () { + this.timeout(30000); + let root: string; + const git = (cwd: string, ...args: string[]): string => + execFileSync( + "git", + ["-c", "commit.gpgsign=false", "-c", "tag.gpgsign=false", ...args], + { + cwd, + encoding: "utf8", + env: { + ...process.env, + GIT_AUTHOR_NAME: "test", + GIT_AUTHOR_EMAIL: "test@example.com", + GIT_COMMITTER_NAME: "test", + GIT_COMMITTER_EMAIL: "test@example.com" + } + } + ).trim(); + + beforeEach(() => (root = temporaryDirectory())); + afterEach(() => fs.rmSync(root, { recursive: true, force: true })); + + it("fetches missing history so ancestor pins are deleted, never unknown ones", async () => { + const origin = path.join(root, "origin"); + fs.mkdirSync(origin); + git(origin, "init", "--quiet", "--initial-branch=feature"); + const commits: string[] = []; + for (const n of [1, 2, 3]) { + fs.writeFileSync(path.join(origin, "file"), String(n)); + git(origin, "add", "file"); + git(origin, "commit", "--quiet", "-m", `commit ${n}`); + commits.push(git(origin, "rev-parse", "HEAD")); + } + const clone = path.join(root, "clone"); + git(root, "clone", "--quiet", "--depth=1", `file://${origin}`, clone); + expect(git(clone, "rev-parse", "--is-shallow-repository")).to.equal("true"); + + const foreign = "f".repeat(40); + const pinata = { + pinList: async () => + [...commits, foreign].map(commit => ({ + ipfs_pin_hash: commit, + metadata: { keyvalues: { commit } } + })) + } as unknown as PinataPinManager; + const pins = await fetchPinsWithBranchToDelete( + pinata, + manifest, + { branch: "feature", commit: commits[2] }, + clone + ); + expect(pins.map(pin => pin.commit)).to.deep.equal(commits.slice(0, 2)); + }); +}); From 2a2689a810d35f28d2308e8a370e601984d11c7a Mon Sep 17 00:00:00 2001 From: 3alpha <15694175+3alpha@users.noreply.github.com> Date: Wed, 4 Nov 2026 22:19:36 +0100 Subject: [PATCH 09/15] Show the pinning phase and use an idle timeout for uploads Uploads report when all bytes are sent and then show the time spent waiting for pinning confirmation. Requests now abort only after 15 minutes without socket activity instead of at a fixed total, so slow but healthy uploads of large releases are not cut off. HTTP/2 is kept for IPFS uploads. The Swarm upload URL is relative to prefixUrl. --- src/releaseUploader/interface.ts | 1 + src/releaseUploader/ipfsNode/addFromFs.ts | 7 +- src/releaseUploader/ipfsNode/index.ts | 11 +- src/releaseUploader/pinata/addDirFromFs.ts | 10 +- src/releaseUploader/pinata/index.ts | 7 +- src/releaseUploader/swarmNode/addDirFromFs.ts | 11 +- src/releaseUploader/swarmNode/index.ts | 11 +- src/tasks/buildAndUpload/getUploadTasks.ts | 34 +++-- test/tasks/uploadProgress.test.ts | 121 ++++++++++++++++++ 9 files changed, 193 insertions(+), 20 deletions(-) create mode 100644 test/tasks/uploadProgress.test.ts diff --git a/src/releaseUploader/interface.ts b/src/releaseUploader/interface.ts index 40097035..e78b1e6e 100644 --- a/src/releaseUploader/interface.ts +++ b/src/releaseUploader/interface.ts @@ -15,6 +15,7 @@ export interface IReleaseUploader { dirPath: string; metadata: PinataMetadata; onProgress?: (percent: number) => void; + onUploadComplete?: () => void; }): Promise; /** diff --git a/src/releaseUploader/ipfsNode/addFromFs.ts b/src/releaseUploader/ipfsNode/addFromFs.ts index 1a338db3..ee8c06ba 100644 --- a/src/releaseUploader/ipfsNode/addFromFs.ts +++ b/src/releaseUploader/ipfsNode/addFromFs.ts @@ -1,4 +1,5 @@ import { got } from "got"; +import { uploadTimeout } from "../utils/uploadTimeout.js"; import { normalizeIpfsProvider } from "./ipfsProvider.js"; import { getFormDataFileUpload } from "../utils/formDataFileUpload.js"; @@ -12,7 +13,8 @@ import { getFormDataFileUpload } from "../utils/formDataFileUpload.js"; export async function ipfsAddFromFs( dirOrFilePath: string, ipfsProvider: string, - onProgress?: (percent: number) => void + onProgress?: (percent: number) => void, + onUploadComplete?: () => void ): Promise { // Create form and append all files recursively const form = getFormDataFileUpload(dirOrFilePath); @@ -26,6 +28,8 @@ export async function ipfsAddFromFs( method: "POST", headers: form.getHeaders(), body: form, + timeout: uploadTimeout, + retry: { limit: 0 }, http2: true }).on("uploadProgress", progress => { // Report upload progress, and throttle to one update per percent point @@ -35,6 +39,7 @@ export async function ipfsAddFromFs( lastPercent = currentRoundPercent; if (onProgress) onProgress(progress.percent); } + if (progress.percent === 1) onUploadComplete?.(); }); // res.body = '{"Name":"dir/file","Hash":"Qm...","Size":"2203"}\n{"Name":"dir","Hash":"Qm...","Size":"24622"}\n' diff --git a/src/releaseUploader/ipfsNode/index.ts b/src/releaseUploader/ipfsNode/index.ts index 5dd655ec..0ae1f28c 100644 --- a/src/releaseUploader/ipfsNode/index.ts +++ b/src/releaseUploader/ipfsNode/index.ts @@ -12,12 +12,19 @@ export class ReleaseUploaderIpfsNode implements IReleaseUploader { async addFromFs({ dirPath, - onProgress + onProgress, + onUploadComplete }: { dirPath: string; onProgress?: (percent: number) => void; + onUploadComplete?: () => void; }): Promise { - return await ipfsAddFromFs(dirPath, this.ipfsProvider, onProgress); + return await ipfsAddFromFs( + dirPath, + this.ipfsProvider, + onProgress, + onUploadComplete + ); } async testConnection(): Promise { diff --git a/src/releaseUploader/pinata/addDirFromFs.ts b/src/releaseUploader/pinata/addDirFromFs.ts index 5e9c0cab..d8f5263a 100644 --- a/src/releaseUploader/pinata/addDirFromFs.ts +++ b/src/releaseUploader/pinata/addDirFromFs.ts @@ -1,4 +1,5 @@ import { got } from "got"; +import { uploadTimeout } from "../utils/uploadTimeout.js"; import { getFormDataFileUpload } from "../utils/formDataFileUpload.js"; import { PinataMetadata, @@ -19,7 +20,8 @@ export async function pinataAddFromFs({ pinataMetadata, pinataOptions, credentials, - onProgress + onProgress, + onUploadComplete }: { dirOrFilePath: string; pinataUrl: string; @@ -27,6 +29,7 @@ export async function pinataAddFromFs({ pinataMetadata?: PinataMetadata; pinataOptions?: PinataOptions; onProgress?: (percent: number) => void; + onUploadComplete?: () => void; }): Promise { // Create form and append all files recursively const form = getFormDataFileUpload(dirOrFilePath); @@ -45,7 +48,9 @@ export async function pinataAddFromFs({ pinata_secret_api_key: credentials.secretApiKey }), body: form, - responseType: "json" + responseType: "json", + timeout: uploadTimeout, + retry: { limit: 0 } }).on("uploadProgress", progress => { // Report upload progress, and throttle to one update per percent point // { percent: 0.9995998225975282, transferred: 733675762, total: 733969480 } @@ -54,6 +59,7 @@ export async function pinataAddFromFs({ lastPercent = currentRoundPercent; if (onProgress) onProgress(progress.percent); } + if (progress.percent === 1) onUploadComplete?.(); }); const uploadData = response.body as IpfsUploadResult; diff --git a/src/releaseUploader/pinata/index.ts b/src/releaseUploader/pinata/index.ts index 09755972..dc299d03 100644 --- a/src/releaseUploader/pinata/index.ts +++ b/src/releaseUploader/pinata/index.ts @@ -25,18 +25,21 @@ export class ReleaseUploaderIpfsPinata implements IReleaseUploader { async addFromFs({ dirPath, metadata, - onProgress + onProgress, + onUploadComplete }: { dirPath: string; metadata: PinataMetadata; onProgress?: (percent: number) => void; + onUploadComplete?: () => void; }): Promise { return await pinataAddFromFs({ dirOrFilePath: dirPath, pinataUrl: this.pinataUrl, pinataMetadata: metadata, credentials: { apiKey: this.apiKey, secretApiKey: this.secretApiKey }, - onProgress + onProgress, + onUploadComplete }); } diff --git a/src/releaseUploader/swarmNode/addDirFromFs.ts b/src/releaseUploader/swarmNode/addDirFromFs.ts index 31be3761..bc21c49c 100644 --- a/src/releaseUploader/swarmNode/addDirFromFs.ts +++ b/src/releaseUploader/swarmNode/addDirFromFs.ts @@ -1,4 +1,5 @@ import tarFS from "tar-fs"; +import { uploadTimeout } from "../utils/uploadTimeout.js"; import { got } from "got"; /** @@ -7,18 +8,22 @@ import { got } from "got"; export async function swarmAddDirFromFs( dirPath: string, gatewayUrl: string, - onProgress?: (percent: number) => void + onProgress?: (percent: number) => void, + onUploadComplete?: () => void ): Promise { const res = await got({ prefixUrl: gatewayUrl, - url: "/bzz:/", + url: "bzz:/", method: "POST", headers: { "content-type": "application/x-tar" }, - body: tarFS.pack(dirPath) + body: tarFS.pack(dirPath), + timeout: uploadTimeout, + retry: { limit: 0 } }).on("uploadProgress", progress => { // Report upload progress // { percent: 0.9995998225975282, transferred: 733675762, total: 733969480 } if (onProgress) onProgress(progress.percent); + if (progress.percent === 1) onUploadComplete?.(); }); const rootHash = res.body; diff --git a/src/releaseUploader/swarmNode/index.ts b/src/releaseUploader/swarmNode/index.ts index 9975c2ca..2eb11519 100644 --- a/src/releaseUploader/swarmNode/index.ts +++ b/src/releaseUploader/swarmNode/index.ts @@ -12,12 +12,19 @@ export class ReleaseUploaderSwarmNode implements IReleaseUploader { async addFromFs({ dirPath, - onProgress + onProgress, + onUploadComplete }: { dirPath: string; onProgress?: (percent: number) => void; + onUploadComplete?: () => void; }): Promise { - return await swarmAddDirFromFs(dirPath, this.gatewayUrl, onProgress); + return await swarmAddDirFromFs( + dirPath, + this.gatewayUrl, + onProgress, + onUploadComplete + ); } async testConnection(): Promise { diff --git a/src/tasks/buildAndUpload/getUploadTasks.ts b/src/tasks/buildAndUpload/getUploadTasks.ts index 0523d4bd..33bb0ce5 100644 --- a/src/tasks/buildAndUpload/getUploadTasks.ts +++ b/src/tasks/buildAndUpload/getUploadTasks.ts @@ -2,7 +2,6 @@ import { ListrTask } from "listr/index.js"; import { PackageToBuildProps, ListrContextBuild } from "../../types.js"; import { getGitHeadIfAvailable } from "../../utils/git.js"; import { getPinMetadata } from "../../pinStrategy/index.js"; -import { PinKeyvaluesDefault } from "../../releaseUploader/pinata/index.js"; import { IReleaseUploader } from "../../releaseUploader/index.js"; import { composeDeleteBuildProperties } from "../../files/index.js"; @@ -21,24 +20,43 @@ export function getUploadTasks({ }): ListrTask[] { const uploadTasks: ListrTask[] = []; - for (const { manifest, releaseDir } of packagesToBuildProps) { + for (const { manifest, releaseDir, manifestPaths } of packagesToBuildProps) { const { name: dnpName } = manifest; uploadTasks.push({ title: `Upload release for ${dnpName} to ${releaseUploader.networkName}`, skip: () => skipUpload, task: async (ctx, task) => { - const gitHead = await getGitHeadIfAvailable({ requireGitData }); + const gitHead = await getGitHeadIfAvailable({ + requireGitData, + dir: manifestPaths[0]?.dir + }); // Remove `build` property AFTER building. Otherwise it may break ISO installations // https://github.com/dappnode/DAppNode_Installer/issues/161 composeDeleteBuildProperties({ dir: releaseDir, composeFileName }); - ctx[dnpName].releaseMultiHash = await releaseUploader.addFromFs({ - dirPath: releaseDir, - metadata: getPinMetadata(manifest, gitHead) as PinKeyvaluesDefault, - onProgress: percent => (task.output = percentToMessage(percent)) - }); + let waiting: ReturnType | undefined; + try { + ctx[dnpName].releaseMultiHash = await releaseUploader.addFromFs({ + dirPath: releaseDir, + metadata: getPinMetadata(manifest, gitHead), + onProgress: percent => (task.output = percentToMessage(percent)), + onUploadComplete: () => { + const started = Date.now(); + task.output = "Upload sent · waiting for pinning confirmation..."; + if (waiting) clearInterval(waiting); + waiting = setInterval( + () => { + task.output = `Waiting for pinning confirmation · ${Math.floor((Date.now() - started) / 1000)}s`; + }, + process.stdout.isTTY ? 1000 : 15000 + ); + } + }); + } finally { + if (waiting) clearInterval(waiting); + } } }); } diff --git a/test/tasks/uploadProgress.test.ts b/test/tasks/uploadProgress.test.ts new file mode 100644 index 00000000..a3b8697c --- /dev/null +++ b/test/tasks/uploadProgress.test.ts @@ -0,0 +1,121 @@ +import fs from "fs"; +import path from "path"; +import http from "http"; +import { expect } from "chai"; +import { pinataAddFromFs } from "../../src/releaseUploader/pinata/addDirFromFs.js"; +import { swarmAddDirFromFs } from "../../src/releaseUploader/swarmNode/addDirFromFs.js"; +import { ipfsAddDirFromUrls } from "../../src/releaseUploader/ipfsNode/addDirFromUrls.js"; +import { temporaryDirectory } from "../helpers/fixtures.js"; + +describe("local upload transport and progress", function () { + this.timeout(10000); + let dir: string; + let server: http.Server; + let url: string; + let route: ( + request: http.IncomingMessage, + response: http.ServerResponse + ) => void; + beforeEach(async () => { + dir = temporaryDirectory(); + fs.writeFileSync(path.join(dir, "image.txz"), Buffer.alloc(1024 * 1024, 7)); + server = http.createServer((request, response) => route(request, response)); + await new Promise((resolve, reject) => { + server.once("error", reject); + server.listen(0, "127.0.0.1", resolve); + }); + const address = server.address(); + if (!address || typeof address === "string") + throw new Error("No server address"); + url = `http://127.0.0.1:${address.port}`; + }); + afterEach(async () => { + server?.closeAllConnections(); + await new Promise(resolve => server?.close(() => resolve())); + fs.rmSync(dir, { recursive: true, force: true }); + }); + + it("changes to pinning confirmation after transmission, before the response", async () => { + let confirmed = false; + let sent = false; + const events: string[] = []; + route = (request, response) => { + expect(request.url).to.equal("/pinning/pinFileToIPFS"); + request.resume(); + request.on("end", () => + setTimeout(() => { + expect(sent).to.equal(true); + confirmed = true; + response.setHeader("content-type", "application/json"); + response.end('{"IpfsHash":"QmTest"}'); + }, 100) + ); + }; + const hash = await pinataAddFromFs({ + dirOrFilePath: dir, + pinataUrl: url, + credentials: { apiKey: "fake", secretApiKey: "fake" }, + onProgress: percent => events.push(`bytes:${percent}`), + onUploadComplete: () => { + sent = true; + expect(confirmed).to.equal(false); + events.push("pinning"); + } + }); + expect(hash).to.equal("/ipfs/QmTest"); + expect(events.at(-1)).to.equal("pinning"); + }); + + it("posts Swarm archives using a relative path under prefixUrl", async () => { + route = (request, response) => { + expect(request.url).to.equal("/bzz:/"); + request.resume(); + request.on("end", () => response.end("swarm-hash")); + }; + expect(await swarmAddDirFromFs(dir, url)).to.equal("/bzz/swarm-hash"); + }); + + it("streams GitHub-style downloads through got into the IPFS upload", async () => { + let upload = ""; + route = (request, response) => { + if (request.url === "/asset") { + response.end("downloaded contents"); + return; + } + expect(request.url).to.equal("/api/v0/add"); + request.setEncoding("utf8"); + request.on("data", chunk => { + upload += chunk; + }); + request.on("end", () => + response.end('{"Name":"release","Hash":"QmDownloaded"}\n') + ); + }; + expect( + await ipfsAddDirFromUrls( + [{ filepath: "release/file.txt", url: `${url}/asset` }], + url + ) + ).to.equal("/ipfs/QmDownloaded"); + expect(upload) + .to.include("downloaded contents") + .and.include("release/file.txt"); + }); + + it("rejects HTTP failures during downloads instead of uploading an error page", async () => { + route = (request, response) => { + if (request.url === "/missing") { + response.writeHead(404); + response.end("missing"); + return; + } + request.resume(); + }; + const error = await ipfsAddDirFromUrls( + [{ filepath: "release/file.txt", url: `${url}/missing` }], + url + ).catch(error => error); + expect(error).to.be.instanceOf(Error); + expect(error.message).to.include("404"); + }); +}); From 802673b5d5a01659f79aab6addc22e911ac88a47 Mon Sep 17 00:00:00 2001 From: 3alpha <15694175+3alpha@users.noreply.github.com> Date: Wed, 4 Nov 2026 22:19:36 +0100 Subject: [PATCH 10/15] Complete GitHub releases and honour --dir in GitHub actions - GitHub releases upload every defined optional asset (setup wizard, schemas, UI, dashboards, ...). - Release preparation and upload errors fail the publish. An asset that a failed attempt already stored completely is accepted, and a partial one is replaced. - Branches and releases are paginated, and tag lookups match the exact ref. - GitHub action and bump-upstream builds pass --dir, the variants directory and the compose file name to the build, and read git metadata from the package directory. --- src/commands/githubActions/build/index.ts | 37 ++++- src/commands/githubActions/build/types.ts | 5 +- .../githubActions/bumpUpstream/index.ts | 3 +- src/providers/github/Github.ts | 96 +++++++++---- .../subtasks/getCreateReleaseTask.ts | 90 ++++++------ test/commands/buildProgress.test.ts | 135 ++++++++++++++++++ test/providers/github/pagination.test.ts | 31 ++++ .../github/uploadReleaseAssets.test.ts | 84 +++++++++++ test/tasks/releaseAssets.test.ts | 96 +++++++++++++ 9 files changed, 494 insertions(+), 83 deletions(-) create mode 100644 test/commands/buildProgress.test.ts create mode 100644 test/providers/github/pagination.test.ts create mode 100644 test/providers/github/uploadReleaseAssets.test.ts create mode 100644 test/tasks/releaseAssets.test.ts diff --git a/src/commands/githubActions/build/index.ts b/src/commands/githubActions/build/index.ts index 0b34fae4..7c6c4953 100644 --- a/src/commands/githubActions/build/index.ts +++ b/src/commands/githubActions/build/index.ts @@ -1,6 +1,6 @@ import { CommandModule } from "yargs"; import { CliGlobalOptions } from "../../../types.js"; -import { defaultDir } from "../../../params.js"; +import { defaultDir, defaultVariantsDirName } from "../../../params.js"; import { getGithubContext } from "../../../providers/github/githubActions.js"; import { buildHandler } from "../../build/handler.js"; import { Github } from "../../../providers/github/Github.js"; @@ -30,6 +30,12 @@ export const gaBuild: CommandModule = { describe: "Build and upload test release and post a comment with install link to the triggering PR", builder: { + variants_dir_name: { + alias: "variants-dir-name", + type: "string", + default: defaultVariantsDirName, + description: "Directory containing package variants" + }, all_variants: { alias: "all-variants", description: `Build all package variants at once, by merging the dappnode_package.json and docker-compose.yml files in the root of the project with the specific ones defined for each package variant`, @@ -50,7 +56,9 @@ export const gaBuild: CommandModule = { async function gaBuildHandler({ dir = defaultDir, all_variants, - variants + variants, + variants_dir_name, + compose_file_name }: BuildActionOptions): Promise { const { eventName, sha: commitSha, ref: refString } = getGithubContext(); const ref = parseRef(refString); @@ -59,7 +67,10 @@ async function gaBuildHandler({ // Doing it here prevents having to add two workflows per repo. // Also, ensures that pins are deleted eventually, even if this fails sometimes try { - await cleanPinsFromDeletedBranches({ dir }); + await cleanPinsFromDeletedBranches({ + dir, + variantsDirName: variants_dir_name + }); } catch (e) { console.error("Error on cleanPinsFromDeletedBranches", e); } @@ -77,7 +88,9 @@ async function gaBuildHandler({ commitSha, branch: ref.branch, all_variants, - variants + variants, + variants_dir_name, + compose_file_name }); } else if (eventName === "push" || eventName === "pull_request") { // Consider that for 'pull_request' commitSha does not represent a known commit @@ -88,12 +101,15 @@ async function gaBuildHandler({ // By default just do a test build and skip_save await buildHandler({ + dir, provider: "dappnode", upload_to: "ipfs", skip_save: true, verbose: true, all_variants, - variants + variants, + variants_dir_name, + compose_file_name }); } else if (!eventName) { throw Error("Not in Github action context"); @@ -107,25 +123,32 @@ export async function buildAndComment({ commitSha, branch, all_variants, - variants + variants, + variants_dir_name, + compose_file_name }: { dir: string; commitSha: string; branch: string; all_variants?: boolean; variants?: string; + variants_dir_name?: string; + compose_file_name?: string; }): Promise { // Connect to Github Octokit REST API and post or edit a comment on PR const github = Github.fromLocal(dir); const buildResults = await buildHandler({ + dir, provider: "pinata", upload_to: "ipfs", require_git_data: true, delete_old_pins: true, verbose: true, all_variants, - variants + variants, + variants_dir_name, + compose_file_name }); const body = getBuildBotComment({ diff --git a/src/commands/githubActions/build/types.ts b/src/commands/githubActions/build/types.ts index 42b2dd61..d708e839 100644 --- a/src/commands/githubActions/build/types.ts +++ b/src/commands/githubActions/build/types.ts @@ -1,6 +1,7 @@ import { CliGlobalOptions } from "../../../types.js"; export interface BuildActionOptions extends CliGlobalOptions { - variants?: string; - all_variants?: boolean; + variants?: string; + variants_dir_name?: string; + all_variants?: boolean; } diff --git a/src/commands/githubActions/bumpUpstream/index.ts b/src/commands/githubActions/bumpUpstream/index.ts index f43fab3f..34d2d160 100644 --- a/src/commands/githubActions/bumpUpstream/index.ts +++ b/src/commands/githubActions/bumpUpstream/index.ts @@ -151,7 +151,8 @@ async function gaBumpUpstreamHandler({ dir, commitSha: gitHead.commit, branch: branchName, - all_variants: useVariants + all_variants: useVariants, + variants_dir_name: variantsDir }); } diff --git a/src/providers/github/Github.ts b/src/providers/github/Github.ts index a6cbd1ee..35125c89 100644 --- a/src/providers/github/Github.ts +++ b/src/providers/github/Github.ts @@ -46,7 +46,6 @@ export class Github { return `${this.owner}/${this.repo}`; } - // eslint-disable-next-line @typescript-eslint/explicit-module-boundary-types async getRepo() { try { const repoResponse = await this.octokit.rest.repos.get({ @@ -60,7 +59,7 @@ export class Github { return repoResponse.data; } catch (e) { if (e instanceof RequestError && e.status === 404) { - throw new Error(`Repo does not exist: ${this.repoSlug}`); + throw new Error(`Repo does not exist: ${this.repoSlug}`, { cause: e }); } e.message = `Error verifying repo ${this.repoSlug}: ${e.message}`; @@ -100,7 +99,8 @@ export class Github { } }); - if (matchingTags.data.length > 0) return true; + if (matchingTags.data.some(item => item.ref === `refs/tags/${tag}`)) + return true; return false; } catch (e) { @@ -131,17 +131,14 @@ export class Github { } } - // eslint-disable-next-line @typescript-eslint/explicit-module-boundary-types async listReleases() { - return await this.octokit.rest.repos - .listReleases({ - owner: this.owner, - repo: this.repo, - headers: { - "X-GitHub-Api-Version": "2022-11-28" - } - }) - .then(res => res.data); + return await this.octokit.paginate(this.octokit.rest.repos.listReleases, { + owner: this.owner, + repo: this.repo, + headers: { + "X-GitHub-Api-Version": "2022-11-28" + } + }); } /** @@ -238,21 +235,41 @@ export class Github { const filepath = path.resolve(assetsDir, file); const contentType = mime.lookup(filepath) || "application/octet-stream"; + const name = `${fileNamePrefix || ""}${path.basename(filepath)}`; + const size = fs.statSync(filepath).size; try { // The uploadReleaseAssetApi fails sometimes, retry 3 times await retry( async () => { - await this.octokit.repos.uploadReleaseAsset({ - owner: this.owner, - repo: this.repo, - release_id: releaseId, - data: fs.createReadStream(filepath) as any, - headers: { - "content-type": contentType, - "content-length": fs.statSync(filepath).size - }, - name: `${fileNamePrefix || ""}${path.basename(filepath)}` - }); + try { + await this.octokit.request({ + method: "POST", + url: "https://uploads.github.com/repos/{owner}/{repo}/releases/{release_id}/assets{?name}", + owner: this.owner, + repo: this.repo, + release_id: releaseId, + data: fs.createReadStream(filepath), + headers: { + "content-type": contentType, + "content-length": size + }, + name + }); + } catch (e) { + // A failed attempt may still have stored the asset; the retry then gets 422. + if (!isAssetAlreadyExistsError(e)) throw e; + const existing = await this.findReleaseAsset(releaseId, name); + if (existing?.state === "uploaded" && existing.size === size) + return; + // Partial or different asset: remove it so the next attempt can upload. + if (existing) + await this.octokit.rest.repos.deleteReleaseAsset({ + owner: this.owner, + repo: this.repo, + asset_id: existing.id + }); + throw e; + } }, { retries: 3 } ); @@ -263,6 +280,19 @@ export class Github { } } + private async findReleaseAsset(releaseId: number, name: string) { + const assets = await this.octokit.paginate( + this.octokit.rest.repos.listReleaseAssets, + { + owner: this.owner, + repo: this.repo, + release_id: releaseId, + per_page: 100 + } + ); + return assets.find(asset => asset.name === name); + } + /** * Receives a tag and returns a prettified release name * @@ -392,7 +422,6 @@ export class Github { * Returns open PRs where head branch equals `branch` * Only branches and PRs originating from the same repo */ - // eslint-disable-next-line @typescript-eslint/explicit-module-boundary-types async getOpenPrsFromBranch(branch: string) { const openPrsResponse = await this.octokit.rest.pulls.list({ owner: this.owner, @@ -408,7 +437,7 @@ export class Github { } /** - * Returns list of branches, limited to 100. For more implement pagination + * Returns all branches; cleanup must never infer deletion from a partial page. * @returns branch = { * name: "octocat-patch-1" * commit: { @@ -416,23 +445,20 @@ export class Github { * } * } */ - // eslint-disable-next-line @typescript-eslint/explicit-module-boundary-types async listBranches() { - const branchesResponse = await this.octokit.rest.repos.listBranches({ + return await this.octokit.paginate(this.octokit.rest.repos.listBranches, { owner: this.owner, repo: this.repo, + per_page: 100, headers: { "X-GitHub-Api-Version": "2022-11-28" } }); - - return branchesResponse.data; } /** * @param branch "octocat-patch-1" */ - // eslint-disable-next-line @typescript-eslint/explicit-module-boundary-types async getBranch(branch: string) { const branchResponse = await this.octokit.rest.repos.getBranch({ owner: this.owner, @@ -482,3 +508,11 @@ export class Github { } } } + +function isAssetAlreadyExistsError(e: unknown): boolean { + const error = e as { status?: number; response?: { data?: unknown } }; + return ( + error?.status === 422 && + JSON.stringify(error.response?.data ?? "").includes("already_exists") + ); +} diff --git a/src/tasks/createGithubRelease/subtasks/getCreateReleaseTask.ts b/src/tasks/createGithubRelease/subtasks/getCreateReleaseTask.ts index 03b326e7..70597429 100644 --- a/src/tasks/createGithubRelease/subtasks/getCreateReleaseTask.ts +++ b/src/tasks/createGithubRelease/subtasks/getCreateReleaseTask.ts @@ -1,3 +1,4 @@ +import { releaseFiles } from "@dappnode/types"; import path from "path"; import fs from "fs"; import { Github } from "../../../providers/github/Github.js"; @@ -11,7 +12,10 @@ import { getNextGitTag } from "../getNextGitTag.js"; import { contentHashFileName } from "../../../params.js"; import { ReleaseDetailsMap } from "../types.js"; import { buildReleaseDetailsMap } from "../buildReleaseDetailsMap.js"; -import { compactManifestIfCore, composeDeleteBuildProperties } from "../../../files/index.js"; +import { + compactManifestIfCore, + composeDeleteBuildProperties +} from "../../../files/index.js"; /** * Create release @@ -34,21 +38,25 @@ export function getCreateReleaseTask({ const tag = getNextGitTag(releaseDetailsMap, isMultiVariant); + task.output = "Preparing release files..."; + prepareGithubReleaseFiles({ releaseDetailsMap, composeFileName }); + task.output = "Deleting existing release..."; await github.deleteReleaseAndAssets(tag); task.output = `Creating release for tag ${tag}...`; const releaseId = await github.createRelease(tag, { body: await getReleaseBody({ releaseDetailsMap }), - prerelease: true, // Until it is actually published to mainnet + prerelease: true // Until it is actually published to mainnet }); - task.output = "Preparing release directories for Github release..."; - prepareGithubReleaseFiles({ releaseDetailsMap, composeFileName }); - task.output = "Uploading assets..."; - await uploadAssets({ releaseDetailsMap, github, releaseId, isMultiVariant }); - + await uploadAssets({ + releaseDetailsMap, + github, + releaseId, + isMultiVariant + }); } }; } @@ -60,26 +68,21 @@ function prepareGithubReleaseFiles({ releaseDetailsMap: ReleaseDetailsMap; composeFileName?: string; }) { - for (const [, { releaseMultiHash, releaseDir }] of Object.entries(releaseDetailsMap)) { - + for (const [, { releaseMultiHash, releaseDir }] of Object.entries( + releaseDetailsMap + )) { const contentHashPath = path.join(releaseDir, `${contentHashFileName}`); - try { - - /** - * Plain text file which should contain the IPFS hash of the release - * Necessary for the installer script to fetch the latest content hash - * of the eth clients. The resulting hashes are used by the DAPPMANAGER - * to install an eth client when the user does not want to use a remote node - */ - fs.writeFileSync(contentHashPath, releaseMultiHash); - - compactManifestIfCore(releaseDir); - composeDeleteBuildProperties({ dir: releaseDir, composeFileName }); + /** + * Plain text file which should contain the IPFS hash of the release + * Necessary for the installer script to fetch the latest content hash + * of the eth clients. The resulting hashes are used by the DAPPMANAGER + * to install an eth client when the user does not want to use a remote node + */ + fs.writeFileSync(contentHashPath, releaseMultiHash); - } catch (e) { - console.error(`Error found while preparing files in ${releaseDir} for Github release`, e); - } + compactManifestIfCore(releaseDir); + composeDeleteBuildProperties({ dir: releaseDir, composeFileName }); } } @@ -105,11 +108,17 @@ async function uploadAssets({ await github.uploadReleaseAssets({ releaseId, assetsDir: releaseDir, - // Only upload yml, txz and dappnode_package.json files - matchPattern: /(.*\.ya?ml$)|(.*\.txz$)|(dappnode_package\.json)|(content-hash)/, + // Use the shared release-file definitions so optional artifacts are retained. + matchPattern: new RegExp( + [ + "\\.txz$", + `^${contentHashFileName}$`, + ...Object.entries(releaseFiles) + .filter(([id]) => id !== "avatar") + .map(([, spec]) => spec.regex.source) + ].join("|") + ), fileNamePrefix: isMultiVariant ? `${shortDnpName}_` : "" - }).catch((e) => { - console.error(`Error uploading assets from ${releaseDir}`, e); }); } } @@ -126,19 +135,16 @@ async function uploadAvatar({ await github.uploadReleaseAssets({ releaseId, assetsDir: avatarDir, - matchPattern: /.*\.png/, - }).catch((e) => { - console.error(`Error uploading avatar from ${avatarDir}`, e); + matchPattern: /.*\.png/ }); } - /** * Write the release body * */ async function getReleaseBody({ - releaseDetailsMap, + releaseDetailsMap }: { releaseDetailsMap: ReleaseDetailsMap; }) { @@ -155,15 +161,15 @@ function getPackageVersionsTable(releaseDetailsMap: ReleaseDetailsMap) { Package | Version | Hash | Install | Publish --- | --- | --- | --- | --- ${Object.entries(releaseDetailsMap) - .map(([dnpName, { nextVersion, releaseMultiHash, txData }]) => - getPackageVersionsRow({ - dnpName, - nextVersion, - releaseMultiHash, - txData - }) - ) - .join("\n")} + .map(([dnpName, { nextVersion, releaseMultiHash, txData }]) => + getPackageVersionsRow({ + dnpName, + nextVersion, + releaseMultiHash, + txData + }) + ) + .join("\n")} `.trim(); } diff --git a/test/commands/buildProgress.test.ts b/test/commands/buildProgress.test.ts new file mode 100644 index 00000000..7c04ce20 --- /dev/null +++ b/test/commands/buildProgress.test.ts @@ -0,0 +1,135 @@ +import fs from "fs"; +import os from "os"; +import path from "path"; +import { execFile } from "child_process"; +import { promisify } from "util"; +import { expect } from "chai"; +import Listr from "listr"; +import { initHandler } from "../../src/commands/init/handler.js"; +import { buildWithCompose } from "../../src/tasks/buildAndUpload/buildWithCompose.js"; +import { + temporaryDirectory, + executable, + useExecutables +} from "../helpers/fixtures.js"; + +const execute = promisify(execFile); +describe("build commands and native architecture", function () { + this.timeout(15000); + let dir: string; + let bin: string; + let restorePath: () => void; + beforeEach(async () => { + dir = temporaryDirectory(); + bin = path.join(dir, "bin"); + await initHandler({ dir, yes: true, force: true }); + const manifestPath = path.join(dir, "dappnode_package.json"); + const manifest = JSON.parse(fs.readFileSync(manifestPath, "utf8")); + manifest.architectures = ["linux/amd64", "linux/arm64"]; + fs.writeFileSync(manifestPath, JSON.stringify(manifest)); + executable( + bin, + "docker", + ` + const fs = require('fs'); + const args = process.argv.slice(2); + if (args[0] === 'pull') fs.appendFileSync(${JSON.stringify(path.join(dir, "pulls.jsonl"))}, JSON.stringify(args)+'\\n'); + if (args[0] === 'image') console.log(JSON.stringify([{Os:'linux',Architecture:'arm64'}])); + if (args[0] === 'compose' && args.includes('build')) {process.stdout.write('building'); setTimeout(() => process.stdout.write(' layer\\n'), 15);} + ` + ); + restorePath = useExecutables(bin); + }); + afterEach(() => { + restorePath(); + fs.rmSync(dir, { recursive: true, force: true }); + }); + + it("reports a successful build when --skip-save implicitly skips uploading", async () => { + const arch = os.arch() === "arm64" ? "arm64" : "amd64"; + const { stdout } = await execute(process.execPath, [ + "--import=tsx", + "src/dappnodesdk.ts", + "build", + "--dir", + dir, + "--arch", + arch, + "--skip-save" + ]); + expect(stdout).to.include("DNP (DAppNode Package) built"); + expect(stdout).not.to.include("Error building"); + expect(stdout).to.include("building layer"); + }); + + it("shows resolved variant names and builds each selected template", async () => { + await initHandler({ dir, yes: true, force: true, use_variants: true }); + const manifestPath = path.join(dir, "dappnode_package.json"); + const manifest = JSON.parse(fs.readFileSync(manifestPath, "utf8")); + manifest.architectures = ["linux/amd64", "linux/arm64"]; + fs.writeFileSync(manifestPath, JSON.stringify(manifest)); + const arch = os.arch() === "arm64" ? "arm64" : "amd64"; + const { stdout } = await execute(process.execPath, [ + "--import=tsx", + "src/dappnodesdk.ts", + "build", + "--dir", + dir, + "--all-variants", + "--arch", + arch, + "--skip-save" + ]); + expect(stdout).to.include("mainnet, testnet"); + expect(stdout).not.to.include("undefined"); + expect(stdout).to.include("[1/2]").and.include("[2/2]"); + }); + + it("honors --dir in pull-request GitHub action builds", async () => { + const { stdout } = await execute( + process.execPath, + [ + "--import=tsx", + "src/dappnodesdk.ts", + "github-action", + "build", + "--dir", + dir + ], + { + env: { + ...process.env, + GITHUB_TOKEN: "", + GITHUB_EVENT_NAME: "pull_request", + GITHUB_REF: "refs/pull/1/merge", + GITHUB_REPOSITORY: "example/demo" + } + } + ); + expect(stdout).to.include(path.basename(dir).toLowerCase()); + expect(stdout).to.include("[completed]"); + }); + + it("uses the requested native platform for external images", async () => { + const tasks = buildWithCompose({ + architecture: "linux/arm64", + images: [ + { + type: "external", + imageTag: "demo:1", + originalImageTag: "alpine:3.21" + } + ], + compose: { version: "3.5", services: { app: { image: "alpine:3.21" } } }, + manifest: { name: "demo.public.dappnode.eth", version: "0.1.0" }, + destPath: path.join(dir, "image.txz"), + buildTimeout: 3000, + skipSave: true, + rootDir: dir + }); + await new Listr(tasks, { renderer: "silent" }).run(); + expect( + JSON.parse(fs.readFileSync(path.join(dir, "pulls.jsonl"), "utf8").trim()) + ).to.include("--platform=linux/arm64"); + }); +}); diff --git a/test/providers/github/pagination.test.ts b/test/providers/github/pagination.test.ts new file mode 100644 index 00000000..1e595833 --- /dev/null +++ b/test/providers/github/pagination.test.ts @@ -0,0 +1,31 @@ +import { expect } from "chai"; +import { Github } from "../../../src/providers/github/Github.js"; + +describe("GitHub branch pagination", () => { + it("uses the paginator so cleanup sees branches after the first page", async () => { + const original = process.env.GITHUB_TOKEN; + process.env.GITHUB_TOKEN = "test-token"; + try { + const github = new Github({ owner: "example", repo: "demo" }); + const branches = Array.from({ length: 135 }, (_, index) => ({ + name: `branch-${index}` + })); + const listBranches = () => {}; + let called = false; + (github as unknown as { octokit: unknown }).octokit = { + rest: { repos: { listBranches } }, + paginate: async (method: unknown, parameters: { per_page: number }) => { + expect(method).to.equal(listBranches); + expect(parameters.per_page).to.equal(100); + called = true; + return branches; + } + }; + expect(await github.listBranches()).to.have.length(135); + expect(called).to.equal(true); + } finally { + if (original === undefined) delete process.env.GITHUB_TOKEN; + else process.env.GITHUB_TOKEN = original; + } + }); +}); diff --git a/test/providers/github/uploadReleaseAssets.test.ts b/test/providers/github/uploadReleaseAssets.test.ts new file mode 100644 index 00000000..0c0fe555 --- /dev/null +++ b/test/providers/github/uploadReleaseAssets.test.ts @@ -0,0 +1,84 @@ +import fs from "fs"; +import path from "path"; +import { expect } from "chai"; +import { Github } from "../../../src/providers/github/Github.js"; +import { temporaryDirectory } from "../../helpers/fixtures.js"; + +const alreadyExists = Object.assign(new Error("Validation Failed"), { + status: 422, + response: { + data: { errors: [{ resource: "ReleaseAsset", code: "already_exists" }] } + } +}); + +function githubWith(octokit: unknown): Github { + const original = process.env.GITHUB_TOKEN; + process.env.GITHUB_TOKEN = "fake"; + const github = new Github({ owner: "dappnode", repo: "demo" }); + if (original === undefined) delete process.env.GITHUB_TOKEN; + else process.env.GITHUB_TOKEN = original; + (github as unknown as { octokit: unknown }).octokit = octokit; + return github; +} + +describe("idempotent GitHub release asset upload", function () { + this.timeout(30000); // async-retry backs off ~7s across its 3 retries + let dir: string; + beforeEach(() => { + dir = temporaryDirectory(); + fs.writeFileSync(path.join(dir, "image.txz"), "12345"); + }); + afterEach(() => fs.rmSync(dir, { recursive: true, force: true })); + + it("accepts an asset a failed attempt already stored completely", async () => { + let posts = 0; + const github = githubWith({ + request: async () => { + posts++; + throw alreadyExists; + }, + paginate: async () => [ + { id: 7, name: "image.txz", size: 5, state: "uploaded" } + ], + rest: { repos: { listReleaseAssets: {}, deleteReleaseAsset: {} } } + }); + await github.uploadReleaseAssets({ releaseId: 1, assetsDir: dir }); + expect(posts).to.equal(1); + }); + + it("replaces a partial asset and uploads again", async () => { + const calls: string[] = []; + const github = githubWith({ + request: async () => { + calls.push("post"); + if (calls.filter(call => call === "post").length === 1) + throw alreadyExists; + }, + paginate: async () => [ + { id: 7, name: "image.txz", size: 2, state: "uploaded" } + ], + rest: { + repos: { + listReleaseAssets: {}, + deleteReleaseAsset: async ({ asset_id }: { asset_id: number }) => { + calls.push(`delete:${asset_id}`); + } + } + } + }); + await github.uploadReleaseAssets({ releaseId: 1, assetsDir: dir }); + expect(calls).to.deep.equal(["post", "delete:7", "post"]); + }); + + it("still fails on other errors", async () => { + const github = githubWith({ + request: async () => { + throw Object.assign(new Error("Bad credentials"), { status: 401 }); + } + }); + const error = await github + .uploadReleaseAssets({ releaseId: 1, assetsDir: dir }) + .catch(error => error); + expect(error.message).to.include("Bad credentials"); + }); +}); diff --git a/test/tasks/releaseAssets.test.ts b/test/tasks/releaseAssets.test.ts new file mode 100644 index 00000000..69e8ce2d --- /dev/null +++ b/test/tasks/releaseAssets.test.ts @@ -0,0 +1,96 @@ +import fs from "fs"; +import path from "path"; +import { expect } from "chai"; +import Listr from "listr"; +import { getCreateReleaseTask } from "../../src/tasks/createGithubRelease/subtasks/getCreateReleaseTask.js"; +import { Github } from "../../src/providers/github/Github.js"; +import type { ListrContextPublish } from "../../src/types.js"; +import { temporaryDirectory } from "../helpers/fixtures.js"; + +describe("complete GitHub releases", () => { + let dir: string; + let ctx: ListrContextPublish; + beforeEach(() => { + dir = temporaryDirectory(); + fs.writeFileSync( + path.join(dir, "dappnode_package.json"), + '{"name":"demo.public.dappnode.eth","version":"0.1.0"}' + ); + fs.writeFileSync( + path.join(dir, "docker-compose.yml"), + 'version: "3.5"\nservices:\n app:\n image: demo:1\n' + ); + for (const name of [ + "setup-wizard.json", + "setup.schema.json", + "setup-ui.json", + "dashboard-grafana-dashboard.json" + ]) + fs.writeFileSync(path.join(dir, name), "{}"); + fs.writeFileSync(path.join(dir, "avatar.png"), "avatar"); + fs.writeFileSync(path.join(dir, "image.txz"), "image"); + ctx = { + "demo.public.dappnode.eth": { + variant: null, + releaseDir: dir, + nextVersion: "0.1.0", + releaseMultiHash: "/ipfs/QmTest", + txData: { + to: "0x0000000000000000000000000000000000001234", + value: 0, + data: "0x", + gasLimit: 300000, + ensName: "demo.public.dappnode.eth", + currentVersion: "0.1.0", + releaseMultiHash: "/ipfs/QmTest" + } + } + }; + }); + afterEach(() => fs.rmSync(dir, { recursive: true, force: true })); + + it("includes every defined optional release artifact", async () => { + const uploaded: string[] = []; + const github = { + deleteReleaseAndAssets: async () => {}, + createRelease: async () => 1, + uploadReleaseAssets: async ({ + matchPattern + }: { + matchPattern: RegExp; + }) => { + uploaded.push( + ...fs.readdirSync(dir).filter(file => matchPattern.test(file)) + ); + } + } as unknown as Github; + await new Listr([getCreateReleaseTask({ github, isMultiVariant: false })], { + renderer: "silent" + }).run(ctx); + expect(uploaded).to.include.members([ + "setup-wizard.json", + "setup.schema.json", + "setup-ui.json", + "dashboard-grafana-dashboard.json", + "image.txz", + "avatar.png" + ]); + }); + + it("fails the release when asset upload fails", async () => { + const github = { + deleteReleaseAndAssets: async () => {}, + createRelease: async () => 1, + uploadReleaseAssets: async () => { + throw new Error("upload failed"); + } + } as unknown as Github; + const error = await new Listr( + [getCreateReleaseTask({ github, isMultiVariant: false })], + { renderer: "silent" } + ) + .run(ctx) + .catch(error => error); + expect(error.message).to.equal("upload failed"); + }); +}); From 29231063f30b0339da25a1c9da9c39a91b7fdad3 Mon Sep 17 00:00:00 2001 From: 3alpha <15694175+3alpha@users.noreply.github.com> Date: Wed, 4 Nov 2026 22:39:29 +0100 Subject: [PATCH 11/15] Report failed commands once and log each line once A failed build printed its command output three or four times, and verbose logs repeated each line up to four times. - Shell errors carry a summary line plus the last 20 output lines; the full stdout and stderr stay on the error. - The terminal renderer keeps its own short per-task history, and a failed task shows only its title. - A verbose renderer logs every streamed line once and leaves the error to the CLI. - The CLI reports an error once and exits with code 1 instead of rethrowing. It also handles yargs' rejected parse promise, which Node otherwise printed as an unhandled rejection. When the log was already streamed only the summary is shown, and stack frames appear only with --verbose/--debug. --- src/commands/build/handler.ts | 17 ++-- src/commands/build/types.ts | 6 +- src/commands/publish/handler.ts | 9 +- src/dappnodesdk.ts | 25 +++++- src/utils/formatCliError.ts | 34 +++++++ src/utils/progress.ts | 143 ++++++++++++++++++++++++++---- src/utils/shell.ts | 54 +++++++++-- test/utils/formatCliError.test.ts | 46 ++++++++++ test/utils/progress.test.ts | 74 ++++++++++++++-- test/utils/shell.test.ts | 26 ++++-- 10 files changed, 379 insertions(+), 55 deletions(-) create mode 100644 src/utils/formatCliError.ts create mode 100644 test/utils/formatCliError.test.ts diff --git a/src/commands/build/handler.ts b/src/commands/build/handler.ts index 880e538a..f67b4b7c 100644 --- a/src/commands/build/handler.ts +++ b/src/commands/build/handler.ts @@ -1,4 +1,4 @@ -import { ProgressRenderer } from "../../utils/progress.js"; +import { getRendererOptions } from "../../utils/progress.js"; import Listr from "listr"; import { Architecture, architectures } from "@dappnode/types"; import { buildAndUpload } from "../../tasks/buildAndUpload/index.js"; @@ -52,7 +52,9 @@ export async function buildHandler({ for (const pkg of packagesToBuildProps) { if (!pkg.architectures.includes(architecture)) throw Error( - `Architecture '${architecture}' is not supported by package ${pkg.manifest.name}. Supported: ${pkg.architectures.join(", ")}` + `Architecture '${architecture}' is not supported by package ${ + pkg.manifest.name + }. Supported: ${pkg.architectures.join(", ")}` ); pkg.architectures = [architecture]; } @@ -74,9 +76,10 @@ export async function buildHandler({ packagesToBuildProps }; - const verbosityOptions: VerbosityOptions = { - renderer: verbose ? "verbose" : silent ? "silent" : ProgressRenderer - }; + const verbosityOptions: VerbosityOptions = getRendererOptions({ + verbose, + silent + }); const buildTasks = new Listr(buildAndUpload(buildOptions), verbosityOptions); @@ -96,7 +99,9 @@ export function normalizeArchitecture(arch: string): Architecture { const normalized = archShorthands[arch] ?? arch; if (!architectures.includes(normalized as Architecture)) throw Error( - `Invalid architecture '${arch}', allowed values: ${architectures.join(", ")} (or shorthands: ${Object.keys(archShorthands).join(", ")})` + `Invalid architecture '${arch}', allowed values: ${architectures.join( + ", " + )} (or shorthands: ${Object.keys(archShorthands).join(", ")})` ); return normalized as Architecture; } diff --git a/src/commands/build/types.ts b/src/commands/build/types.ts index f42a5b94..5183a657 100644 --- a/src/commands/build/types.ts +++ b/src/commands/build/types.ts @@ -1,4 +1,4 @@ -import type { ProgressRenderer } from "../../utils/progress.js"; +import type { getRendererOptions } from "../../utils/progress.js"; import { UploadTo } from "../../releaseUploader/index.js"; import { CliGlobalOptions } from "../../types.js"; @@ -18,6 +18,4 @@ export interface BuildCommandOptions extends CliGlobalOptions { arch?: string; } -export interface VerbosityOptions { - renderer: "verbose" | "silent" | "default" | typeof ProgressRenderer; -} +export type VerbosityOptions = ReturnType; diff --git a/src/commands/publish/handler.ts b/src/commands/publish/handler.ts index 1eea4386..81c6c3c7 100644 --- a/src/commands/publish/handler.ts +++ b/src/commands/publish/handler.ts @@ -1,4 +1,4 @@ -import { ProgressRenderer } from "../../utils/progress.js"; +import { getRendererOptions } from "../../utils/progress.js"; import Listr from "listr"; import path from "path"; import { @@ -58,9 +58,10 @@ export async function publishHandler({ githubRelease = true; } - const verbosityOptions: VerbosityOptions = { - renderer: verbose ? "verbose" : silent ? "silent" : ProgressRenderer - }; + const verbosityOptions: VerbosityOptions = getRendererOptions({ + verbose, + silent + }); const releaseType = parseReleaseType({ type }); diff --git a/src/dappnodesdk.ts b/src/dappnodesdk.ts index 7699f01e..e8219abe 100755 --- a/src/dappnodesdk.ts +++ b/src/dappnodesdk.ts @@ -3,6 +3,7 @@ import yargs from "yargs"; import { hideBin } from "yargs/helpers"; import chalk from "chalk"; +import { formatCliError } from "./utils/formatCliError.js"; import figlet from "figlet"; import dotenv from "dotenv"; @@ -82,10 +83,25 @@ dappnodesdk.epilogue( /** * Handle errors */ +const reportedErrors = new WeakSet(); +function reportError(err: unknown): void { + process.exitCode = 1; + if (typeof err === "object" && err !== null) { + if (reportedErrors.has(err)) return; + reportedErrors.add(err); + } + const debug = Boolean( + (globalThis as typeof globalThis & { DEBUG_MODE?: boolean }).DEBUG_MODE + ); + console.error(`${formatCliError(err, { debug })}\n`); +} + dappnodesdk.fail((msg, err, yargs) => { + // Report once and exit with an error code. Rethrowing would make Node print the + // whole error object again (including the full command output and Listr context). + process.exitCode = 1; if (err) { - console.error(` ${chalk.red("✖")} ${err.message}\n`); - throw err; + reportError(err); } else { // If no specific error object is passed, use the message console.error(` ${chalk.red("✖")} ${msg}\n`); @@ -94,5 +110,6 @@ dappnodesdk.fail((msg, err, yargs) => { } }); -// Run CLI -dappnodesdk.parse(); +// Run CLI. yargs reports a failed async command through .fail() but still rejects +// the parse promise; handle it here so Node does not print the error a second time. +dappnodesdk.parseAsync().catch(reportError); diff --git a/src/utils/formatCliError.ts b/src/utils/formatCliError.ts new file mode 100644 index 00000000..c711690d --- /dev/null +++ b/src/utils/formatCliError.ts @@ -0,0 +1,34 @@ +import chalk from "chalk"; +import { ShellError } from "./shell.js"; +import { wasTaskOutputStreamed } from "./progress.js"; + +/** + * Formats an error for the terminal, once. + * A failed command whose log was already streamed (verbose/CI) is reported by its summary line only; + * otherwise the message includes the last lines of its output. Stack frames are shown only with --debug/--verbose. + */ +export function formatCliError( + error: unknown, + { + debug = false, + outputStreamed = wasTaskOutputStreamed() + }: { debug?: boolean; outputStreamed?: boolean } = {} +): string { + const err = error instanceof Error ? error : new Error(String(error)); + const body = + err instanceof ShellError && err.streamed && outputStreamed + ? err.summary + : err.message; + const [first, ...rest] = body.trimEnd().split("\n"); + const lines = [ + `${chalk.red("✖")} ${first}`, + ...rest.map(line => ` ${line}`) + ]; + // `--verbose` is also `--debug`. The stack starts with the message, which is already + // printed above, so only the frames are added. + const frames = (err.stack || "") + .split("\n") + .filter(line => /^\s+at /.test(line)); + if (debug && frames.length > 0) lines.push(chalk.dim(frames.join("\n"))); + return lines.join("\n"); +} diff --git a/src/utils/progress.ts b/src/utils/progress.ts index da0304fd..3fa45077 100644 --- a/src/utils/progress.ts +++ b/src/utils/progress.ts @@ -1,11 +1,15 @@ import { createLogUpdate } from "log-update"; import wrapAnsi from "wrap-ansi"; +import chalk from "chalk"; import { stripVTControlCharacters } from "util"; import type Listr from "listr"; +const previewLines = 4; + export interface ProgressTask { title: string; output?: string; + state?: string; subtasks: readonly ProgressTask[]; isEnabled(): boolean; isPending(): boolean; @@ -14,20 +18,42 @@ export interface ProgressTask { hasFailed(): boolean; } -/** Keep a useful preview while verbose renderers still receive every complete line. */ -export function taskLog(task: { output: string }): (line: string) => void { - const lines: string[] = []; +interface ListrEvent { + type: string; + data?: string; +} + +interface ObservableTask extends ProgressTask { + subtasks: readonly ObservableTask[]; + subscribe(next: (event: ListrEvent) => void, error?: () => void): unknown; +} + +/** + * Report each complete log line once as the task output. + * Verbose renderers log every line exactly once; the terminal renderer keeps its own short history. + */ +export function taskLog(task: { output?: string }): (line: string) => void { return line => { - lines.push(stripVTControlCharacters(line)); - if (lines.length > 4) lines.shift(); - task.output = lines.join("\n"); + task.output = stripVTControlCharacters(line); }; } +/** Whether a renderer has streamed task output to the console, so a failed command's log was already shown. */ +let outputStreamed = false; +export function wasTaskOutputStreamed(): boolean { + return outputStreamed; +} + +/** + * Renders the task tree. A pending task shows its last few output lines. + * A failed task shows only its title, because listr sets the failed task's output to the error message + * and the CLI reports that error once, after rendering ends. + */ export function renderProgress( tasks: readonly ProgressTask[], frame = "⠋", - depth = 0 + depth = 0, + history?: WeakMap ): string[] { const lines: string[] = []; for (const task of tasks) { @@ -39,27 +65,46 @@ export function renderProgress( const symbol = failed ? "✖" : pending - ? frame - : task.isSkipped() - ? "↓" - : "✔"; + ? frame + : task.isSkipped() + ? "↓" + : "✔"; const indent = " ".repeat(depth); lines.push(`${indent}${symbol} ${stripVTControlCharacters(task.title)}`); - if ((pending || failed) && task.output) - for (const line of stripVTControlCharacters(task.output) - .split(/\r?\n/) - .slice(-4)) + if (pending) { + const recent = history + ? history.get(task) || [] + : stripVTControlCharacters(task.output || "").split(/\r?\n/); + for (const line of recent.slice(-previewLines)) if (line.trim()) lines.push(`${indent} │ ${line}`); + } if (pending || failed) - lines.push(...renderProgress(task.subtasks, frame, depth + 1)); + lines.push(...renderProgress(task.subtasks, frame, depth + 1, history)); } return lines; } +/** Calls `onEvent` for every event of every task, including subtasks created later. */ +function watchTasks( + tasks: readonly ObservableTask[], + onEvent: (task: ObservableTask, event: ListrEvent) => void +): void { + for (const task of tasks) + task.subscribe( + event => { + if (event.type === "SUBTASKS") watchTasks(task.subtasks, onEvent); + else onEvent(task, event); + }, + // Errors are reported once by the CLI, not by the renderer. + () => {} + ); +} + /** One renderer owns the terminal; nested task lists share its bounded preview. */ export class ProgressRenderer { static nonTTY = false; private readonly update = createLogUpdate(process.stdout); + private readonly history = new WeakMap(); private interval?: ReturnType; private frame = 0; constructor( @@ -70,7 +115,9 @@ export class ProgressRenderer { const frames = ["⠋", "⠙", "⠹", "⠸", "⠼", "⠴", "⠦", "⠧", "⠇", "⠏"]; const lines = renderProgress( this.tasks as unknown as readonly ProgressTask[], - frames[this.frame++ % frames.length] + frames[this.frame++ % frames.length], + 0, + this.history ); const rows = lines.flatMap(line => wrapAnsi(line, Math.max(10, process.stdout.columns || 80), { @@ -85,6 +132,15 @@ export class ProgressRenderer { } render(): void { + watchTasks( + this.tasks as unknown as readonly ObservableTask[], + (task, event) => { + if (event.type !== "DATA" || task.hasFailed() || !event.data) return; + const lines = this.history.get(task) || []; + lines.push(...stripVTControlCharacters(event.data).split(/\r?\n/)); + this.history.set(task, lines.slice(-previewLines)); + } + ); this.draw(); this.interval = setInterval(() => this.draw(), 100); } @@ -95,3 +151,56 @@ export class ProgressRenderer { this.update.done(); } } + +/** Line-by-line log for CI and --verbose: every output line once, without repeating the error. */ +export class VerboseRenderer { + static nonTTY = true; + constructor( + private readonly tasks: ReadonlyArray> + ) {} + + private log(message: string): void { + const time = new Date().toTimeString().slice(0, 8); + console.log(`${chalk.dim(`[${time}]`)} ${message}`); + } + + render(): void { + outputStreamed = true; + watchTasks( + this.tasks as unknown as readonly ObservableTask[], + (task, event) => { + if (event.type === "STATE") { + this.log( + `${task.title} [${task.isPending() ? "started" : task.state}]` + ); + if (task.isSkipped() && task.output) this.log(`→ ${task.output}`); + } else if (event.type === "DATA") { + // On failure listr sets the output to the error message; the CLI prints it once. + if (!task.hasFailed() && event.data) this.log(`→ ${event.data}`); + } else if (event.type === "TITLE") { + this.log(`${task.title} [title changed]`); + } + } + ); + } + + end(): void {} +} + +export function getRendererOptions({ + verbose, + silent +}: { + verbose?: boolean; + silent?: boolean; +}): { + renderer: "silent" | typeof ProgressRenderer | typeof VerboseRenderer; + nonTTYRenderer: "silent" | typeof VerboseRenderer; +} { + if (silent && !verbose) + return { renderer: "silent", nonTTYRenderer: "silent" }; + return { + renderer: verbose ? VerboseRenderer : ProgressRenderer, + nonTTYRenderer: VerboseRenderer + }; +} diff --git a/src/utils/shell.ts b/src/utils/shell.ts index aab42914..045a9310 100644 --- a/src/utils/shell.ts +++ b/src/utils/shell.ts @@ -5,6 +5,7 @@ import { ExecFileException } from "child_process"; import { StringDecoder } from "string_decoder"; +import { stripVTControlCharacters } from "util"; /** * If timeout is greater than 0, the parent will send the signal @@ -46,7 +47,14 @@ export async function shell( ): void => { if (err) { // Rethrow a typed error, and ignore the internal NodeJS stack trace - reject(new ShellError(err, { stdout, stderr, cmd: cmdStr })); + reject( + new ShellError(err, { + stdout, + stderr, + cmd: cmdStr, + streamed: Boolean(onData) + }) + ); } else { resolve(stdout.trim() || stderr); } @@ -94,6 +102,9 @@ export async function shell( * Typed error implementing the native node child exception error * Can be rethrow to ignore the internal NodeJS stack trace */ +/** Lines of command output kept in the error message; the full streams stay on `stdout`/`stderr`. */ +const errorOutputLines = 20; + export class ShellError extends Error { cmd?: string; killed?: boolean; @@ -101,16 +112,29 @@ export class ShellError extends Error { signal?: NodeJS.Signals; stdout: string; stderr: string; + /** One line describing what failed, e.g. "Command failed (exit 1): docker compose build". */ + summary: string; + /** True when the output was streamed to the task log while the command ran. */ + streamed: boolean; constructor( e: ExecException | ExecFileException, - { cmd, stdout, stderr }: { cmd: string; stdout: string; stderr: string } + { + cmd, + stdout, + stderr, + streamed = false + }: { cmd: string; stdout: string; stderr: string; streamed?: boolean } ) { - const msg = [ - e.signal === "SIGTERM" ? `TIMEOUT: ${e.message}` : e.message, - `stdout: ${stdout}`, - `stderr: ${stderr}` - ].join("\n"); - super(msg); + const summary = + e.signal === "SIGTERM" + ? `TIMEOUT: command killed by SIGTERM: ${cmd}` + : e.signal + ? `Command killed by ${e.signal}: ${cmd}` + : typeof e.code === "number" + ? `Command failed (exit ${e.code}): ${cmd}` + : `Command failed (${e.code || e.message}): ${cmd}`; + const tail = outputTail(stderr.trim() ? stderr : stdout); + super(tail ? `${summary}\n${tail}` : summary); this.cmd = cmd; this.killed = e.killed; @@ -118,5 +142,19 @@ export class ShellError extends Error { this.signal = e.signal; this.stdout = stdout; this.stderr = stderr; + this.summary = summary; + this.streamed = streamed; } } + +/** Last lines of output without terminal control sequences or blank lines. */ +function outputTail(output: string): string { + const lines = stripVTControlCharacters(output) + .split(/\r?\n|\r/) + .filter(line => line.trim()); + const omitted = lines.length - errorOutputLines; + return [ + ...(omitted > 0 ? [`... (${omitted} earlier lines omitted)`] : []), + ...lines.slice(-errorOutputLines) + ].join("\n"); +} diff --git a/test/utils/formatCliError.test.ts b/test/utils/formatCliError.test.ts new file mode 100644 index 00000000..27ecea74 --- /dev/null +++ b/test/utils/formatCliError.test.ts @@ -0,0 +1,46 @@ +import { expect } from "chai"; +import { stripVTControlCharacters } from "util"; +import { formatCliError } from "../../src/utils/formatCliError.js"; +import { shell } from "../../src/utils/shell.js"; + +const plain = (text: string) => stripVTControlCharacters(text); + +describe("CLI error output", () => { + const failing = (onData?: (line: string) => void) => + shell(["sh", "-c", "echo building; echo 'ERROR: boom' >&2; exit 1"], { + onData + }).catch(e => e); + + it("prints a failed command once, with the end of its output", async () => { + const output = plain( + formatCliError(await failing(), { outputStreamed: false }) + ); + expect(output).to.equal( + "✖ Command failed (exit 1): sh -c echo building; echo 'ERROR: boom' >&2; exit 1\n ERROR: boom" + ); + }); + + it("prints only the summary when the log was already streamed", async () => { + const error = await failing(() => {}); + expect(plain(formatCliError(error, { outputStreamed: true }))).to.equal( + "✖ Command failed (exit 1): sh -c echo building; echo 'ERROR: boom' >&2; exit 1" + ); + // The terminal renderer only previews a few lines, so the output tail is still shown there. + expect(plain(formatCliError(error, { outputStreamed: false }))).to.include( + "ERROR: boom" + ); + }); + + it("prints other errors by message, and the stack only with --debug", () => { + const error = new Error("Invalid compose:\ninvalid containerPort: 70007"); + expect(plain(formatCliError(error, { outputStreamed: false }))).to.equal( + "✖ Invalid compose:\n invalid containerPort: 70007" + ); + const debugOutput = plain( + formatCliError(error, { debug: true, outputStreamed: false }) + ); + expect(debugOutput).to.include(" at "); + // The message is not repeated through the stack header. + expect(debugOutput.match(/invalid containerPort/g)).to.have.length(1); + }); +}); diff --git a/test/utils/progress.test.ts b/test/utils/progress.test.ts index 6b9e30ef..2e2030e8 100644 --- a/test/utils/progress.test.ts +++ b/test/utils/progress.test.ts @@ -1,9 +1,13 @@ import { expect } from "chai"; +import { mock } from "node:test"; +import Listr from "listr"; import { renderProgress, taskLog, + VerboseRenderer, type ProgressTask } from "../../src/utils/progress.js"; +import { shell } from "../../src/utils/shell.js"; function pending(title: string, output: string): ProgressTask { return { @@ -19,16 +23,37 @@ function pending(title: string, output: string): ProgressTask { } describe("build progress preview", () => { - it("retains complete recent log lines and renders them together", () => { - const task = pending("Build mainnet · linux/arm64", ""); - const write = taskLog(task as { output: string }); - for (let index = 0; index < 6; index++) write(`layer ${index}`); - const lines = renderProgress([task]); + afterEach(() => mock.restoreAll()); + + it("reports each log line once, as its own output update", () => { + const task: { output?: string } = {}; + const write = taskLog(task); + write("layer 1"); + expect(task.output).to.equal("layer 1"); + write("\u001b[32mlayer 2\u001b[0m"); + expect(task.output).to.equal("layer 2"); + }); + + it("shows the last few lines of a pending task from the renderer history", () => { + const task = pending("Build mainnet · linux/arm64", "layer 5"); + const history = new WeakMap([ + [task, ["layer 2", "layer 3", "layer 4", "layer 5"]] + ]); + const lines = renderProgress([task], "⠋", 0, history); expect(lines.join("\n")).to.include("layer 2").and.include("layer 5"); - expect(lines.join("\n")).not.to.include("layer 1"); expect(lines[0]).to.include("mainnet").and.include("arm64"); }); + it("does not repeat the error under a failed task", () => { + const failed = { + ...pending("Build docker image", "Command failed (exit 1): docker build"), + isPending: () => false, + hasFailed: () => true + }; + const lines = renderProgress([failed], "⠋", 0, new WeakMap()); + expect(lines).to.deep.equal(["✖ Build docker image"]); + }); + it("keeps the active upload/pinning stage visible without future task clutter", () => { const task = pending( "Upload mainnet", @@ -39,4 +64,41 @@ describe("build progress preview", () => { expect(lines.join("\n")).to.include("waiting for pinning confirmation"); expect(lines.join("\n")).not.to.include("Future stage"); }); + + it("logs every streamed line once in verbose mode and leaves the error to the CLI", async () => { + const logged: string[] = []; + mock.method(console, "log", (line: string) => logged.push(line)); + const error = await new Listr( + [ + { + title: "Build docker image", + task: (_, task) => + shell( + [ + "sh", + "-c", + "for i in 1 2 3 4 5 6; do echo step-$i; done; exit 3" + ], + { onData: taskLog(task) } + ) + } + ], + { renderer: VerboseRenderer } + ) + .run() + .catch(error => error); + mock.restoreAll(); + expect(error.summary).to.equal( + "Command failed (exit 3): sh -c for i in 1 2 3 4 5 6; do echo step-$i; done; exit 3" + ); + for (const step of [1, 2, 3, 4, 5, 6]) + expect( + logged.filter(line => line.includes(`step-${step}`)), + `step-${step}` + ).to.have.length(1); + expect(logged.some(line => line.includes("Command failed"))).to.equal( + false + ); + expect(logged.some(line => line.includes("[failed]"))).to.equal(true); + }); }); diff --git a/test/utils/shell.test.ts b/test/utils/shell.test.ts index 04f5831b..86b3a56a 100644 --- a/test/utils/shell.test.ts +++ b/test/utils/shell.test.ts @@ -35,14 +35,13 @@ echo "hello" if (!error) throw Error("Command did not throw"); expect(error.message).to.equal( - `Command failed: cat does-not-exist -cat: does-not-exist: No such file or directory - -stdout: -stderr: cat: does-not-exist: No such file or directory -`, + `Command failed (exit 1): cat does-not-exist +cat: does-not-exist: No such file or directory`, "wrong error.message" ); + expect(error.summary).to.equal( + "Command failed (exit 1): cat does-not-exist" + ); expect({ cmd: error.cmd, @@ -57,6 +56,21 @@ stderr: cat: does-not-exist: No such file or directory }); }); + it("keeps only the last lines of long output in the message", async () => { + const error = await shell([ + "sh", + "-c", + "for i in $(seq 1 30); do echo line-$i >&2; done; exit 2" + ]).catch(e => e); + const lines = error.message.split("\n"); + expect(lines[0]).to.match(/^Command failed \(exit 2\): sh -c /); + expect(lines[1]).to.equal("... (10 earlier lines omitted)"); + expect(lines.slice(2)).to.deep.equal( + Array.from({ length: 20 }, (_, i) => `line-${i + 11}`) + ); + expect(error.stderr.split("\n").filter(Boolean)).to.have.length(30); + }); + after(() => { fs.unlinkSync(scriptPath); }); From e843207e9c9ced02559e0506e9e960c7d58031e1 Mon Sep 17 00:00:00 2001 From: 3alpha <15694175+3alpha@users.noreply.github.com> Date: Wed, 4 Nov 2026 22:53:14 +0100 Subject: [PATCH 12/15] Require Node 22.13 and restrict workflow token permissions @octokit/request depends on content-type 3, which requires Node 22, so frozen installs failed on Node 20 (end of life since April 2026). The dappnode/workflows that run the SDK already use Node 24. - Engines: >=22.13.0, the strictest requirement across dependencies (ESLint needs ^22.13 || >=24). - CI matrix 22/24/26. The GitHub-action test workflows and the integration job use Node 24, like production. - Explicit least-privilege token permissions for main and the GitHub-action test workflows (CodeQL actions/missing-workflow-permissions). - Shell tests run `node` from PATH instead of process.execPath, which CodeQL traced as an uncontrolled absolute path into execFile. --- .github/workflows/main.yml | 7 +++++-- .github/workflows/test-ga-build.yml | 9 +++++++-- .github/workflows/test-ga-bump-upstream-template.yml | 9 +++++++-- .github/workflows/test-ga-bump-upstream.yml | 9 +++++++-- README.md | 2 +- package.json | 2 +- test/utils/process.test.ts | 4 ++-- 7 files changed, 30 insertions(+), 12 deletions(-) diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml index 02cdcb13..cf1d558c 100644 --- a/.github/workflows/main.yml +++ b/.github/workflows/main.yml @@ -7,13 +7,16 @@ on: branches: - master +permissions: + contents: read + jobs: test: runs-on: ubuntu-latest strategy: fail-fast: false # don't cancel all jobs if some of them failed matrix: - node: ["20", "22", "24", "26"] + node: ["22", "24", "26"] steps: - uses: actions/checkout@v4 - name: Setup node @@ -35,7 +38,7 @@ jobs: - name: Setup node uses: actions/setup-node@v4 with: - node-version: "20" + node-version: "24" - run: yarn install --frozen-lockfile - run: yarn build - run: yarn test:integration diff --git a/.github/workflows/test-ga-build.yml b/.github/workflows/test-ga-build.yml index e8dd0170..74f09cf7 100644 --- a/.github/workflows/test-ga-build.yml +++ b/.github/workflows/test-ga-build.yml @@ -5,15 +5,20 @@ on: branches: - master +permissions: + contents: read + issues: write # build bot comment on the PR + pull-requests: read + jobs: test: runs-on: ubuntu-latest steps: - uses: actions/checkout@v4 - - name: Set up Node.js 20.x + - name: Set up Node.js 24.x uses: actions/setup-node@v4 with: - node-version: 20.x + node-version: 24.x - run: yarn install --frozen-lockfile - run: yarn build diff --git a/.github/workflows/test-ga-bump-upstream-template.yml b/.github/workflows/test-ga-bump-upstream-template.yml index b41d66d0..37a10874 100644 --- a/.github/workflows/test-ga-bump-upstream-template.yml +++ b/.github/workflows/test-ga-bump-upstream-template.yml @@ -9,15 +9,20 @@ env: ENVIRONMENT: TEST INITIAL_VERSION: "0.1.0" +permissions: + contents: write # bump branch + pull-requests: write # bump PR + issues: write # build bot comment + jobs: test: runs-on: ubuntu-latest steps: - uses: actions/checkout@v4 - - name: Set up Node.js 20.x + - name: Set up Node.js 24.x uses: actions/setup-node@v4 with: - node-version: 20.x + node-version: 24.x - run: yarn install --frozen-lockfile - run: yarn build diff --git a/.github/workflows/test-ga-bump-upstream.yml b/.github/workflows/test-ga-bump-upstream.yml index 69b9c4ea..f75462fb 100644 --- a/.github/workflows/test-ga-bump-upstream.yml +++ b/.github/workflows/test-ga-bump-upstream.yml @@ -9,15 +9,20 @@ env: ENVIRONMENT: TEST INITIAL_VERSION: "0.1.0" +permissions: + contents: write # bump branch + pull-requests: write # bump PR + issues: write # build bot comment + jobs: test: runs-on: ubuntu-latest steps: - uses: actions/checkout@v4 - - name: Set up Node.js 20.x + - name: Set up Node.js 24.x uses: actions/setup-node@v4 with: - node-version: 20.x + node-version: 24.x - run: yarn install --frozen-lockfile - run: yarn build diff --git a/README.md b/README.md index b213c812..d9d72cdb 100644 --- a/README.md +++ b/README.md @@ -143,7 +143,7 @@ In order to have a better developing experience these modules lives inside the D ## Development -Use Node.js 20.19+, Node.js 22.13+, or Node.js 24+ for development, and install the exact locked dependencies with `yarn install --frozen-lockfile`. +Use Node.js 22.13+ or Node.js 24+ (Node.js 20 reached end of life in April 2026), and install the exact locked dependencies with `yarn install --frozen-lockfile`. - `yarn lint` checks source and tests without changing files; `yarn lint:fix` applies automatic fixes. - `yarn build` checks and compiles the SDK. diff --git a/package.json b/package.json index 69d8a245..d1693051 100644 --- a/package.json +++ b/package.json @@ -87,7 +87,7 @@ "typescript-eslint": "^8.72.1" }, "engines": { - "node": ">=20.19.0" + "node": ">=22.13.0" }, "resolutions": { "minimatch": "^11.0.1", diff --git a/test/utils/process.test.ts b/test/utils/process.test.ts index aa106799..a7534150 100644 --- a/test/utils/process.test.ts +++ b/test/utils/process.test.ts @@ -14,7 +14,7 @@ describe("safe commands and line buffering", () => { it("passes metacharacters literally instead of executing them", async () => { const value = '$(touch SHOULD_NOT_EXIST);echo unsafe "quoted"'; const result = await shell([ - process.execPath, + "node", "-e", "process.stdout.write(process.argv[1])", value @@ -43,7 +43,7 @@ describe("safe commands and line buffering", () => { const lines: string[] = []; await shell( [ - process.execPath, + "node", "-e", 'process.stdout.write("hel"); process.stderr.write("warn\\n"); setTimeout(() => { process.stdout.write("lo\\nlast"); }, 30);' ], From b117b3e7fb5faf42d2b8e222421e830062ba79a5 Mon Sep 17 00:00:00 2001 From: 3alpha <15694175+3alpha@users.noreply.github.com> Date: Wed, 4 Nov 2026 22:53:14 +0100 Subject: [PATCH 13/15] Close GitHub asset upload streams after each attempt Every upload attempt opened a new file stream, and a failed attempt never closed it. Besides leaking a file descriptor per retry, a stream still opening after its file was removed raised an unhandled 'error' event, which crashed the test run on Node 24. Each attempt now destroys its stream and handles its error event; read errors still fail the request that consumes the stream. --- src/providers/github/Github.ts | 9 +++++- .../github/uploadReleaseAssets.test.ts | 32 +++++++++++++++++++ 2 files changed, 40 insertions(+), 1 deletion(-) diff --git a/src/providers/github/Github.ts b/src/providers/github/Github.ts index 35125c89..12a125e1 100644 --- a/src/providers/github/Github.ts +++ b/src/providers/github/Github.ts @@ -241,6 +241,11 @@ export class Github { // The uploadReleaseAssetApi fails sometimes, retry 3 times await retry( async () => { + // One stream per attempt. A read error fails the request that consumes it; + // the listener and destroy() stop a stream left over by a failed attempt from + // keeping the file open or raising an unhandled 'error' event later. + const data = fs.createReadStream(filepath); + data.on("error", () => {}); try { await this.octokit.request({ method: "POST", @@ -248,7 +253,7 @@ export class Github { owner: this.owner, repo: this.repo, release_id: releaseId, - data: fs.createReadStream(filepath), + data, headers: { "content-type": contentType, "content-length": size @@ -269,6 +274,8 @@ export class Github { asset_id: existing.id }); throw e; + } finally { + data.destroy(); } }, { retries: 3 } diff --git a/test/providers/github/uploadReleaseAssets.test.ts b/test/providers/github/uploadReleaseAssets.test.ts index 0c0fe555..81bbf84e 100644 --- a/test/providers/github/uploadReleaseAssets.test.ts +++ b/test/providers/github/uploadReleaseAssets.test.ts @@ -1,5 +1,6 @@ import fs from "fs"; import path from "path"; +import { mock } from "node:test"; import { expect } from "chai"; import { Github } from "../../../src/providers/github/Github.js"; import { temporaryDirectory } from "../../helpers/fixtures.js"; @@ -70,6 +71,37 @@ describe("idempotent GitHub release asset upload", function () { expect(calls).to.deep.equal(["post", "delete:7", "post"]); }); + it("closes the file stream of every attempt, including failed ones", async () => { + const streams: fs.ReadStream[] = []; + const original = fs.createReadStream; + mock.method( + fs, + "createReadStream", + (...args: Parameters) => { + const stream = original(...args); + streams.push(stream); + return stream; + } + ); + let posts = 0; + const github = githubWith({ + request: async () => { + if (++posts === 1) + throw Object.assign(new Error("reset"), { status: 502 }); + } + }); + try { + await github.uploadReleaseAssets({ releaseId: 1, assetsDir: dir }); + } finally { + mock.restoreAll(); + } + expect(streams).to.have.length(2); + expect(streams.every(stream => stream.destroyed)).to.equal(true); + // Removing the file while a stream of a failed attempt is still opening must not crash. + fs.rmSync(dir, { recursive: true, force: true }); + await new Promise(resolve => setTimeout(resolve, 50)); + }); + it("still fails on other errors", async () => { const github = githubWith({ request: async () => { From a6f7b5b3bf31391277f69605732caf503b2cba1c Mon Sep 17 00:00:00 2001 From: 3alpha <15694175+3alpha@users.noreply.github.com> Date: Wed, 4 Nov 2026 22:53:14 +0100 Subject: [PATCH 14/15] Match the GitHub host exactly when reading the repository slug The manifest repository URL was accepted if it merely contained "https://github.com/" (CodeQL js/incomplete-url-substring-sanitization), and ".git" was removed from anywhere in the name. The URL is now parsed and must be https or git+https on github.com, and only a trailing ".git" is removed. All repository URLs of the 97 dappnode/DAppNodePackage* repos resolve to the same slug as before. --- src/files/manifest/getRepoSlugFromManifest.ts | 30 +++++++++++----- test/files/getRepoSlugFromManifest.test.ts | 34 +++++++++++++++++++ 2 files changed, 56 insertions(+), 8 deletions(-) create mode 100644 test/files/getRepoSlugFromManifest.test.ts diff --git a/src/files/manifest/getRepoSlugFromManifest.ts b/src/files/manifest/getRepoSlugFromManifest.ts index 363649cd..b5e146ab 100644 --- a/src/files/manifest/getRepoSlugFromManifest.ts +++ b/src/files/manifest/getRepoSlugFromManifest.ts @@ -2,18 +2,32 @@ import { readManifest } from "./readManifest.js"; import { ManifestPaths } from "./types.js"; /** - * Gets the repo slug from a manifest, using the repository property + * Gets the repo slug from a manifest, using the repository property. + * Accepts `https://github.com/owner/repo(.git)` and the npm-style `git+https://` form. * - * @returns repoSlug = "dappnode/DNP_ADMIN" + * @returns repoSlug = "dappnode/DNP_ADMIN", or "" if the repository is not on GitHub */ export function getRepoSlugFromManifest(paths: ManifestPaths): string { - const githubBaseUrl = "https://github.com/"; - const { manifest } = readManifest([paths]); const { type, url } = manifest.repository || {}; // Ignore faulty manifests - if (type !== "git" || !url || !url.includes(githubBaseUrl)) return ""; - // Get repo slug from the repoUrl, i.e. "https://github.com/dappnode/DNP_VPN" - const repoSlug = url.split(githubBaseUrl)[1] || ""; - return repoSlug.replace(/\/+$/, "").replace(".git", ""); + if (type !== "git" || !url) return ""; + return parseGithubRepoSlug(url); +} + +export function parseGithubRepoSlug(url: string): string { + let parsed: URL; + try { + parsed = new URL(url); + } catch { + return ""; + } + // Match the host exactly; a substring check would accept URLs that only mention github.com. + if (!["https:", "git+https:"].includes(parsed.protocol)) return ""; + if (parsed.hostname !== "github.com") return ""; + const [owner, repo] = parsed.pathname + .replace(/^\/+|\/+$/g, "") + .replace(/\.git$/, "") + .split("/"); + return owner && repo ? `${owner}/${repo}` : ""; } diff --git a/test/files/getRepoSlugFromManifest.test.ts b/test/files/getRepoSlugFromManifest.test.ts new file mode 100644 index 00000000..597609ba --- /dev/null +++ b/test/files/getRepoSlugFromManifest.test.ts @@ -0,0 +1,34 @@ +import { expect } from "chai"; +import { parseGithubRepoSlug } from "../../src/files/manifest/getRepoSlugFromManifest.js"; + +describe("GitHub repository slug from the manifest", () => { + it("accepts the forms used by real package manifests", () => { + for (const url of [ + "https://github.com/dappnode/DAppNodePackage-geth.git", + "git+https://github.com/dappnode/DAppNodePackage-geth.git", + "https://github.com/dappnode/DAppNodePackage-geth", + "git+https://github.com/dappnode/DAppNodePackage-geth", + "https://github.com/dappnode/DAppNodePackage-geth/" + ]) + expect(parseGithubRepoSlug(url), url).to.equal( + "dappnode/DAppNodePackage-geth" + ); + }); + + it("only strips a trailing .git", () => { + expect( + parseGithubRepoSlug("https://github.com/dappnode/tools.github-x") + ).to.equal("dappnode/tools.github-x"); + }); + + it("rejects URLs that merely mention github.com", () => { + for (const url of [ + "https://evil.example/?https://github.com/dappnode/x", + "https://github.com.evil.example/dappnode/x", + "http://github.com/dappnode/x", + "https://github.com/dappnode", + "not a url" + ]) + expect(parseGithubRepoSlug(url), url).to.equal(""); + }); +}); From 7fc843739437094823961dcebe7fc4c586e63e44 Mon Sep 17 00:00:00 2001 From: 3alpha <15694175+3alpha@users.noreply.github.com> Date: Wed, 4 Nov 2026 22:55:09 +0100 Subject: [PATCH 15/15] Allow the GA build test to comment on pull requests Commenting on a pull request through the issues API needs pull-requests: write; with read the build bot comment failed with 403 "Resource not accessible by integration". --- .github/workflows/test-ga-build.yml | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/.github/workflows/test-ga-build.yml b/.github/workflows/test-ga-build.yml index 74f09cf7..3f406de3 100644 --- a/.github/workflows/test-ga-build.yml +++ b/.github/workflows/test-ga-build.yml @@ -7,8 +7,10 @@ on: permissions: contents: read - issues: write # build bot comment on the PR - pull-requests: read + # The build bot creates/updates its comment through the issues API; on a pull + # request GitHub requires pull-requests: write for that. + issues: write + pull-requests: write jobs: test: