From 61d2874d89555ede8c9f66287f3b3b2caaeac521 Mon Sep 17 00:00:00 2001 From: alexcos20 Date: Fri, 24 Jul 2026 11:21:18 +0300 Subject: [PATCH 01/13] global ocean-cli --- .github/workflows/ci.yml | 49 + .github/workflows/publish.yml | 41 + CLAUDE.md | 11 +- README.md | 45 +- package-lock.json | 2374 ++++++++++++++++++++++++++++++++- package.json | 48 +- src/cli.ts | 47 +- src/helpers.ts | 17 +- src/index.ts | 69 +- src/interactiveFlow.ts | 2 +- src/policyServerHelper.ts | 2 +- test/replMenu.test.ts | 2 +- 12 files changed, 2596 insertions(+), 111 deletions(-) create mode 100644 .github/workflows/publish.yml diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 007fd6b4..6907ed85 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -40,6 +40,55 @@ jobs: - name: Run lint run: npm run lint + pack_smoke: + # Guards the global-install contract without needing a full Ocean stack: + # a broken bin, cwd-dependent module loading, or env-gated --help/--version + # would all fail here. Also asserts the publish tarball excludes sources. + runs-on: ubuntu-latest + + steps: + - name: Checkout code + uses: actions/checkout@v4 + + - name: Set up Node.js + uses: actions/setup-node@v4 + with: + node-version: "22.5.1" + + - name: Install dependencies + run: npm ci + + - name: Build + run: npm run build + + - name: Pack tarball + run: | + TARBALL=$(npm pack | tail -1) + echo "TARBALL=$TARBALL" >> $GITHUB_ENV + echo "Packed $TARBALL" + + - name: Assert tarball contents (dist/metadata/README in; src/test out) + run: | + FILES=$(tar -tzf "$TARBALL") + echo "$FILES" + echo "$FILES" | grep -q '^package/dist/index.js$' || { echo "MISSING dist/index.js"; exit 1; } + echo "$FILES" | grep -q '^package/README.md$' || { echo "MISSING README.md"; exit 1; } + echo "$FILES" | grep -q '^package/metadata/' || { echo "MISSING metadata/"; exit 1; } + if echo "$FILES" | grep -qE '^package/(src|test)/'; then + echo "Tarball must not ship src/ or test/"; exit 1 + fi + + - name: Install globally from tarball + run: npm i -g "./$TARBALL" + + - name: Run bin from a foreign cwd with NO env vars + working-directory: ${{ runner.temp }} + run: | + ocean-cli --version + ocean-cli --help > /dev/null + ocean-cli -h > /dev/null + ocean-cli -V > /dev/null + test_system: runs-on: ubuntu-latest strategy: diff --git a/.github/workflows/publish.yml b/.github/workflows/publish.yml new file mode 100644 index 00000000..3f078bfe --- /dev/null +++ b/.github/workflows/publish.yml @@ -0,0 +1,41 @@ +name: Publish + +on: + push: + tags: + - "**" + +permissions: + contents: read + id-token: write # required for npm provenance + +jobs: + npm: + runs-on: ubuntu-latest + env: + NODE_AUTH_TOKEN: ${{ secrets.NPM_TOKEN }} + + steps: + - name: Checkout code + uses: actions/checkout@v4 + + - name: Set up Node.js + uses: actions/setup-node@v4 + with: + node-version: "22.5.1" + registry-url: "https://registry.npmjs.org/" + + - name: Install dependencies + run: npm ci + + # prepublishOnly (npm run build) runs automatically during npm publish. + # --access public is required for a scoped package; --provenance attests + # the build to the source commit (needs the package.json `repository` + # field to match this repo and the id-token permission above). + - name: Publish (next) + if: contains(github.ref, 'next') + run: npm publish --tag next --provenance --access public + + - name: Publish (latest) + if: ${{ !contains(github.ref, 'next') }} + run: npm publish --provenance --access public diff --git a/CLAUDE.md b/CLAUDE.md index c3d77241..0645bd5d 100755 --- a/CLAUDE.md +++ b/CLAUDE.md @@ -5,7 +5,7 @@ This file provides guidance to Claude Code (claude.ai/code) when working with co ## What this project is -`ocean-cli` (package name `ocean-cli`, version 2.0.0) is a TypeScript CLI that wraps the Ocean Protocol JavaScript library (`@oceanprotocol/lib`, a.k.a. ocean.js) to publish, edit, consume/download, and run compute-to-data (C2D) on assets, plus manage escrow payments, access lists, persistent-storage buckets, auth tokens, and admin node logs. It talks to an **Ocean Node** (the single service that replaced the old standalone Provider and Aquarius apps — it does metadata caching, indexing, encryption, ordering, and compute) and to an EVM chain via an RPC endpoint. +`ocean-cli` (npm package `@oceanprotocol/cli`, version 2.0.0; installs a `bin` named `ocean-cli`) is a TypeScript CLI that wraps the Ocean Protocol JavaScript library (`@oceanprotocol/lib`, a.k.a. ocean.js) to publish, edit, consume/download, and run compute-to-data (C2D) on assets, plus manage escrow payments, access lists, persistent-storage buckets, auth tokens, and admin node logs. It talks to an **Ocean Node** (the single service that replaced the old standalone Provider and Aquarius apps — it does metadata caching, indexing, encryption, ordering, and compute) and to an EVM chain via an RPC endpoint. The package is pure ESM (`"type": "module"` in `package.json`). All relative imports MUST carry an explicit `.js` extension even though the source is `.ts` (e.g. `import { Commands } from "./commands.js"`). Node 22 is expected (`.nvmrc` = `22`; CI uses `22.5.1`). @@ -22,6 +22,7 @@ Scripts (from `package.json`): - `npm run test` — `npm run lint && npm run test:system` (lint is part of "test"). - `npm run test:system` — `npm run mocha 'test/**/*.test.ts'`. - `npm run mocha` — `NODE_OPTIONS='--experimental-require-module' mocha --config=test/.mocharc.json --node-env=test --exit`. +- `npm run release` — `release-it --non-interactive`: bumps version, builds, regenerates the changelog (`npm run changelog` = `auto-changelog -p`), commits, tags `v${version}`, pushes, and cuts a GitHub Release. Does **not** publish to npm (`release-it` config `npm.publish: false`) — pushing the tag triggers `.github/workflows/publish.yml`, which runs `npm publish` (`--tag next` for tags containing `next`, else `latest`). Mirrors `@oceanprotocol/lib`'s release flow. Mocha config (`test/.mocharc.json`): loader `ts-node/esm`, `bail: true` (stops at first failure), `timeout: 20000`, `exit: true`. @@ -50,7 +51,9 @@ npm run cli h # list commands ("h" and "help" are aliases npm run cli publish metadata/simpleDownloadDataset.json ``` -Important behavior of the entry point (`src/index.ts`): after running the command passed on argv **once**, the process enters an interactive REPL loop, printing `Enter command ('exit' | 'quit' or CTRL-C to terminate')` and reading further commands from stdin until you type `exit`/`quit`/`\q`. To get one-shot behavior (run and exit — required for CI and scripting) set `AVOID_LOOP_RUN=true`. In the REPL you may type either the bare command (`publish metadata/x.json`) or the full `npm run cli publish metadata/x.json` form. +`npm run cli` (= `npx tsx src/index.ts`) runs from source, no build. A globally installed copy (`npm i -g @oceanprotocol/cli`) exposes the same thing as the `ocean-cli` binary — `ocean-cli ` is equivalent to `npm run cli `. + +Important behavior of the entry point (`src/index.ts`): after running the command passed on argv **once**, the process enters an interactive REPL loop, printing `Enter command ('exit' | 'quit' | ESC or CTRL-C to terminate')` and reading further commands from stdin until you type `exit`/`quit`/`\q`, press **ESC** (TTY only), or hit CTRL-C. To get one-shot behavior (run and exit — required for CI and scripting) set `AVOID_LOOP_RUN=true`. In the REPL you may type either the bare command (`publish metadata/x.json`) or the full `npm run cli publish metadata/x.json` / `ocean-cli publish metadata/x.json` form (the leading prefix is stripped). Note: a pure help/version invocation (`--help`, `-h`, `--version`, `-V`, `h`, `help`) skips env-var validation and P2P bootstrap, so it works with no configuration; every other command still validates the env vars below. ### Required environment variables @@ -92,7 +95,7 @@ Per-command flags and examples are exhaustively documented in `README.md` ("Comm `main()` in `index.ts` calls `createCLI()` (in `cli.ts`) to build the Commander `program`, records supported command names/aliases, prints the REPL banner, runs the initial argv command once, then loops on stdin (`waitForCommands`) unless `AVOID_LOOP_RUN=true`. It uses `program.exitOverride()` so Commander errors don't kill the loop. -`createCLI()` does three things: (1) validates the required env vars, (2) if `NODE_URL` is a P2P URI, sets up libp2p (see "Transport"), (3) registers every command. Each command's `.action(...)`: +`createCLI()` does three things: (1) validates the required env vars — **unless** the invocation is a pure help/version one (`--help`/`-h`/`--version`/`-V`/`h`/`help`), which is detected from `process.argv` and skips both validation and P2P so those work with no config, (2) if `NODE_URL` is a P2P URI, sets up libp2p (see "Transport"), (3) registers every command. Each command's `.action(...)`: 1. merges positional + option values, 2. calls the local `initializeSigner()` — builds a `JsonRpcProvider(RPC)`, a `Wallet` from `PRIVATE_KEY` (or `Wallet.fromPhrase(MNEMONIC)`), and reads `chainId` from the network, @@ -121,7 +124,7 @@ One big class holding all command logic. The constructor: `helpers.ts` is the seam between the CLI and ocean.js: -- `createAssetUtil(...)` wraps ocean.js `createAsset` (used by publish/publishAlgo and the interactive publisher). It resolves the active ERC20 template (`calculateActiveTemplateIndex` reads `@oceanprotocol/contracts` `ERC20Template.json` ABI from `node_modules`), and for **Oasis Sapphire** (`config.sdk === 'oasis'`) wraps the signer with `@oasisprotocol/sapphire-paratime` (`getSignerAccordingSdk`) and deploys an allow access list before creating the asset. +- `createAssetUtil(...)` wraps ocean.js `createAsset` (used by publish/publishAlgo and the interactive publisher). It resolves the active ERC20 template (`calculateActiveTemplateIndex` reads and `JSON.parse`s the `@oceanprotocol/contracts` `ERC20Template.json` ABI, resolved via `createRequire`/`require.resolve` so it works from any cwd — e.g. a global install — not a cwd-relative `node_modules` path), and for **Oasis Sapphire** (`config.sdk === 'oasis'`) wraps the signer with `@oasisprotocol/sapphire-paratime` (`getSignerAccordingSdk`) and deploys an allow access list before creating the asset. - `updateAssetMetadata(...)` — used by `editAsset`, `allowAlgo`, `disallowAlgo` and the interactive publisher. It validates the DDO via `aquarius.validate`, then either `ProviderInstance.encrypt`s the DDO (flags = 2) or hexlifies raw JSON (flags = 0) depending on the `encryptDDO` flag, then calls `nft.setMetadata`. - `handleComputeOrder(...)` — the ordering state machine used in compute: validOrder + no fees → reuse as-is; validOrder + fees → `datatoken.reuseOrder` paying only provider fees; no order → `orderAsset` (pay 1 datatoken + fees). Approves provider-fee tokens first when the fee amount > 0. - `resolveComputeInputs(...)` + `parseComputeInput(...)` — parse the datasets/algo CLI strings (DID | JSON object | array | mixed | legacy `[did:a,did:b]`), resolve DID entries through `aquarius.waitForIndexer`, pass raw `fileObject` entries through (aligned with a `null` DDO slot), and pick `providerURI` from the first DID-based DDO's `serviceEndpoint` (else fall back to `NODE_URL`). diff --git a/README.md b/README.md index 209986f2..bf50041d 100644 --- a/README.md +++ b/README.md @@ -34,13 +34,37 @@ If you run into problems, please open up a [new issue](https://github.com/oceanp ## 🏗 Installation & Usage -### Clone and install +### Install globally (recommended) + +Install the CLI from npm to get the `ocean-cli` command available everywhere: + +```bash +npm install -g @oceanprotocol/cli +``` + +Then invoke it directly (from any directory): + +```bash +ocean-cli h # list commands +ocean-cli --version +ocean-cli publish metadata/simpleDownloadDataset.json +``` + +> `ocean-cli --help`, `ocean-cli -h`, `ocean-cli --version` and `ocean-cli h` work with **no** environment variables set. Every other command requires the env vars described below. + +### From source (for contributors) + +Clone and install, then run the CLI straight from TypeScript with `npm run cli` (no build step needed): ```bash -$ git clone https://github.com/oceanprotocol/ocean-cli.git +git clone https://github.com/oceanprotocol/ocean-cli.git +cd ocean-cli npm install +npm run cli h ``` +> **The command examples in this README use the `npm run cli ` form. If you installed globally, drop the `npm run cli` prefix and use `ocean-cli ` instead — the two are otherwise identical.** In interactive mode you can paste either form; a leading `npm run cli` or `ocean-cli` token is stripped automatically. + ### Set up environment variables - Set a private key(by exporting env "PRIVATE_KEY") or a mnemonic (by exporting env "MNEMONIC") @@ -73,22 +97,22 @@ export NODE_URL='XXXX' export ADDRESS_FILE='path-to-address-file' ``` -- Optional, set INDEXING_MAX_RETRIES to the max number of retries when waiting for an asset to be indexed. Default is 100 retries max. +- Optional, set INDEXING_MAX_RETRIES to the max number of retries when waiting for an asset to be indexed. Default is 120 retries max. ``` -export INDEXING_MAX_RETRIES='100' +export INDEXING_MAX_RETRIES='120' ``` -- Optional, set INDEXING_RETRY_INTERVAL to the interval (in miliseconds) for each retry when waiting for an asset to be indexed. Default is 3 seconds. +- Optional, set INDEXING_RETRY_INTERVAL to the interval (in miliseconds) for each retry when waiting for an asset to be indexed. Default is 4 seconds (4000 ms). ``` -export INDEXING_RETRY_INTERVAL='3000' +export INDEXING_RETRY_INTERVAL='4000' ``` -- Optional, set AVOID_LOOP_RUN to 'true' to run each command and exit afterwards (usefull for CI test env and default behaviour). IF not set or set to 'false' the CLI will listen interactively for commands, until exit is manually forced +- Optional, set AVOID_LOOP_RUN to `'true'` to run a single command and exit afterwards (one-shot mode — required for CI and scripting). **By default the CLI is interactive**: it runs the command you pass (if any), then keeps reading further commands from a prompt, just like a REPL. Exit the interactive loop with `exit` / `quit`, the **ESC** key, or **CTRL-C**. ``` -export AVOID_LOOP_RUN='true/false' +export AVOID_LOOP_RUN='true' # one-shot; unset or 'false' = interactive loop ``` - Optional, set SSI_WALLET_API, SSI_WALLET_ID, SSI_WALLET_DID to support v5 DDOs (assets using credentialSubject and SSI policy flows). @@ -138,7 +162,10 @@ npm run cli [options] #### Help Commands - **General help:** - `npm run cli --help` or `npm run cli -h` + `npm run cli --help` or `npm run cli -h` (globally: `ocean-cli --help` / `ocean-cli -h`) + +- **Version:** + `npm run cli --version` (globally: `ocean-cli --version`) - **Command-specific help:** `npm run cli help ` diff --git a/package-lock.json b/package-lock.json index a6822194..905b3d55 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,12 +1,12 @@ { - "name": "ocean-cli", - "version": "2.0.0", + "name": "@oceanprotocol/cli", + "version": "2.0.0-next.1", "lockfileVersion": 3, "requires": true, "packages": { "": { - "name": "ocean-cli", - "version": "2.0.0", + "name": "@oceanprotocol/cli", + "version": "2.0.0-next.1", "license": "Apache-2.0", "dependencies": { "@oasisprotocol/sapphire-paratime": "^1.3.2", @@ -14,16 +14,17 @@ "@oceanprotocol/ddo-js": "^0.3.0", "@oceanprotocol/lib": "^9.0.0-next.4", "axios": "^1.11.0", + "chalk": "^4.1.2", "commander": "^13.1.0", "cross-fetch": "^3.1.5", "crypto-js": "^4.1.1", "decimal.js": "^10.4.1", "enquirer": "^2.4.1", - "esm": "^3.2.25", "ethers": "^6.15.0", - "figlet": "^1.7.0", - "ts-node": "^10.9.1", - "tsx": "^4.19.3" + "figlet": "^1.7.0" + }, + "bin": { + "ocean-cli": "dist/index.js" }, "devDependencies": { "@eslint/js": "^9.4.0", @@ -32,6 +33,7 @@ "@types/node": "^20.2.5", "@typescript-eslint/eslint-plugin": "^5.60.1", "@typescript-eslint/parser": "^5.60.1", + "auto-changelog": "^2.4.0", "chai": "^4.3.7", "crypto": "^1.0.1", "eslint": "^8.44.0", @@ -43,6 +45,8 @@ "mocha": "^10.2.0", "prettier": "^2.8.8", "pretty-quick": "^3.1.3", + "release-it": "^19.2.4", + "ts-node": "^10.9.1", "tsx": "^4.19.2", "typescript": "^5.0.4", "typescript-eslint": "^7.12.0" @@ -1851,6 +1855,7 @@ "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==", + "dev": true, "license": "MIT", "dependencies": { "@jridgewell/trace-mapping": "0.3.9" @@ -1863,6 +1868,7 @@ "version": "0.3.9", "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.9.tgz", "integrity": "sha512-3Belt6tdc8bPgAtbcmdtNJlirVoTmEb5e2gC94PnkwEW9jI6CAHUeoG85tjWP5WquqfavoMtMwiG4P926ZKKuQ==", + "dev": true, "license": "MIT", "dependencies": { "@jridgewell/resolve-uri": "^3.0.3", @@ -2955,6 +2961,401 @@ "dev": true, "license": "BSD-3-Clause" }, + "node_modules/@inquirer/ansi": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/@inquirer/ansi/-/ansi-1.0.2.tgz", + "integrity": "sha512-S8qNSZiYzFd0wAcyG5AXCvUHC5Sr7xpZ9wZ2py9XR88jUz8wooStVx5M6dRzczbBWjic9NP7+rY0Xi7qqK/aMQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=18" + } + }, + "node_modules/@inquirer/checkbox": { + "version": "4.3.2", + "resolved": "https://registry.npmjs.org/@inquirer/checkbox/-/checkbox-4.3.2.tgz", + "integrity": "sha512-VXukHf0RR1doGe6Sm4F0Em7SWYLTHSsbGfJdS9Ja2bX5/D5uwVOEjr07cncLROdBvmnvCATYEWlHqYmXv2IlQA==", + "dev": true, + "license": "MIT", + "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" + }, + "engines": { + "node": ">=18" + }, + "peerDependencies": { + "@types/node": ">=18" + }, + "peerDependenciesMeta": { + "@types/node": { + "optional": true + } + } + }, + "node_modules/@inquirer/confirm": { + "version": "5.1.21", + "resolved": "https://registry.npmjs.org/@inquirer/confirm/-/confirm-5.1.21.tgz", + "integrity": "sha512-KR8edRkIsUayMXV+o3Gv+q4jlhENF9nMYUZs9PA2HzrXeHI8M5uDag70U7RJn9yyiMZSbtF5/UexBtAVtZGSbQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@inquirer/core": "^10.3.2", + "@inquirer/type": "^3.0.10" + }, + "engines": { + "node": ">=18" + }, + "peerDependencies": { + "@types/node": ">=18" + }, + "peerDependenciesMeta": { + "@types/node": { + "optional": true + } + } + }, + "node_modules/@inquirer/core": { + "version": "10.3.2", + "resolved": "https://registry.npmjs.org/@inquirer/core/-/core-10.3.2.tgz", + "integrity": "sha512-43RTuEbfP8MbKzedNqBrlhhNKVwoK//vUFNW3Q3vZ88BLcrs4kYpGg+B2mm5p2K/HfygoCxuKwJJiv8PbGmE0A==", + "dev": true, + "license": "MIT", + "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" + }, + "engines": { + "node": ">=18" + }, + "peerDependencies": { + "@types/node": ">=18" + }, + "peerDependenciesMeta": { + "@types/node": { + "optional": true + } + } + }, + "node_modules/@inquirer/core/node_modules/signal-exit": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-4.1.0.tgz", + "integrity": "sha512-bzyZ1e88w9O1iNJbKnOlvYTrWPDl46O1bG0D3XInv+9tkPrxrN8jUUTiFlDkkmKWgn1M6CfIA13SuGqOa9Korw==", + "dev": true, + "license": "ISC", + "engines": { + "node": ">=14" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/@inquirer/core/node_modules/wrap-ansi": { + "version": "6.2.0", + "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-6.2.0.tgz", + "integrity": "sha512-r6lPcBGxZXlIcymEu7InxDMhdW0KDxpLgoFLcguasxCaJ/SOIZwINatK9KY/tf+ZrlywOKU0UDj3ATXUBfxJXA==", + "dev": true, + "license": "MIT", + "dependencies": { + "ansi-styles": "^4.0.0", + "string-width": "^4.1.0", + "strip-ansi": "^6.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/@inquirer/editor": { + "version": "4.2.23", + "resolved": "https://registry.npmjs.org/@inquirer/editor/-/editor-4.2.23.tgz", + "integrity": "sha512-aLSROkEwirotxZ1pBaP8tugXRFCxW94gwrQLxXfrZsKkfjOYC1aRvAZuhpJOb5cu4IBTJdsCigUlf2iCOu4ZDQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@inquirer/core": "^10.3.2", + "@inquirer/external-editor": "^1.0.3", + "@inquirer/type": "^3.0.10" + }, + "engines": { + "node": ">=18" + }, + "peerDependencies": { + "@types/node": ">=18" + }, + "peerDependenciesMeta": { + "@types/node": { + "optional": true + } + } + }, + "node_modules/@inquirer/expand": { + "version": "4.0.23", + "resolved": "https://registry.npmjs.org/@inquirer/expand/-/expand-4.0.23.tgz", + "integrity": "sha512-nRzdOyFYnpeYTTR2qFwEVmIWypzdAx/sIkCMeTNTcflFOovfqUk+HcFhQQVBftAh9gmGrpFj6QcGEqrDMDOiew==", + "dev": true, + "license": "MIT", + "dependencies": { + "@inquirer/core": "^10.3.2", + "@inquirer/type": "^3.0.10", + "yoctocolors-cjs": "^2.1.3" + }, + "engines": { + "node": ">=18" + }, + "peerDependencies": { + "@types/node": ">=18" + }, + "peerDependenciesMeta": { + "@types/node": { + "optional": true + } + } + }, + "node_modules/@inquirer/external-editor": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/@inquirer/external-editor/-/external-editor-1.0.3.tgz", + "integrity": "sha512-RWbSrDiYmO4LbejWY7ttpxczuwQyZLBUyygsA9Nsv95hpzUWwnNTVQmAq3xuh7vNwCp07UTmE5i11XAEExx4RA==", + "dev": true, + "license": "MIT", + "dependencies": { + "chardet": "^2.1.1", + "iconv-lite": "^0.7.0" + }, + "engines": { + "node": ">=18" + }, + "peerDependencies": { + "@types/node": ">=18" + }, + "peerDependenciesMeta": { + "@types/node": { + "optional": true + } + } + }, + "node_modules/@inquirer/external-editor/node_modules/iconv-lite": { + "version": "0.7.3", + "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.7.3.tgz", + "integrity": "sha512-IKXpvIzjnC9XTAUbVBcMfGS0EPaIXtW6v+zr+RRp+hqULEpo0owZax6wyRwPOJbWbzjYspQwusTsfVr0ifh4uQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "safer-buffer": ">= 2.1.2 < 3.0.0" + }, + "engines": { + "node": ">=0.10.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/express" + } + }, + "node_modules/@inquirer/figures": { + "version": "1.0.15", + "resolved": "https://registry.npmjs.org/@inquirer/figures/-/figures-1.0.15.tgz", + "integrity": "sha512-t2IEY+unGHOzAaVM5Xx6DEWKeXlDDcNPeDyUpsRc6CUhBfU3VQOEl+Vssh7VNp1dR8MdUJBWhuObjXCsVpjN5g==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=18" + } + }, + "node_modules/@inquirer/input": { + "version": "4.3.1", + "resolved": "https://registry.npmjs.org/@inquirer/input/-/input-4.3.1.tgz", + "integrity": "sha512-kN0pAM4yPrLjJ1XJBjDxyfDduXOuQHrBB8aLDMueuwUGn+vNpF7Gq7TvyVxx8u4SHlFFj4trmj+a2cbpG4Jn1g==", + "dev": true, + "license": "MIT", + "dependencies": { + "@inquirer/core": "^10.3.2", + "@inquirer/type": "^3.0.10" + }, + "engines": { + "node": ">=18" + }, + "peerDependencies": { + "@types/node": ">=18" + }, + "peerDependenciesMeta": { + "@types/node": { + "optional": true + } + } + }, + "node_modules/@inquirer/number": { + "version": "3.0.23", + "resolved": "https://registry.npmjs.org/@inquirer/number/-/number-3.0.23.tgz", + "integrity": "sha512-5Smv0OK7K0KUzUfYUXDXQc9jrf8OHo4ktlEayFlelCjwMXz0299Y8OrI+lj7i4gCBY15UObk76q0QtxjzFcFcg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@inquirer/core": "^10.3.2", + "@inquirer/type": "^3.0.10" + }, + "engines": { + "node": ">=18" + }, + "peerDependencies": { + "@types/node": ">=18" + }, + "peerDependenciesMeta": { + "@types/node": { + "optional": true + } + } + }, + "node_modules/@inquirer/password": { + "version": "4.0.23", + "resolved": "https://registry.npmjs.org/@inquirer/password/-/password-4.0.23.tgz", + "integrity": "sha512-zREJHjhT5vJBMZX/IUbyI9zVtVfOLiTO66MrF/3GFZYZ7T4YILW5MSkEYHceSii/KtRk+4i3RE7E1CUXA2jHcA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@inquirer/ansi": "^1.0.2", + "@inquirer/core": "^10.3.2", + "@inquirer/type": "^3.0.10" + }, + "engines": { + "node": ">=18" + }, + "peerDependencies": { + "@types/node": ">=18" + }, + "peerDependenciesMeta": { + "@types/node": { + "optional": true + } + } + }, + "node_modules/@inquirer/prompts": { + "version": "7.10.1", + "resolved": "https://registry.npmjs.org/@inquirer/prompts/-/prompts-7.10.1.tgz", + "integrity": "sha512-Dx/y9bCQcXLI5ooQ5KyvA4FTgeo2jYj/7plWfV5Ak5wDPKQZgudKez2ixyfz7tKXzcJciTxqLeK7R9HItwiByg==", + "dev": true, + "license": "MIT", + "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" + }, + "engines": { + "node": ">=18" + }, + "peerDependencies": { + "@types/node": ">=18" + }, + "peerDependenciesMeta": { + "@types/node": { + "optional": true + } + } + }, + "node_modules/@inquirer/rawlist": { + "version": "4.1.11", + "resolved": "https://registry.npmjs.org/@inquirer/rawlist/-/rawlist-4.1.11.tgz", + "integrity": "sha512-+LLQB8XGr3I5LZN/GuAHo+GpDJegQwuPARLChlMICNdwW7OwV2izlCSCxN6cqpL0sMXmbKbFcItJgdQq5EBXTw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@inquirer/core": "^10.3.2", + "@inquirer/type": "^3.0.10", + "yoctocolors-cjs": "^2.1.3" + }, + "engines": { + "node": ">=18" + }, + "peerDependencies": { + "@types/node": ">=18" + }, + "peerDependenciesMeta": { + "@types/node": { + "optional": true + } + } + }, + "node_modules/@inquirer/search": { + "version": "3.2.2", + "resolved": "https://registry.npmjs.org/@inquirer/search/-/search-3.2.2.tgz", + "integrity": "sha512-p2bvRfENXCZdWF/U2BXvnSI9h+tuA8iNqtUKb9UWbmLYCRQxd8WkvwWvYn+3NgYaNwdUkHytJMGG4MMLucI1kA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@inquirer/core": "^10.3.2", + "@inquirer/figures": "^1.0.15", + "@inquirer/type": "^3.0.10", + "yoctocolors-cjs": "^2.1.3" + }, + "engines": { + "node": ">=18" + }, + "peerDependencies": { + "@types/node": ">=18" + }, + "peerDependenciesMeta": { + "@types/node": { + "optional": true + } + } + }, + "node_modules/@inquirer/select": { + "version": "4.4.2", + "resolved": "https://registry.npmjs.org/@inquirer/select/-/select-4.4.2.tgz", + "integrity": "sha512-l4xMuJo55MAe+N7Qr4rX90vypFwCajSakx59qe/tMaC1aEHWLyw68wF4o0A4SLAY4E0nd+Vt+EyskeDIqu1M6w==", + "dev": true, + "license": "MIT", + "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" + }, + "engines": { + "node": ">=18" + }, + "peerDependencies": { + "@types/node": ">=18" + }, + "peerDependenciesMeta": { + "@types/node": { + "optional": true + } + } + }, + "node_modules/@inquirer/type": { + "version": "3.0.10", + "resolved": "https://registry.npmjs.org/@inquirer/type/-/type-3.0.10.tgz", + "integrity": "sha512-BvziSRxfz5Ov8ch0z/n3oijRSEcEsHnhggm4xFZe93DHcUCTlutlq9Ox4SVENAfcRD22UQq7T/atg9Wr3k09eA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=18" + }, + "peerDependencies": { + "@types/node": ">=18" + }, + "peerDependenciesMeta": { + "@types/node": { + "optional": true + } + } + }, "node_modules/@jridgewell/gen-mapping": { "version": "0.3.12", "resolved": "https://registry.npmjs.org/@jridgewell/gen-mapping/-/gen-mapping-0.3.12.tgz", @@ -2970,6 +3371,7 @@ "version": "3.1.2", "resolved": "https://registry.npmjs.org/@jridgewell/resolve-uri/-/resolve-uri-3.1.2.tgz", "integrity": "sha512-bRISgCIjP20/tbWSPWMEi54QVPRZExkuD9lJL+UIxUKtwVJA8wW1Trb1jMs1RFXo1CBTNZ/5hpC9QvmKWdopKw==", + "dev": true, "license": "MIT", "engines": { "node": ">=6.0.0" @@ -2990,6 +3392,7 @@ "version": "1.5.4", "resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.5.4.tgz", "integrity": "sha512-VT2+G1VQs/9oz078bLrYbecdZKs912zQlkelYpuf+SXF+QvZDYJlbx/LSx+meSAwdDFnF8FVXW92AVjjkVmgFw==", + "dev": true, "license": "MIT" }, "node_modules/@jridgewell/trace-mapping": { @@ -3077,9 +3480,19 @@ "node": ">= 8" } }, - "node_modules/@oasisprotocol/deoxysii": { - "version": "0.0.5", - "resolved": "https://registry.npmjs.org/@oasisprotocol/deoxysii/-/deoxysii-0.0.5.tgz", + "node_modules/@nodeutils/defaults-deep": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@nodeutils/defaults-deep/-/defaults-deep-1.1.0.tgz", + "integrity": "sha512-gG44cwQovaOFdSR02jR9IhVRpnDP64VN6JdjYJTfNz4J4fWn7TQnmrf22nSjRqlwlxPcW8PL/L3KbJg3tdwvpg==", + "dev": true, + "license": "ISC", + "dependencies": { + "lodash": "^4.15.0" + } + }, + "node_modules/@oasisprotocol/deoxysii": { + "version": "0.0.5", + "resolved": "https://registry.npmjs.org/@oasisprotocol/deoxysii/-/deoxysii-0.0.5.tgz", "integrity": "sha512-a6wYPjk8ALDIiQW/971AKOTSTY1qSdld+Y05F44gVZvlb3FOyHfgbIxXm7CZnUG1A+jK49g5SCWYP+V3/Tc75Q==", "license": "MIT", "dependencies": { @@ -3209,6 +3622,201 @@ "web3": "^1.8.0" } }, + "node_modules/@octokit/auth-token": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/@octokit/auth-token/-/auth-token-6.0.0.tgz", + "integrity": "sha512-P4YJBPdPSpWTQ1NU4XYdvHvXJJDxM6YwpS0FZHRgP7YFkdVxsWcpWGy/NVqlAA7PcPCnMacXlRm1y2PFZRWL/w==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 20" + } + }, + "node_modules/@octokit/core": { + "version": "7.0.6", + "resolved": "https://registry.npmjs.org/@octokit/core/-/core-7.0.6.tgz", + "integrity": "sha512-DhGl4xMVFGVIyMwswXeyzdL4uXD5OGILGX5N8Y+f6W7LhC1Ze2poSNrkF/fedpVDHEEZ+PHFW0vL14I+mm8K3Q==", + "dev": true, + "license": "MIT", + "dependencies": { + "@octokit/auth-token": "^6.0.0", + "@octokit/graphql": "^9.0.3", + "@octokit/request": "^10.0.6", + "@octokit/request-error": "^7.0.2", + "@octokit/types": "^16.0.0", + "before-after-hook": "^4.0.0", + "universal-user-agent": "^7.0.0" + }, + "engines": { + "node": ">= 20" + } + }, + "node_modules/@octokit/endpoint": { + "version": "11.0.3", + "resolved": "https://registry.npmjs.org/@octokit/endpoint/-/endpoint-11.0.3.tgz", + "integrity": "sha512-FWFlNxghg4HrXkD3ifYbS/IdL/mDHjh9QcsNyhQjN8dplUoZbejsdpmuqdA76nxj2xoWPs7p8uX2SNr9rYu0Ag==", + "dev": true, + "license": "MIT", + "dependencies": { + "@octokit/types": "^16.0.0", + "universal-user-agent": "^7.0.2" + }, + "engines": { + "node": ">= 20" + } + }, + "node_modules/@octokit/graphql": { + "version": "9.0.3", + "resolved": "https://registry.npmjs.org/@octokit/graphql/-/graphql-9.0.3.tgz", + "integrity": "sha512-grAEuupr/C1rALFnXTv6ZQhFuL1D8G5y8CN04RgrO4FIPMrtm+mcZzFG7dcBm+nq+1ppNixu+Jd78aeJOYxlGA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@octokit/request": "^10.0.6", + "@octokit/types": "^16.0.0", + "universal-user-agent": "^7.0.0" + }, + "engines": { + "node": ">= 20" + } + }, + "node_modules/@octokit/openapi-types": { + "version": "27.0.0", + "resolved": "https://registry.npmjs.org/@octokit/openapi-types/-/openapi-types-27.0.0.tgz", + "integrity": "sha512-whrdktVs1h6gtR+09+QsNk2+FO+49j6ga1c55YZudfEG+oKJVvJLQi3zkOm5JjiUXAagWK2tI2kTGKJ2Ys7MGA==", + "dev": true, + "license": "MIT" + }, + "node_modules/@octokit/plugin-paginate-rest": { + "version": "14.0.0", + "resolved": "https://registry.npmjs.org/@octokit/plugin-paginate-rest/-/plugin-paginate-rest-14.0.0.tgz", + "integrity": "sha512-fNVRE7ufJiAA3XUrha2omTA39M6IXIc6GIZLvlbsm8QOQCYvpq/LkMNGyFlB1d8hTDzsAXa3OKtybdMAYsV/fw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@octokit/types": "^16.0.0" + }, + "engines": { + "node": ">= 20" + }, + "peerDependencies": { + "@octokit/core": ">=6" + } + }, + "node_modules/@octokit/plugin-request-log": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/@octokit/plugin-request-log/-/plugin-request-log-6.0.0.tgz", + "integrity": "sha512-UkOzeEN3W91/eBq9sPZNQ7sUBvYCqYbrrD8gTbBuGtHEuycE4/awMXcYvx6sVYo7LypPhmQwwpUe4Yyu4QZN5Q==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 20" + }, + "peerDependencies": { + "@octokit/core": ">=6" + } + }, + "node_modules/@octokit/plugin-rest-endpoint-methods": { + "version": "17.0.0", + "resolved": "https://registry.npmjs.org/@octokit/plugin-rest-endpoint-methods/-/plugin-rest-endpoint-methods-17.0.0.tgz", + "integrity": "sha512-B5yCyIlOJFPqUUeiD0cnBJwWJO8lkJs5d8+ze9QDP6SvfiXSz1BF+91+0MeI1d2yxgOhU/O+CvtiZ9jSkHhFAw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@octokit/types": "^16.0.0" + }, + "engines": { + "node": ">= 20" + }, + "peerDependencies": { + "@octokit/core": ">=6" + } + }, + "node_modules/@octokit/request": { + "version": "10.0.11", + "resolved": "https://registry.npmjs.org/@octokit/request/-/request-10.0.11.tgz", + "integrity": "sha512-+s7HUxjfFqOMS9VlIwDffq0MikjSAK0gSpG73W+meAvVAvX4MBrHYTK5Bj3Uot55qFT4gzUtfzE4mGWY4Br8/Q==", + "dev": true, + "license": "MIT", + "dependencies": { + "@octokit/endpoint": "^11.0.3", + "@octokit/request-error": "^7.0.2", + "@octokit/types": "^16.0.0", + "content-type": "^2.0.0", + "json-with-bigint": "^3.5.3", + "universal-user-agent": "^7.0.2" + }, + "engines": { + "node": ">= 20" + } + }, + "node_modules/@octokit/request-error": { + "version": "7.1.0", + "resolved": "https://registry.npmjs.org/@octokit/request-error/-/request-error-7.1.0.tgz", + "integrity": "sha512-KMQIfq5sOPpkQYajXHwnhjCC0slzCNScLHs9JafXc4RAJI+9f+jNDlBNaIMTvazOPLgb4BnlhGJOTbnN0wIjPw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@octokit/types": "^16.0.0" + }, + "engines": { + "node": ">= 20" + } + }, + "node_modules/@octokit/request/node_modules/content-type": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/content-type/-/content-type-2.0.0.tgz", + "integrity": "sha512-j/O/d7GcZCyNl7/hwZAb606rzqkyvaDctLmckbxLzHvFBzTJHuGEdodATcP3yIRoDrLHkIATJuvzbFlp/ki2cQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=18" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/express" + } + }, + "node_modules/@octokit/rest": { + "version": "22.0.1", + "resolved": "https://registry.npmjs.org/@octokit/rest/-/rest-22.0.1.tgz", + "integrity": "sha512-Jzbhzl3CEexhnivb1iQ0KJ7s5vvjMWcmRtq5aUsKmKDrRW6z3r84ngmiFKFvpZjpiU/9/S6ITPFRpn5s/3uQJw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@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" + }, + "engines": { + "node": ">= 20" + } + }, + "node_modules/@octokit/types": { + "version": "16.0.0", + "resolved": "https://registry.npmjs.org/@octokit/types/-/types-16.0.0.tgz", + "integrity": "sha512-sKq+9r1Mm4efXW1FCk7hFSeJo4QKreL/tTbR0rz/qx/r1Oa2VV83LTA/H/MuCOX7uCIJmQVRKBcbmWoySjAnSg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@octokit/openapi-types": "^27.0.0" + } + }, + "node_modules/@phun-ky/typeof": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/@phun-ky/typeof/-/typeof-2.0.3.tgz", + "integrity": "sha512-oeQJs1aa8Ghke8JIK9yuq/+KjMiaYeDZ38jx7MhkXncXlUKjqQ3wEm2X3qCKyjo+ZZofZj+WsEEiqkTtRuE2xQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": "^20.9.0 || >=22.0.0", + "npm": ">=10.8.2" + }, + "funding": { + "url": "https://github.com/phun-ky/typeof?sponsor=1" + } + }, "node_modules/@rdfjs/data-model": { "version": "2.1.1", "resolved": "https://registry.npmjs.org/@rdfjs/data-model/-/data-model-2.1.1.tgz", @@ -3520,6 +4128,13 @@ "node": ">=14.16" } }, + "node_modules/@tootallnate/quickjs-emscripten": { + "version": "0.23.0", + "resolved": "https://registry.npmjs.org/@tootallnate/quickjs-emscripten/-/quickjs-emscripten-0.23.0.tgz", + "integrity": "sha512-C5Mc6rdnsaJDjO3UpGW/CQTHtCKaYlScZTly4JIu97Jxo/odCiH0ITnDXSJPTOrEKk/ycSZ0AOgTmkDtkOsvIA==", + "dev": true, + "license": "MIT" + }, "node_modules/@tpluscode/rdf-ns-builders": { "version": "4.3.0", "resolved": "https://registry.npmjs.org/@tpluscode/rdf-ns-builders/-/rdf-ns-builders-4.3.0.tgz", @@ -3547,24 +4162,28 @@ "version": "1.0.11", "resolved": "https://registry.npmjs.org/@tsconfig/node10/-/node10-1.0.11.tgz", "integrity": "sha512-DcRjDCujK/kCk/cUe8Xz8ZSpm8mS3mNNpta+jGCA6USEDfktlNvm1+IuZ9eTcDbNk41BHwpHHeW+N1lKCz4zOw==", + "dev": true, "license": "MIT" }, "node_modules/@tsconfig/node12": { "version": "1.0.11", "resolved": "https://registry.npmjs.org/@tsconfig/node12/-/node12-1.0.11.tgz", "integrity": "sha512-cqefuRsh12pWyGsIoBKJA9luFu3mRxCA+ORZvA4ktLSzIuCUtWVxGIuXigEwO5/ywWFMZ2QEGKWvkZG1zDMTag==", + "dev": true, "license": "MIT" }, "node_modules/@tsconfig/node14": { "version": "1.0.3", "resolved": "https://registry.npmjs.org/@tsconfig/node14/-/node14-1.0.3.tgz", "integrity": "sha512-ysT8mhdixWK6Hw3i1V2AeRqZ5WfXg1G43mqoYlM2nc6388Fq5jcXyr5mRsqViLx/GJYdoL0bfXD8nmF+Zn/Iow==", + "dev": true, "license": "MIT" }, "node_modules/@tsconfig/node16": { "version": "1.0.4", "resolved": "https://registry.npmjs.org/@tsconfig/node16/-/node16-1.0.4.tgz", "integrity": "sha512-vxhUy4J8lyeyinH7Azl1pdd43GJhZH/tP2weN8TntQblOY+A0XbT8DJk1/oCPuOOyg/Ja757rG0CgHcWC8OfMA==", + "dev": true, "license": "MIT" }, "node_modules/@types/bn.js": { @@ -3658,6 +4277,13 @@ "dev": true, "license": "MIT" }, + "node_modules/@types/parse-path": { + "version": "7.0.3", + "resolved": "https://registry.npmjs.org/@types/parse-path/-/parse-path-7.0.3.tgz", + "integrity": "sha512-LriObC2+KYZD3FzCrgWGv/qufdUy4eXrxcLgQMfYXgPbLIecKIsVBaQgUPmxSSLcjmYbDTQbMgr6qr6l/eb7Bg==", + "dev": true, + "license": "MIT" + }, "node_modules/@types/pbkdf2": { "version": "3.1.2", "resolved": "https://registry.npmjs.org/@types/pbkdf2/-/pbkdf2-3.1.2.tgz", @@ -3969,6 +4595,7 @@ "version": "8.15.0", "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.15.0.tgz", "integrity": "sha512-NZyJarBfL7nWwIq+FDL6Zp/yHEhePMNnnJ0y3qfieCrmNvYct8uvtiV41UvlSe6apAfk0fY1FbWx+NwfmpvtTg==", + "dev": true, "license": "MIT", "bin": { "acorn": "bin/acorn" @@ -3991,6 +4618,7 @@ "version": "8.3.4", "resolved": "https://registry.npmjs.org/acorn-walk/-/acorn-walk-8.3.4.tgz", "integrity": "sha512-ueEepnujpqee2o5aIYnvHU6C0A42MNdsIDeqy5BydrkuC5R1ZuUFnm27EeFJGoEHJQgn3uleRvmTXaJgfXbt4g==", + "dev": true, "license": "MIT", "dependencies": { "acorn": "^8.11.0" @@ -4005,6 +4633,16 @@ "integrity": "sha512-G965FqalsNyrPqgEGON7nIx1e/OVENSgiEIzyC63haUMuvNnwIgIjMs52hlTCKhkBny7A2ORNlfY9Zu+jmGk1Q==", "license": "MIT" }, + "node_modules/agent-base": { + "version": "7.1.4", + "resolved": "https://registry.npmjs.org/agent-base/-/agent-base-7.1.4.tgz", + "integrity": "sha512-MnA+YT8fwfJPgBx3m60MNqakm30XOkyIoH1y6huTQvC0PwZG7ki8NacLBcrPbNoo8vEZy7Jpuk7+jMO+CUovTQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 14" + } + }, "node_modules/ajv": { "version": "6.12.6", "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.6.tgz", @@ -4043,7 +4681,6 @@ "version": "4.3.0", "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", - "dev": true, "license": "MIT", "dependencies": { "color-convert": "^2.0.1" @@ -4073,6 +4710,7 @@ "version": "4.1.3", "resolved": "https://registry.npmjs.org/arg/-/arg-4.1.3.tgz", "integrity": "sha512-58S9QDqG0Xx27YwPSt9fJxivjYl432YCwfDMfZ+71RAqUrZef7LrKQZ3LHLOwCS4FLNBplP533Zx895SeOCHvA==", + "dev": true, "license": "MIT" }, "node_modules/argparse": { @@ -4289,6 +4927,19 @@ "node": "*" } }, + "node_modules/ast-types": { + "version": "0.13.4", + "resolved": "https://registry.npmjs.org/ast-types/-/ast-types-0.13.4.tgz", + "integrity": "sha512-x1FCFnFifvYDDzTaLII71vG5uvDwgtmDTEVWAxrgeiR8VjMONcCXJx7E+USjDtHlwFmt9MysbqgF9b9Vjr6w+w==", + "dev": true, + "license": "MIT", + "dependencies": { + "tslib": "^2.0.1" + }, + "engines": { + "node": ">=4" + } + }, "node_modules/async": { "version": "3.2.6", "resolved": "https://registry.npmjs.org/async/-/async-3.2.6.tgz", @@ -4313,6 +4964,16 @@ "license": "MIT", "peer": true }, + "node_modules/async-retry": { + "version": "1.3.3", + "resolved": "https://registry.npmjs.org/async-retry/-/async-retry-1.3.3.tgz", + "integrity": "sha512-wfr/jstw9xNi/0teMHrRW7dsz3Lt5ARhYNZ2ewpadnhaIp5mbALhOAP+EAdsC7t4Z6wqsDVv9+W6gm1Dk9mEyw==", + "dev": true, + "license": "MIT", + "dependencies": { + "retry": "0.13.1" + } + }, "node_modules/asynckit": { "version": "0.4.0", "resolved": "https://registry.npmjs.org/asynckit/-/asynckit-0.4.0.tgz", @@ -4326,6 +4987,49 @@ "dev": true, "license": "MIT" }, + "node_modules/auto-changelog": { + "version": "2.6.0", + "resolved": "https://registry.npmjs.org/auto-changelog/-/auto-changelog-2.6.0.tgz", + "integrity": "sha512-jJgUkuWXQ7fPLPXOMQk/XSSmy7KvzpzhjJa6w660dq1KTEez/GW2CPckBra3jMMMMpcwxp84bOslo29qRCewzA==", + "dev": true, + "license": "MIT", + "dependencies": { + "commander": "^7.2.0", + "handlebars": "^4.7.9", + "import-cwd": "^3.0.0", + "parse-github-url": "^1.0.4", + "semver": "^7.8.1" + }, + "bin": { + "auto-changelog": "src/index.js" + }, + "engines": { + "node": ">= 10" + } + }, + "node_modules/auto-changelog/node_modules/commander": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/commander/-/commander-7.2.0.tgz", + "integrity": "sha512-QrWXB+ZQSVPmIWIhtEO9H+gwHaMGYiF5ChvoJ+K9ZGHG/sVsa6yiesAD1GC/x46sET00Xlwo1u49RVVVzvcSkw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 10" + } + }, + "node_modules/auto-changelog/node_modules/semver": { + "version": "7.8.5", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.8.5.tgz", + "integrity": "sha512-Y7/KDsb8LjooZpwaqGyulO6DQlksgCncchHGk+sZIY4SBvUocMBEFH5Ur1fI4dV+Jvl0w6cjvucaIi40puRioA==", + "dev": true, + "license": "ISC", + "bin": { + "semver": "bin/semver.js" + }, + "engines": { + "node": ">=10" + } + }, "node_modules/autoprefixer": { "version": "10.4.21", "resolved": "https://registry.npmjs.org/autoprefixer/-/autoprefixer-10.4.21.tgz", @@ -4548,6 +5252,16 @@ ], "license": "MIT" }, + "node_modules/basic-ftp": { + "version": "5.3.1", + "resolved": "https://registry.npmjs.org/basic-ftp/-/basic-ftp-5.3.1.tgz", + "integrity": "sha512-bopVNp6ugyA150DDuZfPFdt1KZ5a94ZDiwX4hMgZDzF+GttD80lEy8kj98kbyhLXnPvhtIo93mdnLIjpCAeeOw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=10.0.0" + } + }, "node_modules/bcrypt-pbkdf": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/bcrypt-pbkdf/-/bcrypt-pbkdf-1.0.2.tgz", @@ -4565,6 +5279,13 @@ "license": "Unlicense", "peer": true }, + "node_modules/before-after-hook": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/before-after-hook/-/before-after-hook-4.0.0.tgz", + "integrity": "sha512-q6tR3RPqIB1pMiTRMFcZwuG5T8vwp+vUvEG0vuI6B+Rikh5BfPp2fQ82c925FOs+b0lcFQ8CFrL+KbilfZFhOQ==", + "dev": true, + "license": "Apache-2.0" + }, "node_modules/bignumber.js": { "version": "9.3.1", "resolved": "https://registry.npmjs.org/bignumber.js/-/bignumber.js-9.3.1.tgz", @@ -4875,6 +5596,22 @@ "semver": "^7.0.0" } }, + "node_modules/bundle-name": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/bundle-name/-/bundle-name-4.1.0.tgz", + "integrity": "sha512-tjwM5exMg6BGRI+kNmTntNsvdZS1X8BFYS6tnJ2hdH0kVxM6/eVZ2xy+FqStSWvYmtfFMDLIxurorHwDKfDz5Q==", + "dev": true, + "license": "MIT", + "dependencies": { + "run-applescript": "^7.0.0" + }, + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, "node_modules/bytes": { "version": "3.1.2", "resolved": "https://registry.npmjs.org/bytes/-/bytes-3.1.2.tgz", @@ -4885,6 +5622,65 @@ "node": ">= 0.8" } }, + "node_modules/c12": { + "version": "3.3.3", + "resolved": "https://registry.npmjs.org/c12/-/c12-3.3.3.tgz", + "integrity": "sha512-750hTRvgBy5kcMNPdh95Qo+XUBeGo8C7nsKSmedDmaQI+E0r82DwHeM6vBewDe4rGFbnxoa4V9pw+sPh5+Iz8Q==", + "dev": true, + "license": "MIT", + "dependencies": { + "chokidar": "^5.0.0", + "confbox": "^0.2.2", + "defu": "^6.1.4", + "dotenv": "^17.2.3", + "exsolve": "^1.0.8", + "giget": "^2.0.0", + "jiti": "^2.6.1", + "ohash": "^2.0.11", + "pathe": "^2.0.3", + "perfect-debounce": "^2.0.0", + "pkg-types": "^2.3.0", + "rc9": "^2.1.2" + }, + "peerDependencies": { + "magicast": "*" + }, + "peerDependenciesMeta": { + "magicast": { + "optional": true + } + } + }, + "node_modules/c12/node_modules/chokidar": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-5.0.0.tgz", + "integrity": "sha512-TQMmc3w+5AxjpL8iIiwebF73dRDF4fBIieAqGn9RGCWaEVwQ6Fb2cGe31Yns0RRIzii5goJ1Y7xbMwo1TxMplw==", + "dev": true, + "license": "MIT", + "dependencies": { + "readdirp": "^5.0.0" + }, + "engines": { + "node": ">= 20.19.0" + }, + "funding": { + "url": "https://paulmillr.com/funding/" + } + }, + "node_modules/c12/node_modules/readdirp": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-5.0.0.tgz", + "integrity": "sha512-9u/XQ1pvrQtYyMpZe7DXKv2p5CNvyVwzUB6uhLAnQwHMSgKMBR62lc7AHljaeteeHXn11XTAaLLUVZYVZyuRBQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 20.19.0" + }, + "funding": { + "type": "individual", + "url": "https://paulmillr.com/funding/" + } + }, "node_modules/cacheable-lookup": { "version": "6.1.0", "resolved": "https://registry.npmjs.org/cacheable-lookup/-/cacheable-lookup-6.1.0.tgz", @@ -5089,7 +5885,6 @@ "version": "4.1.2", "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", - "dev": true, "license": "MIT", "dependencies": { "ansi-styles": "^4.1.0", @@ -5102,6 +5897,13 @@ "url": "https://github.com/chalk/chalk?sponsor=1" } }, + "node_modules/chardet": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/chardet/-/chardet-2.2.0.tgz", + "integrity": "sha512-rddelWYNPRrXq6PtNEN2S3f6t9ILzvqaN5pVgi4kqt9jHQaXIial9PznB5iSPVlQSLNaaH22ItWz3EJtQ10+OA==", + "dev": true, + "license": "MIT" + }, "node_modules/check-error": { "version": "1.0.3", "resolved": "https://registry.npmjs.org/check-error/-/check-error-1.0.3.tgz", @@ -5160,6 +5962,22 @@ "license": "ISC", "peer": true }, + "node_modules/ci-info": { + "version": "4.4.0", + "resolved": "https://registry.npmjs.org/ci-info/-/ci-info-4.4.0.tgz", + "integrity": "sha512-77PSwercCZU2Fc4sX94eF8k8Pxte6JAwL4/ICZLFjJLqegs7kCuAsqqj/70NQF6TvDpgFjkubQB2FW2ZZddvQg==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/sibiraj-s" + } + ], + "license": "MIT", + "engines": { + "node": ">=8" + } + }, "node_modules/cids": { "version": "0.7.5", "resolved": "https://registry.npmjs.org/cids/-/cids-0.7.5.tgz", @@ -5230,6 +6048,16 @@ "node": ">= 0.10" } }, + "node_modules/citty": { + "version": "0.1.6", + "resolved": "https://registry.npmjs.org/citty/-/citty-0.1.6.tgz", + "integrity": "sha512-tskPPKEs8D2KPafUypv2gxwJP8h/OaJmC82QQGGDQcHvXX43xF2VDACcJVmZ0EuSxkpO9Kc4MlrA3q0+FG58AQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "consola": "^3.2.3" + } + }, "node_modules/class-is": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/class-is/-/class-is-1.1.0.tgz", @@ -5237,7 +6065,46 @@ "license": "MIT", "peer": true }, - "node_modules/cliui": { + "node_modules/cli-cursor": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/cli-cursor/-/cli-cursor-5.0.0.tgz", + "integrity": "sha512-aCj4O5wKyszjMmDT4tZj93kxyydN/K5zPWSCe6/0AV/AA1pqe5ZBIw0a2ZfPQV7lL5/yb5HsUreJ6UFAF1tEQw==", + "dev": true, + "license": "MIT", + "dependencies": { + "restore-cursor": "^5.0.0" + }, + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/cli-spinners": { + "version": "3.4.0", + "resolved": "https://registry.npmjs.org/cli-spinners/-/cli-spinners-3.4.0.tgz", + "integrity": "sha512-bXfOC4QcT1tKXGorxL3wbJm6XJPDqEnij2gQ2m7ESQuE+/z9YFIWnl/5RpTiKWbMq3EVKR4fRLJGn6DVfu0mpw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=18.20" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/cli-width": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/cli-width/-/cli-width-4.1.0.tgz", + "integrity": "sha512-ouuZd4/dm2Sw5Gmqy6bGyNNNe1qt9RpmxveLSO7KcgsTnU7RXfsw+/bukWGo1abgBiMAic068rclZsO4IWmmxQ==", + "dev": true, + "license": "ISC", + "engines": { + "node": ">= 12" + } + }, + "node_modules/cliui": { "version": "7.0.4", "resolved": "https://registry.npmjs.org/cliui/-/cliui-7.0.4.tgz", "integrity": "sha512-OcRE68cOsVMXp1Yvonl/fzkQOyjLSu/8bhPDfQt0e0/Eb283TKP20Fs2MqoPsr9SwA595rRCA+QMzYc9nBP+JQ==", @@ -5277,7 +6144,6 @@ "version": "2.0.1", "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", - "dev": true, "license": "MIT", "dependencies": { "color-name": "~1.1.4" @@ -5290,7 +6156,6 @@ "version": "1.1.4", "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", - "dev": true, "license": "MIT" }, "node_modules/colord": { @@ -5345,6 +6210,23 @@ "source-map": "^0.6.1" } }, + "node_modules/confbox": { + "version": "0.2.4", + "resolved": "https://registry.npmjs.org/confbox/-/confbox-0.2.4.tgz", + "integrity": "sha512-ysOGlgTFbN2/Y6Cg3Iye8YKulHw+R2fNXHrgSmXISQdMnomY6eNDprVdW9R5xBguEqI954+S6709UyiO7B+6OQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/consola": { + "version": "3.4.2", + "resolved": "https://registry.npmjs.org/consola/-/consola-3.4.2.tgz", + "integrity": "sha512-5IKcdX0nnYavi6G7TtOhwkYzyjfJlatbjMjuLSfE2kYT5pMDOilZ4OvMhi637CcDICTmz3wARPoyhqyX1Y+XvA==", + "dev": true, + "license": "MIT", + "engines": { + "node": "^14.18.0 || >=16.10.0" + } + }, "node_modules/content-disposition": { "version": "0.5.4", "resolved": "https://registry.npmjs.org/content-disposition/-/content-disposition-0.5.4.tgz", @@ -5502,6 +6384,7 @@ "version": "1.1.1", "resolved": "https://registry.npmjs.org/create-require/-/create-require-1.1.1.tgz", "integrity": "sha512-dcKFX3jn0MpIaXjisoRvexIJVEKzaq7z2rZKxf+MSr9TkdmHmsU4m2lcLojrj/FHl8mk5VxMmYA+ftRkP/3oKQ==", + "dev": true, "license": "MIT" }, "node_modules/cross-fetch": { @@ -5899,6 +6782,36 @@ "node": ">=0.10.0" } }, + "node_modules/default-browser": { + "version": "5.5.0", + "resolved": "https://registry.npmjs.org/default-browser/-/default-browser-5.5.0.tgz", + "integrity": "sha512-H9LMLr5zwIbSxrmvikGuI/5KGhZ8E2zH3stkMgM5LpOWDutGM2JZaj460Udnf1a+946zc7YBgrqEWwbk7zHvGw==", + "dev": true, + "license": "MIT", + "dependencies": { + "bundle-name": "^4.1.0", + "default-browser-id": "^5.0.0" + }, + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/default-browser-id": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/default-browser-id/-/default-browser-id-5.0.1.tgz", + "integrity": "sha512-x1VCxdX4t+8wVfd1so/9w+vQ4vx7lKd2Qp5tDRutErwmR85OgmfX7RlLRMWafRMY7hbEiXIbudNrjOAPa/hL8Q==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, "node_modules/defer-to-connect": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/defer-to-connect/-/defer-to-connect-2.0.1.tgz", @@ -5954,6 +6867,28 @@ "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/defu": { + "version": "6.1.7", + "resolved": "https://registry.npmjs.org/defu/-/defu-6.1.7.tgz", + "integrity": "sha512-7z22QmUWiQ/2d0KkdYmANbRUVABpZ9SNYyH5vx6PZ+nE5bcC0l7uFvEfHlyld/HcGBFTL536ClDt3DEcSlEJAQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/degenerator": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/degenerator/-/degenerator-5.0.1.tgz", + "integrity": "sha512-TllpMR/t0M5sqCXfj85i4XaAzxmS5tVA16dqvdkMwGmzI+dXLXnw3J+3Vdv7VKw+ThlTMboK6i9rnZ6Nntj5CQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "ast-types": "^0.13.4", + "escodegen": "^2.1.0", + "esprima": "^4.0.1" + }, + "engines": { + "node": ">= 14" + } + }, "node_modules/delayed-stream": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/delayed-stream/-/delayed-stream-1.0.0.tgz", @@ -5973,6 +6908,13 @@ "node": ">= 0.8" } }, + "node_modules/destr": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/destr/-/destr-2.0.5.tgz", + "integrity": "sha512-ugFTXCtDZunbzasqBxrK93Ik/DRYsO6S/fedkWEMKqt04xZ4csmnmwGDBAb07QWNaGMAmnTIemsYZCksjATwsA==", + "dev": true, + "license": "MIT" + }, "node_modules/destroy": { "version": "1.2.0", "resolved": "https://registry.npmjs.org/destroy/-/destroy-1.2.0.tgz", @@ -6085,6 +7027,19 @@ "url": "https://github.com/fb55/domutils?sponsor=1" } }, + "node_modules/dotenv": { + "version": "17.4.2", + "resolved": "https://registry.npmjs.org/dotenv/-/dotenv-17.4.2.tgz", + "integrity": "sha512-nI4U3TottKAcAD9LLud4Cb7b2QztQMUEfHbvhTH09bqXTxnSie8WnjPALV/WMCrJZ6UV/qHJ6L03OqO3LcdYZw==", + "dev": true, + "license": "BSD-2-Clause", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://dotenvx.com" + } + }, "node_modules/dunder-proto": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/dunder-proto/-/dunder-proto-1.0.1.tgz", @@ -6569,6 +7524,28 @@ "url": "https://github.com/sponsors/sindresorhus" } }, + "node_modules/escodegen": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/escodegen/-/escodegen-2.1.0.tgz", + "integrity": "sha512-2NlIDTwUWJN0mRPQOdtQBzbUHvdGY2P1VXSyU83Q3xKxM7WHX2Ql8dKq782Q9TgQUNOLEzEYu9bzLNj1q88I5w==", + "dev": true, + "license": "BSD-2-Clause", + "dependencies": { + "esprima": "^4.0.1", + "estraverse": "^5.2.0", + "esutils": "^2.0.2" + }, + "bin": { + "escodegen": "bin/escodegen.js", + "esgenerate": "bin/esgenerate.js" + }, + "engines": { + "node": ">=6.0" + }, + "optionalDependencies": { + "source-map": "~0.6.1" + } + }, "node_modules/eslint": { "version": "8.57.1", "resolved": "https://registry.npmjs.org/eslint/-/eslint-8.57.1.tgz", @@ -7224,15 +8201,6 @@ "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/esm": { - "version": "3.2.25", - "resolved": "https://registry.npmjs.org/esm/-/esm-3.2.25.tgz", - "integrity": "sha512-U1suiZ2oDVWv4zPO56S0NcR5QriEahGtdN2OR6FiOG4WJvcjBVFB0qI4+eKoWFH483PKGuLuu6V8Z4T5g63UVA==", - "license": "MIT", - "engines": { - "node": ">=6" - } - }, "node_modules/esniff": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/esniff/-/esniff-2.0.1.tgz", @@ -7267,6 +8235,20 @@ "url": "https://opencollective.com/eslint" } }, + "node_modules/esprima": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/esprima/-/esprima-4.0.1.tgz", + "integrity": "sha512-eGuFFw7Upda+g4p+QHvnW0RyTX/SVeJBDM/gCtMARO0cLuT2HcEKnTPvhjV6aGeqrCB/sbNop0Kszm0jsaWU4A==", + "dev": true, + "license": "BSD-2-Clause", + "bin": { + "esparse": "bin/esparse.js", + "esvalidate": "bin/esvalidate.js" + }, + "engines": { + "node": ">=4" + } + }, "node_modules/esquery": { "version": "1.6.0", "resolved": "https://registry.npmjs.org/esquery/-/esquery-1.6.0.tgz", @@ -7320,6 +8302,19 @@ "node": ">=0.10.0" } }, + "node_modules/eta": { + "version": "4.5.0", + "resolved": "https://registry.npmjs.org/eta/-/eta-4.5.0.tgz", + "integrity": "sha512-qifAYjuW5AM1eEEIsFnOwB+TGqu6ynU3OKj9WbUTOtUBHFPZqL03XUW34kbp3zm19Ald+U8dEyRXaVsUck+Y1g==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=20" + }, + "funding": { + "url": "https://github.com/bgub/eta?sponsor=1" + } + }, "node_modules/etag": { "version": "1.8.1", "resolved": "https://registry.npmjs.org/etag/-/etag-1.8.1.tgz", @@ -7721,6 +8716,13 @@ "license": "MIT", "peer": true }, + "node_modules/exsolve": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/exsolve/-/exsolve-1.1.0.tgz", + "integrity": "sha512-D+42+T12DdIlJM3uepa55qGiL3sYdLBOxIl2ifQCzCHz4c7eiolaHsi3BIqEr7JxBzxv2pYZQX9kw16ziMcEmw==", + "dev": true, + "license": "MIT" + }, "node_modules/ext": { "version": "1.7.0", "resolved": "https://registry.npmjs.org/ext/-/ext-1.7.0.tgz", @@ -8260,6 +9262,19 @@ "node": "6.* || 8.* || >= 10.*" } }, + "node_modules/get-east-asian-width": { + "version": "1.6.0", + "resolved": "https://registry.npmjs.org/get-east-asian-width/-/get-east-asian-width-1.6.0.tgz", + "integrity": "sha512-QRbvDIbx6YklUe6RxeTeleMR0yv3cYH6PsPZHcnVn7xv7zO1BHN8r0XETu8n6Ye3Q+ahtSarc3WgtNWmehIBfA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, "node_modules/get-func-name": { "version": "2.0.2", "resolved": "https://registry.npmjs.org/get-func-name/-/get-func-name-2.0.2.tgz", @@ -8307,6 +9322,19 @@ "node": ">= 0.4" } }, + "node_modules/get-stream": { + "version": "8.0.1", + "resolved": "https://registry.npmjs.org/get-stream/-/get-stream-8.0.1.tgz", + "integrity": "sha512-VaUJspBffn/LMCJVoMvSAdmscJyS1auj5Zulnn5UoYcY531UWmdwhRWkcGKnGU93m5HSXP9LP2usOryrBtQowA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=16" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, "node_modules/get-symbol-description": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/get-symbol-description/-/get-symbol-description-1.1.0.tgz", @@ -8338,6 +9366,31 @@ "url": "https://github.com/privatenumber/get-tsconfig?sponsor=1" } }, + "node_modules/get-uri": { + "version": "6.0.5", + "resolved": "https://registry.npmjs.org/get-uri/-/get-uri-6.0.5.tgz", + "integrity": "sha512-b1O07XYq8eRuVzBNgJLstU6FYc1tS6wnMtF1I1D9lE8LxZSOGZ7LhxN54yPP6mGw5f2CkXY2BQUL9Fx41qvcIg==", + "dev": true, + "license": "MIT", + "dependencies": { + "basic-ftp": "^5.0.2", + "data-uri-to-buffer": "^6.0.2", + "debug": "^4.3.4" + }, + "engines": { + "node": ">= 14" + } + }, + "node_modules/get-uri/node_modules/data-uri-to-buffer": { + "version": "6.0.2", + "resolved": "https://registry.npmjs.org/data-uri-to-buffer/-/data-uri-to-buffer-6.0.2.tgz", + "integrity": "sha512-7hvf7/GW8e86rW0ptuwS3OcBGDjIi6SZva7hCyWC0yYry2cOPmLIjXAUHI6DK2HsnwJd9ifmt57i8eV2n4YNpw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 14" + } + }, "node_modules/getpass": { "version": "0.1.7", "resolved": "https://registry.npmjs.org/getpass/-/getpass-0.1.7.tgz", @@ -8348,6 +9401,45 @@ "assert-plus": "^1.0.0" } }, + "node_modules/giget": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/giget/-/giget-2.0.0.tgz", + "integrity": "sha512-L5bGsVkxJbJgdnwyuheIunkGatUF/zssUoxxjACCseZYAVbaqdh9Tsmmlkl8vYan09H7sbvKt4pS8GqKLBrEzA==", + "dev": true, + "license": "MIT", + "dependencies": { + "citty": "^0.1.6", + "consola": "^3.4.0", + "defu": "^6.1.4", + "node-fetch-native": "^1.6.6", + "nypm": "^0.6.0", + "pathe": "^2.0.3" + }, + "bin": { + "giget": "dist/cli.mjs" + } + }, + "node_modules/git-up": { + "version": "8.1.1", + "resolved": "https://registry.npmjs.org/git-up/-/git-up-8.1.1.tgz", + "integrity": "sha512-FDenSF3fVqBYSaJoYy1KSc2wosx0gCvKP+c+PRBht7cAaiCeQlBtfBDX9vgnNOHmdePlSFITVcn4pFfcgNvx3g==", + "dev": true, + "license": "MIT", + "dependencies": { + "is-ssh": "^1.4.0", + "parse-url": "^9.2.0" + } + }, + "node_modules/git-url-parse": { + "version": "16.1.0", + "resolved": "https://registry.npmjs.org/git-url-parse/-/git-url-parse-16.1.0.tgz", + "integrity": "sha512-cPLz4HuK86wClEW7iDdeAKcCVlWXmrLpb2L+G9goW0Z1dtpNS6BXXSOckUTlJT/LDQViE1QZKstNORzHsLnobw==", + "dev": true, + "license": "MIT", + "dependencies": { + "git-up": "^8.1.0" + } + }, "node_modules/glob": { "version": "7.2.3", "resolved": "https://registry.npmjs.org/glob/-/glob-7.2.3.tgz", @@ -8548,6 +9640,28 @@ "dev": true, "license": "MIT" }, + "node_modules/handlebars": { + "version": "4.7.9", + "resolved": "https://registry.npmjs.org/handlebars/-/handlebars-4.7.9.tgz", + "integrity": "sha512-4E71E0rpOaQuJR2A3xDZ+GM1HyWYv1clR58tC8emQNeQe3RH7MAzSbat+V0wG78LQBo6m6bzSG/L4pBuCsgnUQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "minimist": "^1.2.5", + "neo-async": "^2.6.2", + "source-map": "^0.6.1", + "wordwrap": "^1.0.0" + }, + "bin": { + "handlebars": "bin/handlebars" + }, + "engines": { + "node": ">=0.4.7" + }, + "optionalDependencies": { + "uglify-js": "^3.1.4" + } + }, "node_modules/har-schema": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/har-schema/-/har-schema-2.0.0.tgz", @@ -8613,7 +9727,6 @@ "version": "4.0.0", "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", - "dev": true, "license": "MIT", "engines": { "node": ">=8" @@ -8780,6 +9893,20 @@ "license": "ISC", "peer": true }, + "node_modules/http-proxy-agent": { + "version": "7.0.2", + "resolved": "https://registry.npmjs.org/http-proxy-agent/-/http-proxy-agent-7.0.2.tgz", + "integrity": "sha512-T1gkAiYYDWYx3V5Bmyu7HcfcvL7mUrTWiM6yOfa3PIphViJ/gFPbvidQ+veqSOHci/PxBcDabeUNCzpOODJZig==", + "dev": true, + "license": "MIT", + "dependencies": { + "agent-base": "^7.1.0", + "debug": "^4.3.4" + }, + "engines": { + "node": ">= 14" + } + }, "node_modules/http-signature": { "version": "1.2.0", "resolved": "https://registry.npmjs.org/http-signature/-/http-signature-1.2.0.tgz", @@ -8810,6 +9937,20 @@ "node": ">=10.19.0" } }, + "node_modules/https-proxy-agent": { + "version": "7.0.6", + "resolved": "https://registry.npmjs.org/https-proxy-agent/-/https-proxy-agent-7.0.6.tgz", + "integrity": "sha512-vK9P5/iUfdl95AI+JVyUuIcVtd4ofvtrOr3HNtM2yxC9bnMbEdp3x01OhQNnjb8IJYi38VlTE3mBXwcfvywuSw==", + "dev": true, + "license": "MIT", + "dependencies": { + "agent-base": "^7.1.2", + "debug": "4" + }, + "engines": { + "node": ">= 14" + } + }, "node_modules/human-signals": { "version": "1.1.1", "resolved": "https://registry.npmjs.org/human-signals/-/human-signals-1.1.1.tgz", @@ -8987,6 +10128,33 @@ "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==", "license": "ISC" }, + "node_modules/inquirer": { + "version": "12.11.1", + "resolved": "https://registry.npmjs.org/inquirer/-/inquirer-12.11.1.tgz", + "integrity": "sha512-9VF7mrY+3OmsAfjH3yKz/pLbJ5z22E23hENKw3/LNSaA/sAt3v49bDRY+Ygct1xwuKT+U+cBfTzjCPySna69Qw==", + "dev": true, + "license": "MIT", + "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" + }, + "engines": { + "node": ">=18" + }, + "peerDependencies": { + "@types/node": ">=18" + }, + "peerDependenciesMeta": { + "@types/node": { + "optional": true + } + } + }, "node_modules/internal-slot": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/internal-slot/-/internal-slot-1.1.0.tgz", @@ -9002,6 +10170,16 @@ "node": ">= 0.4" } }, + "node_modules/ip-address": { + "version": "10.2.0", + "resolved": "https://registry.npmjs.org/ip-address/-/ip-address-10.2.0.tgz", + "integrity": "sha512-/+S6j4E9AHvW9SWMSEY9Xfy66O5PWvVEJ08O0y5JGyEKQpojb0K0GKpz/v5HJ/G0vi3D2sjGK78119oXZeE0qA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 12" + } + }, "node_modules/ipaddr.js": { "version": "1.9.1", "resolved": "https://registry.npmjs.org/ipaddr.js/-/ipaddr.js-1.9.1.tgz", @@ -9284,34 +10462,82 @@ "npm": ">=3" } }, - "node_modules/is-map": { - "version": "2.0.3", - "resolved": "https://registry.npmjs.org/is-map/-/is-map-2.0.3.tgz", - "integrity": "sha512-1Qed0/Hr2m+YqxnM09CjA2d/i6YZNfF6R2oRAOj36eUdS6qIV/huPJNSEpKbupewFs+ZsJlxsjjPbc0/afW6Lw==", + "node_modules/is-inside-container": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-inside-container/-/is-inside-container-1.0.0.tgz", + "integrity": "sha512-KIYLCCJghfHZxqjYBE7rEy0OBuTd5xCHS7tHVgvCLkx7StIoaxwNW3hCALgEUjFfeRk+MG/Qxmp/vtETEF3tRA==", "dev": true, "license": "MIT", + "dependencies": { + "is-docker": "^3.0.0" + }, + "bin": { + "is-inside-container": "cli.js" + }, "engines": { - "node": ">= 0.4" + "node": ">=14.16" }, "funding": { - "url": "https://github.com/sponsors/ljharb" + "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/is-module": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/is-module/-/is-module-1.0.0.tgz", - "integrity": "sha512-51ypPSPCoTEIN9dy5Oy+h4pShgJmPCygKfyRCISBI+JoWT/2oJvK8QPxmwv7b/p239jXrm9M1mlQbyKJ5A152g==", - "dev": true, - "license": "MIT" - }, - "node_modules/is-negative-zero": { - "version": "2.0.3", - "resolved": "https://registry.npmjs.org/is-negative-zero/-/is-negative-zero-2.0.3.tgz", - "integrity": "sha512-5KoIu2Ngpyek75jXodFvnafB6DJgr3u8uuK0LEZJjrU19DrMD3EVERaR8sjz8CCGgpZvxPl9SuE1GMVPFHx1mw==", + "node_modules/is-inside-container/node_modules/is-docker": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/is-docker/-/is-docker-3.0.0.tgz", + "integrity": "sha512-eljcgEDlEns/7AXFosB5K/2nCM4P7FQPkGc/DWLy5rmFEWvZayGrik1d9/QIY5nJ4f9YsVvBkA6kJpHn9rISdQ==", "dev": true, "license": "MIT", - "engines": { - "node": ">= 0.4" + "bin": { + "is-docker": "cli.js" + }, + "engines": { + "node": "^12.20.0 || ^14.13.1 || >=16.0.0" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/is-interactive": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/is-interactive/-/is-interactive-2.0.0.tgz", + "integrity": "sha512-qP1vozQRI+BMOPcjFzrjXuQvdak2pHNUMZoeG2eRbiSqyvbEf/wQtEOTOX1guk6E3t36RkaqiSt8A/6YElNxLQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/is-map": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/is-map/-/is-map-2.0.3.tgz", + "integrity": "sha512-1Qed0/Hr2m+YqxnM09CjA2d/i6YZNfF6R2oRAOj36eUdS6qIV/huPJNSEpKbupewFs+ZsJlxsjjPbc0/afW6Lw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-module": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-module/-/is-module-1.0.0.tgz", + "integrity": "sha512-51ypPSPCoTEIN9dy5Oy+h4pShgJmPCygKfyRCISBI+JoWT/2oJvK8QPxmwv7b/p239jXrm9M1mlQbyKJ5A152g==", + "dev": true, + "license": "MIT" + }, + "node_modules/is-negative-zero": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/is-negative-zero/-/is-negative-zero-2.0.3.tgz", + "integrity": "sha512-5KoIu2Ngpyek75jXodFvnafB6DJgr3u8uuK0LEZJjrU19DrMD3EVERaR8sjz8CCGgpZvxPl9SuE1GMVPFHx1mw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.4" }, "funding": { "url": "https://github.com/sponsors/ljharb" @@ -9421,6 +10647,29 @@ "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/is-ssh": { + "version": "1.4.1", + "resolved": "https://registry.npmjs.org/is-ssh/-/is-ssh-1.4.1.tgz", + "integrity": "sha512-JNeu1wQsHjyHgn9NcWTaXq6zWSR6hqE0++zhfZlkFBbScNkyvxCdeV8sRkSBaeLKxmbpR21brail63ACNxJ0Tg==", + "dev": true, + "license": "MIT", + "dependencies": { + "protocols": "^2.0.1" + } + }, + "node_modules/is-stream": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/is-stream/-/is-stream-3.0.0.tgz", + "integrity": "sha512-LnQR4bZ9IADDRSkvpqMGvt/tEJWclzklNgSw48V5EAaAeDd6qGvN8ei6k5p0tvxSR171VmGyHuTiAOfxAbr8kA==", + "dev": true, + "license": "MIT", + "engines": { + "node": "^12.20.0 || ^14.13.1 || >=16.0.0" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, "node_modules/is-string": { "version": "1.1.1", "resolved": "https://registry.npmjs.org/is-string/-/is-string-1.1.1.tgz", @@ -9570,6 +10819,23 @@ "license": "MIT", "peer": true }, + "node_modules/issue-parser": { + "version": "7.0.1", + "resolved": "https://registry.npmjs.org/issue-parser/-/issue-parser-7.0.1.tgz", + "integrity": "sha512-3YZcUUR2Wt1WsapF+S/WiA2WmlW0cWAoPccMqne7AxEBhCdFeTPjfv/Axb8V2gyCgY3nRw+ksZ3xSUX+R47iAg==", + "dev": true, + "license": "MIT", + "dependencies": { + "lodash.capitalize": "^4.2.1", + "lodash.escaperegexp": "^4.1.2", + "lodash.isplainobject": "^4.0.6", + "lodash.isstring": "^4.0.1", + "lodash.uniqby": "^4.7.0" + }, + "engines": { + "node": "^18.17 || >=20.6.1" + } + }, "node_modules/iterator.prototype": { "version": "1.1.5", "resolved": "https://registry.npmjs.org/iterator.prototype/-/iterator.prototype-1.1.5.tgz", @@ -9621,6 +10887,16 @@ "node": ">= 10.13.0" } }, + "node_modules/jiti": { + "version": "2.7.0", + "resolved": "https://registry.npmjs.org/jiti/-/jiti-2.7.0.tgz", + "integrity": "sha512-AC/7JofJvZGrrneWNaEnJeOLUx+JlGt7tNa0wZiRPT4MY1wmfKjt2+6O2p2uz2+skll8OZZmJMNqeke7kKbNgQ==", + "dev": true, + "license": "MIT", + "bin": { + "jiti": "lib/jiti-cli.mjs" + } + }, "node_modules/js-sha3": { "version": "0.8.0", "resolved": "https://registry.npmjs.org/js-sha3/-/js-sha3-0.8.0.tgz", @@ -9708,6 +10984,13 @@ "license": "ISC", "peer": true }, + "node_modules/json-with-bigint": { + "version": "3.5.10", + "resolved": "https://registry.npmjs.org/json-with-bigint/-/json-with-bigint-3.5.10.tgz", + "integrity": "sha512-Vcx+JVNEBts/xfcoCS69sKrOhOk/3TVlvlT+XzUOefVKnnrbYSCKpDCm10pohsJFtsJVYnwa/cXRZ4eElzaM6w==", + "dev": true, + "license": "MIT" + }, "node_modules/json5": { "version": "2.2.3", "resolved": "https://registry.npmjs.org/json5/-/json5-2.2.3.tgz", @@ -9986,6 +11269,13 @@ "url": "https://github.com/sponsors/sindresorhus" } }, + "node_modules/lodash": { + "version": "4.18.1", + "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.18.1.tgz", + "integrity": "sha512-dMInicTPVE8d1e5otfwmmjlxkZoUpiVLwyeTdUsi/Caj/gfzzblBcCE5sRHV/AsjuCmxWrte2TNGSYuCeCq+0Q==", + "dev": true, + "license": "MIT" + }, "node_modules/lodash.camelcase": { "version": "4.3.0", "resolved": "https://registry.npmjs.org/lodash.camelcase/-/lodash.camelcase-4.3.0.tgz", @@ -9993,6 +11283,13 @@ "dev": true, "license": "MIT" }, + "node_modules/lodash.capitalize": { + "version": "4.2.1", + "resolved": "https://registry.npmjs.org/lodash.capitalize/-/lodash.capitalize-4.2.1.tgz", + "integrity": "sha512-kZzYOKspf8XVX5AvmQF94gQW0lejFVgb80G85bU4ZWzoJ6C03PQg3coYAUpSTpQWelrZELd3XWgHzw4Ck5kaIw==", + "dev": true, + "license": "MIT" + }, "node_modules/lodash.debounce": { "version": "4.0.8", "resolved": "https://registry.npmjs.org/lodash.debounce/-/lodash.debounce-4.0.8.tgz", @@ -10000,6 +11297,13 @@ "dev": true, "license": "MIT" }, + "node_modules/lodash.escaperegexp": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/lodash.escaperegexp/-/lodash.escaperegexp-4.1.2.tgz", + "integrity": "sha512-TM9YBvyC84ZxE3rgfefxUWiQKLilstD6k7PTGt6wfbtXF8ixIJLOL3VYyV/z+ZiPLsVxAsKAFVwWlWeb2Y8Yyw==", + "dev": true, + "license": "MIT" + }, "node_modules/lodash.includes": { "version": "4.3.0", "resolved": "https://registry.npmjs.org/lodash.includes/-/lodash.includes-4.3.0.tgz", @@ -10063,6 +11367,13 @@ "dev": true, "license": "MIT" }, + "node_modules/lodash.uniqby": { + "version": "4.7.0", + "resolved": "https://registry.npmjs.org/lodash.uniqby/-/lodash.uniqby-4.7.0.tgz", + "integrity": "sha512-e/zcLx6CSbmaEgFHCA7BnoQKyCtKMxnuWrJygbwPs/AIn+IMKl66L8/s+wBUn5LRw2pZx3bUHibiV1b6aTWIww==", + "dev": true, + "license": "MIT" + }, "node_modules/log-symbols": { "version": "4.1.0", "resolved": "https://registry.npmjs.org/log-symbols/-/log-symbols-4.1.0.tgz", @@ -10128,6 +11439,19 @@ "node": ">=10" } }, + "node_modules/macos-release": { + "version": "3.5.1", + "resolved": "https://registry.npmjs.org/macos-release/-/macos-release-3.5.1.tgz", + "integrity": "sha512-Lci/1in+elqZ589PXnfP/iwZXpwQifTM94WJRQwG2tZSdfY7NfB/aUaTARHrohWCgHlXoabeaeXRDOnF5X9JQw==", + "dev": true, + "license": "MIT", + "engines": { + "node": "^12.20.0 || ^14.13.1 || >=16.0.0" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, "node_modules/magic-string": { "version": "0.25.9", "resolved": "https://registry.npmjs.org/magic-string/-/magic-string-0.25.9.tgz", @@ -10168,6 +11492,7 @@ "version": "1.3.6", "resolved": "https://registry.npmjs.org/make-error/-/make-error-1.3.6.tgz", "integrity": "sha512-s8UhlNe7vPKomQhC1qFelMokr/Sc3AgNbso3n74mVPA5LTZwkB9NlXf4XPamLxJE8h0gh73rM94xvwRT2CVInw==", + "dev": true, "license": "ISC" }, "node_modules/math-intrinsics": { @@ -10490,6 +11815,19 @@ "node": ">=6" } }, + "node_modules/mimic-function": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/mimic-function/-/mimic-function-5.0.1.tgz", + "integrity": "sha512-VP79XUPxV2CigYP3jWwAUFSku2aKqBH7uTAapFWCBqutsbmDo96KY5o8uh6U+/YSIn5OxJnXp73beVkpqMIGhA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, "node_modules/mimic-response": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/mimic-response/-/mimic-response-1.0.1.tgz", @@ -10819,6 +12157,16 @@ "buffer": "^5.5.0" } }, + "node_modules/mute-stream": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/mute-stream/-/mute-stream-2.0.0.tgz", + "integrity": "sha512-WWdIxpyjEn+FhQJQQv9aQAYlHoNVdzIzUySNV1gHUPDSdZJ3yZn7pAAbQcV7B56Mvu881q9FZV+0Vx2xC44VWA==", + "dev": true, + "license": "ISC", + "engines": { + "node": "^18.17.0 || >=20.5.0" + } + }, "node_modules/n3": { "version": "1.26.0", "resolved": "https://registry.npmjs.org/n3/-/n3-1.26.0.tgz", @@ -10882,6 +12230,39 @@ "node": ">= 0.6" } }, + "node_modules/neo-async": { + "version": "2.6.2", + "resolved": "https://registry.npmjs.org/neo-async/-/neo-async-2.6.2.tgz", + "integrity": "sha512-Yd3UES5mWCSqR+qNT93S3UoYUkqAZ9lLg8a7g9rimsWmYGK8cVToA4/sF3RrshdyV3sAGMXVUmpMYOw+dLpOuw==", + "dev": true, + "license": "MIT" + }, + "node_modules/netmask": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/netmask/-/netmask-2.1.1.tgz", + "integrity": "sha512-eonl3sLUha+S1GzTPxychyhnUzKyeQkZ7jLjKrBagJgPla13F+uQ71HgpFefyHgqrjEbCPkDArxYsjY8/+gLKA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.4.0" + } + }, + "node_modules/new-github-release-url": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/new-github-release-url/-/new-github-release-url-2.0.0.tgz", + "integrity": "sha512-NHDDGYudnvRutt/VhKFlX26IotXe1w0cmkDm6JGquh5bz/bDTw0LufSmH/GxTjEdpHEO+bVKFTwdrcGa/9XlKQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "type-fest": "^2.5.1" + }, + "engines": { + "node": "^12.20.0 || ^14.13.1 || >=16.0.0" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, "node_modules/next-tick": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/next-tick/-/next-tick-1.1.0.tgz", @@ -10936,6 +12317,13 @@ } } }, + "node_modules/node-fetch-native": { + "version": "1.6.7", + "resolved": "https://registry.npmjs.org/node-fetch-native/-/node-fetch-native-1.6.7.tgz", + "integrity": "sha512-g9yhqoedzIUm0nTnTqAQvueMPVOuIY16bqgAJJC8XOOubYFNwz6IER9qs0Gq2Xd0+CecCKFjtdDTMA4u4xG06Q==", + "dev": true, + "license": "MIT" + }, "node_modules/node-gyp-build": { "version": "4.8.4", "resolved": "https://registry.npmjs.org/node-gyp-build/-/node-gyp-build-4.8.4.tgz", @@ -11045,6 +12433,31 @@ "license": "MIT", "peer": true }, + "node_modules/nypm": { + "version": "0.6.8", + "resolved": "https://registry.npmjs.org/nypm/-/nypm-0.6.8.tgz", + "integrity": "sha512-Q9K4Diu6l5u6xJQogeFSs/zKtyMSgFKFtRQV+tHP4kL7KPm2grpBU0dFIwFaXwNxN0MtfKWc43VpCugAa+LPsw==", + "dev": true, + "license": "MIT", + "dependencies": { + "citty": "^0.2.2", + "pathe": "^2.0.3", + "tinyexec": "^1.2.4" + }, + "bin": { + "nypm": "dist/cli.mjs" + }, + "engines": { + "node": ">=18" + } + }, + "node_modules/nypm/node_modules/citty": { + "version": "0.2.2", + "resolved": "https://registry.npmjs.org/citty/-/citty-0.2.2.tgz", + "integrity": "sha512-+6vJA3L98yv+IdfKGZHBNiGW5KHn22e/JwID0Strsz8h4S/csAu/OuICwxrg44k5MRiZHWIo8XXuJgQTriRP4w==", + "dev": true, + "license": "MIT" + }, "node_modules/oauth-sign": { "version": "0.9.0", "resolved": "https://registry.npmjs.org/oauth-sign/-/oauth-sign-0.9.0.tgz", @@ -11186,6 +12599,13 @@ "http-https": "^1.0.0" } }, + "node_modules/ohash": { + "version": "2.0.11", + "resolved": "https://registry.npmjs.org/ohash/-/ohash-2.0.11.tgz", + "integrity": "sha512-RdR9FQrFwNBNXAr4GixM8YaRZRJ5PUWbKYbE5eOsrwAjJW0q2REGcf79oYPsLyskQCZG1PLN+S/K1V00joZAoQ==", + "dev": true, + "license": "MIT" + }, "node_modules/on-finished": { "version": "2.4.1", "resolved": "https://registry.npmjs.org/on-finished/-/on-finished-2.4.1.tgz", @@ -11260,6 +12680,136 @@ "node": ">= 0.8.0" } }, + "node_modules/ora": { + "version": "9.0.0", + "resolved": "https://registry.npmjs.org/ora/-/ora-9.0.0.tgz", + "integrity": "sha512-m0pg2zscbYgWbqRR6ABga5c3sZdEon7bSgjnlXC64kxtxLOyjRcbbUkLj7HFyy/FTD+P2xdBWu8snGhYI0jc4A==", + "dev": true, + "license": "MIT", + "dependencies": { + "chalk": "^5.6.2", + "cli-cursor": "^5.0.0", + "cli-spinners": "^3.2.0", + "is-interactive": "^2.0.0", + "is-unicode-supported": "^2.1.0", + "log-symbols": "^7.0.1", + "stdin-discarder": "^0.2.2", + "string-width": "^8.1.0", + "strip-ansi": "^7.1.2" + }, + "engines": { + "node": ">=20" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/ora/node_modules/ansi-regex": { + "version": "6.2.2", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-6.2.2.tgz", + "integrity": "sha512-Bq3SmSpyFHaWjPk8If9yc6svM8c56dB5BAtW4Qbw5jHTwwXXcTLoRMkpDJp6VL0XzlWaCHTXrkFURMYmD0sLqg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/chalk/ansi-regex?sponsor=1" + } + }, + "node_modules/ora/node_modules/chalk": { + "version": "5.6.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-5.6.2.tgz", + "integrity": "sha512-7NzBL0rN6fMUW+f7A6Io4h40qQlG+xGmtMxfbnH/K7TAtt8JQWVQK+6g0UXKMeVJoyV5EkkNsErQ8pVD3bLHbA==", + "dev": true, + "license": "MIT", + "engines": { + "node": "^12.17.0 || ^14.13 || >=16.0.0" + }, + "funding": { + "url": "https://github.com/chalk/chalk?sponsor=1" + } + }, + "node_modules/ora/node_modules/is-unicode-supported": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/is-unicode-supported/-/is-unicode-supported-2.1.0.tgz", + "integrity": "sha512-mE00Gnza5EEB3Ds0HfMyllZzbBrmLOX3vfWoj9A9PEnTfratQ/BcaJOuMhnkhjXvb2+FkY3VuHqtAGpTPmglFQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/ora/node_modules/log-symbols": { + "version": "7.0.1", + "resolved": "https://registry.npmjs.org/log-symbols/-/log-symbols-7.0.1.tgz", + "integrity": "sha512-ja1E3yCr9i/0hmBVaM0bfwDjnGy8I/s6PP4DFp+yP+a+mrHO4Rm7DtmnqROTUkHIkqffC84YY7AeqX6oFk0WFg==", + "dev": true, + "license": "MIT", + "dependencies": { + "is-unicode-supported": "^2.0.0", + "yoctocolors": "^2.1.1" + }, + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/ora/node_modules/string-width": { + "version": "8.2.2", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-8.2.2.tgz", + "integrity": "sha512-GaPUh5gfdrYzqeVNZvUfT23vYYxXzKYidUcnMtJg/3rxRV63EFZy3k6xfKlmfeJD0176lnUV/Usr3XcwSvFzpg==", + "dev": true, + "license": "MIT", + "dependencies": { + "get-east-asian-width": "^1.5.0", + "strip-ansi": "^7.1.2" + }, + "engines": { + "node": ">=20" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/ora/node_modules/strip-ansi": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-7.2.0.tgz", + "integrity": "sha512-yDPMNjp4WyfYBkHnjIRLfca1i6KMyGCtsVgoKe/z1+6vukgaENdgGBZt+ZmKPc4gavvEZ5OgHfHdrazhgNyG7w==", + "dev": true, + "license": "MIT", + "dependencies": { + "ansi-regex": "^6.2.2" + }, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/chalk/strip-ansi?sponsor=1" + } + }, + "node_modules/os-name": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/os-name/-/os-name-6.1.0.tgz", + "integrity": "sha512-zBd1G8HkewNd2A8oQ8c6BN/f/c9EId7rSUueOLGu28govmUctXmM+3765GwsByv9nYUdrLqHphXlYIc86saYsg==", + "dev": true, + "license": "MIT", + "dependencies": { + "macos-release": "^3.3.0", + "windows-release": "^6.1.0" + }, + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, "node_modules/own-keys": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/own-keys/-/own-keys-1.0.1.tgz", @@ -11370,6 +12920,40 @@ "node": ">=6" } }, + "node_modules/pac-proxy-agent": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/pac-proxy-agent/-/pac-proxy-agent-7.2.0.tgz", + "integrity": "sha512-TEB8ESquiLMc0lV8vcd5Ql/JAKAoyzHFXaStwjkzpOpC5Yv+pIzLfHvjTSdf3vpa2bMiUQrg9i6276yn8666aA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@tootallnate/quickjs-emscripten": "^0.23.0", + "agent-base": "^7.1.2", + "debug": "^4.3.4", + "get-uri": "^6.0.1", + "http-proxy-agent": "^7.0.0", + "https-proxy-agent": "^7.0.6", + "pac-resolver": "^7.0.1", + "socks-proxy-agent": "^8.0.5" + }, + "engines": { + "node": ">= 14" + } + }, + "node_modules/pac-resolver": { + "version": "7.0.1", + "resolved": "https://registry.npmjs.org/pac-resolver/-/pac-resolver-7.0.1.tgz", + "integrity": "sha512-5NPgf87AT2STgwa2ntRMr45jTKrYBGkVU36yT0ig/n/GMAa3oPqhZfIQ2kMEimReg0+t9kZViDVZ83qfVUlckg==", + "dev": true, + "license": "MIT", + "dependencies": { + "degenerator": "^5.0.0", + "netmask": "^2.0.2" + }, + "engines": { + "node": ">= 14" + } + }, "node_modules/parent-module": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/parent-module/-/parent-module-1.0.1.tgz", @@ -11383,6 +12967,19 @@ "node": ">=6" } }, + "node_modules/parse-github-url": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/parse-github-url/-/parse-github-url-1.0.4.tgz", + "integrity": "sha512-CEtCOt55fHmd6DpBc/N7H5NC4vJpcquhzzs9Iw2mRj8bVxo1O5TQI5MXKOMO7+yBOqD+5dKCCRK4Kj1KskZc6Q==", + "dev": true, + "license": "MIT", + "bin": { + "parse-github-url": "cli.js" + }, + "engines": { + "node": ">= 0.10" + } + }, "node_modules/parse-headers": { "version": "2.0.6", "resolved": "https://registry.npmjs.org/parse-headers/-/parse-headers-2.0.6.tgz", @@ -11409,6 +13006,30 @@ "url": "https://github.com/sponsors/sindresorhus" } }, + "node_modules/parse-path": { + "version": "7.1.0", + "resolved": "https://registry.npmjs.org/parse-path/-/parse-path-7.1.0.tgz", + "integrity": "sha512-EuCycjZtfPcjWk7KTksnJ5xPMvWGA/6i4zrLYhRG0hGvC3GPU/jGUj3Cy+ZR0v30duV3e23R95T1lE2+lsndSw==", + "dev": true, + "license": "MIT", + "dependencies": { + "protocols": "^2.0.0" + } + }, + "node_modules/parse-url": { + "version": "9.2.0", + "resolved": "https://registry.npmjs.org/parse-url/-/parse-url-9.2.0.tgz", + "integrity": "sha512-bCgsFI+GeGWPAvAiUv63ZorMeif3/U0zaXABGJbOWt5OH2KCaPHF6S+0ok4aqM9RuIPGyZdx9tR9l13PsW4AYQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/parse-path": "^7.0.0", + "parse-path": "^7.0.0" + }, + "engines": { + "node": ">=14.13.0" + } + }, "node_modules/parseurl": { "version": "1.3.3", "resolved": "https://registry.npmjs.org/parseurl/-/parseurl-1.3.3.tgz", @@ -11473,6 +13094,13 @@ "node": ">=8" } }, + "node_modules/pathe": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/pathe/-/pathe-2.0.3.tgz", + "integrity": "sha512-WUjGcAqP1gQacoQe+OBJsFA7Ld4DyXuUIjZ5cc75cLHvJ7dtNsTugphxIADwspS+AraAUePCKrSVtPLFj/F88w==", + "dev": true, + "license": "MIT" + }, "node_modules/pathval": { "version": "1.1.1", "resolved": "https://registry.npmjs.org/pathval/-/pathval-1.1.1.tgz", @@ -11535,6 +13163,13 @@ "inherits": "^2.0.1" } }, + "node_modules/perfect-debounce": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/perfect-debounce/-/perfect-debounce-2.1.0.tgz", + "integrity": "sha512-LjgdTytVFXeUgtHZr9WYViYSM/g8MkcTPYDlPa3cDqMirHjKiSZPYd6DoL7pK8AJQr+uWkQvCjHNdiMqsrJs+g==", + "dev": true, + "license": "MIT" + }, "node_modules/performance-now": { "version": "2.1.0", "resolved": "https://registry.npmjs.org/performance-now/-/performance-now-2.1.0.tgz", @@ -11644,6 +13279,18 @@ "node": ">=8" } }, + "node_modules/pkg-types": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/pkg-types/-/pkg-types-2.3.1.tgz", + "integrity": "sha512-y+ichcgc2LrADuhLNAx8DFjVfgz91pRxfZdI3UDhxHvcVEZsenLO+7XaU5vOp0u/7V/wZ+plyuQxtrDlZJ+yeg==", + "dev": true, + "license": "MIT", + "dependencies": { + "confbox": "^0.2.4", + "exsolve": "^1.0.8", + "pathe": "^2.0.3" + } + }, "node_modules/possible-typed-array-names": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/possible-typed-array-names/-/possible-typed-array-names-1.1.0.tgz", @@ -12453,6 +14100,13 @@ "react-is": "^16.13.1" } }, + "node_modules/protocols": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/protocols/-/protocols-2.0.2.tgz", + "integrity": "sha512-hHVTzba3wboROl0/aWRRG9dMytgH6ow//STBZh43l/wQgmMhYhOFi0EHWAPtoCz9IAUymsyP0TSBHkhgMEGNnQ==", + "dev": true, + "license": "MIT" + }, "node_modules/proxy-addr": { "version": "2.0.7", "resolved": "https://registry.npmjs.org/proxy-addr/-/proxy-addr-2.0.7.tgz", @@ -12467,6 +14121,43 @@ "node": ">= 0.10" } }, + "node_modules/proxy-agent": { + "version": "6.5.0", + "resolved": "https://registry.npmjs.org/proxy-agent/-/proxy-agent-6.5.0.tgz", + "integrity": "sha512-TmatMXdr2KlRiA2CyDu8GqR8EjahTG3aY3nXjdzFyoZbmB8hrBsTyMezhULIXKnC0jpfjlmiZ3+EaCzoInSu/A==", + "dev": true, + "license": "MIT", + "dependencies": { + "agent-base": "^7.1.2", + "debug": "^4.3.4", + "http-proxy-agent": "^7.0.1", + "https-proxy-agent": "^7.0.6", + "lru-cache": "^7.14.1", + "pac-proxy-agent": "^7.1.0", + "proxy-from-env": "^1.1.0", + "socks-proxy-agent": "^8.0.5" + }, + "engines": { + "node": ">= 14" + } + }, + "node_modules/proxy-agent/node_modules/lru-cache": { + "version": "7.18.3", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-7.18.3.tgz", + "integrity": "sha512-jumlc0BIUrS3qJGgIkWZsyfAM7NCWiBcCDhnd+3NNM5KbBmLTgHVfWBcg6W+rLUsIpzpERPsvwUP7CckAQSOoA==", + "dev": true, + "license": "ISC", + "engines": { + "node": ">=12" + } + }, + "node_modules/proxy-agent/node_modules/proxy-from-env": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/proxy-from-env/-/proxy-from-env-1.1.0.tgz", + "integrity": "sha512-D+zkORCbA9f1tdWRK0RaCR3GPv50cMxcrz4X8k5LTSUD1Dkw47mKJEZQNunItRTkWwgtaUSo1RVFRIG9ZXiFYg==", + "dev": true, + "license": "MIT" + }, "node_modules/proxy-from-env": { "version": "2.1.0", "resolved": "https://registry.npmjs.org/proxy-from-env/-/proxy-from-env-2.1.0.tgz", @@ -12608,6 +14299,17 @@ "node": ">= 0.8" } }, + "node_modules/rc9": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/rc9/-/rc9-2.1.2.tgz", + "integrity": "sha512-btXCnMmRIBINM2LDZoEmOogIZU7Qe7zn4BpomSKZ/ykbLObuBdvG+mFq11DL6fjH1DRwHhrlgtYWG96bJiC7Cg==", + "dev": true, + "license": "MIT", + "dependencies": { + "defu": "^6.1.4", + "destr": "^2.0.3" + } + }, "node_modules/rdf-canonize": { "version": "3.4.0", "resolved": "https://registry.npmjs.org/rdf-canonize/-/rdf-canonize-3.4.0.tgz", @@ -12877,6 +14579,133 @@ "node": ">=6" } }, + "node_modules/release-it": { + "version": "19.2.4", + "resolved": "https://registry.npmjs.org/release-it/-/release-it-19.2.4.tgz", + "integrity": "sha512-BwaJwQYUIIAKuDYvpqQTSoy0U7zIy6cHyEjih/aNaFICphGahia4cjDANuFXb7gVZ51hIK9W0io6fjNQWXqICg==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/webpro" + }, + { + "type": "opencollective", + "url": "https://opencollective.com/webpro" + } + ], + "license": "MIT", + "dependencies": { + "@nodeutils/defaults-deep": "1.1.0", + "@octokit/rest": "22.0.1", + "@phun-ky/typeof": "2.0.3", + "async-retry": "1.3.3", + "c12": "3.3.3", + "ci-info": "^4.3.1", + "eta": "4.5.0", + "git-url-parse": "16.1.0", + "inquirer": "12.11.1", + "issue-parser": "7.0.1", + "lodash.merge": "4.6.2", + "mime-types": "3.0.2", + "new-github-release-url": "2.0.0", + "open": "10.2.0", + "ora": "9.0.0", + "os-name": "6.1.0", + "proxy-agent": "6.5.0", + "semver": "7.7.3", + "tinyglobby": "0.2.15", + "undici": "6.23.0", + "url-join": "5.0.0", + "wildcard-match": "5.1.4", + "yargs-parser": "21.1.1" + }, + "bin": { + "release-it": "bin/release-it.js" + }, + "engines": { + "node": "^20.12.0 || >=22.0.0" + } + }, + "node_modules/release-it/node_modules/define-lazy-prop": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/define-lazy-prop/-/define-lazy-prop-3.0.0.tgz", + "integrity": "sha512-N+MeXYoqr3pOgn8xfyRPREN7gHakLYjhsHhWGT3fWAiL4IkAt0iDw14QiiEm2bE30c5XX5q0FtAA3CK5f9/BUg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/release-it/node_modules/mime-db": { + "version": "1.54.0", + "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.54.0.tgz", + "integrity": "sha512-aU5EJuIN2WDemCcAp2vFBfp/m4EAhWJnUNSSw0ixs7/kXbd6Pg64EmwJkNdFhB8aWt1sH2CTXrLxo/iAGV3oPQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/release-it/node_modules/mime-types": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-3.0.2.tgz", + "integrity": "sha512-Lbgzdk0h4juoQ9fCKXW4by0UJqj+nOOrI9MJ1sSj4nI8aI2eo1qmvQEie4VD1glsS250n15LsWsYtCugiStS5A==", + "dev": true, + "license": "MIT", + "dependencies": { + "mime-db": "^1.54.0" + }, + "engines": { + "node": ">=18" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/express" + } + }, + "node_modules/release-it/node_modules/open": { + "version": "10.2.0", + "resolved": "https://registry.npmjs.org/open/-/open-10.2.0.tgz", + "integrity": "sha512-YgBpdJHPyQ2UE5x+hlSXcnejzAvD0b22U2OuAP+8OnlJT+PjWPxtgmGqKKc+RgTM63U9gN0YzrYc71R2WT/hTA==", + "dev": true, + "license": "MIT", + "dependencies": { + "default-browser": "^5.2.1", + "define-lazy-prop": "^3.0.0", + "is-inside-container": "^1.0.0", + "wsl-utils": "^0.1.0" + }, + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/release-it/node_modules/undici": { + "version": "6.23.0", + "resolved": "https://registry.npmjs.org/undici/-/undici-6.23.0.tgz", + "integrity": "sha512-VfQPToRA5FZs/qJxLIinmU59u0r7LXqoJkCzinq3ckNJp3vKEh7jTWN589YQ5+aoAC/TGRLyJLCPKcLQbM8r9g==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=18.17" + } + }, + "node_modules/release-it/node_modules/yargs-parser": { + "version": "21.1.1", + "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-21.1.1.tgz", + "integrity": "sha512-tVpsJW7DdjecAiFpbIB1e3qxIQsE6NoPc5/eTdrbbIC4h0LVsWhnoa3g+m2HclBIujHzsxZ4VJVA+GUuc2/LBw==", + "dev": true, + "license": "ISC", + "engines": { + "node": ">=12" + } + }, "node_modules/request": { "version": "2.88.2", "resolved": "https://registry.npmjs.org/request/-/request-2.88.2.tgz", @@ -13016,6 +14845,62 @@ "node": ">=8" } }, + "node_modules/restore-cursor": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/restore-cursor/-/restore-cursor-5.1.0.tgz", + "integrity": "sha512-oMA2dcrw6u0YfxJQXm342bFKX/E4sG9rbTzO9ptUcR/e8A33cHuvStiYOwH7fszkZlZ1z/ta9AAoPk2F4qIOHA==", + "dev": true, + "license": "MIT", + "dependencies": { + "onetime": "^7.0.0", + "signal-exit": "^4.1.0" + }, + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/restore-cursor/node_modules/onetime": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/onetime/-/onetime-7.0.0.tgz", + "integrity": "sha512-VXJjc87FScF88uafS3JllDgvAm+c/Slfz06lorj2uAY34rlUu0Nt+v8wreiImcrgAjjIHp1rXpTDlLOGw29WwQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "mimic-function": "^5.0.0" + }, + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/restore-cursor/node_modules/signal-exit": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-4.1.0.tgz", + "integrity": "sha512-bzyZ1e88w9O1iNJbKnOlvYTrWPDl46O1bG0D3XInv+9tkPrxrN8jUUTiFlDkkmKWgn1M6CfIA13SuGqOa9Korw==", + "dev": true, + "license": "ISC", + "engines": { + "node": ">=14" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/retry": { + "version": "0.13.1", + "resolved": "https://registry.npmjs.org/retry/-/retry-0.13.1.tgz", + "integrity": "sha512-XQBQ3I8W1Cge0Seh+6gjj03LbmRFWuoszgK9ooCpwYIrhhoO80pfq4cUkU5DkknwfOfFteRwlZ56PYOGYyFWdg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 4" + } + }, "node_modules/reusify": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/reusify/-/reusify-1.1.0.tgz", @@ -13372,7 +15257,30 @@ "resolved": "https://registry.npmjs.org/estree-walker/-/estree-walker-0.6.1.tgz", "integrity": "sha512-SqmZANLWS0mnatqbSfRP5g8OXZC12Fgg1IwNtLsyHDzJizORW4khDfjPqJZsemPWBB2uqykUah5YpQ6epsqC/w==", "dev": true, - "license": "MIT" + "license": "MIT" + }, + "node_modules/run-applescript": { + "version": "7.1.0", + "resolved": "https://registry.npmjs.org/run-applescript/-/run-applescript-7.1.0.tgz", + "integrity": "sha512-DPe5pVFaAsinSaV6QjQ6gdiedWDcRCbUuiQfQa2wmWV7+xC9bGulGI8+TdRmoFkAPaBXk8CrAbnlY2ISniJ47Q==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/run-async": { + "version": "4.0.6", + "resolved": "https://registry.npmjs.org/run-async/-/run-async-4.0.6.tgz", + "integrity": "sha512-IoDlSLTs3Yq593mb3ZoKWKXMNu3UpObxhgA/Xuid5p4bbfi2jdY1Hj0m1K+0/tEuQTxIGMhQDqGjKb7RuxGpAQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.12.0" + } }, "node_modules/run-parallel": { "version": "1.2.0", @@ -13398,6 +15306,16 @@ "queue-microtask": "^1.2.2" } }, + "node_modules/rxjs": { + "version": "7.8.2", + "resolved": "https://registry.npmjs.org/rxjs/-/rxjs-7.8.2.tgz", + "integrity": "sha512-dhKf903U/PQZY6boNNtAGdWbG85WAbjT/1xYoZIC7FAY0yWapOBQVsVrDl58W86//e1VpMNBtRV4MaXfdMySFA==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "tslib": "^2.1.0" + } + }, "node_modules/sade": { "version": "1.8.1", "resolved": "https://registry.npmjs.org/sade/-/sade-1.8.1.tgz", @@ -13506,8 +15424,7 @@ "version": "2.1.2", "resolved": "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz", "integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==", - "license": "MIT", - "peer": true + "license": "MIT" }, "node_modules/scrypt-js": { "version": "3.0.1", @@ -13540,9 +15457,9 @@ "peer": true }, "node_modules/semver": { - "version": "7.7.2", - "resolved": "https://registry.npmjs.org/semver/-/semver-7.7.2.tgz", - "integrity": "sha512-RF0Fw+rO5AMf9MAyaRXI4AV0Ulj5lMHqVxxdSgiVbixSCXoEmmX/jk0CuJw4+3SqroYO9VoUh+HcuJivvtJemA==", + "version": "7.7.3", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.7.3.tgz", + "integrity": "sha512-SdsKMrI9TdgjdweUSR9MweHA4EJ8YxHn8DFaDisvhVlUOe4BF1tLD7GAj0lIqWVl+dPb/rExr0Btby5loQm20Q==", "license": "ISC", "bin": { "semver": "bin/semver.js" @@ -13886,6 +15803,47 @@ "node": ">=8" } }, + "node_modules/smart-buffer": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/smart-buffer/-/smart-buffer-4.2.0.tgz", + "integrity": "sha512-94hK0Hh8rPqQl2xXc3HsaBoOXKV20MToPkcXvwbISWLEs+64sBq5kFgn2kJDHb1Pry9yrP0dxrCI9RRci7RXKg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 6.0.0", + "npm": ">= 3.0.0" + } + }, + "node_modules/socks": { + "version": "2.8.9", + "resolved": "https://registry.npmjs.org/socks/-/socks-2.8.9.tgz", + "integrity": "sha512-LJhUYUvItdQ0LkJTmPeaEObWXAqFyfmP85x0tch/ez9cahmhlBBLbIqDFnvBnUJGagb0JbIQrkBs1wJ+yRYpEw==", + "dev": true, + "license": "MIT", + "dependencies": { + "ip-address": "^10.1.1", + "smart-buffer": "^4.2.0" + }, + "engines": { + "node": ">= 10.0.0", + "npm": ">= 3.0.0" + } + }, + "node_modules/socks-proxy-agent": { + "version": "8.0.5", + "resolved": "https://registry.npmjs.org/socks-proxy-agent/-/socks-proxy-agent-8.0.5.tgz", + "integrity": "sha512-HehCEsotFqbPW9sJ8WVYB6UbmIMv7kUUORIF2Nncq4VQvBfNBLibW9YZR5dlYCSUhwcD628pRllm7n+E+YTzJw==", + "dev": true, + "license": "MIT", + "dependencies": { + "agent-base": "^7.1.2", + "debug": "^4.3.4", + "socks": "^2.8.3" + }, + "engines": { + "node": ">= 14" + } + }, "node_modules/source-map": { "version": "0.6.1", "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", @@ -13976,6 +15934,19 @@ "node": ">= 0.8" } }, + "node_modules/stdin-discarder": { + "version": "0.2.2", + "resolved": "https://registry.npmjs.org/stdin-discarder/-/stdin-discarder-0.2.2.tgz", + "integrity": "sha512-UhDfHmA92YAlNnCfhmq0VeNL5bDbiZGg7sZ2IvPsXubGkiNa9EC+tUTsjBRsYUAz87btI6/1wf4XoVvQ3uRnmQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, "node_modules/stop-iteration-iterator": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/stop-iteration-iterator/-/stop-iteration-iterator-1.1.0.tgz", @@ -14216,7 +16187,6 @@ "version": "7.2.0", "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", - "dev": true, "license": "MIT", "dependencies": { "has-flag": "^4.0.0" @@ -14523,6 +16493,64 @@ "globrex": "^0.1.2" } }, + "node_modules/tinyexec": { + "version": "1.2.4", + "resolved": "https://registry.npmjs.org/tinyexec/-/tinyexec-1.2.4.tgz", + "integrity": "sha512-SHf/r48b7vOrjve9PxJo3MN5v5yuyjHvdUcrQffT3WXMUfnGmHDVbC4k3sHJaJTgZCwpUplIaAo5ANtMyp3YHg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=18" + } + }, + "node_modules/tinyglobby": { + "version": "0.2.15", + "resolved": "https://registry.npmjs.org/tinyglobby/-/tinyglobby-0.2.15.tgz", + "integrity": "sha512-j2Zq4NyQYG5XMST4cbs02Ak8iJUdxRM0XI5QyxXuZOzKOINmWurp3smXu3y5wDcJrptwpSjgXHzIQxR0omXljQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "fdir": "^6.5.0", + "picomatch": "^4.0.3" + }, + "engines": { + "node": ">=12.0.0" + }, + "funding": { + "url": "https://github.com/sponsors/SuperchupuDev" + } + }, + "node_modules/tinyglobby/node_modules/fdir": { + "version": "6.5.0", + "resolved": "https://registry.npmjs.org/fdir/-/fdir-6.5.0.tgz", + "integrity": "sha512-tIbYtZbucOs0BRGqPJkshJUYdL+SDH7dVM8gjy+ERp3WAUjLEFJE+02kanyHtwjWOnwrKYBiwAmM0p4kLJAnXg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=12.0.0" + }, + "peerDependencies": { + "picomatch": "^3 || ^4" + }, + "peerDependenciesMeta": { + "picomatch": { + "optional": true + } + } + }, + "node_modules/tinyglobby/node_modules/picomatch": { + "version": "4.0.5", + "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-4.0.5.tgz", + "integrity": "sha512-RvwwcruNjI1ncT5xRakeyS9Lf8lcItv34KD+aif+VH9kduAyfYBipGh12274xtenIPZ119/R9BdTBa8gAwSh0A==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/jonschlinkert" + } + }, "node_modules/to-buffer": { "version": "1.2.1", "resolved": "https://registry.npmjs.org/to-buffer/-/to-buffer-1.2.1.tgz", @@ -14598,6 +16626,7 @@ "version": "10.9.2", "resolved": "https://registry.npmjs.org/ts-node/-/ts-node-10.9.2.tgz", "integrity": "sha512-f0FFpIdcHgn8zcPSbf1dRevwt047YMnaiJM3u2w2RewrB+fob/zePZcrOyQoLMMO7aBIddLcQIEK5dYjkLnGrQ==", + "dev": true, "license": "MIT", "dependencies": { "@cspotcode/source-map-support": "^0.8.0", @@ -14641,6 +16670,7 @@ "version": "4.0.2", "resolved": "https://registry.npmjs.org/diff/-/diff-4.0.2.tgz", "integrity": "sha512-58lmxKSA4BNyLz+HHMUzlOEpg09FV+ev6ZMe3vJihgdxzgcwZ8VoEEPmALCZG9LmqfVoNMMKpttIYTVG6uDY7A==", + "dev": true, "license": "BSD-3-Clause", "engines": { "node": ">=0.3.1" @@ -14887,6 +16917,7 @@ "version": "5.9.2", "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.9.2.tgz", "integrity": "sha512-CWBzXQrc/qOkhidw1OzBTQuYRbfyxDXJMVJ1XNwUHGROVmuaeiEm3OslpZ1RV96d7SKKjZKrSJu3+t/xlw3R9A==", + "dev": true, "license": "Apache-2.0", "bin": { "tsc": "bin/tsc", @@ -15142,6 +17173,20 @@ "url": "https://github.com/sponsors/isaacs" } }, + "node_modules/uglify-js": { + "version": "3.19.3", + "resolved": "https://registry.npmjs.org/uglify-js/-/uglify-js-3.19.3.tgz", + "integrity": "sha512-v3Xu+yuwBXisp6QYTcH4UbH+xYJXqnq2m/LtQVWKWzYc1iehYnLixoQDN9FH6/j9/oybfd6W9Ghwkl8+UMKTKQ==", + "dev": true, + "license": "BSD-2-Clause", + "optional": true, + "bin": { + "uglifyjs": "bin/uglifyjs" + }, + "engines": { + "node": ">=0.8.0" + } + }, "node_modules/uint32": { "version": "0.2.1", "resolved": "https://registry.npmjs.org/uint32/-/uint32-0.2.1.tgz", @@ -15236,6 +17281,13 @@ "node": ">=4" } }, + "node_modules/universal-user-agent": { + "version": "7.0.3", + "resolved": "https://registry.npmjs.org/universal-user-agent/-/universal-user-agent-7.0.3.tgz", + "integrity": "sha512-TmnEAEAsBJVZM/AADELsK76llnwcf9vMKuPz8JflO1frO8Lchitr0fNaN9d+Ap0BjKtqWqd/J17qeDnXh8CL2A==", + "dev": true, + "license": "ISC" + }, "node_modules/universalify": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/universalify/-/universalify-2.0.1.tgz", @@ -15296,6 +17348,16 @@ "punycode": "^2.1.0" } }, + "node_modules/url-join": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/url-join/-/url-join-5.0.0.tgz", + "integrity": "sha512-n2huDr9h9yzd6exQVnH/jU5mr+Pfx08LRXXZhkLLetAMESRj+anQsTAh940iMrIetKAmry9coFuZQ2jY8/p3WA==", + "dev": true, + "license": "MIT", + "engines": { + "node": "^12.20.0 || ^14.13.1 || >=16.0.0" + } + }, "node_modules/url-set-query": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/url-set-query/-/url-set-query-1.0.0.tgz", @@ -15369,6 +17431,7 @@ "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==", + "dev": true, "license": "MIT" }, "node_modules/varint": { @@ -16018,6 +18081,147 @@ "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/wildcard-match": { + "version": "5.1.4", + "resolved": "https://registry.npmjs.org/wildcard-match/-/wildcard-match-5.1.4.tgz", + "integrity": "sha512-wldeCaczs8XXq7hj+5d/F38JE2r7EXgb6WQDM84RVwxy81T/sxB5e9+uZLK9Q9oNz1mlvjut+QtvgaOQFPVq/g==", + "dev": true, + "license": "ISC" + }, + "node_modules/windows-release": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/windows-release/-/windows-release-6.1.0.tgz", + "integrity": "sha512-1lOb3qdzw6OFmOzoY0nauhLG72TpWtb5qgYPiSh/62rjc1XidBSDio2qw0pwHh17VINF217ebIkZJdFLZFn9SA==", + "dev": true, + "license": "MIT", + "dependencies": { + "execa": "^8.0.1" + }, + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/windows-release/node_modules/execa": { + "version": "8.0.1", + "resolved": "https://registry.npmjs.org/execa/-/execa-8.0.1.tgz", + "integrity": "sha512-VyhnebXciFV2DESc+p6B+y0LjSm0krU4OgJN44qFAhBY0TJ+1V61tYD2+wHusZ6F9n5K+vl8k0sTy7PEfV4qpg==", + "dev": true, + "license": "MIT", + "dependencies": { + "cross-spawn": "^7.0.3", + "get-stream": "^8.0.1", + "human-signals": "^5.0.0", + "is-stream": "^3.0.0", + "merge-stream": "^2.0.0", + "npm-run-path": "^5.1.0", + "onetime": "^6.0.0", + "signal-exit": "^4.1.0", + "strip-final-newline": "^3.0.0" + }, + "engines": { + "node": ">=16.17" + }, + "funding": { + "url": "https://github.com/sindresorhus/execa?sponsor=1" + } + }, + "node_modules/windows-release/node_modules/human-signals": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/human-signals/-/human-signals-5.0.0.tgz", + "integrity": "sha512-AXcZb6vzzrFAUE61HnN4mpLqd/cSIwNQjtNWR0euPm6y0iqx3G4gOXaIDdtdDwZmhwe82LA6+zinmW4UBWVePQ==", + "dev": true, + "license": "Apache-2.0", + "engines": { + "node": ">=16.17.0" + } + }, + "node_modules/windows-release/node_modules/mimic-fn": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/mimic-fn/-/mimic-fn-4.0.0.tgz", + "integrity": "sha512-vqiC06CuhBTUdZH+RYl8sFrL096vA45Ok5ISO6sE/Mr1jRbGH4Csnhi8f3wKVl7x8mO4Au7Ir9D3Oyv1VYMFJw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/windows-release/node_modules/npm-run-path": { + "version": "5.3.0", + "resolved": "https://registry.npmjs.org/npm-run-path/-/npm-run-path-5.3.0.tgz", + "integrity": "sha512-ppwTtiJZq0O/ai0z7yfudtBpWIoxM8yE6nHi1X47eFR2EWORqfbu6CnPlNsjeN683eT0qG6H/Pyf9fCcvjnnnQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "path-key": "^4.0.0" + }, + "engines": { + "node": "^12.20.0 || ^14.13.1 || >=16.0.0" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/windows-release/node_modules/onetime": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/onetime/-/onetime-6.0.0.tgz", + "integrity": "sha512-1FlR+gjXK7X+AsAHso35MnyN5KqGwJRi/31ft6x0M194ht7S+rWAvd7PHss9xSKMzE0asv1pyIHaJYq+BbacAQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "mimic-fn": "^4.0.0" + }, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/windows-release/node_modules/path-key": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/path-key/-/path-key-4.0.0.tgz", + "integrity": "sha512-haREypq7xkM7ErfgIyA0z+Bj4AGKlMSdlQE2jvJo6huWD1EdkKYV+G/T4nq0YEF2vgTT8kqMFKo1uHn950r4SQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/windows-release/node_modules/signal-exit": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-4.1.0.tgz", + "integrity": "sha512-bzyZ1e88w9O1iNJbKnOlvYTrWPDl46O1bG0D3XInv+9tkPrxrN8jUUTiFlDkkmKWgn1M6CfIA13SuGqOa9Korw==", + "dev": true, + "license": "ISC", + "engines": { + "node": ">=14" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/windows-release/node_modules/strip-final-newline": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/strip-final-newline/-/strip-final-newline-3.0.0.tgz", + "integrity": "sha512-dOESqjYr96iWYylGObzd39EuNTa5VJxyvVAEm5Jnh7KGo75V43Hk1odPQkNDyXNmUR6k+gEiDVXnjB8HJ3crXw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, "node_modules/word-wrap": { "version": "1.2.5", "resolved": "https://registry.npmjs.org/word-wrap/-/word-wrap-1.2.5.tgz", @@ -16028,6 +18232,13 @@ "node": ">=0.10.0" } }, + "node_modules/wordwrap": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/wordwrap/-/wordwrap-1.0.0.tgz", + "integrity": "sha512-gvVzJFlPycKc5dZN4yPkP8w7Dc37BtP1yczEneOb4uq34pXZcvrtRTmWV8W+Ume+XCxKgbjM+nevkyFPMybd4Q==", + "dev": true, + "license": "MIT" + }, "node_modules/workerpool": { "version": "6.5.1", "resolved": "https://registry.npmjs.org/workerpool/-/workerpool-6.5.1.tgz", @@ -16080,6 +18291,38 @@ } } }, + "node_modules/wsl-utils": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/wsl-utils/-/wsl-utils-0.1.0.tgz", + "integrity": "sha512-h3Fbisa2nKGPxCpm89Hk33lBLsnaGBvctQopaBSOW/uIs6FTe1ATyAnKFJrzVs9vpGdsTe73WF3V4lIsk4Gacw==", + "dev": true, + "license": "MIT", + "dependencies": { + "is-wsl": "^3.1.0" + }, + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/wsl-utils/node_modules/is-wsl": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/is-wsl/-/is-wsl-3.1.1.tgz", + "integrity": "sha512-e6rvdUCiQCAuumZslxRJWR/Doq4VpPR82kqclvcS0efgt430SlGIk05vdCN58+VrzgtIcfNODjozVielycD4Sw==", + "dev": true, + "license": "MIT", + "dependencies": { + "is-inside-container": "^1.0.0" + }, + "engines": { + "node": ">=16" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, "node_modules/xhr": { "version": "2.6.0", "resolved": "https://registry.npmjs.org/xhr/-/xhr-2.6.0.tgz", @@ -16215,6 +18458,7 @@ "version": "3.1.1", "resolved": "https://registry.npmjs.org/yn/-/yn-3.1.1.tgz", "integrity": "sha512-Ux4ygGWsu2c7isFWe8Yu1YluJmqVhxqK2cLXNQA5AcC3QfbGNpM7fu0Y8b/z16pXLnFxZYvWhd3fhBY9DLmC6Q==", + "dev": true, "license": "MIT", "engines": { "node": ">=6" @@ -16232,6 +18476,32 @@ "funding": { "url": "https://github.com/sponsors/sindresorhus" } + }, + "node_modules/yoctocolors": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/yoctocolors/-/yoctocolors-2.1.2.tgz", + "integrity": "sha512-CzhO+pFNo8ajLM2d2IW/R93ipy99LWjtwblvC1RsoSUMZgyLbYFr221TnSNT7GjGdYui6P459mw9JH/g/zW2ug==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/yoctocolors-cjs": { + "version": "2.1.3", + "resolved": "https://registry.npmjs.org/yoctocolors-cjs/-/yoctocolors-cjs-2.1.3.tgz", + "integrity": "sha512-U/PBtDf35ff0D8X8D0jfdzHYEPFxAI7jJlxZXwCSez5M3190m+QobIfh+sWDWSHMCWWJN2AWamkegn6vr6YBTw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } } } } diff --git a/package.json b/package.json index c183d962..e8c56ade 100644 --- a/package.json +++ b/package.json @@ -1,8 +1,16 @@ { - "name": "ocean-cli", - "version": "2.0.0", + "name": "@oceanprotocol/cli", + "version": "2.0.0-next.1", "description": "CLI tool to interact with the oceanprotocol's JavaScript library to privately & securely publish, consume and run compute on data.", "type": "module", + "bin": { + "ocean-cli": "dist/index.js" + }, + "files": [ + "dist", + "metadata", + "README.md" + ], "scripts": { "build": "npm run clean && npm run build:tsc", "build:tsc": "tsc --sourceMap", @@ -13,20 +21,46 @@ "cli": "npx tsx src/index.ts", "test:system": "npm run mocha 'test/**/*.test.ts'", "test": "npm run lint && npm run test:system", - "mocha": "NODE_OPTIONS='--experimental-require-module' mocha --config=test/.mocharc.json --node-env=test --exit" + "mocha": "NODE_OPTIONS='--experimental-require-module' mocha --config=test/.mocharc.json --node-env=test --exit", + "prepublishOnly": "npm run build", + "changelog": "auto-changelog -p", + "release": "release-it --non-interactive" }, "author": "Ocean Protocol ", "license": "Apache-2.0", "engines": { "node": ">=22" }, + "repository": { + "type": "git", + "url": "git+https://github.com/oceanprotocol/ocean.js-cli.git" + }, + "publishConfig": { + "access": "public" + }, "bugs": { "url": "https://github.com/oceanprotocol/ocean.js-cli/issues" }, "homepage": "https://github.com/oceanprotocol/ocean.js-cli#readme", + "release-it": { + "hooks": { + "after:bump": "npm run build && npm run changelog && git add CHANGELOG.md" + }, + "git": { + "tagName": "v${version}", + "commitMessage": "Release v${version}" + }, + "github": { + "release": true + }, + "npm": { + "publish": false + } + }, "devDependencies": { "@eslint/js": "^9.4.0", "@types/chai": "^4.3.5", + "auto-changelog": "^2.4.0", "@types/mocha": "^10.0.1", "@types/node": "^20.2.5", "@typescript-eslint/eslint-plugin": "^5.60.1", @@ -42,6 +76,8 @@ "mocha": "^10.2.0", "prettier": "^2.8.8", "pretty-quick": "^3.1.3", + "release-it": "^19.2.4", + "ts-node": "^10.9.1", "tsx": "^4.19.2", "typescript": "^5.0.4", "typescript-eslint": "^7.12.0" @@ -52,15 +88,13 @@ "@oceanprotocol/ddo-js": "^0.3.0", "@oceanprotocol/lib": "^9.0.0-next.4", "axios": "^1.11.0", + "chalk": "^4.1.2", "commander": "^13.1.0", "cross-fetch": "^3.1.5", "crypto-js": "^4.1.1", "decimal.js": "^10.4.1", "enquirer": "^2.4.1", - "esm": "^3.2.25", "ethers": "^6.15.0", - "figlet": "^1.7.0", - "ts-node": "^10.9.1", - "tsx": "^4.19.3" + "figlet": "^1.7.0" } } diff --git a/src/cli.ts b/src/cli.ts index 65f848ad..2d4d06f7 100644 --- a/src/cli.ts +++ b/src/cli.ts @@ -2,6 +2,7 @@ import { Command } from "commander"; import { Commands } from "./commands.js"; import { JsonRpcProvider, Signer, ethers } from "ethers"; import fs from "fs"; +import { createRequire } from "module"; import chalk from "chalk"; import { stdin as input, stdout } from "node:process"; import { createInterface } from "readline/promises"; @@ -13,6 +14,11 @@ import { } from "@oceanprotocol/lib"; import { toBoolean } from "./helpers.js"; +// Single source of truth for the CLI version: read it from package.json instead +// of hardcoding, so it can't drift. `../package.json` resolves from both src/ +// (dev via tsx) and dist/ (published), since both sit one level below the root. +const pkg = createRequire(import.meta.url)("../package.json"); + // Parse a CLI JSON array-of-strings option (e.g. --cmd '["python","app.py"]'). // Returns the array, or throws with a clear message for the action to surface. function parseJsonStringArray(name: string, value: string): string[] { @@ -58,21 +64,36 @@ async function initializeSigner() { } export async function createCLI() { - if (!process.env.MNEMONIC && !process.env.PRIVATE_KEY) { - console.error(chalk.red("Have you forgot to set MNEMONIC or PRIVATE_KEY?")); - process.exit(1); - } - if (!process.env.RPC) { - console.error(chalk.red("Have you forgot to set env RPC?")); - process.exit(1); - } + // A pure help/version invocation must work with no configuration at all (a + // globally installed binary is expected to answer `--help`/`--version` + // without credentials). Detect it from argv and skip both env validation and + // the P2P bootstrap in that case; every real command still validates below. + const argv = process.argv.slice(2); + const isHelpOrVersion = + argv.includes("--help") || + argv.includes("-h") || + argv.includes("--version") || + argv.includes("-V") || + argv[0] === "help" || + argv[0] === "h"; + + if (!isHelpOrVersion) { + if (!process.env.MNEMONIC && !process.env.PRIVATE_KEY) { + console.error(chalk.red("Have you forgot to set MNEMONIC or PRIVATE_KEY?")); + process.exit(1); + } + if (!process.env.RPC) { + console.error(chalk.red("Have you forgot to set env RPC?")); + process.exit(1); + } - if (!process.env.NODE_URL) { - console.error(chalk.red("Have you forgot to set env NODE_URL?")); - process.exit(1); + if (!process.env.NODE_URL) { + console.error(chalk.red("Have you forgot to set env NODE_URL?")); + process.exit(1); + } } - if (isP2pUri(process.env.NODE_URL)) { + if (!isHelpOrVersion && process.env.NODE_URL && isP2pUri(process.env.NODE_URL)) { const extra = process.env.BOOTSTRAP_PEERS?.split(",").filter(Boolean) || []; // Default Ocean bootstrap nodes (must be included explicitly since passing @@ -159,7 +180,7 @@ export async function createCLI() { program .name("ocean-cli") .description("CLI tool to interact with Ocean Protocol") - .version("2.0.0") + .version(pkg.version) .helpOption("-h, --help", "Display help for command"); // Custom help command to support legacy "h" invocation. diff --git a/src/helpers.ts b/src/helpers.ts index 16497a5e..e47baed1 100644 --- a/src/helpers.ts +++ b/src/helpers.ts @@ -25,8 +25,21 @@ import { LoggerInstance } from "@oceanprotocol/lib"; import { homedir } from "os"; - -const ERC20Template = readFileSync('./node_modules/@oceanprotocol/contracts/artifacts/contracts/templates/ERC20Template.sol/ERC20Template.json', 'utf8') as any; +import { createRequire } from "module"; + +// Resolve the ERC20 template ABI through the module system rather than a +// cwd-relative path, so the compiled CLI works from any working directory +// (e.g. when installed globally). require.resolve finds the JSON inside the +// installed @oceanprotocol/contracts package regardless of cwd. +const require = createRequire(import.meta.url); +const ERC20Template = JSON.parse( + readFileSync( + require.resolve( + "@oceanprotocol/contracts/artifacts/contracts/templates/ERC20Template.sol/ERC20Template.json" + ), + "utf8" + ) +); export async function downloadFile( url: string, diff --git a/src/index.ts b/src/index.ts index d9c8f0f1..3c84c208 100644 --- a/src/index.ts +++ b/src/index.ts @@ -1,3 +1,4 @@ +#!/usr/bin/env node import { Command, CommanderError } from "commander"; import chalk from "chalk"; import { stdin as input, stdout as output } from "node:process"; @@ -59,13 +60,17 @@ function tokenize(line: string): string[] { } /** - * Strip an optional leading `npm run cli` prefix so that a pasted example - * command behaves identically to the bare command form. + * Strip an optional leading `npm run cli` or `ocean-cli` prefix so that a pasted + * example command (from either the contributor docs or the global-install docs) + * behaves identically to the bare command form. */ function stripNpmPrefix(tokens: string[]): string[] { if (tokens[0] === "npm" && tokens[1] === "run" && tokens[2] === "cli") { return tokens.slice(3) } + if (tokens[0] === "ocean-cli") { + return tokens.slice(1) + } return tokens } @@ -98,7 +103,7 @@ async function runTokens(tokens: string[]): Promise { } } -const PROMPT = "Enter command ('exit' | 'quit' or CTRL-C to terminate):\n" +const PROMPT = "Enter command ('exit' | 'quit' | ESC or CTRL-C to terminate):\n" /** * Tab-completion for the command name (the first token only). readline completes @@ -124,30 +129,47 @@ function completer(line: string): [string[], string] { */ async function runLoop(): Promise { const rl = createInterface({ input, output, completer }) + + // On a TTY, let the Escape key exit the REPL (Ctrl-C already terminates via + // SIGINT; `exit`/`quit`/`\q`/EOF still work). readline already emits keypress + // events on the input stream in terminal mode, so a listener is enough — no + // raw-mode juggling. Guarded by isTTY so piped stdin (tests, scripts) is + // unaffected. + const onKeypress = (_str: string, key?: { name?: string }): void => { + if (key?.name === "escape") { + output.write("\n") + rl.close() + } + } + if (input.isTTY) input.on("keypress", onKeypress) + rl.setPrompt(PROMPT) rl.prompt() - for await (const rawLine of rl) { - const line = rawLine.trim() + try { + for await (const rawLine of rl) { + const line = rawLine.trim() - if (line === "quit" || line === "exit" || line === "\\q") { - break - } + if (line === "quit" || line === "exit" || line === "\\q") { + break + } + + // Empty input: re-prompt instead of busy-waiting or dropping the session. + if (line === "") { + rl.prompt() + continue + } - // Empty input: re-prompt instead of busy-waiting or dropping the session. - if (line === "") { + const tokens = stripNpmPrefix(tokenize(line)) + rl.pause() + await runTokens(tokens) + rl.resume() rl.prompt() - continue } - - const tokens = stripNpmPrefix(tokenize(line)) - rl.pause() - await runTokens(tokens) - rl.resume() - rl.prompt() + } finally { + if (input.isTTY) input.off("keypress", onKeypress) + rl.close() } - - rl.close() } async function main(): Promise { @@ -159,12 +181,17 @@ async function main(): Promise { if (alias) supportedCommands.push(alias) } - // Handle help flag without initializing signer, and exit so it prints - // once (not again via parseAsync/runLoop below). + // Handle help/version flags without initializing a signer, and exit so + // they print once and never drop into the REPL below. createCLI() already + // skips env validation for these invocations. if (process.argv.includes('--help') || process.argv.includes('-h')) { program.outputHelp(); return; } + if (process.argv.includes('--version') || process.argv.includes('-V')) { + console.log(program.version()); + return; + } if (process.env.AVOID_LOOP_RUN === 'true') { // one shot diff --git a/src/interactiveFlow.ts b/src/interactiveFlow.ts index cbe91a4c..9f5c6f48 100644 --- a/src/interactiveFlow.ts +++ b/src/interactiveFlow.ts @@ -2,7 +2,7 @@ import enquirer from 'enquirer'; const { prompt } = enquirer; -import { PublishAssetParams } from './publishAsset'; +import { PublishAssetParams } from './publishAsset.js'; import chalk from 'chalk'; import figlet from 'figlet'; diff --git a/src/policyServerHelper.ts b/src/policyServerHelper.ts index 8b386920..d1e3124b 100644 --- a/src/policyServerHelper.ts +++ b/src/policyServerHelper.ts @@ -1,5 +1,5 @@ import { Asset } from "@oceanprotocol/ddo-js" -import { PolicyServerActions, PolicyServerGetPdAction, PolicyServerInitiateAction, PolicyServerInitiateActionData, PolicyServerInitiateComputeActionData, PolicyServerPresentationDefinition, SsiVerifiableCredential, SsiWalletDid, SsiWalletSession } from "./policyServerInterfaces" +import { PolicyServerActions, PolicyServerGetPdAction, PolicyServerInitiateAction, PolicyServerInitiateActionData, PolicyServerInitiateComputeActionData, PolicyServerPresentationDefinition, SsiVerifiableCredential, SsiWalletDid, SsiWalletSession } from "./policyServerInterfaces.js" import axios from "axios" import { Signer } from "ethers" diff --git a/test/replMenu.test.ts b/test/replMenu.test.ts index 51b66943..decfc756 100644 --- a/test/replMenu.test.ts +++ b/test/replMenu.test.ts @@ -9,7 +9,7 @@ const __dirname = dirname(__filename); const projectRoot = path.resolve(__dirname, ".."); // Recurring prompt string emitted by the REPL (keep in sync with src/index.ts). -const PROMPT = "Enter command ('exit' | 'quit' or CTRL-C to terminate):\n"; +const PROMPT = "Enter command ('exit' | 'quit' | ESC or CTRL-C to terminate):\n"; /** * Drive the interactive REPL (menu mode) with piped stdin. From 1523adb9a3fb65efc16ac9ed664a03813ff78828 Mon Sep 17 00:00:00 2001 From: alexcos20 Date: Fri, 24 Jul 2026 11:37:27 +0300 Subject: [PATCH 02/13] Release v2.0.0-next.2 --- CHANGELOG.md | 100 ++++++++++++++++++++++++++++++++++++++++++++++ package-lock.json | 4 +- package.json | 2 +- 3 files changed, 103 insertions(+), 3 deletions(-) create mode 100644 CHANGELOG.md diff --git a/CHANGELOG.md b/CHANGELOG.md new file mode 100644 index 00000000..256aa35f --- /dev/null +++ b/CHANGELOG.md @@ -0,0 +1,100 @@ +### Changelog + +All notable changes to this project will be documented in this file. Dates are displayed in UTC. + +Generated by [`auto-changelog`](https://github.com/CookPete/auto-changelog). + +#### [v2.0.0-next.2](https://github.com/oceanprotocol/ocean-cli/compare/v1.0.0...v2.0.0-next.2) + +- fix interactive menu [`#162`](https://github.com/oceanprotocol/ocean-cli/pull/162) +- ddoJs for v5 [`#131`](https://github.com/oceanprotocol/ocean-cli/pull/131) +- Feature/add claude [`#158`](https://github.com/oceanprotocol/ocean-cli/pull/158) +- codeowner [`#157`](https://github.com/oceanprotocol/ocean-cli/pull/157) +- Feature/allow full compute asset [`#156`](https://github.com/oceanprotocol/ocean-cli/pull/156) +- Change order initial users param [`#155`](https://github.com/oceanprotocol/ocean-cli/pull/155) +- Bucket methods [`#154`](https://github.com/oceanprotocol/ocean-cli/pull/154) +- bump ocean.js + ddo.js [`#152`](https://github.com/oceanprotocol/ocean-cli/pull/152) +- ocean.js p2p [`#151`](https://github.com/oceanprotocol/ocean-cli/pull/151) +- feat(#148): expose external storage c2d [`#150`](https://github.com/oceanprotocol/ocean-cli/pull/150) +- use latest ocean.js [`#147`](https://github.com/oceanprotocol/ocean-cli/pull/147) +- chore: add example metadata [`#132`](https://github.com/oceanprotocol/ocean-cli/pull/132) +- chore: buy v5 [`bc2b222`](https://github.com/oceanprotocol/ocean-cli/commit/bc2b2227c08620a63e171ab9e8d1660a3190bd4a) +- fix: removed file downaloded [`c99c066`](https://github.com/oceanprotocol/ocean-cli/commit/c99c06639dd6ad3a4c2f93ba01f5163bc77ec24f) +- fix: lint [`a91ee21`](https://github.com/oceanprotocol/ocean-cli/commit/a91ee21b6c59b44c3b93cee84286abf881bac1bc) + +#### v1.0.0 + +> 27 February 2026 + +- use oceanlib v6 [`#146`](https://github.com/oceanprotocol/ocean-cli/pull/146) +- feat(logs): add downloadNodeLogs cli command [`#144`](https://github.com/oceanprotocol/ocean-cli/pull/144) +- fix: update get logs test after getLogsHandler p2p update [`#143`](https://github.com/oceanprotocol/ocean-cli/pull/143) +- Feature/bump_oceanlib_to_510 [`#141`](https://github.com/oceanprotocol/ocean-cli/pull/141) +- add copilot instructions [`#140`](https://github.com/oceanprotocol/ocean-cli/pull/140) +- add n8n flow [`#139`](https://github.com/oceanprotocol/ocean-cli/pull/139) +- Node version and module type [`#137`](https://github.com/oceanprotocol/ocean-cli/pull/137) +- bump ocean libs [`#136`](https://github.com/oceanprotocol/ocean-cli/pull/136) +- Updated docs [`#135`](https://github.com/oceanprotocol/ocean-cli/pull/135) +- Access list methods [`#133`](https://github.com/oceanprotocol/ocean-cli/pull/133) +- update codeowners [`#134`](https://github.com/oceanprotocol/ocean-cli/pull/134) +- Update libs and ethers [`#127`](https://github.com/oceanprotocol/ocean-cli/pull/127) +- Fix publisher trusted algorithms structure for compute dataset. [`#125`](https://github.com/oceanprotocol/ocean-cli/pull/125) +- Feature/paid auth extra commands [`#124`](https://github.com/oceanprotocol/ocean-cli/pull/124) +- Fix parsing compute envs for ocean-node system tests. [`#121`](https://github.com/oceanprotocol/ocean-cli/pull/121) +- Feature/paid-compute in cli [`#115`](https://github.com/oceanprotocol/ocean-cli/pull/115) +- bump ocean.js [`#120`](https://github.com/oceanprotocol/ocean-cli/pull/120) +- Update ocean.js [`#119`](https://github.com/oceanprotocol/ocean-cli/pull/119) +- Remove legacy env vars like AQUARIUS and PROVIDER urls [`#111`](https://github.com/oceanprotocol/ocean-cli/pull/111) +- Update CODEOWNERS [`#112`](https://github.com/oceanprotocol/ocean-cli/pull/112) +- avoid cli to exit, loop commands [`#99`](https://github.com/oceanprotocol/ocean-cli/pull/99) +- add authorized publishers, update DDO validate call [`#90`](https://github.com/oceanprotocol/ocean-cli/pull/90) +- Fix start free compute - Fix logic for METADATA_CACHE_URI [`#109`](https://github.com/oceanprotocol/ocean-cli/pull/109) +- Release SDK 4.0 C2D V2 [`#89`](https://github.com/oceanprotocol/ocean-cli/pull/89) +- Issue ddo id with lib [`#101`](https://github.com/oceanprotocol/ocean-cli/pull/101) +- fix node branch [`#103`](https://github.com/oceanprotocol/ocean-cli/pull/103) +- use latest ocean.js [`#100`](https://github.com/oceanprotocol/ocean-cli/pull/100) +- Fix consume flow tests for new DDO structure [`#87`](https://github.com/oceanprotocol/ocean-cli/pull/87) +- Fix p2p test. [`#98`](https://github.com/oceanprotocol/ocean-cli/pull/98) +- Issue 96 consumeflow file [`#97`](https://github.com/oceanprotocol/ocean-cli/pull/97) +- updating cli to use command cli library [`#88`](https://github.com/oceanprotocol/ocean-cli/pull/88) +- Use createAsset function from SDK. [`#73`](https://github.com/oceanprotocol/ocean-cli/pull/73) +- pass config argument when we have it [`#84`](https://github.com/oceanprotocol/ocean-cli/pull/84) +- Fixing bug where feeToken is always Ocean [`#79`](https://github.com/oceanprotocol/ocean-cli/pull/79) +- refactor fn call waitForAqua to waitForIndexer [`#86`](https://github.com/oceanprotocol/ocean-cli/pull/86) +- increase MAX_REQ_PER_MINUTE for system tests [`#81`](https://github.com/oceanprotocol/ocean-cli/pull/81) +- Delete node:16 docker image from workflow. [`#76`](https://github.com/oceanprotocol/ocean-cli/pull/76) +- Setting up cli interactive flow [`#71`](https://github.com/oceanprotocol/ocean-cli/pull/71) +- add check for computeoutput, ips [`#65`](https://github.com/oceanprotocol/ocean-cli/pull/65) +- Adding tests for downloading assets [`#68`](https://github.com/oceanprotocol/ocean-cli/pull/68) +- Issue 62 - add default filename on downloadFile [`#63`](https://github.com/oceanprotocol/ocean-cli/pull/63) +- Updating access [`#67`](https://github.com/oceanprotocol/ocean-cli/pull/67) +- Fix compute assets samples [`#61`](https://github.com/oceanprotocol/ocean-cli/pull/61) +- add missing algo meta to request to start compute [`#59`](https://github.com/oceanprotocol/ocean-cli/pull/59) +- Issue 54 agreementid stop [`#56`](https://github.com/oceanprotocol/ocean-cli/pull/56) +- computeStatus - add support for `agreementId` [`#53`](https://github.com/oceanprotocol/ocean-cli/pull/53) +- Bump ocean.js lib [`#55`](https://github.com/oceanprotocol/ocean-cli/pull/55) +- Test flow with Ocean Node [`#49`](https://github.com/oceanprotocol/ocean-cli/pull/49) +- Bump ocean lib [`#51`](https://github.com/oceanprotocol/ocean-cli/pull/51) +- Compute jobs with multiple datasets & selectable compute env [`#34`](https://github.com/oceanprotocol/ocean-cli/pull/34) +- Fix/provider url override if env var is set [`#47`](https://github.com/oceanprotocol/ocean-cli/pull/47) +- fix for loop [`#48`](https://github.com/oceanprotocol/ocean-cli/pull/48) +- Fix validation order [`#45`](https://github.com/oceanprotocol/ocean-cli/pull/45) +- set proper flags for metadata [`#41`](https://github.com/oceanprotocol/ocean-cli/pull/41) +- fix editAsset command [`#44`](https://github.com/oceanprotocol/ocean-cli/pull/44) +- bump ocean.js [`#40`](https://github.com/oceanprotocol/ocean-cli/pull/40) +- Bump ocean lib and remove logs [`#39`](https://github.com/oceanprotocol/ocean-cli/pull/39) +- Fix/ unencrypt publish [`#38`](https://github.com/oceanprotocol/ocean-cli/pull/38) +- Publish DDO without encrypt option [`#35`](https://github.com/oceanprotocol/ocean-cli/pull/35) +- Fix readme private key [`#31`](https://github.com/oceanprotocol/ocean-cli/pull/31) +- Update README.md [`#30`](https://github.com/oceanprotocol/ocean-cli/pull/30) +- Fix/ Mnemonic - Private key & Provider - Aquarius usage [`#29`](https://github.com/oceanprotocol/ocean-cli/pull/29) +- Readme, package.json updates & small fixes [`#21`](https://github.com/oceanprotocol/ocean-cli/pull/21) +- Add download c2d Job Result [`#17`](https://github.com/oceanprotocol/ocean-cli/pull/17) +- Build-in support for Barge on macOS [`#18`](https://github.com/oceanprotocol/ocean-cli/pull/18) +- bump ocean.js lib [`#20`](https://github.com/oceanprotocol/ocean-cli/pull/20) +- Bump ocean.js lib 3.1.1 [`#16`](https://github.com/oceanprotocol/ocean-cli/pull/16) +- Feature/ Support oceanjs v3 [`#6`](https://github.com/oceanprotocol/ocean-cli/pull/6) +- Update URL [`#5`](https://github.com/oceanprotocol/ocean-cli/pull/5) +- remove old code [`719a969`](https://github.com/oceanprotocol/ocean-cli/commit/719a9694749b9f77f45a8bc66ed862f36cfc90c7) +- refactor vars [`3951f5f`](https://github.com/oceanprotocol/ocean-cli/commit/3951f5fa0826ae0d05bd1d25726d1e053fab28c1) +- minor fix, allow empty datasets [`0e0281c`](https://github.com/oceanprotocol/ocean-cli/commit/0e0281ce790045bc8b2a87b2b65e9de27646b245) diff --git a/package-lock.json b/package-lock.json index 905b3d55..6ad19539 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,12 +1,12 @@ { "name": "@oceanprotocol/cli", - "version": "2.0.0-next.1", + "version": "2.0.0-next.2", "lockfileVersion": 3, "requires": true, "packages": { "": { "name": "@oceanprotocol/cli", - "version": "2.0.0-next.1", + "version": "2.0.0-next.2", "license": "Apache-2.0", "dependencies": { "@oasisprotocol/sapphire-paratime": "^1.3.2", diff --git a/package.json b/package.json index e8c56ade..27fc8190 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "@oceanprotocol/cli", - "version": "2.0.0-next.1", + "version": "2.0.0-next.2", "description": "CLI tool to interact with the oceanprotocol's JavaScript library to privately & securely publish, consume and run compute on data.", "type": "module", "bin": { From 1f58c82aba84a9e7b0b49e3e328024c16441ffc8 Mon Sep 17 00:00:00 2001 From: alexcos20 Date: Fri, 24 Jul 2026 11:40:25 +0300 Subject: [PATCH 03/13] fix package url --- package.json | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/package.json b/package.json index 27fc8190..5a25df04 100644 --- a/package.json +++ b/package.json @@ -33,15 +33,15 @@ }, "repository": { "type": "git", - "url": "git+https://github.com/oceanprotocol/ocean.js-cli.git" + "url": "git+https://github.com/oceanprotocol/ocean-cli.git" }, "publishConfig": { "access": "public" }, "bugs": { - "url": "https://github.com/oceanprotocol/ocean.js-cli/issues" + "url": "https://github.com/oceanprotocol/ocean-cli/issues" }, - "homepage": "https://github.com/oceanprotocol/ocean.js-cli#readme", + "homepage": "https://github.com/oceanprotocol/ocean-cli#readme", "release-it": { "hooks": { "after:bump": "npm run build && npm run changelog && git add CHANGELOG.md" From e7c4e13fc8314233d52145e4db306048cc4d404e Mon Sep 17 00:00:00 2001 From: alexcos20 Date: Fri, 24 Jul 2026 11:40:47 +0300 Subject: [PATCH 04/13] Release v2.0.0-next.3 --- CHANGELOG.md | 6 ++++++ package-lock.json | 4 ++-- package.json | 2 +- 3 files changed, 9 insertions(+), 3 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 256aa35f..ccbd7bf0 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -4,8 +4,14 @@ All notable changes to this project will be documented in this file. Dates are d Generated by [`auto-changelog`](https://github.com/CookPete/auto-changelog). +#### [v2.0.0-next.3](https://github.com/oceanprotocol/ocean-cli/compare/v2.0.0-next.2...v2.0.0-next.3) + +- fix package url [`1f58c82`](https://github.com/oceanprotocol/ocean-cli/commit/1f58c82aba84a9e7b0b49e3e328024c16441ffc8) + #### [v2.0.0-next.2](https://github.com/oceanprotocol/ocean-cli/compare/v1.0.0...v2.0.0-next.2) +> 24 July 2026 + - fix interactive menu [`#162`](https://github.com/oceanprotocol/ocean-cli/pull/162) - ddoJs for v5 [`#131`](https://github.com/oceanprotocol/ocean-cli/pull/131) - Feature/add claude [`#158`](https://github.com/oceanprotocol/ocean-cli/pull/158) diff --git a/package-lock.json b/package-lock.json index 6ad19539..734919a1 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,12 +1,12 @@ { "name": "@oceanprotocol/cli", - "version": "2.0.0-next.2", + "version": "2.0.0-next.3", "lockfileVersion": 3, "requires": true, "packages": { "": { "name": "@oceanprotocol/cli", - "version": "2.0.0-next.2", + "version": "2.0.0-next.3", "license": "Apache-2.0", "dependencies": { "@oasisprotocol/sapphire-paratime": "^1.3.2", diff --git a/package.json b/package.json index 5a25df04..efd76bba 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "@oceanprotocol/cli", - "version": "2.0.0-next.2", + "version": "2.0.0-next.3", "description": "CLI tool to interact with the oceanprotocol's JavaScript library to privately & securely publish, consume and run compute on data.", "type": "module", "bin": { From b7b7754fa881f857358c00f2c2ba8aa2b3ac68e7 Mon Sep 17 00:00:00 2001 From: alexcos20 Date: Fri, 24 Jul 2026 11:56:24 +0300 Subject: [PATCH 05/13] fixes --- src/index.ts | 5 +++++ src/warnings.ts | 29 +++++++++++++++++++++++++++++ 2 files changed, 34 insertions(+) create mode 100644 src/warnings.ts diff --git a/src/index.ts b/src/index.ts index 3c84c208..c5350498 100644 --- a/src/index.ts +++ b/src/index.ts @@ -1,4 +1,5 @@ #!/usr/bin/env node +import "./warnings.js"; import { Command, CommanderError } from "commander"; import chalk from "chalk"; import { stdin as input, stdout as output } from "node:process"; @@ -204,9 +205,13 @@ async function main(): Promise { configureForLoop(program) // Run the initial command passed on argv once (if any), surfacing errors. + // When started with no command at all, show the help menu up front so the + // user sees what's available instead of facing a bare prompt. const initialTokens = process.argv.slice(2) if (initialTokens.length > 0) { await runTokens(initialTokens) + } else { + console.log(program.helpInformation()) } // Then loop on stdin until the user exits or input is exhausted. diff --git a/src/warnings.ts b/src/warnings.ts new file mode 100644 index 00000000..f7128bd2 --- /dev/null +++ b/src/warnings.ts @@ -0,0 +1,29 @@ +// Silence noisy Node process warnings emitted by transitive dependencies — +// notably punycode's `DeprecationWarning` (DEP0040) and the Ed25519 Web Crypto +// `ExperimentalWarning` — which fire asynchronously and would otherwise scroll +// the interactive REPL prompt out of view. Only these two low-signal categories +// are dropped; every other warning is still printed (in Node's default format). +// +// Every process warning — however it is emitted — is ultimately dispatched +// through the `'warning'` event, whose default listener is what prints it. So we +// remove that default listener and install our own filtering one. (Overriding +// `process.emitWarning` is not enough: core emits some warnings via a reference +// captured during bootstrap, before user code runs.) +// +// This module is imported FIRST in `src/index.ts`. ESM evaluates a module's +// imports in source order before its own body, so a side-effecting import placed +// before the others installs this hook before the dependency modules that +// trigger the warnings are evaluated. + +const SILENCED = new Set(["DeprecationWarning", "ExperimentalWarning"]); + +process.removeAllListeners("warning"); + +process.on("warning", (warning: Error & { code?: string }) => { + if (SILENCED.has(warning.name)) return; + // Reproduce Node's default one-line format for everything else. + const code = warning.code ? ` [${warning.code}]` : ""; + console.error( + `(node:${process.pid})${code} ${warning.stack ?? `${warning.name}: ${warning.message}`}` + ); +}); From 7395609b7af72ba9e2a7b214dcbac223b7d22971 Mon Sep 17 00:00:00 2001 From: alexcos20 Date: Fri, 24 Jul 2026 11:56:44 +0300 Subject: [PATCH 06/13] Release v2.0.0-next.4 --- CHANGELOG.md | 7 +++++++ package-lock.json | 4 ++-- package.json | 2 +- 3 files changed, 10 insertions(+), 3 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index ccbd7bf0..12a1e3b2 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -4,8 +4,15 @@ All notable changes to this project will be documented in this file. Dates are d Generated by [`auto-changelog`](https://github.com/CookPete/auto-changelog). +#### [v2.0.0-next.4](https://github.com/oceanprotocol/ocean-cli/compare/v2.0.0-next.3...v2.0.0-next.4) + +- fixes [`b7b7754`](https://github.com/oceanprotocol/ocean-cli/commit/b7b7754fa881f857358c00f2c2ba8aa2b3ac68e7) + #### [v2.0.0-next.3](https://github.com/oceanprotocol/ocean-cli/compare/v2.0.0-next.2...v2.0.0-next.3) +> 24 July 2026 + +- Release v2.0.0-next.3 [`e7c4e13`](https://github.com/oceanprotocol/ocean-cli/commit/e7c4e13fc8314233d52145e4db306048cc4d404e) - fix package url [`1f58c82`](https://github.com/oceanprotocol/ocean-cli/commit/1f58c82aba84a9e7b0b49e3e328024c16441ffc8) #### [v2.0.0-next.2](https://github.com/oceanprotocol/ocean-cli/compare/v1.0.0...v2.0.0-next.2) diff --git a/package-lock.json b/package-lock.json index 734919a1..1db45c42 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,12 +1,12 @@ { "name": "@oceanprotocol/cli", - "version": "2.0.0-next.3", + "version": "2.0.0-next.4", "lockfileVersion": 3, "requires": true, "packages": { "": { "name": "@oceanprotocol/cli", - "version": "2.0.0-next.3", + "version": "2.0.0-next.4", "license": "Apache-2.0", "dependencies": { "@oasisprotocol/sapphire-paratime": "^1.3.2", diff --git a/package.json b/package.json index efd76bba..2fb6a5e7 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "@oceanprotocol/cli", - "version": "2.0.0-next.3", + "version": "2.0.0-next.4", "description": "CLI tool to interact with the oceanprotocol's JavaScript library to privately & securely publish, consume and run compute on data.", "type": "module", "bin": { From e5d9c30363f2a0c3ae732afaaf0060e528709ab3 Mon Sep 17 00:00:00 2001 From: Alex Coseru Date: Fri, 24 Jul 2026 15:26:23 +0300 Subject: [PATCH 07/13] Update .github/workflows/ci.yml Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com> --- .github/workflows/ci.yml | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 6907ed85..fc58450c 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -40,6 +40,10 @@ jobs: - name: Run lint run: npm run lint +permissions: + contents: read + +jobs: pack_smoke: # Guards the global-install contract without needing a full Ocean stack: # a broken bin, cwd-dependent module loading, or env-gated --help/--version @@ -49,6 +53,8 @@ jobs: steps: - name: Checkout code uses: actions/checkout@v4 + with: + persist-credentials: false - name: Set up Node.js uses: actions/setup-node@v4 From 265e8fd6bdec47ac85739c6b1614a0b585be1d54 Mon Sep 17 00:00:00 2001 From: alexcos20 Date: Fri, 24 Jul 2026 15:36:41 +0300 Subject: [PATCH 08/13] fixes --- .github/workflows/publish.yml | 19 ++++++++++++++++--- README.md | 8 ++++---- src/index.ts | 10 ++++++++-- 3 files changed, 28 insertions(+), 9 deletions(-) diff --git a/.github/workflows/publish.yml b/.github/workflows/publish.yml index 3f078bfe..65ad8da0 100644 --- a/.github/workflows/publish.yml +++ b/.github/workflows/publish.yml @@ -3,7 +3,7 @@ name: Publish on: push: tags: - - "**" + - "v*" permissions: contents: read @@ -12,8 +12,6 @@ permissions: jobs: npm: runs-on: ubuntu-latest - env: - NODE_AUTH_TOKEN: ${{ secrets.NPM_TOKEN }} steps: - name: Checkout code @@ -25,6 +23,17 @@ jobs: node-version: "22.5.1" registry-url: "https://registry.npmjs.org/" + # Only publish a tag whose version matches package.json, so a stray or + # mistyped tag can never publish a mismatched release. + - name: Verify tag matches package.json version + run: | + TAG_VERSION="${GITHUB_REF_NAME#v}" + PKG_VERSION="$(node -p "require('./package.json').version")" + if [ "$TAG_VERSION" != "$PKG_VERSION" ]; then + echo "Tag $GITHUB_REF_NAME (version $TAG_VERSION) does not match package.json version $PKG_VERSION" + exit 1 + fi + - name: Install dependencies run: npm ci @@ -35,7 +44,11 @@ jobs: - name: Publish (next) if: contains(github.ref, 'next') run: npm publish --tag next --provenance --access public + env: + NODE_AUTH_TOKEN: ${{ secrets.NPM_TOKEN }} - name: Publish (latest) if: ${{ !contains(github.ref, 'next') }} run: npm publish --provenance --access public + env: + NODE_AUTH_TOKEN: ${{ secrets.NPM_TOKEN }} diff --git a/README.md b/README.md index 97d67b6e..c2eb4f4e 100644 --- a/README.md +++ b/README.md @@ -99,19 +99,19 @@ export ADDRESS_FILE='path-to-address-file' - Optional, set INDEXING_MAX_RETRIES to the max number of retries when waiting for an asset to be indexed. Default is 120 retries max. -``` +```bash export INDEXING_MAX_RETRIES='120' ``` -- Optional, set INDEXING_RETRY_INTERVAL to the interval (in miliseconds) for each retry when waiting for an asset to be indexed. Default is 4 seconds (4000 ms). +- Optional, set INDEXING_RETRY_INTERVAL to the interval (in milliseconds) for each retry when waiting for an asset to be indexed. Default is 4 seconds (4000 ms). -``` +```bash export INDEXING_RETRY_INTERVAL='4000' ``` - Optional, set AVOID_LOOP_RUN to `'true'` to run a single command and exit afterwards (one-shot mode — required for CI and scripting). **By default the CLI is interactive**: it runs the command you pass (if any), then keeps reading further commands from a prompt, just like a REPL. Exit the interactive loop with `exit` / `quit`, the **ESC** key, or **CTRL-C**. -``` +```bash export AVOID_LOOP_RUN='true' # one-shot; unset or 'false' = interactive loop ``` diff --git a/src/index.ts b/src/index.ts index c5350498..c26bf759 100644 --- a/src/index.ts +++ b/src/index.ts @@ -184,8 +184,14 @@ async function main(): Promise { // Handle help/version flags without initializing a signer, and exit so // they print once and never drop into the REPL below. createCLI() already - // skips env validation for these invocations. - if (process.argv.includes('--help') || process.argv.includes('-h')) { + // skips env validation for these invocations. The bare positional forms + // `help`/`h` are treated the same as `--help` (print and exit) to match + // createCLI()'s configuration-free behavior; `help ` still routes + // to the registered help command below. + const cmdTokens = process.argv.slice(2); + const isBareHelp = + cmdTokens.length === 1 && (cmdTokens[0] === 'help' || cmdTokens[0] === 'h'); + if (process.argv.includes('--help') || process.argv.includes('-h') || isBareHelp) { program.outputHelp(); return; } From e18575fb332b99a5f94d3297e16b43a077543cc5 Mon Sep 17 00:00:00 2001 From: alexcos20 Date: Fri, 24 Jul 2026 15:42:04 +0300 Subject: [PATCH 09/13] fix ci --- .github/workflows/ci.yml | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index fc58450c..f835318f 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -3,6 +3,9 @@ name: Test Flow on: pull_request: +permissions: + contents: read + jobs: build: runs-on: ubuntu-latest @@ -40,10 +43,6 @@ jobs: - name: Run lint run: npm run lint -permissions: - contents: read - -jobs: pack_smoke: # Guards the global-install contract without needing a full Ocean stack: # a broken bin, cwd-dependent module loading, or env-gated --help/--version From 59bbd58cb3917867aa44e81af7b8bf12d2c07b67 Mon Sep 17 00:00:00 2001 From: alexcos20 Date: Thu, 6 Aug 2026 12:10:56 +0300 Subject: [PATCH 10/13] allow user to setNode --- CLAUDE.md | 27 +++-- README.md | 50 +++++++++- src/cli.ts | 227 ++++++++++++++++++++++++++++-------------- src/index.ts | 34 ++++++- src/nodeConnection.ts | 224 +++++++++++++++++++++++++++++++++++++++++ test/replMenu.test.ts | 50 +--------- test/setNode.test.ts | 135 +++++++++++++++++++++++++ test/util.ts | 63 +++++++++++- 8 files changed, 679 insertions(+), 131 deletions(-) create mode 100644 src/nodeConnection.ts create mode 100644 test/setNode.test.ts diff --git a/CLAUDE.md b/CLAUDE.md index 0645bd5d..eba2756d 100755 --- a/CLAUDE.md +++ b/CLAUDE.md @@ -61,14 +61,15 @@ Validated at startup in `createCLI()` (`src/cli.ts`), which `process.exit(1)`s w - `PRIVATE_KEY` **or** `MNEMONIC` — signer credentials (private key preferred; mnemonic via `ethers.Wallet.fromPhrase`). - `RPC` — JSON-RPC endpoint; chainId is read from `provider.getNetwork()`, not configured manually. -- `NODE_URL` — the Ocean Node. Can be an `http(s)://` URL, a raw libp2p peer id, or a full `/dns4/.../p2p/...` multiaddr (triggers P2P mode, see below). ### Optional environment variables +- `NODE_URL` — the **initial** Ocean Node. An `http(s)://` URL, a raw libp2p peer id, or a full `/dns4/.../p2p/...` multiaddr. **Not required to start:** without it the CLI runs in a node-less state where the `preAction` gate in `createCLI()` refuses every command except `setNode` / `getNode` / `help` (see "Node selection"). Switchable at runtime with `setNode`. +- `DISABLE_P2P` — `true` skips starting libp2p entirely. Combined with a P2P `NODE_URL` it is a fatal contradiction (`exit(1)` at startup). - `ADDRESS_FILE` — path to a contracts `address.json`. Defaults to `${homedir}/.ocean/ocean-contracts/artifacts/address.json`. Needed by escrow / mint / access-list commands (see "Config & chain selection"). - `INDEXING_MAX_RETRIES` / `INDEXING_RETRY_INTERVAL` — how long to wait for an asset to be indexed. **Code defaults are 120 retries × 4000 ms** (`getIndexingWaitSettings()` in `helpers.ts`); the README's "100 / 3000" figures are stale. - `AVOID_LOOP_RUN` — `true` = one-shot (no REPL loop). Unset/`false` = interactive loop. -- `BOOTSTRAP_PEERS` — comma-separated extra libp2p multiaddrs, only used in P2P mode. +- `BOOTSTRAP_PEERS` — comma-separated extra libp2p multiaddrs, added to the bootstrap list built in `nodeConnection.ts`. ## CLI commands exposed @@ -81,6 +82,7 @@ All registered in `src/cli.ts` via Commander (`commander` v13). Every command su - Access lists: `createAccessList`, `addToAccessList`, `checkAccessList`, `removeFromAccessList`. - Persistent storage buckets: `createBucket`, `addFileToBucket`, `listBuckets`, `listFilesInBucket`, `getFileObject`, `deleteFile`. - Admin: `downloadNodeLogs`. +- Node selection: `setNode` (alias `useNode`), `getNode` (alias `currentNode`). - `help` / `h`. Per-command flags and examples are exhaustively documented in `README.md` ("Command Usage" / "Available Named Options Per Command"). A few load-bearing notes: @@ -93,9 +95,9 @@ Per-command flags and examples are exhaustively documented in `README.md` ("Comm ### Entry point and dispatch (`src/index.ts` → `src/cli.ts`) -`main()` in `index.ts` calls `createCLI()` (in `cli.ts`) to build the Commander `program`, records supported command names/aliases, prints the REPL banner, runs the initial argv command once, then loops on stdin (`waitForCommands`) unless `AVOID_LOOP_RUN=true`. It uses `program.exitOverride()` so Commander errors don't kill the loop. +`main()` in `index.ts` calls `createCLI()` (in `cli.ts`) to build the Commander `program`, records supported command names/aliases, prints the REPL banner, runs the initial argv command once, then loops on stdin (`runLoop`) unless `AVOID_LOOP_RUN=true`. It uses `program.exitOverride()` so Commander errors don't kill the loop. -`createCLI()` does three things: (1) validates the required env vars — **unless** the invocation is a pure help/version one (`--help`/`-h`/`--version`/`-V`/`h`/`help`), which is detected from `process.argv` and skips both validation and P2P so those work with no config, (2) if `NODE_URL` is a P2P URI, sets up libp2p (see "Transport"), (3) registers every command. Each command's `.action(...)`: +`createCLI()` does four things: (1) validates `PRIVATE_KEY`/`MNEMONIC` and `RPC` — **unless** the invocation is a pure help/version one (`--help`/`-h`/`--version`/`-V`/`h`/`help`), which is detected from `process.argv` and skips both validation and P2P so those work with no config, (2) starts libp2p and health-checks `NODE_URL` if set (see "Transport" and "Node selection"), (3) registers the `preAction` gate that refuses non-`NODE_FREE_COMMANDS` while no node is set, (4) registers every command. Each command's `.action(...)`: 1. merges positional + option values, 2. calls the local `initializeSigner()` — builds a `JsonRpcProvider(RPC)`, a `Wallet` from `PRIVATE_KEY` (or `Wallet.fromPhrase(MNEMONIC)`), and reads `chainId` from the network, @@ -157,9 +159,20 @@ The `startCompute` **action in `cli.ts`** orchestrates a two-phase flow (not a s - **Auth tokens**: `generateAuthToken` / `invalidateAuthToken` via `ProviderInstance`. - **downloadNodeLogs** (admin): time-range or `--last N` hours; writes `/logs.json`. -### Transport: HTTP vs P2P +### Transport: HTTP vs P2P, and node selection (`src/nodeConnection.ts`) -If `NODE_URL` passes `isP2pUri()`, `createCLI()` boots a libp2p node via `ProviderInstance.setupP2P`, seeding bootstrap peers = local peer (derived from the peer id or full multiaddr) + `BOOTSTRAP_PEERS` + four hard-coded Ocean bootstrap nodes, and then **waits up to 20 s for the specific target peer** (from `NODE_URL`) to connect before proceeding, because signed commands fail if only bootstrap peers are connected. CI exercises both transports (matrix `[http, p2p]`). +All node lifecycle logic lives in `nodeConnection.ts`; `cli.ts` only calls into it. + +**libp2p is transport, not a connection to one node.** Every ocean.js P2P call takes a `nodeUri` and dials that peer on demand (direct dial for a full multiaddr, DHT lookup for a bare peer id), so one libp2p node serves any number of Ocean nodes and switching between them never restarts or stops it. + +- `startP2P(initialNodeUrl?)` — called **once at startup for every invocation** (not lazily, and not only for P2P `NODE_URL`s), because bootstrap dials + DHT warm-up take seconds and should overlap with the user reading the prompt. It is **deliberately not awaited**; the stored promise swallows its own rejection (an unhandled rejection on a fire-and-forget promise would kill the process) and remembers the failure for `ensureP2PReady()`. No-op when `DISABLE_P2P=true` or when `ProviderInstance.getLibp2pNode()` is already non-null. Bootstrap peers = the initial node if it is a P2P URI (bare peer ids get the `/ip4/127.0.0.1/tcp/9001/ws/p2p/` localhost convention) + `BOOTSTRAP_PEERS` + four hard-coded Ocean bootstrap nodes (passing `bootstrapPeers` **replaces** the lib's defaults, so they must be listed explicitly). +- `ensureP2PReady()` — awaited by every P2P-bound path; throws a clear reason instead of hanging when P2P is unavailable. +- `validateNode(url)` — non-destructive health check via `ProviderInstance.getNodeStatus` under an `AbortSignal.timeout` (10 s HTTP, 30 s P2P since a bare peer id may need a DHT lookup). Over P2P the on-demand dial *is* the reachability check, which is what the old 20 s wait-for-target-peer polling loop did — that loop is gone. +- `getCurrentNodeUrl()` / `setCurrentNodeUrl()` / `hasNode()` — `process.env.NODE_URL` stays the **single source of truth**, so switching node is just mutating it: `Commands`' constructor and `getMetadataURI()` re-read it per use. + +`setNode` validates first and only then mutates the env var, so a failed switch leaves everything untouched — there is nothing to roll back. The switch itself never touches the RPC/signer (node selection is independent of them and must work when the RPC is slow); `setNode` calls `initializeSigner()` only *after* committing, under a 5 s `Promise.race` timeout, purely to warn when the node does not serve the RPC's chain. CI exercises both transports (matrix `[http, p2p]`). + +**libp2p keeps the process alive.** A started libp2p node holds the event loop open, and even a clean `stop()` leaves a `MessagePort` behind (confirmed with `process.getActiveResourcesInfo()`). So `index.ts` ends with `if (await stopP2P()) { await flushOutput(); process.exit(...) }` — the flush matters because a piped stdout can still hold buffered output that `process.exit()` would discard. For the same reason the eager `startP2P` is **skipped in one-shot mode** (`AVOID_LOOP_RUN=true`): a one-shot run has no later command to warm up for, and would only pay startup + shutdown cost. One-shot runs that target a P2P node still get libp2p on demand via `validateNode` → `ensureP2PReady`. ### Interactive publish wizard (currently unwired) @@ -190,3 +203,5 @@ CI (`.github/workflows/ci.yml`) has three jobs: `build`, `lint`, and `test_syste - The 1-indexed vs 0-indexed args-array split between `Commands` methods is easy to get wrong when adding/renaming commands. - Running the CLI without `AVOID_LOOP_RUN=true` drops into a stdin REPL after the first command — surprising in scripts. - `fixAndParseProviderFees` is a regex JSON patcher for the initialize→start round trip; prefer fixing the data shape over extending the regex. +- A new command is refused when no node is set unless its canonical name is added to `NODE_FREE_COMMANDS` in `cli.ts`. The gate is a single root-level `preAction` hook keyed on `actionCommand.name()` (canonical, so aliases resolve for free) and throws a **plain `Error`, not a `CommanderError`** — that is what makes `index.ts` report it in red and keep the REPL alive, while one-shot mode exits 1. +- `supportedCommands` in `index.ts` uses `command.aliases()` (plural). The old `alias()` returned only the first alias, silently making extra aliases unreachable in the REPL. diff --git a/README.md b/README.md index c2eb4f4e..4248f0e3 100644 --- a/README.md +++ b/README.md @@ -85,10 +85,26 @@ export MNEMONIC="XXXX" export RPC='XXXX' ``` -- Mandatory, Set an Ocean Node URL. Ocean Nodes infrastructure is responsible for handling assets indexing and metadata caching. It replaced old Provider and Aquarius standalone apps. +- Optional (but recommended), set an Ocean Node URL. Ocean Nodes infrastructure is responsible for handling assets indexing and metadata caching. It replaced old Provider and Aquarius standalone apps. ``` export NODE_URL='XXXX' +``` + + `NODE_URL` is the **initial** node only. If it is not set the CLI still starts, but **only `setNode`, `getNode` and `help` are available** — every other command is refused with `No Ocean Node set` until you pick a node: + +```bash +npm run cli # starts with no node +# > setNode http://127.0.0.1:8001 +# > getComputeEnvironments # now works +``` + + You can switch node at any time with [`setNode`](#setnode) without restarting the CLI. See [`getNode`](#getnode) to check which node is active. + +- Optional, set DISABLE_P2P to `'true'` to skip starting the libp2p transport. By default the CLI starts libp2p at startup (in the background, so it does not delay the prompt) even when `NODE_URL` is an HTTP URL, so that a later switch to a P2P node does not have to wait for bootstrap peers and DHT warm-up. Set this when you only ever use HTTP nodes and do not want the CLI dialing the public Ocean bootstrap nodes. + +```bash +export DISABLE_P2P='true' ``` - Optional, set ADDRESS_FILE if you want to use a custom set of smart contract address @@ -172,6 +188,32 @@ npm run cli [options] #### Examples +**Choosing the Ocean Node:** + + + +- **Switch node (works inside the interactive loop, no restart needed):** + `npm run cli setNode http://127.0.0.1:8001` + Also accepts a peer id or a full multiaddr, and `--node`: + `npm run cli setNode --node /dns4/node.example/tcp/9001/ws/p2p/16Uiu2HAm...` + Alias: `useNode`. + + The node is health-checked before the switch: if it cannot be reached, the current node is kept and nothing changes. + + + +- **Show the node in use:** + `npm run cli getNode` (alias `currentNode`) — prints the active node plus its version and the chain(s) it serves. + +Notes when switching nodes: + +- **Compute jobs live on the node that started them.** After a switch, `getJobStatus` / `downloadJobResults` query the *new* node — switch back to look up older jobs. +- **For a node on your own machine, prefer the full multiaddr** (`/ip4/127.0.0.1/tcp/9001/ws/p2p/`) over a bare peer id: a bare id has to be found via DHT, which may not advertise localhost addresses. +- **In one-shot mode** (`AVOID_LOOP_RUN='true'`) `setNode` only validates the node and prints the result — the switch dies with the process. Use `NODE_URL` for one-shot runs. +- `chainId` still comes from `RPC`, never from the node. `setNode` warns when the node does not serve the chain your RPC is on. + +--- + **Get DDO:** - **Positional:** @@ -613,6 +655,12 @@ Notes: #### Available Named Options Per Command +- **setNode** (alias `useNode`)**:** + `` (Positional. HTTP(S) URL, peer id or full multiaddr) + `-n, --node ` (Same as the positional) + +- **getNode** (alias `currentNode`)**:** no arguments + - **getDDO:** `-d, --did ` diff --git a/src/cli.ts b/src/cli.ts index 799c70c9..faa12711 100644 --- a/src/cli.ts +++ b/src/cli.ts @@ -8,12 +8,24 @@ import { stdin as input, stdout } from "node:process"; import { createInterface } from "readline/promises"; import { unitsToAmount, - ProviderInstance, isP2pUri, ServiceStatusNumber, ServiceRestartParams, } from "@oceanprotocol/lib"; import { toBoolean } from "./helpers.js"; +import { + getCurrentNodeUrl, + hasNode, + nodeChainIds, + setCurrentNodeUrl, + startP2P, + validateNode, +} from "./nodeConnection.js"; + +// Commands usable before any Ocean Node is selected. Everything else is refused by the +// preAction gate below until `setNode` succeeds. Canonical names only — aliases +// (useNode, currentNode, h) resolve to these. +const NODE_FREE_COMMANDS = new Set(["setNode", "getNode", "help"]); // Single source of truth for the CLI version: read it from package.json instead // of hardcoding, so it can't drift. `../package.json` resolves from both src/ @@ -87,90 +99,54 @@ export async function createCLI() { console.error(chalk.red("Have you forgot to set env RPC?")); process.exit(1); } + } - if (!process.env.NODE_URL) { - console.error(chalk.red("Have you forgot to set env NODE_URL?")); + // NODE_URL is optional: without it the CLI still starts, but only the commands in + // NODE_FREE_COMMANDS are accepted until `setNode` picks a node (see the gate below). + if (!isHelpOrVersion) { + if (process.env.DISABLE_P2P === "true" && isP2pUri(getCurrentNodeUrl())) { + console.error( + chalk.red( + "NODE_URL is a P2P URI but DISABLE_P2P=true — no command could reach it." + ) + ); process.exit(1); } - } - if (!isHelpOrVersion && process.env.NODE_URL && isP2pUri(process.env.NODE_URL)) { - const extra = process.env.BOOTSTRAP_PEERS?.split(",").filter(Boolean) || []; - - // Default Ocean bootstrap nodes (must be included explicitly since passing - // bootstrapPeers to setupP2P replaces the built-in defaults) - const oceanDefaults = [ - "/dns4/bootstrap1.oncompute.ai/tcp/9001/ws/p2p/16Uiu2HAmLhRDqfufZiQnxvQs2XHhd6hwkLSPfjAQg1gH8wgRixiP", - "/dns4/bootstrap2.oncompute.ai/tcp/9001/ws/p2p/16Uiu2HAmHwzeVw7RpGopjZe6qNBJbzDDBdqtrSk7Gcx1emYsfgL4", - "/dns4/bootstrap3.oncompute.ai/tcp/9001/ws/p2p/16Uiu2HAmBKSeEP3v4tYEPsZsZv9VELinyMCsrVTJW9BvQeFXx28U", - "/dns4/bootstrap4.oncompute.ai/tcp/9001/ws/p2p/16Uiu2HAmSTVTArioKm2wVcyeASHYEsnx2ZNq467Z4GMDU4ErEPom", - ]; - - const nodeUrl = process.env.NODE_URL; - const isFullMultiaddr = - nodeUrl.startsWith("/") && nodeUrl.includes("/p2p/"); - const localPeer = isFullMultiaddr - ? [nodeUrl] - : [`/ip4/127.0.0.1/tcp/9001/ws/p2p/${nodeUrl}`]; - const bootstrapPeers = [...localPeer, ...extra, ...oceanDefaults]; - console.log(chalk.cyan("P2P mode detected. Initializing libp2p...")); - console.log(chalk.cyan(`Bootstrap peers: ${bootstrapPeers.length}`)); - - for (const peer of localPeer) { - console.log(chalk.cyan(` Local: ${peer}`)); + // Eager, non-blocking: libp2p warms up (bootstrap dials + DHT) while the user reads + // the prompt, so a later switch to a P2P node doesn't pay that cost interactively. + // + // Only in loop mode. A one-shot run has no "later command" to warm up for, and + // starting a libp2p node it never uses would just delay its exit — the process + // cannot end until the node is up and stopped again. One-shot runs that *do* target + // a P2P node still get it: validateNode() -> ensureP2PReady() starts it on demand. + if (process.env.AVOID_LOOP_RUN !== "true") { + startP2P(process.env.NODE_URL); } - // Allow localhost connections / local nodes - await ProviderInstance.setupP2P({ - bootstrapPeers, - libp2p: { - connectionGater: { - denyDialMultiaddr: () => false, - }, - }, - } as any); - console.log( - chalk.cyan("libp2p node started. Waiting for peer connections...") - ); - // Wait for the TARGET peer (the one in NODE_URL) to be connected, - // not just any bootstrap peer — otherwise signed commands fail with - // "Cannot reach peer ...". - const targetPeerId = isFullMultiaddr - ? nodeUrl.split("/p2p/").pop()! - : nodeUrl; - const maxWait = 20_000; - const interval = 500; - let waited = 0; - const libp2p = (ProviderInstance as any).p2pProvider?.libp2pNode; - const isTargetConnected = () => - (libp2p?.getPeers() ?? []).some( - (p: { toString(): string }) => p.toString() === targetPeerId - ); - while (waited < maxWait) { - if (isTargetConnected()) { - const total = libp2p?.getConnections()?.length ?? 0; + if (hasNode()) { + // Confirms the startup node is reachable before the user types anything. For a + // P2P node the status call dials the peer, which is what the old wait-for-peer + // polling loop used to do. + const status = await validateNode(getCurrentNodeUrl()); + if (status) { console.log( chalk.green( - `Connected to target peer ${targetPeerId.slice(0, 12)}… in ${waited}ms (total peers: ${total})` + `Using node ${getCurrentNodeUrl()} (version ${status.version})` ) ); - break; - } - await new Promise((r) => setTimeout(r, interval)); - waited += interval; - if (waited % 3000 === 0) { - const total = libp2p?.getConnections()?.length ?? 0; - console.log( - chalk.yellow( - ` Waiting for target peer ${targetPeerId.slice(0, 12)}… (${waited / 1000}s, ${total} other peer(s))` + } else { + console.error( + chalk.red( + `Node ${getCurrentNodeUrl()} is not reachable. Commands may fail.` ) ); } - } - if (!isTargetConnected()) { - console.error( - chalk.red( - `Target peer ${targetPeerId} not reachable after ${maxWait / 1000}s. Commands will fail.` + } else { + console.log( + chalk.yellow( + "No Ocean Node configured. Run `setNode ` to choose one — " + + `only ${[...NODE_FREE_COMMANDS].join(", ")} are available until then.` ) ); } @@ -184,6 +160,23 @@ export async function createCLI() { .version(pkg.version) .helpOption("-h, --help", "Display help for command"); + // Every command except the node-free ones needs an Ocean Node. A single preAction + // hook on the root program runs before *any* subcommand action, so this covers both + // the REPL loop and one-shot mode without touching 40 action bodies. + // + // A plain Error (not a CommanderError) is thrown on purpose: in loop mode index.ts + // reports it in red and keeps the REPL alive; in one-shot mode main() reports it and + // exits 1, so scripts see a non-zero status. + program.hook("preAction", (_thisCommand, actionCommand) => { + // actionCommand.name() is the canonical name, so aliases resolve for free. + if (!hasNode() && !NODE_FREE_COMMANDS.has(actionCommand.name())) { + throw new Error( + `No Ocean Node set. Run \`setNode \` first ` + + `(available now: ${[...NODE_FREE_COMMANDS].join(", ")}).` + ); + } + }); + // Custom help command to support legacy "h" invocation. // Note: We use console.log(program.helpInformation()) to print the full help output. program @@ -194,6 +187,96 @@ export async function createCLI() { console.log(program.helpInformation()); }); + // setNode command. The switch itself never touches the RPC/signer: choosing a node is + // independent of them and must work even when the RPC is slow or wrong. The RPC is + // consulted only afterwards, under a timeout, to warn about a chain mismatch. + program + .command("setNode") + .alias("useNode") + .description( + "Sets / switches the Ocean Node used by subsequent commands, without restarting" + ) + .argument("", "HTTP(S) URL, peer id or full multiaddr of the node") + .option("-n, --node ", "Ocean Node to use") + .action(async (nodeUrl, options) => { + const target = options.node || nodeUrl; + const previous = getCurrentNodeUrl(); + if (target === previous) { + console.log(chalk.green(`Node ${target} is already the active one.`)); + return; + } + + const status = await validateNode(target); + if (!status) { + console.error( + chalk.red( + previous + ? `Cannot reach ${target}. Keeping current node: ${previous}` + : `Cannot reach ${target}. Still no node set.` + ) + ); + return; + } + + setCurrentNodeUrl(target); + console.log( + chalk.green(`Using node: ${target} (version ${status.version})`) + ); + + // chainId comes from RPC, not from the node, so the two can disagree. The switch + // is already committed at this point, so this is a courtesy warning only — bound + // it so an unresponsive RPC cannot leave the command hanging. + const chainIds = nodeChainIds(status); + if (chainIds.length > 0) { + let timer: NodeJS.Timeout | undefined; + try { + const { chainId } = await Promise.race([ + initializeSigner(), + new Promise((_resolve, reject) => { + timer = setTimeout(() => reject(new Error("RPC timeout")), 5000); + }), + ]); + if (!chainIds.includes(String(chainId))) { + console.log( + chalk.yellow( + `Warning: this node serves chain(s) ${chainIds.join(", ")} but RPC is on chain ${chainId}. Commands may fail.` + ) + ); + } + } catch { + // A bad/slow RPC must not make a successful node switch look like a failure. + } finally { + // Leaving the loser pending would keep the event loop alive for 5s. + clearTimeout(timer); + } + } + }); + + // getNode command + program + .command("getNode") + .alias("currentNode") + .description("Shows the Ocean Node currently in use") + .action(async () => { + const current = getCurrentNodeUrl(); + if (!current) { + console.log( + chalk.yellow("No Ocean Node set. Run `setNode ` to pick one.") + ); + return; + } + console.log(`Current Ocean Node: ${current}`); + // Best effort: a node that is down must not fail the command. + const status = await validateNode(current); + if (status) { + console.log( + `Version: ${status.version}, chain(s): ${nodeChainIds(status).join(", ") || "none"}` + ); + } else { + console.log(chalk.yellow("Node is not reachable right now.")); + } + }); + // getDDO command program .command("getDDO") diff --git a/src/index.ts b/src/index.ts index c26bf759..32dc421e 100644 --- a/src/index.ts +++ b/src/index.ts @@ -5,6 +5,7 @@ import chalk from "chalk"; import { stdin as input, stdout as output } from "node:process"; import { createInterface } from "readline/promises"; import { createCLI } from './cli.js'; +import { stopP2P } from './nodeConnection.js'; let program: Command const supportedCommands: string[] = [] @@ -173,13 +174,31 @@ async function runLoop(): Promise { } } +/** + * Wait until everything written to stdout/stderr has actually been handed over, so a + * forced process.exit() cannot truncate it. Writing an empty chunk queues the callback + * behind any pending writes on the stream. + */ +async function flushOutput(): Promise { + await Promise.all( + [process.stdout, process.stderr].map( + (stream) => + new Promise((resolve) => { + if (stream.writableLength === 0) return resolve() + stream.write("", () => resolve()) + }) + ) + ) +} + async function main(): Promise { try { program = await createCLI(); for (const command of program.commands) { supportedCommands.push(command.name()) - const alias = command.alias() - if (alias) supportedCommands.push(alias) + // aliases() (plural): alias() would only ever return the first one. + const aliases = command.aliases() + supportedCommands.push(...aliases) } // Handle help/version flags without initializing a signer, and exit so @@ -226,6 +245,17 @@ async function main(): Promise { } catch (error) { console.error(chalk.red(`Program Error: ${error.message}`)); process.exit(1); + } finally { + // Once libp2p has started the process can no longer end on its own: stopping + // it cleanly still leaves a MessagePort holding the event loop open. So stop + // it and, if it had been running, exit explicitly — after draining stdout, + // since a piped stdout (tests, scripts) can still hold buffered output that + // process.exit() would discard. Covers every path out of the try above; the + // process.exit(1) in the catch terminates immediately and needs no cleanup. + if (await stopP2P()) { + await flushOutput() + process.exit(process.exitCode ?? 0) + } } } diff --git a/src/nodeConnection.ts b/src/nodeConnection.ts new file mode 100644 index 00000000..fcf93eda --- /dev/null +++ b/src/nodeConnection.ts @@ -0,0 +1,224 @@ +import chalk from "chalk"; +import { ProviderInstance, isP2pUri, NodeStatus } from "@oceanprotocol/lib"; + +/** + * Ocean Node selection and libp2p transport lifecycle. + * + * The active node lives in `process.env.NODE_URL`, which stays the single source of + * truth: `Commands` (its constructor) and `getMetadataURI()` re-read that variable on + * every use, so mutating it switches every subsequent command with no other wiring. + * + * libp2p is *transport*, not a connection to one node: every P2P call in ocean.js takes + * a `nodeUri` and dials that peer on demand (direct dial for a full multiaddr, DHT + * lookup for a bare peer id). So one libp2p node serves any number of Ocean nodes and + * switching between them never restarts or stops it. + */ + +// Default Ocean bootstrap nodes (must be included explicitly since passing +// bootstrapPeers to setupP2P replaces the built-in defaults) +const OCEAN_BOOTSTRAP_PEERS = [ + "/dns4/bootstrap1.oncompute.ai/tcp/9001/ws/p2p/16Uiu2HAmLhRDqfufZiQnxvQs2XHhd6hwkLSPfjAQg1gH8wgRixiP", + "/dns4/bootstrap2.oncompute.ai/tcp/9001/ws/p2p/16Uiu2HAmHwzeVw7RpGopjZe6qNBJbzDDBdqtrSk7Gcx1emYsfgL4", + "/dns4/bootstrap3.oncompute.ai/tcp/9001/ws/p2p/16Uiu2HAmBKSeEP3v4tYEPsZsZv9VELinyMCsrVTJW9BvQeFXx28U", + "/dns4/bootstrap4.oncompute.ai/tcp/9001/ws/p2p/16Uiu2HAmSTVTArioKm2wVcyeASHYEsnx2ZNq467Z4GMDU4ErEPom", +]; + +// A plain HTTP request to a node is quick; a P2P dial may need a DHT lookup first +// (ocean.js defaults dhtLookupTimeout to 60s), so it gets a longer leash. +const HTTP_STATUS_TIMEOUT_MS = 10_000; +const P2P_STATUS_TIMEOUT_MS = 30_000; + +let p2pReady: Promise | null = null; +let p2pFailure: Error | null = null; + +function p2pDisabled(): boolean { + return process.env.DISABLE_P2P === "true"; +} + +/** True when the given URI is a full multiaddr (as opposed to a bare peer id). */ +function isFullMultiaddr(nodeUrl: string): boolean { + return nodeUrl.startsWith("/") && nodeUrl.includes("/p2p/"); +} + +/** + * Bootstrap peers for the libp2p node: the initial node (so a local node given as a + * bare peer id is dialable via the localhost convention), any BOOTSTRAP_PEERS, and the + * Ocean defaults. + */ +function buildBootstrapPeers(initialNodeUrl?: string): string[] { + const extra = process.env.BOOTSTRAP_PEERS?.split(",").filter(Boolean) || []; + const localPeer = + initialNodeUrl && isP2pUri(initialNodeUrl) + ? isFullMultiaddr(initialNodeUrl) + ? [initialNodeUrl] + : [`/ip4/127.0.0.1/tcp/9001/ws/p2p/${initialNodeUrl}`] + : []; + return [...localPeer, ...extra, ...OCEAN_BOOTSTRAP_PEERS]; +} + +/** + * Start the shared libp2p node. Called once at startup and deliberately *not* awaited: + * connecting to bootstrap peers and warming the DHT takes seconds, and that should + * happen while the user reads the prompt rather than on their first P2P command. Any + * P2P-bound path awaits `ensureP2PReady()` before dialing. + * + * No-op when DISABLE_P2P=true or when libp2p is already up. + */ +export function startP2P(initialNodeUrl?: string): void { + if (p2pDisabled() || p2pReady) return; + if (ProviderInstance.getLibp2pNode()) { + p2pReady = Promise.resolve(); + return; + } + + const bootstrapPeers = buildBootstrapPeers(initialNodeUrl); + console.log( + chalk.cyan(`Starting libp2p (${bootstrapPeers.length} bootstrap peers)...`) + ); + + // The promise is stored, not awaited, so it MUST swallow its own rejection here: + // an unhandled rejection on a fire-and-forget promise would take the process down. + // The failure is remembered and re-surfaced to whoever awaits ensureP2PReady(). + p2pReady = ProviderInstance.setupP2P({ + bootstrapPeers, + libp2p: { + connectionGater: { + // Allow localhost connections / local nodes + denyDialMultiaddr: () => false, + }, + }, + } as any).then( + () => { + console.log(chalk.cyan("libp2p node started.")); + }, + (error) => { + p2pFailure = error instanceof Error ? error : new Error(String(error)); + console.error( + chalk.yellow(`libp2p failed to start: ${p2pFailure.message}`) + ); + } + ); +} + +/** + * Await the shared libp2p node before making a P2P call. Throws with a clear reason + * when P2P is unavailable, so callers can report it instead of timing out. + */ +export async function ensureP2PReady(): Promise { + if (p2pDisabled()) { + throw new Error("P2P transport is disabled (DISABLE_P2P=true)"); + } + // Pass the active node so a lazy start (one-shot run against a P2P node) still gets + // the localhost multiaddr for a bare peer id in its bootstrap list — without it a + // node on this machine could only be found through the DHT. + if (!p2pReady) startP2P(getCurrentNodeUrl()); + await p2pReady; + if (p2pFailure) { + throw new Error(`libp2p is not running: ${p2pFailure.message}`); + } +} + +/** + * Stop the shared libp2p node when the CLI is finished (see index.ts). + * + * Returns true when libp2p had been started, because stopping it is *not* enough to + * let the process end: it leaves a `MessagePort` behind that keeps the event loop + * alive even after a clean `stop()` (verified with `process.getActiveResourcesInfo()` + * — `stop()` itself completes in ~2ms and reports status "stopped"). The caller must + * therefore exit explicitly when this returns true. + */ +export async function stopP2P(waitForStartMs = 15_000): Promise { + const pending = p2pReady; + p2pReady = null; + if (!pending && !ProviderInstance.getLibp2pNode()) return false; + + if (pending) { + // A start still in flight has no node to stop yet, and stopping "nothing" would + // leave it to come up *after* cleanup and hold the process open forever. So wait + // for it — but boundedly, since a start dialing unreachable bootstrap peers must + // not stall exit. (startP2P's promise handles its own rejection, so this is safe + // to await.) + let timer: NodeJS.Timeout | undefined; + await Promise.race([ + pending, + new Promise((resolve) => { + timer = setTimeout(resolve, waitForStartMs); + }), + ]); + clearTimeout(timer); + // Belt and braces for the timed-out case: stop whatever the start eventually + // produces, so a slow start delays exit instead of preventing it. + pending + .then(() => ProviderInstance.getLibp2pNode()?.stop()) + .catch(() => undefined); + } + + const node = ProviderInstance.getLibp2pNode(); + if (node) { + try { + await node.stop(); + } catch (error) { + // Shutting down is best effort — never turn it into a command failure. + console.error( + chalk.yellow(`libp2p did not stop cleanly: ${error?.message ?? error}`) + ); + } + } + return true; +} + +/** The active Ocean Node, or "" when none has been set yet. */ +export function getCurrentNodeUrl(): string { + return process.env.NODE_URL || ""; +} + +/** Make `nodeUrl` the active Ocean Node for every subsequent command. */ +export function setCurrentNodeUrl(nodeUrl: string): void { + process.env.NODE_URL = nodeUrl; +} + +/** Whether a node is currently selected (gates most commands, see cli.ts). */ +export function hasNode(): boolean { + return getCurrentNodeUrl().length > 0; +} + +/** + * Health-check a candidate node without touching any existing state. Over HTTP this is + * a plain status request; over P2P the on-demand dial *is* the reachability check. + * Returns the node status (for display), or null when the node cannot be reached. + */ +export async function validateNode( + nodeUrl: string +): Promise { + try { + let timeout = HTTP_STATUS_TIMEOUT_MS; + if (isP2pUri(nodeUrl)) { + await ensureP2PReady(); + timeout = P2P_STATUS_TIMEOUT_MS; + if (!isFullMultiaddr(nodeUrl)) { + console.log(chalk.cyan(`Looking up peer ${nodeUrl.slice(0, 12)}...`)); + } + } + const status = await ProviderInstance.getNodeStatus( + nodeUrl, + AbortSignal.timeout(timeout) + ); + return status || null; + } catch (error) { + console.error( + chalk.yellow( + `Could not get status of ${nodeUrl}: ${error?.message ?? error}` + ) + ); + return null; + } +} + +/** Chain ids the node serves, as reported by its status (provider + indexer). */ +export function nodeChainIds(status: NodeStatus): string[] { + const ids = [ + ...(status.provider || []).map((p) => String(p.chainId)), + ...(status.indexer || []).map((i) => String(i.chainId)), + ]; + return [...new Set(ids)]; +} diff --git a/test/replMenu.test.ts b/test/replMenu.test.ts index decfc756..28dcf575 100644 --- a/test/replMenu.test.ts +++ b/test/replMenu.test.ts @@ -1,53 +1,5 @@ import { expect } from "chai"; -import { spawn } from "child_process"; -import path from "path"; -import { dirname } from "path"; -import { fileURLToPath } from "url"; - -const __filename = fileURLToPath(import.meta.url); -const __dirname = dirname(__filename); -const projectRoot = path.resolve(__dirname, ".."); - -// Recurring prompt string emitted by the REPL (keep in sync with src/index.ts). -const PROMPT = "Enter command ('exit' | 'quit' | ESC or CTRL-C to terminate):\n"; - -/** - * Drive the interactive REPL (menu mode) with piped stdin. - * - * These tests are infra-free: PRIVATE_KEY/RPC/NODE_URL point at an unreachable - * port, so a command that actually parses and runs surfaces a "Command error" - * (connection refused) while a command that is dropped or rejected at parse time - * does not. AVOID_LOOP_RUN is left unset so the process enters the REPL loop. - */ -function runRepl( - inputLines: string[], - extraArgs: string[] = [] -): Promise<{ output: string; code: number | null }> { - return new Promise((resolve, reject) => { - const env = { ...process.env }; - delete env.AVOID_LOOP_RUN; - env.PRIVATE_KEY = - "0x1d751ded5a32226054cd2e71261039b65afb9ee1c746d055dd699b1150a5befc"; - env.RPC = "http://127.0.0.1:1"; - env.NODE_URL = "http://127.0.0.1:1"; - - const child = spawn("npx", ["tsx", "src/index.ts", ...extraArgs], { - cwd: projectRoot, - env, - }); - - let output = ""; - child.stdout.on("data", (d) => (output += d.toString())); - child.stderr.on("data", (d) => (output += d.toString())); - child.on("error", reject); - child.on("close", (code) => resolve({ output, code })); - - for (const line of inputLines) { - child.stdin.write(line + "\n"); - } - child.stdin.end(); - }); -} +import { REPL_PROMPT as PROMPT, runRepl } from "./util.js"; describe("Ocean CLI interactive menu (REPL)", function () { this.timeout(60000); diff --git a/test/setNode.test.ts b/test/setNode.test.ts new file mode 100644 index 00000000..91bb267b --- /dev/null +++ b/test/setNode.test.ts @@ -0,0 +1,135 @@ +import { expect } from "chai"; +import { runRepl } from "./util.js"; + +// The Ocean Node exposed by Barge over HTTP. Hardcoded (as in http.test.ts) so these +// tests behave identically on both CI transport legs: the p2p leg only changes the +// NODE_URL env, the node's HTTP interface is up either way. +const LIVE_NODE = "http://127.0.0.1:8001"; + +describe("Ocean CLI node selection", function () { + this.timeout(120000); + + describe("with no NODE_URL set (no infra needed)", function () { + it("starts anyway and says which commands are available", async function () { + const { output, code } = await runRepl(["exit"], { + env: { NODE_URL: undefined }, + }); + expect(output).to.contain("No Ocean Node configured"); + expect(output).to.contain("setNode"); + expect(code).to.equal(0); + }); + + it("refuses a command that needs a node, without running it", async function () { + const { output } = await runRepl(["getComputeEnvironments", "exit"], { + env: { NODE_URL: undefined }, + }); + expect(output).to.contain("No Ocean Node set"); + // The Commands constructor logs this line, so its absence proves the gate + // fired before the action body ran (rather than the action failing later). + expect(output).to.not.contain("Using Ocean Node URL"); + expect(output).to.not.contain("Invalid option"); + }); + + it("still allows help and getNode", async function () { + const { output } = await runRepl(["help", "getNode", "exit"], { + env: { NODE_URL: undefined }, + }); + expect(output).to.contain("Usage: ocean-cli"); + // Both new commands must be discoverable from the menu. + expect(output).to.contain("setNode"); + expect(output).to.contain("getNode"); + expect(output).to.contain("No Ocean Node set"); + }); + + it("keeps the CLI node-less when setNode cannot reach the node", async function () { + const { output } = await runRepl( + ["setNode http://127.0.0.1:1", "getComputeEnvironments", "exit"], + { env: { NODE_URL: undefined } } + ); + expect(output).to.contain("Still no node set"); + // The gate is still closed: no half-switch. + expect(output).to.contain("No Ocean Node set"); + expect(output).to.not.contain("Using Ocean Node URL"); + }); + + it("accepts the useNode alias", async function () { + const { output } = await runRepl(["useNode http://127.0.0.1:1", "exit"], { + env: { NODE_URL: undefined }, + }); + expect(output).to.not.contain("Invalid option"); + expect(output).to.contain("Cannot reach"); + }); + }); + + describe("with an unreachable NODE_URL set (no infra needed)", function () { + it("does not gate commands — they run and fail at the network", async function () { + const { output } = await runRepl(["getComputeEnvironments", "exit"]); + expect(output).to.not.contain("No Ocean Node set"); + expect(output).to.contain("Command error"); + }); + }); + + describe("libp2p lifecycle (no infra needed)", function () { + it("still exits when libp2p has been started", async function () { + // Regression guard: libp2p is started eagerly in loop mode, and a started + // libp2p node keeps the event loop alive — even after a clean stop() it leaves + // a MessagePort behind. Without the explicit shutdown+exit in index.ts the CLI + // hangs forever here instead of returning to the shell. + const { code } = await runRepl(["exit"], { + env: { DISABLE_P2P: undefined }, + }); + expect(code).to.equal(0); + }); + + it("does not start libp2p for a one-shot HTTP run", async function () { + // One-shot has no later command to warm up for, so paying the libp2p + // startup/shutdown cost would only slow every scripted invocation down. + const { output } = await runRepl([], { + extraArgs: ["getNode"], + env: { DISABLE_P2P: undefined, AVOID_LOOP_RUN: "true" }, + }); + expect(output).to.not.contain("Starting libp2p"); + }); + }); + + describe("against a running node (requires Barge)", function () { + it("reports the startup node and its version", async function () { + const { output } = await runRepl(["getNode", "exit"], { + env: { NODE_URL: LIVE_NODE }, + }); + expect(output).to.contain(`Current Ocean Node: ${LIVE_NODE}`); + expect(output).to.contain("Version:"); + }); + + it("switches from no node to a live node, opening the gate", async function () { + const { output } = await runRepl( + [`setNode ${LIVE_NODE}`, "getNode", "getComputeEnvironments", "exit"], + { env: { NODE_URL: undefined } } + ); + expect(output).to.contain(`Using node: ${LIVE_NODE}`); + expect(output).to.contain(`Current Ocean Node: ${LIVE_NODE}`); + // The gate opened: the action ran (its constructor logged the node) and the + // command was not refused. + expect(output).to.contain("Using Ocean Node URL"); + expect(output).to.not.contain("No Ocean Node set"); + }); + + it("recognises a switch to the node already in use", async function () { + const { output } = await runRepl([`setNode ${LIVE_NODE}`, "exit"], { + env: { NODE_URL: LIVE_NODE }, + }); + expect(output).to.contain("already the active one"); + }); + + it("keeps the current node when the new one is unreachable", async function () { + const { output } = await runRepl( + ["setNode http://127.0.0.1:9999", "getNode", "getComputeEnvironments", "exit"], + { env: { NODE_URL: LIVE_NODE } } + ); + expect(output).to.contain(`Keeping current node: ${LIVE_NODE}`); + expect(output).to.contain(`Current Ocean Node: ${LIVE_NODE}`); + // A real command still works against the original node. + expect(output).to.contain(`Using Ocean Node URL : ${LIVE_NODE}`); + }); + }); +}); diff --git a/test/util.ts b/test/util.ts index d830ecb7..d61350db 100644 --- a/test/util.ts +++ b/test/util.ts @@ -1,4 +1,4 @@ -import { exec } from "child_process"; +import { exec, spawn } from "child_process"; import path from "path"; import util from "util"; @@ -41,4 +41,65 @@ export const runCommandAs = async ( console.error(`[ERROR]:\n${error.stderr || error.message}`); throw error; } +}; + +/** Recurring prompt string emitted by the REPL (keep in sync with src/index.ts). */ +export const REPL_PROMPT = + "Enter command ('exit' | 'quit' | ESC or CTRL-C to terminate):\n"; + +export interface RunReplOptions { + /** Extra argv for the initial command run before the loop starts. */ + extraArgs?: string[]; + /** + * Env overrides applied on top of the defaults. A key set to undefined is + * deleted, which is how a test starts the CLI with no NODE_URL at all. + */ + env?: Record; +} + +/** + * Drive the interactive REPL (menu mode) with piped stdin. + * + * The defaults are infra-free: PRIVATE_KEY/RPC/NODE_URL point at an unreachable + * port, so a command that actually parses and runs surfaces a "Command error" + * (connection refused) while a command that is dropped, rejected at parse time or + * refused by the node gate does not. AVOID_LOOP_RUN is unset so the process enters + * the REPL loop. + */ +export const runRepl = ( + inputLines: string[], + options: RunReplOptions = {} +): Promise<{ output: string; code: number | null }> => { + return new Promise((resolve, reject) => { + const env: Record = { ...process.env }; + delete env.AVOID_LOOP_RUN; + env.PRIVATE_KEY = + "0x1d751ded5a32226054cd2e71261039b65afb9ee1c746d055dd699b1150a5befc"; + env.RPC = "http://127.0.0.1:1"; + env.NODE_URL = "http://127.0.0.1:1"; + // These tests must not dial the public Ocean bootstrap nodes. + env.DISABLE_P2P = "true"; + + for (const [key, value] of Object.entries(options.env || {})) { + if (value === undefined) delete env[key]; + else env[key] = value; + } + + const child = spawn( + "npx", + ["tsx", "src/index.ts", ...(options.extraArgs || [])], + { cwd: projectRoot, env } + ); + + let output = ""; + child.stdout.on("data", (d) => (output += d.toString())); + child.stderr.on("data", (d) => (output += d.toString())); + child.on("error", reject); + child.on("close", (code) => resolve({ output, code })); + + for (const line of inputLines) { + child.stdin.write(line + "\n"); + } + child.stdin.end(); + }); }; \ No newline at end of file From d37b2129fd383b16170068588b355fa489d6b4d8 Mon Sep 17 00:00:00 2001 From: alexcos20 Date: Thu, 6 Aug 2026 13:02:17 +0300 Subject: [PATCH 11/13] fix --- test/setNode.test.ts | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/test/setNode.test.ts b/test/setNode.test.ts index 91bb267b..3e5d8e19 100644 --- a/test/setNode.test.ts +++ b/test/setNode.test.ts @@ -24,10 +24,12 @@ describe("Ocean CLI node selection", function () { env: { NODE_URL: undefined }, }); expect(output).to.contain("No Ocean Node set"); - // The Commands constructor logs this line, so its absence proves the gate - // fired before the action body ran (rather than the action failing later). - expect(output).to.not.contain("Using Ocean Node URL"); + // The refusal must come from the gate, not from the command being unknown. expect(output).to.not.contain("Invalid option"); + // "Using Ocean Node URL" is logged by the Commands constructor, so the action + // body clearly never ran. (Weak on its own — runRepl's RPC is unreachable, so a + // command that got past the gate would die before that log too.) + expect(output).to.not.contain("Using Ocean Node URL"); }); it("still allows help and getNode", async function () { @@ -108,9 +110,9 @@ describe("Ocean CLI node selection", function () { ); expect(output).to.contain(`Using node: ${LIVE_NODE}`); expect(output).to.contain(`Current Ocean Node: ${LIVE_NODE}`); - // The gate opened: the action ran (its constructor logged the node) and the - // command was not refused. - expect(output).to.contain("Using Ocean Node URL"); + // The gate opened: the command that follows the switch is no longer refused. + // (It still fails further on — runRepl points RPC at an unreachable port — so + // this cannot assert anything the action itself would print.) expect(output).to.not.contain("No Ocean Node set"); }); @@ -123,13 +125,11 @@ describe("Ocean CLI node selection", function () { it("keeps the current node when the new one is unreachable", async function () { const { output } = await runRepl( - ["setNode http://127.0.0.1:9999", "getNode", "getComputeEnvironments", "exit"], + ["setNode http://127.0.0.1:9999", "getNode", "exit"], { env: { NODE_URL: LIVE_NODE } } ); expect(output).to.contain(`Keeping current node: ${LIVE_NODE}`); expect(output).to.contain(`Current Ocean Node: ${LIVE_NODE}`); - // A real command still works against the original node. - expect(output).to.contain(`Using Ocean Node URL : ${LIVE_NODE}`); }); }); }); From e40a4cb8f73c7a8d43431a72a92e1f6a871feb9a Mon Sep 17 00:00:00 2001 From: alexcos20 Date: Thu, 6 Aug 2026 13:16:07 +0300 Subject: [PATCH 12/13] fix review --- README.md | 2 +- src/index.ts | 10 ++++++++-- 2 files changed, 9 insertions(+), 3 deletions(-) diff --git a/README.md b/README.md index 4248f0e3..dda87c14 100644 --- a/README.md +++ b/README.md @@ -101,7 +101,7 @@ npm run cli # starts with no node You can switch node at any time with [`setNode`](#setnode) without restarting the CLI. See [`getNode`](#getnode) to check which node is active. -- Optional, set DISABLE_P2P to `'true'` to skip starting the libp2p transport. By default the CLI starts libp2p at startup (in the background, so it does not delay the prompt) even when `NODE_URL` is an HTTP URL, so that a later switch to a P2P node does not have to wait for bootstrap peers and DHT warm-up. Set this when you only ever use HTTP nodes and do not want the CLI dialing the public Ocean bootstrap nodes. +- Optional, set DISABLE_P2P to `'true'` to skip starting the libp2p transport. In interactive mode the CLI starts libp2p at startup (in the background, so it does not delay the prompt) even when `NODE_URL` is an HTTP URL, so that a later switch to a P2P node does not have to wait for bootstrap peers and DHT warm-up. One-shot runs (`AVOID_LOOP_RUN='true'`) skip that warm-up — they have no later command to benefit from it — and start libp2p only when the node they target is a P2P one. Set this when you only ever use HTTP nodes and do not want the CLI dialing the public Ocean bootstrap nodes. ```bash export DISABLE_P2P='true' diff --git a/src/index.ts b/src/index.ts index 32dc421e..aca3ece0 100644 --- a/src/index.ts +++ b/src/index.ts @@ -244,14 +244,20 @@ async function main(): Promise { } catch (error) { console.error(chalk.red(`Program Error: ${error.message}`)); + // Flush before exiting: process.exit() discards whatever a piped stdout/stderr + // still has buffered, which could swallow the message just written. Exiting + // here (rather than falling through to the finally) keeps failures immediate — + // the process is going away, so libp2p needs no orderly shutdown. + await flushOutput() process.exit(1); } finally { // Once libp2p has started the process can no longer end on its own: stopping // it cleanly still leaves a MessagePort holding the event loop open. So stop // it and, if it had been running, exit explicitly — after draining stdout, // since a piped stdout (tests, scripts) can still hold buffered output that - // process.exit() would discard. Covers every path out of the try above; the - // process.exit(1) in the catch terminates immediately and needs no cleanup. + // process.exit() would discard. Reached on every non-throwing path out of the + // try above; when nothing was started, Node exits on its own and drains the + // streams as part of that. if (await stopP2P()) { await flushOutput() process.exit(process.exitCode ?? 0) From df66ae33ac671574a8761703b443a1ae018e5f50 Mon Sep 17 00:00:00 2001 From: alexcos20 Date: Thu, 6 Aug 2026 13:28:49 +0300 Subject: [PATCH 13/13] fix review --- CLAUDE.md | 2 +- src/nodeConnection.ts | 13 +++++++++++-- 2 files changed, 12 insertions(+), 3 deletions(-) diff --git a/CLAUDE.md b/CLAUDE.md index eba2756d..7091aac6 100755 --- a/CLAUDE.md +++ b/CLAUDE.md @@ -165,7 +165,7 @@ All node lifecycle logic lives in `nodeConnection.ts`; `cli.ts` only calls into **libp2p is transport, not a connection to one node.** Every ocean.js P2P call takes a `nodeUri` and dials that peer on demand (direct dial for a full multiaddr, DHT lookup for a bare peer id), so one libp2p node serves any number of Ocean nodes and switching between them never restarts or stops it. -- `startP2P(initialNodeUrl?)` — called **once at startup for every invocation** (not lazily, and not only for P2P `NODE_URL`s), because bootstrap dials + DHT warm-up take seconds and should overlap with the user reading the prompt. It is **deliberately not awaited**; the stored promise swallows its own rejection (an unhandled rejection on a fire-and-forget promise would kill the process) and remembers the failure for `ensureP2PReady()`. No-op when `DISABLE_P2P=true` or when `ProviderInstance.getLibp2pNode()` is already non-null. Bootstrap peers = the initial node if it is a P2P URI (bare peer ids get the `/ip4/127.0.0.1/tcp/9001/ws/p2p/` localhost convention) + `BOOTSTRAP_PEERS` + four hard-coded Ocean bootstrap nodes (passing `bootstrapPeers` **replaces** the lib's defaults, so they must be listed explicitly). +- `startP2P(initialNodeUrl?)` — called **once at startup**, not lazily and not only for P2P `NODE_URL`s, because bootstrap dials + DHT warm-up take seconds and should overlap with the user reading the prompt. The one exception is one-shot mode (`AVOID_LOOP_RUN="true"`), where `cli.ts` skips it — there is no later command to warm up for (see the exit note at the end of this section). It is **deliberately not awaited**; the stored promise swallows its own rejection (an unhandled rejection on a fire-and-forget promise would kill the process) and remembers the failure for `ensureP2PReady()`. No-op when `DISABLE_P2P=true` or when `ProviderInstance.getLibp2pNode()` is already non-null. Bootstrap peers = the initial node if it is a P2P URI (bare peer ids get the `/ip4/127.0.0.1/tcp/9001/ws/p2p/` localhost convention) + `BOOTSTRAP_PEERS` + four hard-coded Ocean bootstrap nodes (passing `bootstrapPeers` **replaces** the lib's defaults, so they must be listed explicitly). - `ensureP2PReady()` — awaited by every P2P-bound path; throws a clear reason instead of hanging when P2P is unavailable. - `validateNode(url)` — non-destructive health check via `ProviderInstance.getNodeStatus` under an `AbortSignal.timeout` (10 s HTTP, 30 s P2P since a bare peer id may need a DHT lookup). Over P2P the on-demand dial *is* the reachability check, which is what the old 20 s wait-for-target-peer polling loop did — that loop is gone. - `getCurrentNodeUrl()` / `setCurrentNodeUrl()` / `hasNode()` — `process.env.NODE_URL` stays the **single source of truth**, so switching node is just mutating it: `Commands`' constructor and `getMetadataURI()` re-read it per use. diff --git a/src/nodeConnection.ts b/src/nodeConnection.ts index fcf93eda..0321798d 100644 --- a/src/nodeConnection.ts +++ b/src/nodeConnection.ts @@ -216,9 +216,18 @@ export async function validateNode( /** Chain ids the node serves, as reported by its status (provider + indexer). */ export function nodeChainIds(status: NodeStatus): string[] { + // Drop entries with no chainId before stringifying: String(undefined) would put the + // literal "undefined" in the list, which then shows up in getNode output and in the + // mismatch warning — and would make the list look non-empty when it holds no real ids. const ids = [ - ...(status.provider || []).map((p) => String(p.chainId)), - ...(status.indexer || []).map((i) => String(i.chainId)), + ...(status.provider || []) + .map((p) => p.chainId) + .filter(Boolean) + .map(String), + ...(status.indexer || []) + .map((i) => i.chainId) + .filter(Boolean) + .map(String), ]; return [...new Set(ids)]; }